def __init__(self, soc, platform, tosbus_fifo, fromsbus_fifo, fromsbus_req_fifo, dram_dma_writer, dram_dma_reader, mem_size=256, burst_size = 8, do_checksum = False): #self.wishbone_r_slave = wishbone.Interface(data_width=soc.bus.data_width) #self.wishbone_w_slave = wishbone.Interface(data_width=soc.bus.data_width) self.tosbus_fifo = tosbus_fifo self.fromsbus_fifo = fromsbus_fifo self.fromsbus_req_fifo = fromsbus_req_fifo self.dram_dma_writer = dram_dma_writer self.dram_dma_reader = dram_dma_reader tosbus_fifo_din = Record(soc.tosbus_layout) self.comb += self.tosbus_fifo.din.eq(tosbus_fifo_din.raw_bits()) fromsbus_req_fifo_din = Record(soc.fromsbus_req_layout) self.comb += self.fromsbus_req_fifo.din.eq(fromsbus_req_fifo_din.raw_bits()) fromsbus_fifo_dout = Record(soc.fromsbus_layout) self.comb += fromsbus_fifo_dout.raw_bits().eq(self.fromsbus_fifo.dout) print(f"Configuring the SDRAM for {mem_size} MiB\n") data_width = burst_size * 4 data_width_bits = burst_size * 32 blk_addr_width = 32 - log2_int(data_width) # 27 for burst_size == 8 assert(len(self.dram_dma_writer.sink.data) == data_width_bits) assert(len(self.dram_dma_reader.source.data) == data_width_bits) #self.wishbone_r_master = wishbone.Interface(data_width=data_width_bits) #self.wishbone_w_master = wishbone.Interface(data_width=data_width_bits) #self.submodules += wishbone.Converter(self.wishbone_r_master, self.wishbone_r_slave) #self.submodules += wishbone.Converter(self.wishbone_w_master, self.wishbone_w_slave) print("ExchangeWithMem: data_width = {}, data_width_bits = {}, blk_addr_width = {}\n".format(data_width, data_width_bits, blk_addr_width)) print("ExchangeWithMem: tosbus_fifo width = {}, fromsbus_fifo width = {}, fromsbus_req_fifo width = {}\n".format(len(tosbus_fifo.din), len(fromsbus_fifo.dout), len(fromsbus_req_fifo.din))) local_r_addr = Signal(blk_addr_width) dma_r_addr = Signal(32) #local_r_widx = Signal(log2_int(burst_size)) # so width is 3 for burst_size == 8 #local_r_buffer = Signal(data_width_bits) local_w_addr = Signal(blk_addr_width) dma_w_addr = Signal(32) #local_w_widx = Signal(log2_int(burst_size)) # so width is 3 for burst_size == 8 #local_w_buffer = Signal(data_width_bits) max_block_bits=16 # CSRConstant do not seem to appear in the CSR Map, but they need to be accessible to the OS driver #self.blk_size = CSRConstant(value=data_width) # report the block size to the SW layer #self.blk_base = CSRConstant(value=soc.wb_mem_map["main_ram"] >> log2_int(data_width)) # report where the blk starts self.blk_size = CSRStatus(32) # report the block size to the SW layer self.blk_base = CSRStatus(32) # report where the blk starts self.mem_size = CSRStatus(32) # report how much memory we have self.comb += self.blk_size.status.eq(data_width) self.comb += self.blk_base.status.eq(soc.wb_mem_map["main_ram"] >> log2_int(data_width)) self.comb += self.mem_size.status.eq((mem_size * 1024 * 1024) >> log2_int(data_width)) self.irqctrl = CSRStorage(write_from_dev=True, fields = [CSRField("irq_enable", 1, description = "Enable interrupt"), CSRField("irq_clear", 1, description = "Clear interrupt"), CSRField("reserved", 30, description = "Reserved"), ]) self.blk_addr = CSRStorage(32, description = "SDRAM Block address to read/write from Wishbone memory (block of size {})".format(data_width)) self.dma_addr = CSRStorage(32, description = "Host Base address where to write/read data (i.e. SPARC Virtual addr)") #self.blk_cnt = CSRStorage(32, write_from_dev=True, description = "How many blk to read/write (max 2^{}-1); bit 31 is RD".format(max_block_bits), reset = 0) self.blk_cnt = CSRStorage(write_from_dev=True, fields = [CSRField("blk_cnt", max_block_bits, description = "How many blk to read/write (max 2^{}-1)".format(max_block_bits)), CSRField("rsvd", 32 - (max_block_bits + 1), description = "Reserved"), CSRField("rd_wr", 1, description = "Read/Write selector"), ]) self.last_blk = CSRStatus(32, description = "Last Blk addr finished on WB side") self.last_dma = CSRStatus(32, description = "Last DMA addr finished on WB side") self.dma_wrdone = CSRStatus(32, description = "DMA Block written to SDRAM", reset = 0) self.blk_rem = CSRStatus(32, description = "How many block remaining; bit 31 is RD", reset = 0) self.dma_status = CSRStatus(fields = [CSRField("rd_fsm_busy", 1, description = "Read FSM is doing some work"), CSRField("wr_fsm_busy", 1, description = "Write FSM is doing some work"), CSRField("has_wr_data", 1, description = "Data available to write to SDRAM"), CSRField("has_requests", 1, description = "There's outstanding requests to the SBus"), CSRField("has_rd_data", 1, description = "Data available to write to SBus"), ]) self.wr_tosdram = CSRStatus(32, description = "Last address written to SDRAM") #if (do_checksum): self.checksum = CSRStorage(data_width_bits, write_from_dev=True, description = "checksum (XOR)"); self.submodules.req_r_fsm = req_r_fsm = FSM(reset_state="Reset") self.submodules.req_w_fsm = req_w_fsm = FSM(reset_state="Reset") self.comb += self.dma_status.fields.rd_fsm_busy.eq(~req_r_fsm.ongoing("Idle")) # Read FSM Busy self.comb += self.dma_status.fields.wr_fsm_busy.eq(~req_w_fsm.ongoing("Idle")) # Write FSM Busy self.comb += self.dma_status.fields.has_wr_data.eq(self.fromsbus_fifo.readable) # Some data available to write to memory # The next two status bits reflect stats in the SBus clock domain self.submodules.fromsbus_req_fifo_readable_sync = BusSynchronizer(width = 1, idomain = "sbus", odomain = "sys") fromsbus_req_fifo_readable_in_sys = Signal() self.comb += self.fromsbus_req_fifo_readable_sync.i.eq(self.fromsbus_req_fifo.readable) self.comb += fromsbus_req_fifo_readable_in_sys.eq(self.fromsbus_req_fifo_readable_sync.o) # w/o this extra delay, the driver sees an outdated checksum for some reason... # there's probably a more fundamental issue :-( # note: replaced PulseSynchronizer with BusSynchronizer, should I retry w/o this ? fromsbus_req_fifo_readable_in_sys_cnt = Signal(5) self.sync += If(fromsbus_req_fifo_readable_in_sys, fromsbus_req_fifo_readable_in_sys_cnt.eq(0x1F) ).Else( If(fromsbus_req_fifo_readable_in_sys_cnt > 0, fromsbus_req_fifo_readable_in_sys_cnt.eq(fromsbus_req_fifo_readable_in_sys_cnt - 1) ) ) #self.comb += self.dma_status.fields.has_requests.eq(fromsbus_req_fifo_readable_in_sys) # we still have outstanding requests self.comb += self.dma_status.fields.has_requests.eq(fromsbus_req_fifo_readable_in_sys | (fromsbus_req_fifo_readable_in_sys_cnt != 0)) # we still have outstanding requests, or had recently self.submodules.tosbus_fifo_readable_sync = BusSynchronizer(width = 1, idomain = "sbus", odomain = "sys") tosbus_fifo_readable_in_sys = Signal() self.comb += self.tosbus_fifo_readable_sync.i.eq(self.tosbus_fifo.readable) self.comb += tosbus_fifo_readable_in_sys.eq(self.tosbus_fifo_readable_sync.o) self.comb += self.dma_status.fields.has_rd_data.eq(tosbus_fifo_readable_in_sys) # there's still data to be sent to memory; this will drop before the last SBus Master Cycle is finished, but then the SBus is busy so the host won't be able to read the status before the cycle is finished so we're good ongoing_m1 = Signal() ongoing = Signal() temp_irq = Signal() self.irq = Signal() self.sync += ongoing_m1.eq(ongoing) self.sync += ongoing.eq(self.dma_status.fields.rd_fsm_busy | self.dma_status.fields.wr_fsm_busy | self.dma_status.fields.has_wr_data | self.dma_status.fields.has_requests | self.dma_status.fields.has_rd_data | (self.blk_cnt.fields.blk_cnt != 0)) self.sync += temp_irq.eq((ongoing_m1 & ~ongoing) | # irq on falling edge of ongoing (temp_irq & ~self.irqctrl.fields.irq_clear & ~(~ongoing_m1 & ongoing))) # keep irq until cleared or rising edge of ongoing self.comb += self.irq.eq(temp_irq & self.irqctrl.fields.irq_enable) self.sync += If(self.irqctrl.fields.irq_clear, ## auto-reset irq_clear self.irqctrl.we.eq(1), self.irqctrl.dat_w.eq(self.irqctrl.storage & 0xFFFFFFFD)).Else( self.irqctrl.we.eq(0), ) #pad_SBUS_DATA_OE_LED = platform.request("SBUS_DATA_OE_LED") #self.comb += pad_SBUS_DATA_OE_LED.eq(self.irq) #self.comb += self.dma_status.status[16:17].eq(self.wishbone_w_master.cyc) # show the WB iface status (W) #self.comb += self.dma_status.status[17:18].eq(self.wishbone_w_master.stb) #self.comb += self.dma_status.status[18:19].eq(self.wishbone_w_master.we) #self.comb += self.dma_status.status[19:20].eq(self.wishbone_w_master.ack) #self.comb += self.dma_status.status[20:21].eq(self.wishbone_w_master.err) #self.comb += self.dma_status.status[24:25].eq(self.wishbone_r_master.cyc) # show the WB iface status (R) #self.comb += self.dma_status.status[25:26].eq(self.wishbone_r_master.stb) #self.comb += self.dma_status.status[26:27].eq(self.wishbone_r_master.we) #self.comb += self.dma_status.status[27:28].eq(self.wishbone_r_master.ack) #self.comb += self.dma_status.status[28:29].eq(self.wishbone_r_master.err) req_r_fsm.act("Reset", NextState("Idle") ) req_r_fsm.act("Idle", If(((self.blk_cnt.fields.blk_cnt != 0) & # checking self.blk_cnt.re might be too transient ? -> need to auto-reset (~self.blk_cnt.fields.rd_wr)), # !read -> write NextValue(local_r_addr, self.blk_addr.storage), NextValue(dma_r_addr, self.dma_addr.storage), NextValue(self.blk_rem.status, Cat(self.blk_cnt.fields.blk_cnt, Signal(32-max_block_bits, reset = 0))), NextState("ReqFromMemory") ).Elif(((self.blk_cnt.fields.blk_cnt != 0) & # checking self.blk_cnt.re might be too transient ? -> need to auto-reset (self.blk_cnt.fields.rd_wr)), # read NextValue(local_r_addr, self.blk_addr.storage), NextValue(dma_r_addr, self.dma_addr.storage), NextValue(self.blk_rem.status, Cat(self.blk_cnt.fields.blk_cnt, Signal(32-max_block_bits, reset = 0))), NextState("QueueReqToMemory") ) ) req_r_fsm.act("ReqFromMemory", self.dram_dma_reader.sink.address.eq(local_r_addr), self.dram_dma_reader.sink.valid.eq(1), If(self.dram_dma_reader.sink.ready, NextState("WaitForData") ) ) req_r_fsm.act("WaitForData", If(self.dram_dma_reader.source.valid & self.tosbus_fifo.writable, self.tosbus_fifo.we.eq(1), tosbus_fifo_din.address.eq(dma_r_addr), tosbus_fifo_din.data.eq(self.dram_dma_reader.source.data), If(do_checksum, self.checksum.we.eq(1), self.checksum.dat_w.eq(self.checksum.storage ^ self.dram_dma_reader.source.data), ), self.dram_dma_reader.source.ready.eq(1), NextValue(self.last_blk.status, local_r_addr), NextValue(self.last_dma.status, dma_r_addr), NextValue(self.blk_rem.status, self.blk_rem.status - 1), If(self.blk_rem.status[0:max_block_bits] <= 1, self.blk_cnt.we.eq(1), ## auto-reset self.blk_cnt.dat_w.eq(0), NextState("Idle"), ).Else( NextValue(local_r_addr, local_r_addr + 1), NextValue(dma_r_addr, dma_r_addr + data_width), NextState("ReqFromMemory"), ) ) ) req_r_fsm.act("QueueReqToMemory", If(self.fromsbus_req_fifo.writable, self.fromsbus_req_fifo.we.eq(1), fromsbus_req_fifo_din.blkaddress.eq(local_r_addr), fromsbus_req_fifo_din.dmaaddress.eq(dma_r_addr), NextValue(self.last_blk.status, local_r_addr), NextValue(self.last_dma.status, dma_r_addr), NextValue(self.blk_rem.status, self.blk_rem.status - 1), If(self.blk_rem.status[0:max_block_bits] <= 1, self.blk_cnt.we.eq(1), ## auto-reset self.blk_cnt.dat_w.eq(0), NextState("Idle"), ).Else( NextValue(local_r_addr, local_r_addr + 1), NextValue(dma_r_addr, dma_r_addr + data_width), NextValue(self.blk_rem.status, self.blk_rem.status - 1), NextState("QueueReqToMemory"), #redundant ) ) ) # req_w_fsm.act("Reset", # NextState("Idle") # ) # req_w_fsm.act("Idle", # If(self.fromsbus_fifo.readable & # ~self.wishbone_w_master.ack, # self.fromsbus_fifo.re.eq(1), # NextValue(self.wishbone_w_master.cyc, 1), # NextValue(self.wishbone_w_master.stb, 1), # NextValue(self.wishbone_w_master.sel, 2**len(self.wishbone_w_master.sel)-1), # NextValue(self.wishbone_w_master.we, 1), # NextValue(self.wishbone_w_master.adr, self.fromsbus_fifo.dout[0:blk_addr_width]), # NextValue(self.wishbone_w_master.dat_w, self.fromsbus_fifo.dout[blk_addr_width:(blk_addr_width + data_width_bits)]), # NextValue(self.wr_tosdram.status, self.fromsbus_fifo.dout[0:blk_addr_width]), # NextState("WaitForAck") # ) # ) # req_w_fsm.act("WaitForAck", # If(self.wishbone_w_master.ack, # NextValue(self.wishbone_w_master.cyc, 0), # NextValue(self.wishbone_w_master.stb, 0), # NextState("Idle"), # ) # ) req_w_fsm.act("Reset", NextState("Idle") ) req_w_fsm.act("Idle", If(self.fromsbus_fifo.readable, self.dram_dma_writer.sink.address.eq(fromsbus_fifo_dout.blkaddress), self.dram_dma_writer.sink.data.eq(fromsbus_fifo_dout.data), self.dram_dma_writer.sink.valid.eq(1), NextValue(self.wr_tosdram.status, fromsbus_fifo_dout.blkaddress), If(self.dram_dma_writer.sink.ready, self.fromsbus_fifo.re.eq(1), NextValue(self.dma_wrdone.status, self.dma_wrdone.status + 1), If(do_checksum, self.checksum.we.eq(1), self.checksum.dat_w.eq(self.checksum.storage ^ fromsbus_fifo_dout.data), ) ) ) )
def __init__(self, dram_port, fifo_depth=512, genlock_stream=None): self.sink = sink = stream.Endpoint( frame_dma_layout) # "inputs" are the DMA frame parameters self.source = source = stream.Endpoint([ ("data", dram_port.dw) ]) # "output" is the data stream # # # self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth, True) self.submodules.fsm = fsm = FSM(reset_state="IDLE") shift = log2_int(dram_port.dw // 8) base = Signal(dram_port.aw) length = Signal(dram_port.aw) offset = Signal(dram_port.aw) self.delay_base = CSRStorage(32) delay_base = Signal(32) self.line_align = CSRStorage(16) line_align = Signal(16) self.line_skip = CSRStorage(32) line_skip = Signal(32) self.hres_out = CSRStorage(16) self.vres_out = CSRStorage(16) self.comb += [ base.eq( sink.base[shift:] ), # ignore the lower bits of the base + length to match the DMA's expectations length.eq( sink.length[shift:] ), # need to noodle on what that expectation is, exactly... ] hres = Signal(16) vres = Signal(16) self.comb += [ hres.eq(self.hres_out.storage), vres.eq(self.vres_out.storage), ] hcount = Signal(16) vcount = Signal(16) linecount = Signal(16) self.field = Signal() vsyncpos = Signal(16) even_loc = Signal(16) odd_loc = Signal(16) self.even_pos = CSRStatus(16) self.odd_pos = CSRStatus(16) self.comb += [ self.even_pos.status.eq(even_loc), self.odd_pos.status.eq(odd_loc), ] self.field_pos = CSRStorage(16) self.interlace = CSRStorage( 2) # bit 0 is enable, bit 1 is even/odd priority field_pos = Signal(16) interlace = Signal(2) self.submodules.sync_field_pos = BusSynchronizer( self.field_pos.size, "sys", "pix_o") self.submodules.sync_interlace = BusSynchronizer( self.interlace.size, "sys", "pix_o") self.submodules.sync_delay_base = BusSynchronizer( self.delay_base.size, "sys", "pix_o") self.submodules.sync_line_skip = BusSynchronizer( self.line_skip.size, "sys", "pix_o") self.submodules.sync_line_align = BusSynchronizer( self.line_align.size, "sys", "pix_o") self.comb += [ self.sync_field_pos.i.eq(self.field_pos.storage), self.sync_interlace.i.eq(self.interlace.storage), self.sync_delay_base.i.eq(self.delay_base.storage), self.sync_line_skip.i.eq(self.line_skip.storage), self.sync_line_align.i.eq(self.line_align.storage), field_pos.eq(self.sync_field_pos.o), interlace.eq(self.sync_interlace.o), delay_base.eq(self.sync_delay_base.o), line_skip.eq(self.sync_line_skip.o), line_align.eq(self.sync_line_align.o), ] squash = Signal() if genlock_stream != None: self.v = Signal() self.v_r = Signal() self.sof = Signal() self.sync += [ self.v.eq(genlock_stream.vsync), self.v_r.eq(self.v), self.sof.eq(self.v & ~self.v_r), ] self.h = Signal() self.h_r = Signal() self.sol = Signal() self.sync += [ self.h.eq(genlock_stream.hsync), self.h_r.eq(self.h), self.sol.eq(self.h & ~self.h_r), ] self.sync += [ If(self.sol, vsyncpos.eq(0)).Else(vsyncpos.eq(vsyncpos + 1)), If( self.sof, self.field.eq(~self.field), If( self.field, odd_loc.eq(vsyncpos), ).Else(even_loc.eq(vsyncpos), ), ), ] if genlock_stream == None: fsm.act( "IDLE", NextValue(offset, 0), If( sink.valid, # if our parameters are valid, start reading NextState("READ")).Else(dram_port.flush.eq(1), )) fsm.act( "READ", self.dma.sink.valid.eq( 1 ), # tell the DMA reader that we've got a valid address for it If( self.dma.sink. ready, # if the LiteDRAMDMAReader shows it's ready for an address (e.g. taken the current address) NextValue(offset, offset + 1), # increment the offset If( offset == (length - 1), # at the end... self.sink.ready.eq( 1), # indicate we're ready for more parameters NextState("IDLE")))) else: fsm.act( "IDLE", NextValue(linecount, 0), If( self.interlace.storage[0], # interlace If( self.field ^ interlace[1] ^ ( odd_loc < vsyncpos ), # xor against actual odd_loc vs vsyncpos in case we caught the wrong field polarity NextValue(offset, delay_base), NextValue(hcount, 0), NextValue(vcount, 0), ).Else( NextValue(offset, delay_base + hres + 1), NextValue(hcount, 0), NextValue(vcount, 1), )).Else( # non-interlace NextValue(offset, delay_base), NextValue(hcount, 0), NextValue(vcount, 0), ), If( sink.valid, # if our parameters are valid, start reading If( line_align == 0, NextState("READ"), ).Else(NextState("WAIT_LINE"), )).Else( dram_port.flush.eq(1), )) fsm.act( "WAIT_LINE", # insert dummy waits until wait_line is done squash.eq(1), self.dma.sink.valid.eq( 1 ), # tell the DMA reader that we've got a valid address for it If( self.dma.sink. ready, # if the LiteDRAMDMAReader shows it's ready for an address (e.g. taken the current address) If( linecount < line_align, NextValue(linecount, linecount + 1), ).Else(NextState("READ"), ))) fsm.act( "READ", self.dma.sink.valid.eq( 1 ), # tell the DMA reader that we've got a valid address for it If( self.dma.sink. ready, # if the LiteDRAMDMAReader shows it's ready for an address (e.g. taken the current address) NextValue(hcount, hcount + 1), If( hcount >= hres, If( interlace[0], # interlaced NextValue(offset, offset + line_skip + 1 + hres + 1), NextValue(hcount, 0), NextValue(vcount, vcount + 2), ).Else( # not interlaced NextValue(offset, offset + line_skip + 1), NextValue(hcount, 0), NextValue(vcount, vcount + 1), )).Else( NextValue(offset, offset + 1), # increment the offset ), If( (offset >= (length - 1)) | vcount >= vres, # at the end... self.sink.ready.eq( 1), # indicate we're ready for more parameters NextState("WAIT_SOF")))) fsm.act( "WAIT_SOF", # wait till vsync/start of frame If(self.sof, NextState("IDLE"))) self.comb += [ self.dma.sink.address.eq( base + offset), # input to the DMA is an address of base + offset self.dma.source.connect( self.source ) # connect the DMA's output to the output of this module ]
def __init__(self, soc, sbus_bus): self.stat_ctrl = CSRStorage(fields = [CSRField("update", 1, description = "update")]) self.submodules.sync_update = BusSynchronizer(width = 1, idomain="sys", odomain="sbus") self.comb += self.sync_update.i.eq(self.stat_ctrl.fields.update) self.comb += sbus_bus.stat_update.eq(self.sync_update.o) self.live_stat_cycle_counter = CSRStatus(32, description="live_stat_cycle_counter") self.stat_cycle_counter = CSRStatus(32, description="stat_cycle_counter") self.stat_slave_start_counter = CSRStatus(32, description="stat_slave_start_counter") self.stat_slave_done_counter = CSRStatus(32, description="stat_slave_done_counter") self.stat_slave_rerun_counter = CSRStatus(32, description="stat_slave_rerun_counter") #self.stat_slave_rerun_last_pa = CSRStatus(32, description="stat_slave_rerun_last_pa") #self.stat_slave_rerun_last_state = CSRStatus(32, description="stat_slave_rerun_last_state") self.stat_slave_early_error_counter = CSRStatus(32, description="stat_slave_early_error_counter") self.stat_master_start_counter = CSRStatus(32, description="stat_master_start_counter") self.stat_master_done_counter = CSRStatus(32, description="stat_master_done_counter") self.stat_master_error_counter = CSRStatus(32, description="stat_master_error_counter") self.stat_master_rerun_counter = CSRStatus(32, description="stat_master_rerun_counter") self.sbus_master_error_virtual = CSRStatus(32, description="sbus_master_error_virtual") self.submodules.sync_live_stat_cycle_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys") self.comb += self.sync_live_stat_cycle_counter.i.eq(sbus_bus.stat_cycle_counter) self.comb += self.live_stat_cycle_counter.status.eq(self.sync_live_stat_cycle_counter.o) self.submodules.sync_stat_cycle_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys") self.comb += self.sync_stat_cycle_counter.i.eq(sbus_bus.buf_stat_cycle_counter) self.comb += self.stat_cycle_counter.status.eq(self.sync_stat_cycle_counter.o) self.submodules.sync_stat_slave_start_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_slave_start_counter.i.eq(sbus_bus.buf_stat_slave_start_counter) self.comb += self.stat_slave_start_counter.status.eq(self.sync_stat_slave_start_counter.o) self.submodules.sync_stat_slave_done_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_slave_done_counter.i.eq(sbus_bus.buf_stat_slave_done_counter) self.comb += self.stat_slave_done_counter.status.eq(self.sync_stat_slave_done_counter.o) self.submodules.sync_stat_slave_rerun_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_slave_rerun_counter.i.eq(sbus_bus.buf_stat_slave_rerun_counter) self.comb += self.stat_slave_rerun_counter.status.eq(self.sync_stat_slave_rerun_counter.o) #self.submodules.sync_stat_slave_rerun_last_pa = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); #self.comb += self.sync_stat_slave_rerun_last_pa.i.eq(sbus_bus.stat_slave_rerun_last_pa) # no 'buf_' #self.comb += self.stat_slave_rerun_last_pa.status.eq(self.sync_stat_slave_rerun_last_pa.o) #self.submodules.sync_stat_slave_rerun_last_state = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); #self.comb += self.sync_stat_slave_rerun_last_state.i.eq(sbus_bus.stat_slave_rerun_last_state) # no 'buf_' #self.comb += self.stat_slave_rerun_last_state.status.eq(self.sync_stat_slave_rerun_last_state.o) self.submodules.sync_stat_slave_early_error_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_slave_early_error_counter.i.eq(sbus_bus.buf_stat_slave_early_error_counter) self.comb += self.stat_slave_early_error_counter.status.eq(self.sync_stat_slave_early_error_counter.o) self.submodules.sync_stat_master_start_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_master_start_counter.i.eq(sbus_bus.buf_stat_master_start_counter) self.comb += self.stat_master_start_counter.status.eq(self.sync_stat_master_start_counter.o) self.submodules.sync_stat_master_done_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_master_done_counter.i.eq(sbus_bus.buf_stat_master_done_counter) self.comb += self.stat_master_done_counter.status.eq(self.sync_stat_master_done_counter.o) self.submodules.sync_stat_master_error_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_master_error_counter.i.eq(sbus_bus.buf_stat_master_error_counter) self.comb += self.stat_master_error_counter.status.eq(self.sync_stat_master_error_counter.o) self.submodules.sync_stat_master_rerun_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_stat_master_rerun_counter.i.eq(sbus_bus.buf_stat_master_rerun_counter) self.comb += self.stat_master_rerun_counter.status.eq(self.sync_stat_master_rerun_counter.o) self.submodules.sync_sbus_master_error_virtual = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); self.comb += self.sync_sbus_master_error_virtual.i.eq(sbus_bus.buf_sbus_master_error_virtual) self.comb += self.sbus_master_error_virtual.status.eq(self.sync_sbus_master_error_virtual.o)
def __init__(self, dram_port): ashift, awidth = get_ashift_awidth(dram_port) self.reset = CSR() self.start = CSR() self.done = CSRStatus() self.run = CSRStorage(reset=1) self.ready = CSRStatus() self.base = CSRStorage(awidth) self.end = CSRStorage(awidth) self.length = CSRStorage(awidth) self.random = CSRStorage(fields=[ CSRField("data", size=1), CSRField("addr", size=1), ]) self.ticks = CSRStatus(32) self.errors = CSRStatus(32) # # # clock_domain = dram_port.clock_domain core = _LiteDRAMBISTChecker(dram_port) core = ClockDomainsRenamer(clock_domain)(core) self.submodules += core if clock_domain != "sys": reset_sync = PulseSynchronizer("sys", clock_domain) start_sync = PulseSynchronizer("sys", clock_domain) self.submodules += reset_sync, start_sync self.comb += [ reset_sync.i.eq(self.reset.re), core.reset.eq(reset_sync.o), start_sync.i.eq(self.start.re), core.start.eq(start_sync.o) ] done_sync = BusSynchronizer(1, clock_domain, "sys") self.submodules += done_sync self.comb += [ done_sync.i.eq(core.done), self.done.status.eq(done_sync.o) ] run_sync = BusSynchronizer(1, clock_domain, "sys") ready_sync = BusSynchronizer(1, clock_domain, "sys") self.submodules += run_sync, ready_sync self.comb += [ run_sync.i.eq(self.run.storage), core.run.eq(run_sync.o), ready_sync.i.eq(core.ready), self.ready.status.eq(ready_sync.o), ] base_sync = BusSynchronizer(awidth, "sys", clock_domain) end_sync = BusSynchronizer(awidth, "sys", clock_domain) length_sync = BusSynchronizer(awidth, "sys", clock_domain) self.submodules += base_sync, end_sync, length_sync self.comb += [ base_sync.i.eq(self.base.storage), core.base.eq(base_sync.o), end_sync.i.eq(self.end.storage), core.end.eq(end_sync.o), length_sync.i.eq(self.length.storage), core.length.eq(length_sync.o) ] self.specials += [ MultiReg(self.random.fields.data, core.random_data, clock_domain), MultiReg(self.random.fields.addr, core.random_addr, clock_domain), ] ticks_sync = BusSynchronizer(32, clock_domain, "sys") self.submodules += ticks_sync self.comb += [ ticks_sync.i.eq(core.ticks), self.ticks.status.eq(ticks_sync.o) ] errors_sync = BusSynchronizer(32, clock_domain, "sys") self.submodules += errors_sync self.comb += [ errors_sync.i.eq(core.errors), self.errors.status.eq(errors_sync.o) ] else: self.comb += [ core.reset.eq(self.reset.re), core.start.eq(self.start.re), self.done.status.eq(core.done), core.run.eq(self.run.storage), self.ready.status.eq(core.ready), core.base.eq(self.base.storage), core.end.eq(self.end.storage), core.length.eq(self.length.storage), core.random_data.eq(self.random.fields.data), core.random_addr.eq(self.random.fields.addr), self.ticks.status.eq(core.ticks), self.errors.status.eq(core.errors) ]
def __init__(self, lvds_in, _debug, sim = False): self._adjust = CSRStorage(16, atomic_write=True) self._adjust_direction = CSRStorage(1) self._adjptotal = CSRStatus(32) self._adjmtotal = CSRStatus(32) self._lock = CSRStatus(1) self._invert = CSRStorage(1) self._update_counter = CSRStorage(1) self._debug_mux = CSRStorage(8) self.submodules.adjptotal_sync = BusSynchronizer(32, "pix1x", "sys") self.submodules.adjmtotal_sync = BusSynchronizer(32, "pix1x", "sys") # IBUFDS lvds_se = Signal() if not sim: self.specials += Instance("IBUFDS", i_I=lvds_in[0], i_IB=lvds_in[1], o_O=lvds_se) debug = Signal(len(_debug)) self.comb += _debug.eq(debug) d0 = Signal() self.sync.pix1x += [ d0.eq(~d0) ] # SERDES self.i = Signal(8) self.comb += debug[0].eq(lvds_se) pd_valid = Signal() pd_incdec = Signal() pd_edge = Signal() pd_cascade = Signal() self.serdesstrobe = Signal() if not sim: self.specials += Instance("ISERDES2", p_SERDES_MODE="MASTER", p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=8, p_INTERFACE_TYPE="RETIMED", i_D=lvds_se, o_Q4=self.i[7], o_Q3=self.i[6], o_Q2=self.i[5], o_Q1=self.i[4], i_BITSLIP=0, i_CE0=1, i_RST=0, i_CLK0=ClockSignal("pix8x"), i_CLKDIV=ClockSignal("pix1x"), i_IOCE=self.serdesstrobe, o_VALID=pd_valid, o_INCDEC=pd_incdec, i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade) self.specials += Instance("ISERDES2", p_SERDES_MODE="SLAVE", p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=8, p_INTERFACE_TYPE="RETIMED", i_D=lvds_se, o_Q4=self.i[3], o_Q3=self.i[2], o_Q2=self.i[1], o_Q1=self.i[0], i_BITSLIP=0, i_CE0=1, i_RST=0, i_CLK0=ClockSignal("pix8x"), i_CLKDIV=ClockSignal("pix1x"), i_IOCE=self.serdesstrobe, i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge) self.lock = Signal() self.submodules.sampler = ClockDomainsRenamer({"sys": "pix1x"})(Sampler()) fifo = AsyncFIFO(28, 64) self.submodules.fifo = ClockDomainsRenamer( {"write":"pix1x", "read":"sys"})(fifo) self.submodules.slip = PulseSynchronizer(idomain = "sys", odomain = "pix1x") self.submodules.decoder = Decoder() # CDC for adjust set self.submodules.adjust_sync = BusSynchronizer(1 + 16, "sys", "pix1x") self.comb += [ self.adjust_sync.i[-1].eq(self._adjust_direction.storage), self.adjust_sync.i[:16].eq(self._adjust.storage), self.sampler.adjust_direction.eq(self.adjust_sync.o[-1]), self.sampler.adjust_inc.eq(self.adjust_sync.o[:16]), ] self.comb += [ # SERDES -> sampler # If(self._invert.storage, # self.sampler.i.eq(self.i[::-1])) # .Else( # self.sampler.i.eq(~self.i[::-1])), self.sampler.i.eq(self.i[::-1]), # sampler -> fifo self.fifo.din.eq(self.sampler.q), self.fifo.we.eq(self.sampler.s), self.fifo.re.eq(1), # fifo -> decoder self.decoder.i.eq(self.fifo.dout[::-1]), self.decoder.s.eq(self.fifo.readable), # decoder slip request -> pulse sync -> sampler slip self.slip.i.eq(self.decoder.slip), self.sampler.slip.eq(self.slip.o), # self.source.stb.eq(self.decoder.qs), # self.source.d.eq(self.decoder.q[24:32]), self.lock.eq(self.decoder.lock), ] # capture decoder output on decoder.qs self.decoder_q = Signal(32) self.sync += [ If(self.decoder.qs, self.decoder_q.eq(self.decoder.q) ) ] # self.comb += debug[11].eq(self.source.stb) # self.comb += debug[9].eq(self.lock) self.samplerq = Signal(28) self.submodules.samplerq_sync = BusSynchronizer(idomain = "pix1x", odomain = "sys", width=len(self.samplerq)) self.comb += [ self.samplerq_sync.i.eq(self.sampler.q), self.samplerq.eq(self.samplerq_sync.o) ] self.comb += [ If(self._debug_mux.storage == 0, debug[1:9].eq(self.sampler.edge)). Elif(self._debug_mux.storage == 1, debug[1:9].eq(self.decoder.i[0:8])). Elif(self._debug_mux.storage == 2, debug[1:9].eq(self.decoder.i[8:16])). Elif(self._debug_mux.storage == 3, debug[1:9].eq(self.decoder.i[16:24])). Elif(self._debug_mux.storage == 4, debug[1:9].eq(self.decoder.i[24:28])). Elif(self._debug_mux.storage == 5, debug[1:9].eq(self.samplerq[0:8])). Elif(self._debug_mux.storage == 6, debug[1:9].eq(self.samplerq[8:16])). Elif(self._debug_mux.storage == 7, debug[1:9].eq(self.samplerq[16:24])). Elif(self._debug_mux.storage == 8, debug[1:9].eq(self.samplerq[24:28])). Elif(self._debug_mux.storage == 9, debug[1:9].eq(self.sampler.sr)) ] # self.comb += debug[2].eq(self.sampler.numbits[0]) self.comb += debug[0].eq(d0) # self.comb += debug[6].eq(self.i[0]) # self.comb += debug[8].eq(self.sampler.s) self.comb += debug[10].eq(self.fifo.readable) self.comb += debug[11].eq(self.decoder.lock) self.comb += debug[12].eq(self.decoder.qs) # self.comb += debug[10].eq(self.sampler.phase[0]) # self.comb += debug[11].eq(self.sampler.phase[1]) # self.comb += debug[12].eq(self.sampler.phase[2]) self.comb += self._lock.status.eq(self.decoder.lock) # status (via synchronizer) self.comb += [ self.adjptotal_sync.i.eq(self.sampler.adjptotal), self.adjmtotal_sync.i.eq(self.sampler.adjmtotal), ] self.sync += [ If(self._update_counter.storage, self._adjptotal.status.eq(self.adjptotal_sync.o), self._adjmtotal.status.eq(self.adjmtotal_sync.o), ) ] # output self.source = Endpoint([('d', 8)]) self.submodules.fifo_read_fsm = FSM() self.fifo_read_fsm.act("B0", If (self.source.ack & self.decoder.qs & self.decoder.lock, NextState("B1") ), self.source.stb.eq(self.decoder.qs & self.decoder.lock,), self.source.payload.d.eq(Cat(self.decoder.q[8:14], self.decoder.q[15:17])) ) self.fifo_read_fsm.act("B1", If (self.source.ack, NextState("B0") ), self.source.stb.eq(1), self.source.payload.d.eq(self.decoder_q[0:8]) )
def __init__(self, phy, csr_data_width=32): self.sink = stream.Endpoint([("data", 32)]) self.source = stream.Endpoint([("data", 32)]) self.argument = CSRStorage(32) self.command = CSRStorage(32) if csr_data_width == 8: self.issue_cmd = CSRStorage(1) self.response = CSRStatus(120) self.cmdevt = CSRStatus(32) self.dataevt = CSRStatus(32) self.blocksize = CSRStorage(16) self.blockcount = CSRStorage(32) self.datatimeout = CSRStorage(32, reset=2**16) self.cmdtimeout = CSRStorage(32, reset=2**16) self.datawcrcclear = CSRStorage() self.datawcrcvalids = CSRStatus(32) self.datawcrcerrors = CSRStatus(32) # # # argument = Signal(32) command = Signal(32) response = Signal(120) cmdevt = Signal(32) dataevt = Signal(32) blocksize = Signal(16) blockcount = Signal(32) datatimeout = Signal(32) cmdtimeout = Signal(32) # sys to sd cdc self.specials += [ MultiReg(self.argument.storage, argument, "sd"), MultiReg(self.command.storage, command, "sd"), MultiReg(self.blocksize.storage, blocksize, "sd"), MultiReg(self.blockcount.storage, blockcount, "sd"), MultiReg(self.datatimeout.storage, datatimeout, "sd"), MultiReg(self.cmdtimeout.storage, cmdtimeout, "sd") ] # sd to sys cdc response_cdc = BusSynchronizer(120, "sd", "sys") cmdevt_cdc = BusSynchronizer(32, "sd", "sys") dataevt_cdc = BusSynchronizer(32, "sd", "sys") self.submodules += response_cdc, cmdevt_cdc, dataevt_cdc self.comb += [ response_cdc.i.eq(response), self.response.status.eq(response_cdc.o), cmdevt_cdc.i.eq(cmdevt), self.cmdevt.status.eq(cmdevt_cdc.o), dataevt_cdc.i.eq(dataevt), self.dataevt.status.eq(dataevt_cdc.o) ] self.submodules.new_command = PulseSynchronizer("sys", "sd") if csr_data_width == 8: self.comb += self.new_command.i.eq(self.issue_cmd.re) else: self.comb += self.new_command.i.eq(self.command.re) self.comb += [ phy.cfg.blocksize.eq(blocksize), phy.cfg.datatimeout.eq(datatimeout), phy.cfg.cmdtimeout.eq(cmdtimeout), phy.dataw.crc_clear.eq(self.datawcrcclear.storage), self.datawcrcvalids.status.eq(phy.dataw.crc_valids), self.datawcrcerrors.status.eq(phy.dataw.crc_errors) ] self.submodules.crc7inserter = ClockDomainsRenamer("sd")(CRC(9, 7, 40)) self.submodules.crc7checker = ClockDomainsRenamer("sd")(CRCChecker( 9, 7, 120)) self.submodules.crc16inserter = ClockDomainsRenamer("sd")( CRCUpstreamInserter()) self.submodules.crc16checker = ClockDomainsRenamer("sd")( CRCDownstreamChecker()) self.submodules.upstream_cdc = ClockDomainsRenamer({ "write": "sys", "read": "sd" })(stream.AsyncFIFO(self.sink.description, 4)) self.submodules.downstream_cdc = ClockDomainsRenamer({ "write": "sd", "read": "sys" })(stream.AsyncFIFO(self.source.description, 4)) self.submodules.upstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 32)], [('data', 8)], reverse=True)) self.submodules.downstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 8)], [('data', 32)], reverse=True)) self.comb += [ self.sink.connect(self.upstream_cdc.sink), self.upstream_cdc.source.connect(self.upstream_converter.sink), self.upstream_converter.source.connect(self.crc16inserter.sink), self.crc16checker.source.connect(self.downstream_converter.sink), self.downstream_converter.source.connect(self.downstream_cdc.sink), self.downstream_cdc.source.connect(self.source) ] self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM()) csel = Signal(max=6) waitresp = Signal(2) dataxfer = Signal(2) cmddone = Signal(reset=1) datadone = Signal(reset=1) blkcnt = Signal(32) pos = Signal(2) cerrtimeout = Signal() cerrcrc_en = Signal() derrtimeout = Signal() derrwrite = Signal() derrread_en = Signal() self.comb += [ waitresp.eq(command[0:2]), dataxfer.eq(command[5:7]), cmdevt.eq( Cat(cmddone, C(0, 1), cerrtimeout, cerrcrc_en & ~self.crc7checker.valid)), dataevt.eq( Cat(datadone, derrwrite, derrtimeout, derrread_en & ~self.crc16checker.valid)), self.crc7inserter.val.eq(Cat(argument, command[8:14], 1, 0)), self.crc7inserter.clr.eq(1), self.crc7inserter.enable.eq(1), self.crc7checker.val.eq(response) ] ccases = {} # To send command and CRC ccases[0] = phy.sink.data.eq(Cat(command[8:14], 1, 0)) for i in range(4): ccases[i + 1] = phy.sink.data.eq(argument[24 - 8 * i:32 - 8 * i]) ccases[5] = [ phy.sink.data.eq(Cat(1, self.crc7inserter.crc)), phy.sink.last.eq(waitresp == SDCARD_CTRL_RESPONSE_NONE) ] fsm.act( "IDLE", NextValue(pos, 0), If(self.new_command.o, NextValue(cmddone, 0), NextValue(cerrtimeout, 0), NextValue(cerrcrc_en, 0), NextValue(datadone, 0), NextValue(derrtimeout, 0), NextValue(derrwrite, 0), NextValue(derrread_en, 0), NextValue(response, 0), NextState("SEND_CMD"))) fsm.act( "SEND_CMD", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1), phy.sink.rd_wr_n.eq(0), Case(csel, ccases), If( phy.sink.valid & phy.sink.ready, If(csel < 5, NextValue(csel, csel + 1)).Else( NextValue(csel, 0), If(waitresp == SDCARD_CTRL_RESPONSE_NONE, NextValue(cmddone, 1), NextState("IDLE")).Else(NextValue(cerrcrc_en, 1), NextState("RECV_RESP"))))) fsm.act( "RECV_RESP", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1), phy.sink.rd_wr_n.eq(1), phy.sink.last.eq(dataxfer == SDCARD_CTRL_DATA_TRANSFER_NONE), If( waitresp == SDCARD_CTRL_RESPONSE_SHORT, phy.sink.data.eq(5) # (5+1)*8 == 48bits ).Elif( waitresp == SDCARD_CTRL_RESPONSE_LONG, phy.sink.data.eq(16) # (16+1)*8 == 136bits ), If( phy.source.valid, # Wait for resp or timeout coming from phy phy.source.ready.eq(1), If(phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(cerrtimeout, 1), NextValue(cmddone, 1), NextValue(datadone, 1), NextState("IDLE")).Elif( phy.source.last, # Check response CRC NextValue(self.crc7checker.check, phy.source.data[1:8]), NextValue(cmddone, 1), If(dataxfer == SDCARD_CTRL_DATA_TRANSFER_READ, NextValue(derrread_en, 1), NextState("RECV_DATA")).Elif( dataxfer == SDCARD_CTRL_DATA_TRANSFER_WRITE, NextState("SEND_DATA")).Else( NextValue(datadone, 1), NextState("IDLE")), ).Else( NextValue(response, Cat(phy.source.data, response[0:112]))))) fsm.act( "RECV_DATA", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(1), phy.sink.last.eq(blkcnt == (blockcount - 1)), phy.sink.data.eq(0), # Read 1 block If( phy.source.valid, phy.source.ready.eq(1), If( phy.source.status == SDCARD_STREAM_STATUS_OK, self.crc16checker.sink.data.eq( phy.source.data), # Manual connect streams except ctrl self.crc16checker.sink.valid.eq(phy.source.valid), self.crc16checker.sink.last.eq(phy.source.last), phy.source.ready.eq(self.crc16checker.sink.ready), If( phy.source.last & phy.source.ready, # End of block If(blkcnt < (blockcount - 1), NextValue(blkcnt, blkcnt + 1), NextState("RECV_DATA")).Else( NextValue(blkcnt, 0), NextValue(datadone, 1), NextState("IDLE")))).Elif( phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(derrtimeout, 1), NextValue(blkcnt, 0), NextValue(datadone, 1), phy.source.ready.eq(1), NextState("IDLE")))) fsm.act( "SEND_DATA", phy.sink.valid.eq(self.crc16inserter.source.valid), phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(0), phy.sink.last.eq(self.crc16inserter.source.last), phy.sink.data.eq(self.crc16inserter.source.data), self.crc16inserter.source.ready.eq(phy.sink.ready), If( self.crc16inserter.source.valid & self.crc16inserter.source.last & self.crc16inserter.source.ready, If(blkcnt < (blockcount - 1), NextValue(blkcnt, blkcnt + 1)).Else(NextValue(blkcnt, 0), NextValue(datadone, 1), NextState("IDLE"))), If( phy.source.valid, phy.source.ready.eq(1), If(phy.source.status != SDCARD_STREAM_STATUS_DATAACCEPTED, NextValue(derrwrite, 1))))
def __init__(self, platform): default_period = 325000000 self.intro = ModuleDoc("""Watch Dog Timer A watchdog timer for Betrusted. Once enabled, it cannot be disabled, and it must have the reset_wdt bit written periodically to avoid a watchdog reset event. If this does not happen, the WDT will attempt to toggle reset of the full chip via GSR. The timeout period is specified in 'approximately 65MHz' (15.38ns) periods by the period register. According to Xilinx, 'approximately' is +/-50%. The register cannot be updated once the WDT is running. """) self.gsr = Signal() # wire to the GSR line for the FPGA self.cfgmclk = Signal( ) # wire to FPGA's CFGMCLK ring oscillator, a "typical" 65MHz clock self.clock_domains.cd_wdt = ClockDomain() self.specials += Instance("BUFG", i_I=self.cfgmclk, o_O=self.cd_wdt.clk) platform.add_platform_command( "create_clock -name wdt -period 10.256 [get_nets {net}]", net=self.cd_wdt.clk) # 65MHz + 50% tolerance ### WATCHDOG RESET, uses the extcomm_div divider to save on gates self.watchdog = CSRStorage(fields=[ CSRField("reset_wdt", size=1, description= "Write to this register to reset the watchdog timer", pulse=True), CSRField( "enable", description= "Enable the watchdog timer. Cannot be disabled once enabled, except with a reset. Notably, a watchdog reset will disable the watchdog.", reset=0), ]) reset_wdt = Signal() w_stretch = Signal(3) reset_wdt_sys = Signal() self.sync += [ If(self.watchdog.fields.reset_wdt, w_stretch.eq(7)).Elif(w_stretch > 0, w_stretch.eq(w_stretch - 1)), reset_wdt_sys.eq(w_stretch != 0), ] self.submodules.reset_sync = BlindTransfer("sys", "wdt") self.comb += [ self.reset_sync.i.eq(reset_wdt_sys), reset_wdt.eq(self.reset_sync.o), ] self.period = CSRStorage( 32, fields=[ CSRField( "period", size=32, description= "Number of 'approximately 65MHz' CFGMCLK cycles before each reset_code must be entered. Defaults to a range of {:0.2f}-{:0.2f} seconds" .format((default_period * 10.256e-9) * 0.5, (default_period * 10.256e-9) * 1.5), reset=default_period) ]) self.state = CSRStatus( 4, fields=[ CSRField("enabled", size=1, description="WDT has been enabled"), CSRField("armed1", size=1, description="WDT in the armed1 state"), CSRField("armed2", size=1, description="WDT in the armed2 state"), CSRField("disarmed", size=1, description="WDT in the disarmed state"), ]) armed1 = Signal() armed2 = Signal() disarmed = Signal() self.specials += MultiReg(armed1, self.state.fields.armed1) self.specials += MultiReg(armed2, self.state.fields.armed2) self.specials += MultiReg(disarmed, self.state.fields.disarmed) wdog_enable_wdt = Signal() self.specials += MultiReg(self.watchdog.fields.enable, wdog_enable_wdt, odomain="wdt") wdog_enabled = Signal(reset=0) wdog_enabled_r = Signal(reset=0) self.sync.wdt += [ If(wdog_enable_wdt, wdog_enabled.eq(1)).Else(wdog_enabled.eq(wdog_enabled)), wdog_enabled_r.eq(wdog_enabled) ] self.specials += MultiReg(wdog_enabled, self.state.fields.enabled) self.submodules.period_sync = BusSynchronizer(32, "sys", "wdt") wdt_count = Signal(32) self.comb += [ self.period_sync.i.eq(self.period.fields.period), wdt_count.eq(self.period_sync.o) ] wdt_count_lock = Signal(32) wdt_start = Signal() self.sync.wdt += [ wdt_start.eq(~wdog_enabled_r & wdog_enabled), If(~wdog_enabled_r & wdog_enabled, wdt_count_lock.eq(wdt_count)).Else( wdt_count_lock.eq(wdt_count_lock), ) ] wdog_counter = Signal(32, reset=default_period) wdog_cycle = Signal() self.sync.wdt += [ If( wdt_start, wdog_counter.eq(wdt_count_lock), ).Else( If( wdog_enabled, If(wdog_counter == 0, wdog_cycle.eq(1), wdog_counter.eq(wdt_count_lock)).Else( wdog_counter.eq(wdog_counter - 1), wdog_cycle.eq(0), ))) ] do_reset = Signal() wdog = ClockDomainsRenamer("wdt")(FSM(reset_state="IDLE")) self.submodules += wdog wdog.act("IDLE", If(wdog_enabled, NextState("DISARMED"))) wdog.act( "ARMED_HOT", armed2.eq(1), If(reset_wdt, NextState("DISARMED")).Elif( wdog_cycle, do_reset.eq(1), ), ) # double-interlock: not having responded to the watchdog code immediately # is not cause for a reset: this could just be the wdog_cycle hitting at an # inopportune time relative to the watchdog reset routine. # instead, escalate to the ARMED_HOT state so that # the watchdog next period, if no action was taken, we do a reset wdog.act( "ARMED", armed1.eq(1), If(reset_wdt, NextState("DISARMED")).Elif(wdog_cycle, NextState("ARMED_HOT"))) wdog.act("DISARMED", disarmed.eq(1), If(wdog_cycle, NextState("ARMED"))) do_reset_sys = Signal() reset_stretch = Signal(5, reset=0) self.submodules.do_res_sync = BlindTransfer("wdt", "sys") self.comb += [ self.do_res_sync.i.eq(do_reset), do_reset_sys.eq(self.do_res_sync.o), ] self.sync += [ If( do_reset_sys, reset_stretch.eq(31), self.gsr.eq(0), ).Elif( reset_stretch != 0, self.gsr.eq(1), reset_stretch.eq(reset_stretch - 1), ).Else( reset_stretch.eq(0), self.gsr.eq(0), ) ]
def __init__(self, input_pads, rtio_clk_freq=150e6): N = 64 self.reset = CSRStorage(reset=1) self.locked = CSRStatus() self.dt = CSRStatus(N.bit_length()) # # # self.clock_domains.cd_helper = ClockDomain(reset_less=True) helper_locked = Signal() helper_fb = Signal() helper_output = Signal() input_se = Signal() beat1 = Signal() beat2 = Signal() self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio"), i_RST=self.reset.storage, o_LOCKED=helper_locked, # VCO at 1200MHz with 150MHz RTIO frequency p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, o_CLKFBOUT=helper_fb, i_CLKFBIN=helper_fb, # helper PLL ratio: 64/65 (N=64) p_CLKOUT0_DIVIDE_F=8.125, o_CLKOUT0=helper_output, ), MultiReg(helper_locked, self.locked.status), Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1, attr={("IOB", "TRUE")}), Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), ] ed1 = DDMTDEdgeDetector(beat1) ed2 = DDMTDEdgeDetector(beat2) self.submodules += ed1, ed2 counting = Signal() counter = Signal(N.bit_length()) result = Signal.like(counter) self.sync.helper += [ If(counting, counter.eq(counter + 1) ).Else( result.eq(counter) ), If(ed1.rising, counting.eq(1), counter.eq(0)), If(ed2.rising, counting.eq(0)) ] bsync = BusSynchronizer(len(result), "helper", "sys") self.submodules += bsync self.comb += [ bsync.i.eq(result), self.dt.status.eq(bsync.o) ]
def __init__(self, clkspertick, clkfreq, bits=64): self.clkspertick = int(clkfreq / clkspertick) self.intro = ModuleDoc("""TickTimer: A practical systick timer. TIMER0 in the system gives a high-resolution, sysclk-speed timer which overflows very quickly and requires OS overhead to convert it into a practically usable time source which counts off in systicks, instead of sysclks. The hardware parameter to the block is the divisor of sysclk, and sysclk. So if the divisor is 1000, then the increment for a tick is 1ms. If the divisor is 2000, the increment for a tick is 0.5ms. Note to self: substantial area savings could be hand by being smarter about the synchronization between the always-on and the TickTimer domains. Right now about 1.8% of the chip is eaten up by ~1100 synchronization registers to cross the 64-bit values between the clock domains. Since the values move rarely, a slightly smarter method would be to create a lock-out around a read pulse and then create some false_path rules around the datapaths to keep the place/route from getting distracted by the cross-domain clocks. """) resolution_in_ms = 1000 * (self.clkspertick / clkfreq) self.note = ModuleDoc( title="Configuration", body= "This timer was configured with {} bits, which rolls over in {:.2f} years, with each bit giving {}ms resolution" .format(bits, (2**bits / (60 * 60 * 24 * 365)) * (self.clkspertick / clkfreq), resolution_in_ms)) prescaler = Signal(max=self.clkspertick, reset=self.clkspertick) timer = Signal(bits) # cross-process domain signals. Broken out to a different CSR so it can be on a different virtual memory page. self.pause = Signal() pause = Signal() self.specials += MultiReg(self.pause, pause, "always_on") self.load = Signal() self.submodules.load_xfer = BlindTransfer("sys", "always_on") self.comb += self.load_xfer.i.eq(self.load) self.paused = Signal() paused = Signal() self.specials += MultiReg(paused, self.paused) self.timer = Signal(bits) self.submodules.timer_sync = BusSynchronizer(bits, "always_on", "sys") self.comb += [ self.timer_sync.i.eq(timer), self.timer.eq(self.timer_sync.o) ] self.resume_time = Signal(bits) self.submodules.resume_sync = BusSynchronizer(bits, "sys", "always_on") self.comb += [self.resume_sync.i.eq(self.resume_time)] self.control = CSRStorage(fields=[ CSRField( "reset", description= "Write a `1` to this bit to reset the count to 0. This bit has priority over all other requests.", pulse=True), ]) self.time = CSRStatus(bits, name="time", description="""Elapsed time in systicks""") self.comb += self.time.status.eq(self.timer_sync.o) self.submodules.reset_xfer = BlindTransfer("sys", "always_on") self.comb += [ self.reset_xfer.i.eq(self.control.fields.reset), ] self.sync.always_on += [ If( self.reset_xfer.o, timer.eq(0), prescaler.eq(self.clkspertick), ).Elif( self.load_xfer.o, prescaler.eq(self.clkspertick), timer.eq(self.resume_sync.o), ).Else( If( prescaler == 0, prescaler.eq(self.clkspertick), If(pause == 0, timer.eq(timer + 1), paused.eq(0)).Else(timer.eq(timer), paused.eq(1))).Else( prescaler.eq(prescaler - 1), )) ] self.msleep = ModuleDoc("""msleep extension The msleep extension is a Xous-specific add-on to aid the implementation of the msleep server. msleep fires an interrupt when the requested time is less than or equal to the current elapsed time in systicks. The interrupt remains active until a new target is set, or masked. There is a slight slip in time (~200ns) from when the msleep timer is set before it can take effect. This is because it takes many CPU clock cycles to transfer this data into the always-on clock domain, which runs at a much slower rate than the CPU clock. """) self.msleep_target = CSRStorage( size=bits, description="Target time in {}ms ticks".format(resolution_in_ms)) self.submodules.ev = EventManager() self.ev.alarm = EventSourceLevel() # sys-domain alarm is computed using sys-domain time view, so that the trigger condition # corresponds tightly to the setting of the target time alarm_trigger = Signal() self.comb += self.ev.alarm.trigger.eq(alarm_trigger) # always_on domain gets a delayed copy of msleep_target # thus its output may not match that of the sys-domain alarm # in particular, it takes time for msleep_target update to propagate through # the bus synchronizers; however, the "trigger" enable for the system is handled # in the sys-domain, and can be set *before* the bus synchronizers have passed the # data through. This causes the alarm to glitch prematurely. # if we seem to be errantly aborting WFI's that are entered shortly after # setting an msleep target, this race condition is likely the culprit. # the circuit below locks out alarms for the duration of time that it takes for # msleep_target to propagate to its target, and back again self.submodules.ping = BlindTransfer("sys", "always_on") self.comb += self.ping.i.eq(self.msleep_target.re) self.submodules.pong = BlindTransfer("always_on", "sys") self.comb += self.pong.i.eq(self.ping.o) lockout_alarm = Signal() self.comb += [ If(lockout_alarm, alarm_trigger.eq(0)).Else( alarm_trigger.eq( self.msleep_target.storage <= self.timer_sync.o)) ] self.sync += [ If(self.msleep_target.re, lockout_alarm.eq(1)).Elif( self.pong.o, lockout_alarm.eq(0)).Else(lockout_alarm.eq(lockout_alarm)) ] # re-compute the alarm signal in the "always on" domain -- so that this can trigger even when the CPU clock is stopped alarm = Signal() self.submodules.target_xfer = BusSynchronizer(bits, "sys", "always_on") self.comb += self.target_xfer.i.eq(self.msleep_target.storage) self.sync.always_on += alarm.eq(self.target_xfer.o <= timer) self.alarm_always_on = Signal() self.comb += self.alarm_always_on.eq(alarm)
def __init__(self, dram_port): ashift, awidth = get_ashift_awidth(dram_port) self.reset = CSR() self.start = CSR() self.done = CSRStatus() self.base = CSRStorage(awidth) self.length = CSRStorage(awidth) self.random = CSRStorage() self.ticks = CSRStatus(32) self.errors = CSRStatus(32) # # # clock_domain = dram_port.clock_domain core = _LiteDRAMBISTChecker(dram_port) core = ClockDomainsRenamer(clock_domain)(core) self.submodules += core if clock_domain != "sys": reset_sync = PulseSynchronizer("sys", clock_domain) start_sync = PulseSynchronizer("sys", clock_domain) self.submodules += reset_sync, start_sync self.comb += [ reset_sync.i.eq(self.reset.re), core.reset.eq(reset_sync.o), start_sync.i.eq(self.start.re), core.start.eq(start_sync.o) ] done_sync = BusSynchronizer(1, clock_domain, "sys") self.submodules += done_sync self.comb += [ done_sync.i.eq(core.done), self.done.status.eq(done_sync.o) ] base_sync = BusSynchronizer(awidth, "sys", clock_domain) length_sync = BusSynchronizer(awidth, "sys", clock_domain) self.submodules += base_sync, length_sync self.comb += [ base_sync.i.eq(self.base.storage), core.base.eq(base_sync.o), length_sync.i.eq(self.length.storage), core.length.eq(length_sync.o) ] self.specials += MultiReg(self.random.storage, core.random, clock_domain) ticks_sync = BusSynchronizer(32, clock_domain, "sys") self.submodules += ticks_sync self.comb += [ ticks_sync.i.eq(core.ticks), self.ticks.status.eq(ticks_sync.o) ] errors_sync = BusSynchronizer(32, clock_domain, "sys") self.submodules += errors_sync self.comb += [ errors_sync.i.eq(core.errors), self.errors.status.eq(errors_sync.o) ] else: self.comb += [ core.reset.eq(self.reset.re), core.start.eq(self.start.re), self.done.status.eq(core.done), core.base.eq(self.base.storage), core.length.eq(self.length.storage), core.random.eq(self.random.storage), self.ticks.status.eq(core.ticks), self.errors.status.eq(core.errors) ]