From e9b81f6e33992ddd2e6ce699a4a754821e877921 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 18:09:42 +0800 Subject: [PATCH] remove serwb DRTIO is a better solution --- artiq/firmware/libboard_artiq/lib.rs | 2 - artiq/firmware/libboard_artiq/serwb.rs | 138 ---- artiq/firmware/runtime/main.rs | 2 - artiq/firmware/satman/main.rs | 4 - artiq/gateware/remote_csr.py | 47 -- artiq/gateware/serwb/__init__.py | 1 - artiq/gateware/serwb/core.py | 37 - artiq/gateware/serwb/datapath.py | 200 ----- artiq/gateware/serwb/etherbone.py | 741 ------------------- artiq/gateware/serwb/genphy.py | 346 --------- artiq/gateware/serwb/kuserdes.py | 149 ---- artiq/gateware/serwb/packet.py | 173 ----- artiq/gateware/serwb/phy.py | 381 ---------- artiq/gateware/serwb/s7serdes.py | 160 ---- artiq/gateware/serwb/scrambler.py | 89 --- artiq/gateware/targets/sayma_amc.py | 54 +- artiq/gateware/test/serwb/__init__.py | 0 artiq/gateware/test/serwb/test_serwb_core.py | 158 ---- artiq/gateware/test/serwb/test_serwb_init.py | 144 ---- 19 files changed, 11 insertions(+), 2815 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/serwb.rs delete mode 100644 artiq/gateware/remote_csr.py delete mode 100644 artiq/gateware/serwb/__init__.py delete mode 100644 artiq/gateware/serwb/core.py delete mode 100644 artiq/gateware/serwb/datapath.py delete mode 100644 artiq/gateware/serwb/etherbone.py delete mode 100644 artiq/gateware/serwb/genphy.py delete mode 100644 artiq/gateware/serwb/kuserdes.py delete mode 100644 artiq/gateware/serwb/packet.py delete mode 100644 artiq/gateware/serwb/phy.py delete mode 100644 artiq/gateware/serwb/s7serdes.py delete mode 100644 artiq/gateware/serwb/scrambler.py delete mode 100644 artiq/gateware/test/serwb/__init__.py delete mode 100644 artiq/gateware/test/serwb/test_serwb_core.py delete mode 100644 artiq/gateware/test/serwb/test_serwb_init.py diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 697afed3b..241002879 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -34,8 +34,6 @@ pub mod i2c_eeprom; #[cfg(has_slave_fpga_cfg)] pub mod slave_fpga; -#[cfg(has_serwb_phy_amc)] -pub mod serwb; #[cfg(has_hmc830_7043)] pub mod hmc830_7043; #[cfg(has_ad9154)] diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs deleted file mode 100644 index 7f9d750a0..000000000 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ /dev/null @@ -1,138 +0,0 @@ -use core::{cmp, str}; -use board_misoc::{csr, clock}; - -fn debug_print(rtm: bool) { - debug!("AMC serwb settings:"); - debug!(" bitslip: {}", unsafe { csr::serwb_phy_amc::control_bitslip_read() }); - debug!(" ready: {}", unsafe { csr::serwb_phy_amc::control_ready_read() }); - debug!(" error: {}", unsafe { csr::serwb_phy_amc::control_error_read() }); - - if rtm { - debug!("RTM serwb settings:"); - debug!(" bitslip: {}", unsafe { csr::serwb_phy_rtm::control_bitslip_read() }); - debug!(" ready: {}", unsafe { csr::serwb_phy_rtm::control_ready_read() }); - debug!(" error: {}", unsafe { csr::serwb_phy_rtm::control_error_read() }); - } -} - -fn prbs_test() { - let prbs_test_cycles : u32 = 1<<22; - // 40 bits @125MHz linerate - let prbs_test_us : u64 = ((prbs_test_cycles as u64)*40)/125; - - info!("RTM to AMC link test..."); - unsafe { - csr::serwb_phy_amc::control_prbs_cycles_write(prbs_test_cycles); - csr::serwb_phy_amc::control_prbs_start_write(1); - } - clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% - let errors = unsafe { - csr::serwb_phy_amc::control_prbs_errors_read() - }; - if errors == 0 { - info!(" ...passed") - } else { - error!(" {} errors found", errors); - } - - info!("AMC to RTM link test..."); - unsafe { - csr::serwb_phy_rtm::control_prbs_cycles_write(prbs_test_cycles); - csr::serwb_phy_rtm::control_prbs_start_write(1); - } - clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% - let errors = unsafe { - csr::serwb_phy_rtm::control_prbs_errors_read() - }; - if errors == 0 { - info!(" ...passed"); - } else { - error!(" {} errors found", errors); - } -} - -fn magic_test() { - // Try reading the magic number register on the other side of the bridge. - let rtm_magic = unsafe { - csr::rtm_magic::magic_read() - }; - if rtm_magic != 0x5352544d { - error!("incorrect RTM magic number: 0x{:08x}", rtm_magic); - // proceed anyway - } -} - -fn prng32(seed: &mut u32) -> u32 { - *seed = 1664525 * *seed + 1013904223; - *seed -} - -fn wishbone_test() { - let test_length: u32 = 512; - let mut test_errors : u32 = 0; - - let mut seed : u32; - - info!("Wishbone test..."); - unsafe { - // Alternate pseudo random write/read bursts of - // increasing size. - for length in 0..test_length { - // Pseudo random writes - seed = length; - for _ in 0..length { - csr::rtm_scratch::write_data_write(prng32(&mut seed)); - csr::rtm_scratch::write_stb_write(1); - } - // Pseudo random reads - seed = length; - for _ in 0..length { - if csr::rtm_scratch::read_data_read() != prng32(&mut seed) { - test_errors += 1; - } - csr::rtm_scratch::read_ack_write(1); - } - } - } - if test_errors == 0 { - info!(" ...passed"); - } else { - error!(" {} errors found", test_errors); - } -} - -fn read_rtm_ident(buf: &mut [u8]) -> &str { - unsafe { - csr::rtm_identifier::address_write(0); - let len = csr::rtm_identifier::data_read(); - let len = cmp::min(len, buf.len() as u8); - for i in 0..len { - csr::rtm_identifier::address_write(1 + i); - buf[i as usize] = csr::rtm_identifier::data_read(); - } - str::from_utf8_unchecked(&buf[..len as usize]) - } -} - -pub fn wait_init() { - info!("waiting for AMC/RTM serwb bridge to be ready..."); - unsafe { - csr::serwb_phy_amc::control_reset_write(1); - while csr::serwb_phy_amc::control_ready_read() == 0 { - if csr::serwb_phy_amc::control_error_read() == 1 { - debug_print(false); - warn!("AMC/RTM serwb bridge initialization failed, retrying."); - csr::serwb_phy_amc::control_reset_write(1); - } - } - } - info!(" ...done."); - - prbs_test(); - magic_test(); - wishbone_test(); - - debug_print(true); - - info!("RTM gateware version {}", read_rtm_ident(&mut [0; 64])); -} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 61412bc6c..82f691a35 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -91,8 +91,6 @@ fn setup_log_levels() { fn sayma_hw_init() { #[cfg(has_slave_fpga_cfg)] board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); - #[cfg(has_serwb_phy_amc)] - board_artiq::serwb::wait_init(); #[cfg(has_hmc830_7043)] /* must be the first SPI init because of HMC830 SPI mode selection */ diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 180ccbcba..b71386d70 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -10,8 +10,6 @@ extern crate board_artiq; use core::convert::TryFrom; use board_misoc::{csr, irq, ident, clock, uart_logger}; use board_artiq::{i2c, spi, si5324, drtioaux}; -#[cfg(has_serwb_phy_amc)] -use board_artiq::serwb; use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; @@ -413,8 +411,6 @@ pub extern fn main() -> i32 { #[cfg(has_slave_fpga_cfg)] board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); - #[cfg(has_serwb_phy_amc)] - serwb::wait_init(); i2c::init(); si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); diff --git a/artiq/gateware/remote_csr.py b/artiq/gateware/remote_csr.py deleted file mode 100644 index ae028a9b2..000000000 --- a/artiq/gateware/remote_csr.py +++ /dev/null @@ -1,47 +0,0 @@ -from collections import OrderedDict -from operator import itemgetter -import csv - -from misoc.interconnect.csr import CSRStatus, CSRStorage - - -def _get_csr_data(csv_file): - csr_data = OrderedDict() - with open(csv_file) as csv_file_f: - csv_reader = csv.reader(csv_file_f) - for name, address, length, ro in csv_reader: - region_name, csr_name = name.split(".") - address = int(address, 0) - length = int(length, 0) - if ro == "ro": - ro = True - elif ro == "rw": - ro = False - else: - raise ValueError - if region_name not in csr_data: - csr_data[region_name] = [] - csr_data[region_name].append((csr_name, address, length, ro)) - return csr_data - - -def get_remote_csr_regions(offset, csv_file): - busword = 32 - regions = [] - for region_name, csrs_info in _get_csr_data(csv_file).items(): - csrs_info = sorted(csrs_info, key=itemgetter(1)) - origin = csrs_info[0][1] - next_address = origin - csrs = [] - for csr_name, address, length, ro in csrs_info: - if address != next_address: - raise ValueError("CSRs are not contiguous") - nr = (length + busword - 1)//busword - next_address += nr*busword//8 - if ro: - csr = CSRStatus(length, name=csr_name) - else: - csr = CSRStorage(length, name=csr_name) - csrs.append(csr) - regions.append((region_name, offset + origin, busword, csrs)) - return regions diff --git a/artiq/gateware/serwb/__init__.py b/artiq/gateware/serwb/__init__.py deleted file mode 100644 index 46938e85f..000000000 --- a/artiq/gateware/serwb/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from artiq.gateware.serwb import s7serdes, kuserdes, genphy, phy, core, packet, etherbone diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py deleted file mode 100644 index 72b4b8119..000000000 --- a/artiq/gateware/serwb/core.py +++ /dev/null @@ -1,37 +0,0 @@ -from migen import * - -from misoc.interconnect import stream - -from artiq.gateware.serwb.packet import Packetizer, Depacketizer -from artiq.gateware.serwb.etherbone import Etherbone - - -class SERWBCore(Module): - def __init__(self, phy, clk_freq, mode): - # etherbone - self.submodules.etherbone = etherbone = Etherbone(mode) - - # packetizer / depacketizer - depacketizer = Depacketizer(clk_freq) - packetizer = Packetizer() - self.submodules += depacketizer, packetizer - - # fifos - tx_fifo = stream.SyncFIFO([("data", 32)], 8, buffered=True) - rx_fifo = stream.SyncFIFO([("data", 32)], 8, buffered=True) - self.submodules += tx_fifo, rx_fifo - - # modules connection - self.comb += [ - # core --> phy - packetizer.source.connect(tx_fifo.sink), - tx_fifo.source.connect(phy.sink), - - # phy --> core - phy.source.connect(rx_fifo.sink), - rx_fifo.source.connect(depacketizer.sink), - - # etherbone <--> core - depacketizer.source.connect(etherbone.sink), - etherbone.source.connect(packetizer.sink) - ] diff --git a/artiq/gateware/serwb/datapath.py b/artiq/gateware/serwb/datapath.py deleted file mode 100644 index f91cd602f..000000000 --- a/artiq/gateware/serwb/datapath.py +++ /dev/null @@ -1,200 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler - - -def K(x, y): - return (y << 5) | x - - -class _8b10bEncoder(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) - self.source = source = stream.Endpoint([("data", 40)]) - - # # # - - encoder = CEInserter()(Encoder(4, True)) - self.submodules += encoder - - # control - self.comb += [ - source.stb.eq(sink.stb), - sink.ack.eq(source.ack), - encoder.ce.eq(source.stb & source.ack) - ] - - # datapath - for i in range(4): - self.comb += [ - encoder.k[i].eq(sink.k[i]), - encoder.d[i].eq(sink.d[8*i:8*(i+1)]), - source.data[10*i:10*(i+1)].eq(encoder.output[i]) - ] - - -class _8b10bDecoder(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("data", 40)]) - self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) - - # # # - - decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.submodules += decoders - - # control - self.comb += [ - source.stb.eq(sink.stb), - sink.ack.eq(source.ack) - ] - self.comb += [decoders[i].ce.eq(source.stb & source.ack) for i in range(4)] - - # datapath - for i in range(4): - self.comb += [ - decoders[i].input.eq(sink.data[10*i:10*(i+1)]), - source.k[i].eq(decoders[i].k), - source.d[8*i:8*(i+1)].eq(decoders[i].d) - ] - - -class _Bitslip(Module): - def __init__(self): - self.value = value = Signal(6) - self.sink = sink = stream.Endpoint([("data", 40)]) - self.source = source = stream.Endpoint([("data", 40)]) - - # # # - - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip - - # control - self.comb += [ - source.stb.eq(sink.stb), - sink.ack.eq(source.ack), - bitslip.value.eq(value), - bitslip.ce.eq(source.stb & source.ack) - ] - - # datapath - self.comb += [ - bitslip.i.eq(sink.data), - source.data.eq(bitslip.o) - ] - - -class TXDatapath(Module): - def __init__(self, phy_dw, with_scrambling=True): - self.idle = idle = Signal() - self.comma = comma = Signal() - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", phy_dw)]) - - # # # - - # scrambler - if with_scrambling: - self.submodules.scrambler = scrambler = Scrambler() - - # line coding - self.submodules.encoder = encoder = _8b10bEncoder() - - # converter - self.submodules.converter = converter = stream.Converter(40, phy_dw) - - # dataflow - if with_scrambling: - self.comb += [ - sink.connect(scrambler.sink), - If(comma, - encoder.sink.stb.eq(1), - encoder.sink.k.eq(1), - encoder.sink.d.eq(K(28,5)) - ).Else( - scrambler.source.connect(encoder.sink) - ) - ] - else: - self.comb += [ - If(comma, - encoder.sink.stb.eq(1), - encoder.sink.k.eq(1), - encoder.sink.d.eq(K(28,5)) - ).Else( - sink.connect(encoder.sink, omit={"data"}), - encoder.sink.d.eq(sink.data) - ), - ] - self.comb += [ - If(idle, - converter.sink.stb.eq(1), - converter.sink.data.eq(0) - ).Else( - encoder.source.connect(converter.sink), - ), - converter.source.connect(source) - ] - - -class RXDatapath(Module): - def __init__(self, phy_dw, with_scrambling=True): - self.bitslip_value = bitslip_value = Signal(6) - self.sink = sink = stream.Endpoint([("data", phy_dw)]) - self.source = source = stream.Endpoint([("data", 32)]) - self.idle = idle = Signal() - self.comma = comma = Signal() - - # # # - - # converter - self.submodules.converter = converter = stream.Converter(phy_dw, 40) - - # bitslip - self.submodules.bitslip = bitslip = _Bitslip() - self.comb += bitslip.value.eq(bitslip_value) - - # line coding - self.submodules.decoder = decoder = _8b10bDecoder() - - # descrambler - if with_scrambling: - self.submodules.descrambler = descrambler = Descrambler() - - # dataflow - self.comb += [ - sink.connect(converter.sink), - converter.source.connect(bitslip.sink), - bitslip.source.connect(decoder.sink) - ] - if with_scrambling: - self.comb += [ - decoder.source.connect(descrambler.sink), - descrambler.source.connect(source) - ] - else: - self.comb += [ - decoder.source.connect(source, omit={"d", "k"}), - source.data.eq(decoder.source.d) - ] - - # idle decoding - idle_timer = WaitTimer(32) - self.submodules += idle_timer - self.sync += [ - If(converter.source.stb, - idle_timer.wait.eq((converter.source.data == 0) | (converter.source.data == (2**40-1))) - ), - idle.eq(idle_timer.done) - ] - # comma decoding - self.sync += \ - If(decoder.source.stb, - comma.eq((decoder.source.k == 1) & (decoder.source.d == K(28, 5))) - ) diff --git a/artiq/gateware/serwb/etherbone.py b/artiq/gateware/serwb/etherbone.py deleted file mode 100644 index f0fcf2632..000000000 --- a/artiq/gateware/serwb/etherbone.py +++ /dev/null @@ -1,741 +0,0 @@ -""" -Etherbone - -CERN's Etherbone protocol is initially used to run a Wishbone bus over an -ethernet network. This re-implementation is meant to be run over serdes -and introduces some limitations: -- no probing (pf/pr) -- no address spaces (rca/bca/wca/wff) -- 32bits data and address -- 1 record per frame -""" - -from migen import * - -from misoc.interconnect import stream -from misoc.interconnect import wishbone - -from artiq.gateware.serwb.packet import * - - -class _Packetizer(Module): - def __init__(self, sink_description, source_description, header): - self.sink = sink = stream.Endpoint(sink_description) - self.source = source = stream.Endpoint(source_description) - self.header = Signal(header.length*8) - - # # # - - dw = len(self.sink.data) - - header_reg = Signal(header.length*8, reset_less=True) - header_words = (header.length*8)//dw - load = Signal() - shift = Signal() - counter = Signal(max=max(header_words, 2)) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - self.comb += header.encode(sink, self.header) - if header_words == 1: - self.sync += [ - If(load, - header_reg.eq(self.header) - ) - ] - else: - self.sync += [ - If(load, - header_reg.eq(self.header) - ).Elif(shift, - header_reg.eq(Cat(header_reg[dw:], Signal(dw))) - ) - ] - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - if header_words == 1: - idle_next_state = "COPY" - else: - idle_next_state = "SEND_HEADER" - - fsm.act("IDLE", - sink.ack.eq(1), - counter_reset.eq(1), - If(sink.stb, - sink.ack.eq(0), - source.stb.eq(1), - source.eop.eq(0), - source.data.eq(self.header[:dw]), - If(source.stb & source.ack, - load.eq(1), - NextState(idle_next_state) - ) - ) - ) - if header_words != 1: - fsm.act("SEND_HEADER", - source.stb.eq(1), - source.eop.eq(0), - source.data.eq(header_reg[dw:2*dw]), - If(source.stb & source.ack, - shift.eq(1), - counter_ce.eq(1), - If(counter == header_words-2, - NextState("COPY") - ) - ) - ) - if hasattr(sink, "error"): - self.comb += source.error.eq(sink.error) - fsm.act("COPY", - source.stb.eq(sink.stb), - source.eop.eq(sink.eop), - source.data.eq(sink.data), - If(source.stb & source.ack, - sink.ack.eq(1), - If(source.eop, - NextState("IDLE") - ) - ) - ) - - -class _Depacketizer(Module): - def __init__(self, sink_description, source_description, header): - self.sink = sink = stream.Endpoint(sink_description) - self.source = source = stream.Endpoint(source_description) - self.header = Signal(header.length*8) - - # # # - - dw = len(sink.data) - - header_reg = Signal(header.length*8, reset_less=True) - header_words = (header.length*8)//dw - - shift = Signal() - counter = Signal(max=max(header_words, 2)) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - if header_words == 1: - self.sync += \ - If(shift, - header_reg.eq(sink.data) - ) - else: - self.sync += \ - If(shift, - header_reg.eq(Cat(header_reg[dw:], sink.data)) - ) - self.comb += self.header.eq(header_reg) - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - if header_words == 1: - idle_next_state = "COPY" - else: - idle_next_state = "RECEIVE_HEADER" - - fsm.act("IDLE", - sink.ack.eq(1), - counter_reset.eq(1), - If(sink.stb, - shift.eq(1), - NextState(idle_next_state) - ) - ) - if header_words != 1: - fsm.act("RECEIVE_HEADER", - sink.ack.eq(1), - If(sink.stb, - counter_ce.eq(1), - shift.eq(1), - If(counter == header_words-2, - NextState("COPY") - ) - ) - ) - no_payload = Signal() - self.sync += \ - If(fsm.before_entering("COPY"), - no_payload.eq(sink.eop) - ) - - if hasattr(sink, "error"): - self.comb += source.error.eq(sink.error) - self.comb += [ - source.eop.eq(sink.eop | no_payload), - source.data.eq(sink.data), - header.decode(self.header, source) - ] - fsm.act("COPY", - sink.ack.eq(source.ack), - source.stb.eq(sink.stb | no_payload), - If(source.stb & source.ack & source.eop, - NextState("IDLE") - ) - ) - - -etherbone_magic = 0x4e6f -etherbone_version = 1 -etherbone_packet_header_length = 8 -etherbone_packet_header_fields = { - "magic": HeaderField(0, 0, 16), - - "version": HeaderField(2, 4, 4), - "nr": HeaderField(2, 2, 1), - "pr": HeaderField(2, 1, 1), # unused - "pf": HeaderField(2, 0, 1), # unused - - "addr_size": HeaderField(3, 4, 4), # static - "port_size": HeaderField(3, 0, 4) # static -} -etherbone_packet_header = Header(etherbone_packet_header_fields, - etherbone_packet_header_length, - swap_field_bytes=True) - -etherbone_record_header_length = 4 -etherbone_record_header_fields = { - "bca": HeaderField(0, 0, 1), # unused - "rca": HeaderField(0, 1, 1), # unused - "rff": HeaderField(0, 2, 1), # unused - "cyc": HeaderField(0, 4, 1), # unused - "wca": HeaderField(0, 5, 1), # unused - "wff": HeaderField(0, 6, 1), # unused - - "byte_enable": HeaderField(1, 0, 8), - - "wcount": HeaderField(2, 0, 8), - - "rcount": HeaderField(3, 0, 8) -} -etherbone_record_header = Header(etherbone_record_header_fields, - etherbone_record_header_length, - swap_field_bytes=True) - -def _remove_from_layout(layout, *args): - r = [] - for f in layout: - remove = False - for arg in args: - if f[0] == arg: - remove = True - if not remove: - r.append(f) - return r - -def etherbone_packet_description(dw): - layout = etherbone_packet_header.get_layout() - layout += [("data", dw)] - return stream.EndpointDescription(layout) - -def etherbone_packet_user_description(dw): - layout = etherbone_packet_header.get_layout() - layout = _remove_from_layout(layout, - "magic", - "portsize", - "addrsize", - "version") - layout += user_description(dw).payload_layout - return stream.EndpointDescription(layout) - -def etherbone_record_description(dw): - layout = etherbone_record_header.get_layout() - layout += [("data", dw)] - return stream.EndpointDescription(layout) - -def etherbone_mmap_description(dw): - layout = [ - ("we", 1), - ("count", 8), - ("base_addr", 32), - ("be", dw//8), - ("addr", 32), - ("data", dw) - ] - return stream.EndpointDescription(layout) - - -# etherbone packet - -class _EtherbonePacketPacketizer(_Packetizer): - def __init__(self): - _Packetizer.__init__(self, - etherbone_packet_description(32), - user_description(32), - etherbone_packet_header) - - -class _EtherbonePacketTX(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32)) - self.source = source = stream.Endpoint(user_description(32)) - - # # # - - self.submodules.packetizer = packetizer = _EtherbonePacketPacketizer() - self.comb += [ - packetizer.sink.stb.eq(sink.stb), - packetizer.sink.eop.eq(sink.eop), - sink.ack.eq(packetizer.sink.ack), - - packetizer.sink.magic.eq(etherbone_magic), - packetizer.sink.port_size.eq(32//8), - packetizer.sink.addr_size.eq(32//8), - packetizer.sink.nr.eq(sink.nr), - packetizer.sink.version.eq(etherbone_version), - - packetizer.sink.data.eq(sink.data) - ] - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - packetizer.source.ack.eq(1), - If(packetizer.source.stb, - packetizer.source.ack.eq(0), - NextState("SEND") - ) - ) - fsm.act("SEND", - packetizer.source.connect(source), - source.length.eq(sink.length + etherbone_packet_header.length), - If(source.stb & source.eop & source.ack, - NextState("IDLE") - ) - ) - - -class _EtherbonePacketDepacketizer(_Depacketizer): - def __init__(self): - _Depacketizer.__init__(self, - user_description(32), - etherbone_packet_description(32), - etherbone_packet_header) - - -class _EtherbonePacketRX(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(user_description(32)) - self.source = source = stream.Endpoint(etherbone_packet_user_description(32)) - - # # # - - self.submodules.depacketizer = depacketizer = _EtherbonePacketDepacketizer() - self.comb += sink.connect(depacketizer.sink) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - depacketizer.source.ack.eq(1), - If(depacketizer.source.stb, - depacketizer.source.ack.eq(0), - NextState("CHECK") - ) - ) - stb = Signal() - self.sync += stb.eq( - depacketizer.source.stb & - (depacketizer.source.magic == etherbone_magic) - ) - fsm.act("CHECK", - If(stb, - NextState("PRESENT") - ).Else( - NextState("DROP") - ) - ) - self.comb += [ - source.eop.eq(depacketizer.source.eop), - - source.nr.eq(depacketizer.source.nr), - - source.data.eq(depacketizer.source.data), - - source.length.eq(sink.length - etherbone_packet_header.length) - ] - fsm.act("PRESENT", - source.stb.eq(depacketizer.source.stb), - depacketizer.source.ack.eq(source.ack), - If(source.stb & source.eop & source.ack, - NextState("IDLE") - ) - ) - fsm.act("DROP", - depacketizer.source.ack.eq(1), - If(depacketizer.source.stb & - depacketizer.source.eop & - depacketizer.source.ack, - NextState("IDLE") - ) - ) - - -class _EtherbonePacket(Module): - def __init__(self, port_sink, port_source): - self.submodules.tx = tx = _EtherbonePacketTX() - self.submodules.rx = rx = _EtherbonePacketRX() - self.comb += [ - tx.source.connect(port_sink), - port_source.connect(rx.sink) - ] - self.sink, self.source = self.tx.sink, self.rx.source - -# etherbone record - -class _EtherboneRecordPacketizer(_Packetizer): - def __init__(self): - _Packetizer.__init__(self, - etherbone_record_description(32), - etherbone_packet_user_description(32), - etherbone_record_header) - - -class _EtherboneRecordDepacketizer(_Depacketizer): - def __init__(self): - _Depacketizer.__init__(self, - etherbone_packet_user_description(32), - etherbone_record_description(32), - etherbone_record_header) - - -class _EtherboneRecordReceiver(Module): - def __init__(self, buffer_depth=4): - self.sink = sink = stream.Endpoint(etherbone_record_description(32)) - self.source = source = stream.Endpoint(etherbone_mmap_description(32)) - - # # # - - fifo = stream.SyncFIFO(etherbone_record_description(32), buffer_depth, - buffered=True) - self.submodules += fifo - self.comb += sink.connect(fifo.sink) - - base_addr = Signal(32) - base_addr_update = Signal() - self.sync += If(base_addr_update, base_addr.eq(fifo.source.data)) - - counter = Signal(max=512) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - fifo.source.ack.eq(1), - counter_reset.eq(1), - If(fifo.source.stb, - base_addr_update.eq(1), - If(fifo.source.wcount, - NextState("RECEIVE_WRITES") - ).Elif(fifo.source.rcount, - NextState("RECEIVE_READS") - - ) - ) - ) - fsm.act("RECEIVE_WRITES", - source.stb.eq(fifo.source.stb), - source.eop.eq(counter == fifo.source.wcount-1), - source.count.eq(fifo.source.wcount), - source.be.eq(fifo.source.byte_enable), - source.addr.eq(base_addr[2:] + counter), - source.we.eq(1), - source.data.eq(fifo.source.data), - fifo.source.ack.eq(source.ack), - If(source.stb & source.ack, - counter_ce.eq(1), - If(source.eop, - If(fifo.source.rcount, - NextState("RECEIVE_BASE_RET_ADDR") - ).Else( - NextState("IDLE") - ) - ) - ) - ) - fsm.act("RECEIVE_BASE_RET_ADDR", - counter_reset.eq(1), - If(fifo.source.stb, - base_addr_update.eq(1), - NextState("RECEIVE_READS") - ) - ) - fsm.act("RECEIVE_READS", - source.stb.eq(fifo.source.stb), - source.eop.eq(counter == fifo.source.rcount-1), - source.count.eq(fifo.source.rcount), - source.base_addr.eq(base_addr), - source.addr.eq(fifo.source.data[2:]), - fifo.source.ack.eq(source.ack), - If(source.stb & source.ack, - counter_ce.eq(1), - If(source.eop, - NextState("IDLE") - ) - ) - ) - - -class _EtherboneRecordSender(Module): - def __init__(self, buffer_depth=4): - self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) - self.source = source = stream.Endpoint(etherbone_record_description(32)) - - # # # - - pbuffer = stream.SyncFIFO(etherbone_mmap_description(32), buffer_depth, - buffered=True) - self.submodules += pbuffer - self.comb += sink.connect(pbuffer.sink) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - pbuffer.source.ack.eq(1), - If(pbuffer.source.stb, - pbuffer.source.ack.eq(0), - NextState("SEND_BASE_ADDRESS") - ) - ) - self.comb += [ - source.byte_enable.eq(pbuffer.source.be), - If(pbuffer.source.we, - source.wcount.eq(pbuffer.source.count) - ).Else( - source.rcount.eq(pbuffer.source.count) - ) - ] - - fsm.act("SEND_BASE_ADDRESS", - source.stb.eq(pbuffer.source.stb), - source.eop.eq(0), - source.data.eq(pbuffer.source.base_addr), - If(source.ack, - NextState("SEND_DATA") - ) - ) - fsm.act("SEND_DATA", - source.stb.eq(pbuffer.source.stb), - source.eop.eq(pbuffer.source.eop), - source.data.eq(pbuffer.source.data), - If(source.stb & source.ack, - pbuffer.source.ack.eq(1), - If(source.eop, - NextState("IDLE") - ) - ) - ) - - -class _EtherboneRecord(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32)) - self.source = source = stream.Endpoint(etherbone_packet_user_description(32)) - - # # # - - # receive record, decode it and generate mmap stream - self.submodules.depacketizer = depacketizer = _EtherboneRecordDepacketizer() - self.submodules.receiver = receiver = _EtherboneRecordReceiver() - self.comb += [ - sink.connect(depacketizer.sink), - depacketizer.source.connect(receiver.sink) - ] - - # receive mmap stream, encode it and send records - self.submodules.sender = sender = _EtherboneRecordSender() - self.submodules.packetizer = packetizer = _EtherboneRecordPacketizer() - self.comb += [ - sender.source.connect(packetizer.sink), - packetizer.source.connect(source), - source.length.eq(etherbone_record_header.length + - (sender.source.wcount != 0)*4 + sender.source.wcount*4 + - (sender.source.rcount != 0)*4 + sender.source.rcount*4) - ] - - -# etherbone wishbone - -class _EtherboneWishboneMaster(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) - self.source = source = stream.Endpoint(etherbone_mmap_description(32)) - self.bus = bus = wishbone.Interface() - - # # # - - data = Signal(32) - data_update = Signal() - self.sync += If(data_update, data.eq(bus.dat_r)) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb, - sink.ack.eq(0), - If(sink.we, - NextState("WRITE_DATA") - ).Else( - NextState("READ_DATA") - ) - ) - ) - fsm.act("WRITE_DATA", - bus.adr.eq(sink.addr), - bus.dat_w.eq(sink.data), - bus.sel.eq(sink.be), - bus.stb.eq(sink.stb), - bus.we.eq(1), - bus.cyc.eq(1), - If(bus.stb & bus.ack, - sink.ack.eq(1), - If(sink.eop, - NextState("IDLE") - ) - ) - ) - fsm.act("READ_DATA", - bus.adr.eq(sink.addr), - bus.sel.eq(sink.be), - bus.stb.eq(sink.stb), - bus.cyc.eq(1), - If(bus.stb & bus.ack, - data_update.eq(1), - NextState("SEND_DATA") - ) - ) - fsm.act("SEND_DATA", - source.stb.eq(sink.stb), - source.eop.eq(sink.eop), - source.base_addr.eq(sink.base_addr), - source.addr.eq(sink.addr), - source.count.eq(sink.count), - source.be.eq(sink.be), - source.we.eq(1), - source.data.eq(data), - If(source.stb & source.ack, - sink.ack.eq(1), - If(source.eop, - NextState("IDLE") - ).Else( - NextState("READ_DATA") - ) - ) - ) - - -class _EtherboneWishboneSlave(Module): - def __init__(self): - self.bus = bus = wishbone.Interface() - self.ready = Signal(reset=1) - self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) - self.source = source = stream.Endpoint(etherbone_mmap_description(32)) - - # # # - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(bus.stb & bus.cyc, - If(self.ready, - If(bus.we, - NextState("SEND_WRITE") - ).Else( - NextState("SEND_READ") - ) - ).Else( - NextState("SEND_ERROR") - ) - ) - ) - fsm.act("SEND_WRITE", - If(~self.ready, - NextState("SEND_ERROR") - ).Else( - source.stb.eq(1), - source.eop.eq(1), - source.base_addr[2:].eq(bus.adr), - source.count.eq(1), - source.be.eq(bus.sel), - source.we.eq(1), - source.data.eq(bus.dat_w), - If(source.stb & source.ack, - bus.ack.eq(1), - NextState("IDLE") - ) - ) - ) - fsm.act("SEND_READ", - If(~self.ready, - NextState("SEND_ERROR") - ).Else( - source.stb.eq(1), - source.eop.eq(1), - source.base_addr.eq(0), - source.count.eq(1), - source.be.eq(bus.sel), - source.we.eq(0), - source.data[2:].eq(bus.adr), - If(source.stb & source.ack, - NextState("WAIT_READ") - ) - ) - ) - fsm.act("WAIT_READ", - sink.ack.eq(1), - If(~self.ready, - NextState("SEND_ERROR") - ).Elif(sink.stb & sink.we, - bus.ack.eq(1), - bus.dat_r.eq(sink.data), - NextState("IDLE") - ) - ) - fsm.act("SEND_ERROR", - bus.ack.eq(1), - bus.err.eq(1) - ) - -# etherbone - -class Etherbone(Module): - def __init__(self, mode="master"): - self.sink = sink = stream.Endpoint(user_description(32)) - self.source = source = stream.Endpoint(user_description(32)) - - # # # - - self.submodules.packet = _EtherbonePacket(source, sink) - self.submodules.record = _EtherboneRecord() - if mode == "master": - self.submodules.wishbone = _EtherboneWishboneMaster() - elif mode == "slave": - self.submodules.wishbone = _EtherboneWishboneSlave() - else: - raise ValueError - - self.comb += [ - self.packet.source.connect(self.record.sink), - self.record.source.connect(self.packet.sink), - self.record.receiver.source.connect(self.wishbone.sink), - self.wishbone.source.connect(self.record.sender.sink) - ] diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py deleted file mode 100644 index d4d5c0cc5..000000000 --- a/artiq/gateware/serwb/genphy.py +++ /dev/null @@ -1,346 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.interconnect.csr import * - -from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath - - -class _SerdesClocking(Module): - def __init__(self, pads, mode="master"): - self.refclk = Signal() - - # # # - - # In Master mode, generate the clock with 180° phase shift so that Slave - # can use this clock to sample data - if mode == "master": - self.specials += DDROutput(0, 1, self.refclk) - if hasattr(pads, "clk_p"): - self.specials += DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) - else: - self.comb += pads.clk.eq(self.refclk) - # In Slave mode, use the clock provided by Master - elif mode == "slave": - if hasattr(pads, "clk_p"): - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) - else: - self.comb += self.refclk.eq(pads.clk) - else: - raise ValueError - - -class _SerdesTX(Module): - def __init__(self, pads): - # Control - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.sink = sink = stream.Endpoint([("data", 32)]) - - # # # - - # Datapath - self.submodules.datapath = datapath = TXDatapath(1) - self.comb += [ - sink.connect(datapath.sink), - datapath.source.ack.eq(1), - datapath.idle.eq(idle), - datapath.comma.eq(comma) - ] - - # Output data (on rising edge of sys_clk) - data = Signal() - self.sync += data.eq(datapath.source.data) - if hasattr(pads, "tx_p"): - self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) - else: - self.comb += pads.tx.eq(data) - - -class _SerdesRX(Module): - def __init__(self, pads): - # Control - self.bitslip_value = bitslip_value = Signal(6) - - # Status - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Input data (on rising edge of sys_clk) - data = Signal() - data_d = Signal() - if hasattr(pads, "rx_p"): - self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) - else: - self.comb += data.eq(pads.rx) - self.sync += data_d.eq(data) - - # Datapath - self.submodules.datapath = datapath = RXDatapath(1) - self.comb += [ - datapath.sink.stb.eq(1), - datapath.sink.data.eq(data_d), - datapath.bitslip_value.eq(bitslip_value), - datapath.source.connect(source), - idle.eq(datapath.idle), - comma.eq(datapath.comma) - ] - - -@ResetInserter() -class _Serdes(Module): - def __init__(self, pads, mode="master"): - self.submodules.clocking = _SerdesClocking(pads, mode) - self.submodules.tx = _SerdesTX(pads) - self.submodules.rx = _SerdesRX(pads) - - -# SERWB Master <--> Slave physical synchronization process: -# 1) Master sends idle patterns (zeroes) to Slave to reset it. -# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. -# 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. -# 4) Master stops sending K28.5 commas. -# 5) Slave stops sending K28.5 commas. -# 6) Physical link is ready. - - -@ResetInserter() -class _SerdesMasterInit(Module): - def __init__(self, serdes, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - NextValue(bitslip, 0), - NextState("RESET_SLAVE"), - serdes.tx.idle.eq(1) - ) - fsm.act("RESET_SLAVE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("SEND_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - If(~serdes.rx.idle, - timer.wait.eq(1), - If(timer.done, - NextState("CHECK_PATTERN") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - NextState("READY") - ) - ).Else( - NextState("INC_BITSLIP") - ), - serdes.tx.comma.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_BITSLIP", - NextState("WAIT_STABLE"), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(bitslip, bitslip + 1) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -@ResetInserter() -class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - # reset - fsm.act("IDLE", - NextValue(bitslip, 0), - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("WAIT_STABLE"), - ), - serdes.tx.idle.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - NextState("SEND_PATTERN") - ) - ).Else( - NextState("INC_BITSLIP") - ), - serdes.tx.idle.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_BITSLIP", - NextState("WAIT_STABLE"), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(bitslip, bitslip + 1) - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - timer.wait.eq(1), - If(timer.done, - If(~serdes.rx.comma, - NextState("READY") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -class _SerdesControl(Module, AutoCSR): - def __init__(self, serdes, init, mode="master"): - if mode == "master": - self.reset = CSR() - self.ready = CSRStatus() - self.error = CSRStatus() - - self.bitslip = CSRStatus(6) - - self.prbs_error = Signal() - self.prbs_start = CSR() - self.prbs_cycles = CSRStorage(32) - self.prbs_errors = CSRStatus(32) - - # # # - - if mode == "master": - # In Master mode, reset is coming from CSR, - # it resets the Master that will also reset - # the Slave by putting the link in idle. - self.sync += init.reset.eq(self.reset.re) - else: - # In Slave mode, reset is coming from link, - # Master reset the Slave by putting the link - # in idle. - self.sync += [ - init.reset.eq(serdes.rx.idle), - serdes.reset.eq(serdes.rx.idle) - ] - self.comb += [ - self.ready.status.eq(init.ready), - self.error.status.eq(init.error), - self.bitslip.status.eq(init.bitslip) - ] - - # prbs - prbs_cycles = Signal(32) - prbs_errors = self.prbs_errors.status - prbs_fsm = FSM(reset_state="IDLE") - self.submodules += prbs_fsm - prbs_fsm.act("IDLE", - NextValue(prbs_cycles, 0), - If(self.prbs_start.re, - NextValue(prbs_errors, 0), - NextState("CHECK") - ) - ) - prbs_fsm.act("CHECK", - NextValue(prbs_cycles, prbs_cycles + 1), - If(self.prbs_error, - NextValue(prbs_errors, prbs_errors + 1), - ), - If(prbs_cycles == self.prbs_cycles.storage, - NextState("IDLE") - ) - ) - - -class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master", init_timeout=2**16): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", 32)]) - assert mode in ["master", "slave"] - self.submodules.serdes = _Serdes(pads, mode) - if mode == "master": - self.submodules.init = _SerdesMasterInit(self.serdes, init_timeout) - else: - self.submodules.init = _SerdesSlaveInit(self.serdes, init_timeout) - self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - - # tx/rx dataflow - self.comb += [ - If(self.init.ready, - If(sink.stb, - sink.connect(self.serdes.tx.sink), - ), - self.serdes.rx.source.connect(source) - ).Else( - self.serdes.rx.source.ack.eq(1) - ), - self.serdes.tx.sink.stb.eq(1) # always transmitting - ] - - # For PRBS test we are using the scrambler/descrambler as PRBS, - # sending 0 to the scrambler and checking that descrambler - # output is always 0. - self.comb += self.control.prbs_error.eq( - source.stb & - source.ack & - (source.data != 0)) diff --git a/artiq/gateware/serwb/kuserdes.py b/artiq/gateware/serwb/kuserdes.py deleted file mode 100644 index f16d1919f..000000000 --- a/artiq/gateware/serwb/kuserdes.py +++ /dev/null @@ -1,149 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - -from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath - - -class _KUSerdesClocking(Module): - def __init__(self, pads, mode="master"): - self.refclk = Signal() - - # # # - - # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. - if mode == "master": - converter = stream.Converter(40, 8) - self.submodules += converter - self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - ] - self.specials += [ - Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, - p_IS_RST_INVERTED=0, - - o_OQ=self.refclk, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=converter.source.data - ), - DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) - ] - - # In Slave mode, multiply the clock provided by Master with a PLL/MMCM - elif mode == "slave": - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) - - -class _KUSerdesTX(Module): - def __init__(self, pads): - # Control - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.sink = sink = stream.Endpoint([("data", 32)]) - - # # # - - - # Datapath - self.submodules.datapath = datapath = TXDatapath(8) - self.comb += [ - sink.connect(datapath.sink), - datapath.source.ack.eq(1), - datapath.idle.eq(idle), - datapath.comma.eq(comma) - ] - - # Output Data(DDR with sys4x) - data = Signal() - self.specials += [ - Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, - - o_OQ=data, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=datapath.source.data - ), - DifferentialOutput(data, pads.tx_p, pads.tx_n) - ] - - -class _KUSerdesRX(Module): - def __init__(self, pads): - # Control - self.delay_rst = Signal() - self.delay_inc = Signal() - self.bitslip_value = bitslip_value = Signal(6) - - # Status - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Data input (DDR with sys4x) - data_nodelay = Signal() - data_delayed = Signal() - data_deserialized = Signal(8) - self.specials += [ - DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), - Instance("IDELAYE3", - p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, - p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, - p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", - p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, - - i_CLK=ClockSignal("sys"), - i_RST=self.delay_rst, i_LOAD=0, - i_INC=1, i_EN_VTC=0, - i_CE=self.delay_inc, - - i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed - ), - Instance("ISERDESE3", - p_IS_CLK_INVERTED=0, - p_IS_CLK_B_INVERTED=1, - p_DATA_WIDTH=8, - - i_D=data_delayed, - i_RST=ResetSignal("sys"), - i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, - i_CLK=ClockSignal("sys4x"), - i_CLK_B=ClockSignal("sys4x"), # locally inverted - i_CLKDIV=ClockSignal("sys"), - o_Q=data_deserialized - ) - ] - - # Datapath - self.submodules.datapath = datapath = RXDatapath(8) - self.comb += [ - datapath.sink.stb.eq(1), - datapath.sink.data.eq(data_deserialized), - datapath.bitslip_value.eq(bitslip_value), - datapath.source.connect(source), - idle.eq(datapath.idle), - comma.eq(datapath.comma) - ] - - -@ResetInserter() -class KUSerdes(Module): - def __init__(self, pads, mode="master"): - self.submodules.clocking = _KUSerdesClocking(pads, mode) - self.submodules.tx = _KUSerdesTX(pads) - self.submodules.rx = _KUSerdesRX(pads) diff --git a/artiq/gateware/serwb/packet.py b/artiq/gateware/serwb/packet.py deleted file mode 100644 index f22e2d944..000000000 --- a/artiq/gateware/serwb/packet.py +++ /dev/null @@ -1,173 +0,0 @@ -from math import ceil - -from migen import * -from migen.genlib.misc import WaitTimer - -from misoc.interconnect import stream - - -def reverse_bytes(signal): - n = ceil(len(signal)/8) - return Cat(iter([signal[i*8:(i+1)*8] for i in reversed(range(n))])) - - -class HeaderField: - def __init__(self, byte, offset, width): - self.byte = byte - self.offset = offset - self.width = width - - -class Header: - def __init__(self, fields, length, swap_field_bytes=True): - self.fields = fields - self.length = length - self.swap_field_bytes = swap_field_bytes - - def get_layout(self): - layout = [] - for k, v in sorted(self.fields.items()): - layout.append((k, v.width)) - return layout - - def get_field(self, obj, name, width): - if "_lsb" in name: - field = getattr(obj, name.replace("_lsb", ""))[:width] - elif "_msb" in name: - field = getattr(obj, name.replace("_msb", ""))[width:2*width] - else: - field = getattr(obj, name) - if len(field) != width: - raise ValueError("Width mismatch on " + name + " field") - return field - - def encode(self, obj, signal): - r = [] - for k, v in sorted(self.fields.items()): - start = v.byte*8 + v.offset - end = start + v.width - field = self.get_field(obj, k, v.width) - if self.swap_field_bytes: - field = reverse_bytes(field) - r.append(signal[start:end].eq(field)) - return r - - def decode(self, signal, obj): - r = [] - for k, v in sorted(self.fields.items()): - start = v.byte*8 + v.offset - end = start + v.width - field = self.get_field(obj, k, v.width) - if self.swap_field_bytes: - r.append(field.eq(reverse_bytes(signal[start:end]))) - else: - r.append(field.eq(signal[start:end])) - return r - -def phy_description(dw): - layout = [("data", dw)] - return stream.EndpointDescription(layout) - - -def user_description(dw): - layout = [ - ("data", 32), - ("length", 32) - ] - return stream.EndpointDescription(layout) - - -class Packetizer(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(user_description(32)) - self.source = source = stream.Endpoint(phy_description(32)) - - # # # - - # Packet description - # - preamble : 4 bytes - # - length : 4 bytes - # - payload - - fsm = FSM(reset_state="PREAMBLE") - self.submodules += fsm - - fsm.act("PREAMBLE", - If(sink.stb, - source.stb.eq(1), - source.data.eq(0x5aa55aa5), - If(source.ack, - NextState("LENGTH") - ) - ) - ) - fsm.act("LENGTH", - source.stb.eq(1), - source.data.eq(sink.length), - If(source.ack, - NextState("DATA") - ) - ) - fsm.act("DATA", - source.stb.eq(sink.stb), - source.data.eq(sink.data), - sink.ack.eq(source.ack), - If(source.ack & sink.eop, - NextState("PREAMBLE") - ) - ) - - -class Depacketizer(Module): - def __init__(self, clk_freq, timeout=10): - self.sink = sink = stream.Endpoint(phy_description(32)) - self.source = source = stream.Endpoint(user_description(32)) - - # # # - - count = Signal(len(source.length)) - length = Signal(len(source.length)) - - # Packet description - # - preamble : 4 bytes - # - length : 4 bytes - # - payload - - fsm = FSM(reset_state="PREAMBLE") - self.submodules += fsm - - timer = WaitTimer(clk_freq*timeout) - self.submodules += timer - - fsm.act("PREAMBLE", - sink.ack.eq(1), - If(sink.stb & - (sink.data == 0x5aa55aa5), - NextState("LENGTH") - ) - ) - fsm.act("LENGTH", - sink.ack.eq(1), - If(sink.stb, - NextValue(count, 0), - NextValue(length, sink.data), - NextState("DATA") - ), - timer.wait.eq(1) - ) - fsm.act("DATA", - source.stb.eq(sink.stb), - source.eop.eq(count == (length[2:] - 1)), - source.length.eq(length), - source.data.eq(sink.data), - sink.ack.eq(source.ack), - If(timer.done, - NextState("PREAMBLE") - ).Elif(source.stb & source.ack, - NextValue(count, count + 1), - If(source.eop, - NextState("PREAMBLE") - ) - ), - timer.wait.eq(1) - ) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py deleted file mode 100644 index d878cfb17..000000000 --- a/artiq/gateware/serwb/phy.py +++ /dev/null @@ -1,381 +0,0 @@ -from migen import * -from migen.genlib.misc import WaitTimer - -from misoc.interconnect import stream -from misoc.interconnect.csr import * - -from artiq.gateware.serwb.kuserdes import KUSerdes -from artiq.gateware.serwb.s7serdes import S7Serdes - - -# SERWB Master <--> Slave physical synchronization process: -# 1) Master sends idle patterns (zeroes) to Slave to reset it. -# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. -# 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. -# 4) Master stops sending K28.5 commas. -# 5) Slave stops sending K28.5 commas. -# 6) Physical link is ready. - - -@ResetInserter() -class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.delay = delay = Signal(max=taps) - self.delay_min = delay_min = Signal(max=taps) - self.delay_min_found = delay_min_found = Signal() - self.delay_max = delay_max = Signal(max=taps) - self.delay_max_found = delay_max_found = Signal() - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - NextValue(delay, 0), - NextValue(delay_min, 0), - NextValue(delay_min_found, 0), - NextValue(delay_max, 0), - NextValue(delay_max_found, 0), - serdes.rx.delay_rst.eq(1), - NextValue(bitslip, 0), - NextState("RESET_SLAVE"), - serdes.tx.idle.eq(1) - ) - fsm.act("RESET_SLAVE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("SEND_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - If(~serdes.rx.idle, - timer.wait.eq(1), - If(timer.done, - NextState("CHECK_PATTERN") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(~delay_min_found, - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextValue(delay_min, delay), - NextValue(delay_min_found, 1) - ) - ).Else( - NextState("INC_DELAY_BITSLIP") - ), - ).Else( - If(~serdes.rx.comma, - NextValue(delay_max, delay), - NextValue(delay_max_found, 1), - NextState("CHECK_SAMPLING_WINDOW") - ).Else( - NextState("INC_DELAY_BITSLIP") - ) - ), - serdes.tx.comma.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_DELAY_BITSLIP", - NextState("WAIT_STABLE"), - If(delay == (taps - 1), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(delay_min_found, 0), - NextValue(delay_min, 0), - NextValue(delay_max_found, 0), - NextValue(delay_max, 0), - NextValue(bitslip, bitslip + 1) - ), - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1) - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), - NextValue(delay_min_found, 0), - NextValue(delay_max_found, 0), - NextState("WAIT_STABLE") - ).Else( - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1), - NextState("CONFIGURE_SAMPLING_WINDOW") - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CONFIGURE_SAMPLING_WINDOW", - If(delay == (delay_min + (delay_max - delay_min)[1:]), - NextState("READY") - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -@ResetInserter() -class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.delay = delay = Signal(max=taps) - self.delay_min = delay_min = Signal(max=taps) - self.delay_min_found = delay_min_found = Signal() - self.delay_max = delay_max = Signal(max=taps) - self.delay_max_found = delay_max_found = Signal() - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - # reset - fsm.act("IDLE", - NextValue(delay, 0), - NextValue(delay_min, 0), - NextValue(delay_min_found, 0), - NextValue(delay_max, 0), - NextValue(delay_max_found, 0), - serdes.rx.delay_rst.eq(1), - NextValue(bitslip, 0), - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("WAIT_STABLE"), - ), - serdes.tx.idle.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(~delay_min_found, - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextValue(delay_min, delay), - NextValue(delay_min_found, 1) - ) - ).Else( - NextState("INC_DELAY_BITSLIP") - ), - ).Else( - If(~serdes.rx.comma, - NextValue(delay_max, delay), - NextValue(delay_max_found, 1), - NextState("CHECK_SAMPLING_WINDOW") - ).Else( - NextState("INC_DELAY_BITSLIP") - ) - ), - serdes.tx.idle.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_DELAY_BITSLIP", - NextState("WAIT_STABLE"), - If(delay == (taps - 1), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(delay_min_found, 0), - NextValue(delay_min, 0), - NextValue(delay_max_found, 0), - NextValue(delay_max, 0), - NextValue(bitslip, bitslip + 1) - ), - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1) - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1) - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), - NextValue(delay_min_found, 0), - NextValue(delay_max_found, 0), - NextState("WAIT_STABLE") - ).Else( - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1), - NextState("CONFIGURE_SAMPLING_WINDOW") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CONFIGURE_SAMPLING_WINDOW", - If(delay == (delay_min + (delay_max - delay_min)[1:]), - NextState("SEND_PATTERN") - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1), - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - timer.wait.eq(1), - If(timer.done, - If(~serdes.rx.comma, - NextState("READY") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -class _SerdesControl(Module, AutoCSR): - def __init__(self, serdes, init, mode="master"): - if mode == "master": - self.reset = CSR() - self.ready = CSRStatus() - self.error = CSRStatus() - - self.delay = CSRStatus(9) - self.delay_min_found = CSRStatus() - self.delay_min = CSRStatus(9) - self.delay_max_found = CSRStatus() - self.delay_max = CSRStatus(9) - self.bitslip = CSRStatus(6) - - self.prbs_error = Signal() - self.prbs_start = CSR() - self.prbs_cycles = CSRStorage(32) - self.prbs_errors = CSRStatus(32) - - # # # - - if mode == "master": - # In Master mode, reset is coming from CSR, - # it resets the Master that will also reset - # the Slave by putting the link in idle. - self.sync += init.reset.eq(self.reset.re) - else: - # In Slave mode, reset is coming from link, - # Master reset the Slave by putting the link - # in idle. - self.sync += [ - init.reset.eq(serdes.rx.idle), - serdes.reset.eq(serdes.rx.idle) - ] - self.comb += [ - self.ready.status.eq(init.ready), - self.error.status.eq(init.error), - self.delay.status.eq(init.delay), - self.delay_min_found.status.eq(init.delay_min_found), - self.delay_min.status.eq(init.delay_min), - self.delay_max_found.status.eq(init.delay_max_found), - self.delay_max.status.eq(init.delay_max), - self.bitslip.status.eq(init.bitslip) - ] - - # prbs - prbs_cycles = Signal(32) - prbs_errors = self.prbs_errors.status - prbs_fsm = FSM(reset_state="IDLE") - self.submodules += prbs_fsm - prbs_fsm.act("IDLE", - NextValue(prbs_cycles, 0), - If(self.prbs_start.re, - NextValue(prbs_errors, 0), - NextState("CHECK") - ) - ) - prbs_fsm.act("CHECK", - NextValue(prbs_cycles, prbs_cycles + 1), - If(self.prbs_error, - NextValue(prbs_errors, prbs_errors + 1), - ), - If(prbs_cycles == self.prbs_cycles.storage, - NextState("IDLE") - ) - ) - - -class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master", init_timeout=2**15): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", 32)]) - assert mode in ["master", "slave"] - if device[:4] == "xcku": - taps = 512 - self.submodules.serdes = KUSerdes(pads, mode) - elif device[:4] == "xc7a": - taps = 32 - self.submodules.serdes = S7Serdes(pads, mode) - else: - raise NotImplementedError - if mode == "master": - self.submodules.init = _SerdesMasterInit(self.serdes, taps, init_timeout) - else: - self.submodules.init = _SerdesSlaveInit(self.serdes, taps, init_timeout) - self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - - # tx/rx dataflow - self.comb += [ - If(self.init.ready, - If(sink.stb, - sink.connect(self.serdes.tx.sink), - ), - self.serdes.rx.source.connect(source) - ).Else( - self.serdes.rx.source.ack.eq(1) - ), - self.serdes.tx.sink.stb.eq(1) # always transmitting - ] - - # For PRBS test we are using the scrambler/descrambler as PRBS, - # sending 0 to the scrambler and checking that descrambler - # output is always 0. - self.comb += self.control.prbs_error.eq( - source.stb & - source.ack & - (source.data != 0)) diff --git a/artiq/gateware/serwb/s7serdes.py b/artiq/gateware/serwb/s7serdes.py deleted file mode 100644 index 9daee338a..000000000 --- a/artiq/gateware/serwb/s7serdes.py +++ /dev/null @@ -1,160 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - -from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath - - -class _S7SerdesClocking(Module): - def __init__(self, pads, mode="master"): - self.refclk = Signal() - - # # # - - # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. - if mode == "master": - converter = stream.Converter(40, 8) - self.submodules += converter - self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - ] - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", - - o_OQ=self.refclk, - i_OCE=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=converter.source.data[0], i_D2=converter.source.data[1], - i_D3=converter.source.data[2], i_D4=converter.source.data[3], - i_D5=converter.source.data[4], i_D6=converter.source.data[5], - i_D7=converter.source.data[6], i_D8=converter.source.data[7] - ), - DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) - ] - - # In Slave mode, multiply the clock provided by Master with a PLL/MMCM - elif mode == "slave": - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) - - -class _S7SerdesTX(Module): - def __init__(self, pads, mode="master"): - # Control - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.sink = sink = stream.Endpoint([("data", 32)]) - - # # # - - # Datapath - self.submodules.datapath = datapath = TXDatapath(8) - self.comb += [ - sink.connect(datapath.sink), - datapath.source.ack.eq(1), - datapath.idle.eq(idle), - datapath.comma.eq(comma) - ] - - # Output Data(DDR with sys4x) - data = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", - - o_OQ=data, - i_OCE=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=datapath.source.data[0], i_D2=datapath.source.data[1], - i_D3=datapath.source.data[2], i_D4=datapath.source.data[3], - i_D5=datapath.source.data[4], i_D6=datapath.source.data[5], - i_D7=datapath.source.data[6], i_D8=datapath.source.data[7] - ), - DifferentialOutput(data, pads.tx_p, pads.tx_n) - ] - - -class _S7SerdesRX(Module): - def __init__(self, pads, mode="master"): - # Control - self.delay_rst = Signal() - self.delay_inc = Signal() - self.bitslip_value = bitslip_value = Signal(6) - - # Status - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Data input (DDR with sys4x) - data_nodelay = Signal() - data_delayed = Signal() - data_deserialized = Signal(8) - self.specials += [ - DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), - Instance("IDELAYE2", - p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", - p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", - p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, - - i_C=ClockSignal(), - i_LD=self.delay_rst, - i_CE=self.delay_inc, - i_LDPIPEEN=0, i_INC=1, - - i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed - ), - Instance("ISERDESE2", - p_DATA_WIDTH=8, p_DATA_RATE="DDR", - p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", - p_NUM_CE=1, p_IOBDELAY="IFD", - - i_DDLY=data_delayed, - i_CE1=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), - i_CLKDIV=ClockSignal("sys"), - i_BITSLIP=0, - o_Q8=data_deserialized[0], o_Q7=data_deserialized[1], - o_Q6=data_deserialized[2], o_Q5=data_deserialized[3], - o_Q4=data_deserialized[4], o_Q3=data_deserialized[5], - o_Q2=data_deserialized[6], o_Q1=data_deserialized[7] - ) - ] - - # Datapath - self.submodules.datapath = datapath = RXDatapath(8) - self.comb += [ - datapath.sink.stb.eq(1), - datapath.sink.data.eq(data_deserialized), - datapath.bitslip_value.eq(bitslip_value), - datapath.source.connect(source), - idle.eq(datapath.idle), - comma.eq(datapath.comma) - ] - - -@ResetInserter() -class S7Serdes(Module): - def __init__(self, pads, mode="master"): - self.submodules.clocking = _S7SerdesClocking(pads, mode) - self.submodules.tx = _S7SerdesTX(pads, mode) - self.submodules.rx = _S7SerdesRX(pads, mode) diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py deleted file mode 100644 index dc367fb6c..000000000 --- a/artiq/gateware/serwb/scrambler.py +++ /dev/null @@ -1,89 +0,0 @@ -from functools import reduce -from operator import xor - -from migen import * - -from misoc.interconnect import stream - - -def K(x, y): - return (y << 5) | x - - -@ResetInserter() -@CEInserter() -class _Scrambler(Module): - def __init__(self, n_io, n_state=23, taps=[17, 22]): - self.i = Signal(n_io) - self.o = Signal(n_io) - - # # # - - state = Signal(n_state, reset=1) - curval = [state[i] for i in range(n_state)] - for i in reversed(range(n_io)): - flip = reduce(xor, [curval[tap] for tap in taps]) - self.comb += self.o[i].eq(flip ^ self.i[i]) - curval.insert(0, flip) - curval.pop() - - self.sync += state.eq(Cat(*curval[:n_state])) - - -class Scrambler(Module): - def __init__(self, sync_interval=2**10): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) - - # # # - - # Scrambler - self.submodules.scrambler = scrambler = _Scrambler(32) - - # Insert K29.7 SYNC character every "sync_interval" cycles - count = Signal(max=sync_interval) - self.sync += If(source.ack, count.eq(count + 1)) - self.comb += [ - source.stb.eq(1), - If(count == 0, - scrambler.reset.eq(1), - source.k.eq(0b1), - source.d.eq(K(29, 7)), - ).Else( - If(sink.stb, scrambler.i.eq(sink.data)), - source.k.eq(0), - source.d.eq(scrambler.o), - If(source.ack, - sink.ack.eq(1), - scrambler.ce.eq(1) - ) - ) - ] - - -class Descrambler(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Descrambler - self.submodules.descrambler = descrambler = _Scrambler(32) - self.comb += descrambler.i.eq(sink.d) - - # Detect K29.7 SYNC character and synchronize Descrambler - self.comb += \ - If(sink.stb, - If((sink.k == 0b1) & (sink.d == K(29,7)), - sink.ack.eq(1), - descrambler.reset.eq(1) - ).Else( - source.stb.eq(1), - source.data.eq(descrambler.o), - If(source.ack, - sink.ack.eq(1), - descrambler.ce.eq(1) - ) - ) - ) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index ca5ff169c..78809671b 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -14,7 +14,6 @@ from misoc.targets.sayma_amc import * from artiq.gateware.amp import AMPSoC from artiq.gateware import eem from artiq.gateware import fmcdio_vhdci_eem -from artiq.gateware import serwb, remote_csr from artiq.gateware import rtio from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg @@ -216,10 +215,19 @@ class AD9154NoSAWG(Module, AutoCSR): ] -class RTMSerWb: - def __init__(self): +class Satellite(SatelliteBase): + """ + DRTIO satellite with local DAC/SAWG channels. + """ + def __init__(self, with_sawg, **kwargs): + SatelliteBase.__init__(self, 150e6, + identifier_suffix=".without-sawg" if not with_sawg else "", + **kwargs) + platform = self.platform + self.submodules += RTMUARTForward(platform) + # RTM bitstream upload slave_fpga_cfg = self.platform.request("rtm_fpga_cfg") self.submodules.slave_fpga_cfg = gpio.GPIOTristate([ @@ -232,36 +240,6 @@ class RTMSerWb: self.csr_devices.append("slave_fpga_cfg") self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 - # AMC/RTM serwb - serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="master") - self.submodules.serwb_phy_amc = serwb_phy_amc - self.csr_devices.append("serwb_phy_amc") - - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave") - self.submodules += serwb_core - self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) - - -class Satellite(SatelliteBase, RTMSerWb): - """ - DRTIO satellite with local DAC/SAWG channels. - """ - mem_map = { - "serwb": 0x13000000, - } - mem_map.update(SatelliteBase.mem_map) - - def __init__(self, with_sawg, **kwargs): - SatelliteBase.__init__(self, 150e6, - identifier_suffix=".without-sawg" if not with_sawg else "", - **kwargs) - RTMSerWb.__init__(self) - - platform = self.platform - - self.submodules += RTMUARTForward(platform) - rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -509,16 +487,6 @@ def main(): variant = args.variant.lower() if variant == "satellite": soc = Satellite(with_sawg=not args.without_sawg, **soc_sayma_amc_argdict(args)) - remote_csr_regions = remote_csr.get_remote_csr_regions( - soc.mem_map["serwb"] | soc.shadow_base, - args.rtm_csr_csv) - for name, origin, busword, csrs in remote_csr_regions: - soc.add_csr_region(name, origin, busword, csrs) - # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! - soc.config["HAS_HMC830_7043"] = None - soc.config["CONVERTER_SPI_HMC830_CS"] = 0 - soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 - soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 elif variant == "simplesatellite": soc = SimpleSatellite(**soc_sayma_amc_argdict(args)) elif variant == "master": diff --git a/artiq/gateware/test/serwb/__init__.py b/artiq/gateware/test/serwb/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py deleted file mode 100644 index 4a3fa7898..000000000 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ /dev/null @@ -1,158 +0,0 @@ -import unittest -import random - -from migen import * - -from artiq.gateware.serwb import scrambler -from artiq.gateware.serwb import core - -from misoc.interconnect import stream -from misoc.interconnect.wishbone import SRAM - - -class FakeInit(Module): - def __init__(self): - self.ready = Signal(reset=1) - - -class FakeSerdes(Module): - def __init__(self): - self.tx_ce = Signal() - self.tx_k = Signal(4) - self.tx_d = Signal(32) - self.rx_ce = Signal() - self.rx_k = Signal(4) - self.rx_d = Signal(32) - - # # # - - data_ce = Signal(5, reset=0b00001) - self.sync += data_ce.eq(Cat(data_ce[1:], data_ce[0])) - - self.comb += [ - self.tx_ce.eq(data_ce[0]), - self.rx_ce.eq(data_ce[0]) - ] - -class FakePHY(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - self.submodules.init = FakeInit() - self.submodules.serdes = FakeSerdes() - - # tx dataflow - self.comb += \ - If(self.init.ready, - sink.ack.eq(self.serdes.tx_ce), - If(sink.stb, - self.serdes.tx_d.eq(sink.data) - ) - ) - - # rx dataflow - self.comb += \ - If(self.init.ready, - source.stb.eq(self.serdes.rx_ce), - source.data.eq(self.serdes.rx_d) - ) - - -class DUTScrambler(Module): - def __init__(self): - self.submodules.scrambler = scrambler.Scrambler(sync_interval=16) - self.submodules.descrambler = scrambler.Descrambler() - self.comb += self.scrambler.source.connect(self.descrambler.sink) - - -class DUTCore(Module): - def __init__(self): - # wishbone slave - phy_slave = FakePHY() - serwb_slave = core.SERWBCore(phy_slave, int(1e6), "slave") - self.submodules += phy_slave, serwb_slave - - # wishbone master - phy_master = FakePHY() - serwb_master = core.SERWBCore(phy_master, int(1e6), "master") - self.submodules += phy_master, serwb_master - - # connect phy - self.comb += [ - phy_master.serdes.rx_ce.eq(phy_slave.serdes.tx_ce), - phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), - phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), - - phy_slave.serdes.rx_ce.eq(phy_master.serdes.tx_ce), - phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), - phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) - ] - - # add wishbone sram to wishbone master - sram = SRAM(1024, bus=serwb_master.etherbone.wishbone.bus) - self.submodules += sram - - # expose wishbone slave - self.wishbone = serwb_slave.etherbone.wishbone.bus - - -class TestSERWBCore(unittest.TestCase): - def test_scrambler(self): - def generator(dut, rand_level=50): - # prepare test - prng = random.Random(42) - i = 0 - last_data = -1 - # test loop - while i != 256: - # stim - yield dut.scrambler.sink.stb.eq(1) - if (yield dut.scrambler.sink.stb) & (yield dut.scrambler.sink.ack): - i += 1 - yield dut.scrambler.sink.data.eq(i) - - # check - yield dut.descrambler.source.ack.eq(prng.randrange(100) > rand_level) - if (yield dut.descrambler.source.stb) & (yield dut.descrambler.source.ack): - current_data = (yield dut.descrambler.source.data) - if (current_data != (last_data + 1)): - dut.errors += 1 - last_data = current_data - - # cycle - yield - - dut = DUTScrambler() - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) - - def test_serwb(self): - def generator(dut): - # prepare test - prng = random.Random(42) - data_base = 0x100 - data_length = 4 - datas_w = [prng.randrange(2**32) for i in range(data_length)] - datas_r = [] - - # write - for i in range(data_length): - yield from dut.wishbone.write(data_base + i, datas_w[i]) - - # read - for i in range(data_length): - datas_r.append((yield from dut.wishbone.read(data_base + i))) - - # check - for i in range(data_length): - if datas_r[i] != datas_w[i]: - dut.errors += 1 - - dut = DUTCore() - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) diff --git a/artiq/gateware/test/serwb/test_serwb_init.py b/artiq/gateware/test/serwb/test_serwb_init.py deleted file mode 100644 index c54e9cae9..000000000 --- a/artiq/gateware/test/serwb/test_serwb_init.py +++ /dev/null @@ -1,144 +0,0 @@ -import unittest - -from migen import * - -from artiq.gateware.serwb import packet -from artiq.gateware.serwb.phy import _SerdesMasterInit, _SerdesSlaveInit - - -class SerdesModel(Module): - def __init__(self, taps, mode="slave"): - self.tx = Module() - self.rx = Module() - - self.tx.idle = Signal() - self.tx.comma = Signal() - self.rx.idle = Signal() - self.rx.comma = Signal() - - self.rx.bitslip_value = Signal(6) - self.rx.delay_rst = Signal() - self.rx.delay_inc = Signal() - - self.valid_bitslip = Signal(6) - self.valid_delays = Signal(taps) - - # # # - - delay = Signal(max=taps) - bitslip = Signal(6) - - valid_delays = Array(Signal() for i in range(taps)) - for i in range(taps): - self.comb += valid_delays[taps-1-i].eq(self.valid_delays[i]) - - self.sync += [ - bitslip.eq(self.rx.bitslip_value), - If(self.rx.delay_rst, - delay.eq(0) - ).Elif(self.rx.delay_inc, - delay.eq(delay + 1) - ) - ] - - if mode == "master": - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += self.fsm.reset.eq(self.tx.idle) - fsm.act("IDLE", - If(self.tx.comma, - NextState("SEND_COMMA") - ), - self.rx.idle.eq(1) - ) - fsm.act("SEND_COMMA", - If(valid_delays[delay] & - (bitslip == self.valid_bitslip), - self.rx.comma.eq(1) - ), - If(~self.tx.comma, - NextState("READY") - ) - ) - fsm.act("READY") - elif mode == "slave": - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - self.rx.idle.eq(1), - NextState("SEND_COMMA") - ) - fsm.act("SEND_COMMA", - If(valid_delays[delay] & - (bitslip == self.valid_bitslip), - self.rx.comma.eq(1) - ), - If(~self.tx.idle, - NextState("READY") - ) - ) - fsm.act("READY") - - -class DUTMaster(Module): - def __init__(self, taps=32): - self.submodules.serdes = SerdesModel(taps, mode="master") - self.submodules.init = _SerdesMasterInit(self.serdes, taps, timeout=1) - - -class DUTSlave(Module): - def __init__(self, taps=32): - self.submodules.serdes = SerdesModel(taps, mode="slave") - self.submodules.init = _SerdesSlaveInit(self.serdes, taps, timeout=1) - - -def generator(test, dut, valid_bitslip, valid_delays, check_success): - yield dut.serdes.valid_bitslip.eq(valid_bitslip) - yield dut.serdes.valid_delays.eq(valid_delays) - while not ((yield dut.init.ready) or - (yield dut.init.error)): - yield - if check_success: - ready = (yield dut.init.ready) - error = (yield dut.init.error) - delay_min = (yield dut.init.delay_min) - delay_max = (yield dut.init.delay_max) - delay = (yield dut.init.delay) - bitslip = (yield dut.init.bitslip) - test.assertEqual(ready, 1) - test.assertEqual(error, 0) - test.assertEqual(delay_min, 4) - test.assertEqual(delay_max, 9) - test.assertEqual(delay, 6) - test.assertEqual(bitslip, valid_bitslip) - else: - ready = (yield dut.init.ready) - error = (yield dut.init.error) - test.assertEqual(ready, 0) - test.assertEqual(error, 1) - - -class TestSERWBInit(unittest.TestCase): - def test_master_init_success(self): - dut = DUTMaster() - valid_bitslip = 2 - valid_delays = 0b10001111100000111110000011111000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, True)) - - def test_master_init_failure(self): - # too small window - dut = DUTMaster() - valid_bitslip = 2 - valid_delays = 0b00000000000000010000000000000000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) - - def test_slave_init_success(self): - dut = DUTSlave() - valid_bitslip = 2 - valid_delays = 0b10001111100000111110000011111000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, True)) - - def test_slave_init_failure(self): - # too small window - dut = DUTSlave() - valid_bitslip = 2 - valid_delays = 0b00000000000000010000000000000000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False))