Loading .settings/com.elphel.vdt.cocotb.prefs +2 −1 Original line number Diff line number Diff line Loading @@ -7,8 +7,9 @@ cocotb_@_CocotbTESTCASE=run_test<-@\#\#@-> cocotb_@_GTKWaveSavFile=x393_cocotb_02.sav cocotb_@_GrepFindErr=error|ERROR cocotb_@_GrepFindErrWarn=error|warning|ERROR|WARNING cocotb_@_PatternInfo=.*[\\s.](\\w*\\.py)\:([0-9]+)\\s*\\S*\\s*\\S*\\s*(.*) cocotb_@_SaveLogsPreprocessor=true cocotb_@_SaveLogsSimulator=true com.elphel.store.context.cocotb=cocotb_@_CocotbExtraFiles<-@\#\#@->cocotb_@_CocotbMODULE<-@\#\#@->cocotb_@_GTKWaveSavFile<-@\#\#@->cocotb_@_CocotbIncludeDir<-@\#\#@->cocotb_@_CocotbDutTopFile<-@\#\#@->cocotb_@_CocotbTESTCASE<-@\#\#@->cocotb_@_GrepFindErrWarn<-@\#\#@->cocotb_@_COCOTB_DEBUG<-@\#\#@->cocotb_@_SaveLogsPreprocessor<-@\#\#@->cocotb_@_SaveLogsSimulator<-@\#\#@->cocotb_@_GrepFindErr<-@\#\#@-> com.elphel.store.context.cocotb=cocotb_@_CocotbExtraFiles<-@\#\#@->cocotb_@_CocotbMODULE<-@\#\#@->cocotb_@_GTKWaveSavFile<-@\#\#@->cocotb_@_CocotbIncludeDir<-@\#\#@->cocotb_@_CocotbDutTopFile<-@\#\#@->cocotb_@_CocotbTESTCASE<-@\#\#@->cocotb_@_GrepFindErrWarn<-@\#\#@->cocotb_@_SaveLogsPreprocessor<-@\#\#@->cocotb_@_SaveLogsSimulator<-@\#\#@->cocotb_@_GrepFindErr<-@\#\#@->cocotb_@_PatternInfo<-@\#\#@->cocotb_@_COCOTB_DEBUG<-@\#\#@-> com.elphel.store.version.cocotb=0.8 eclipse.preferences.version=1 axi/cmprs_afi_mux.v +11 −8 Original line number Diff line number Diff line Loading @@ -170,6 +170,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), //`endif reg en; // enable mux reg en_d; // or use it to reset all channels? wire en_nrst = en && ! hrst; // when hclk is not yet available reg [3:0] en_chn; // per-channel enable wire [31:0] cmd_data; Loading Loading @@ -272,6 +273,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), wire [1:0] want_wleft32 = (|items_left[7:2])? 2'b11 : items_left[1:0]; // want to set wleft[3:2] if not roll-over (actually "3" means 2) wire rollover_limited_w = max_wlen[1:0] < want_wleft32; wire afi_wvalid_w; assign cmd_we_status_w = cmd_we && ((cmd_a & 'hc) == CMPRS_AFIMUX_STATUS_CNTRL); Loading @@ -280,7 +282,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), assign cmd_we_sa_len_w = cmd_we && ((cmd_a & 'h8) == CMPRS_AFIMUX_SA_LEN); assign cmd_we_en_w = cmd_we && (cmd_a == CMPRS_AFIMUX_EN); assign cmd_we_rst_w = cmd_we && (cmd_a == CMPRS_AFIMUX_RST); assign afi_wvalid = afi_wvalid_w && !hrst; // use last_chunk_w to apply a special id to waddr and wdata and watch for it during readout Loading @@ -300,7 +302,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), assign afi_awaddr = {chunk_addr,5'b0}; assign afi_awid = afi_awid_r; // {1'b0,wleft[3:2],last_burst_in_frame,cur_chn}; assign afi_awvalid = awvalid[1]; assign afi_awvalid = awvalid[1] && !hrst; // assign afi_awlen = {wleft[3:2],2'b11}; assign afi_wdata = wdata; // assign afi_bready = 1'b1; // always ready Loading Loading @@ -371,7 +373,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), always @ (posedge hclk) begin en_d <= en; en_d <= en && !hrst; ready_to_start <= en && // ready to strta a burst !afi_wacount[5] && !(&afi_wacount[4:1]) && // >=2 free Loading Loading @@ -472,7 +474,8 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), else if (wleft != 0) wleft <= wleft - 1; if (!en) wvalid <= 0; // if (!en) wvalid <= 0; if (!en_nrst) wvalid <= 0; else if (pre_busy_w) wvalid <= 1; else if (wlast) wvalid <= 0; // should be after pre_busy_w as both can happen simultaneously Loading @@ -489,8 +492,8 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), awvalid <= {awvalid[0],pre_busy_w}; // no need to wait for afi_awready, will use fifo levels to enable pre_busy_w if (hrst) awvalid <= 0; else awvalid <= {awvalid[0],pre_busy_w}; // no need to wait for afi_awready, will use fifo levels to enable pre_busy_w if (pre_busy_w) begin cur_chn <= winner2; Loading Loading @@ -523,7 +526,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), .rst (!en), // input .dly (AFI_MUX_BUF_LATENCY), // input[3:0] will delay by AFI_MUX_BUF_LATENCY+1 (normally 3) .din ({ wvalid, wlast}), // , afi_awid_r}), // afi_awid}), // input[0:0] .dout ({afi_wvalid, afi_wlast}) //, afi_wid}) // output[0:0] .dout ({afi_wvalid_w, afi_wlast}) //, afi_wid}) // output[0:0] ); localparam [3:0] AFI_MUX_BUF_LATENCYM1 = AFI_MUX_BUF_LATENCY - 1; dly_16 #( Loading cocotb/socket_command.py +18 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,10 @@ class SocketCommand(): return self.command == "stop" def getWrite(self): return self.arguments if self.command == "write" else None def getWait(self): return self.arguments if self.command == "wait" else None def getFlush(self): return self.command == "flush" def getRead(self): return self.arguments if self.command == "read" else None def setStart(self): Loading @@ -48,6 +52,11 @@ class SocketCommand(): def setWrite(self,arguments): self.command = "write" self.arguments=arguments def setWait(self,arguments): # wait irq mask, timeout (ns) self.command = "wait" self.arguments=arguments def setFlush(self): #flush memory file (use when sync_for_* self.command = "flush" def setRead(self,arguments): self.command = "read" self.arguments=arguments Loading Loading @@ -88,7 +97,15 @@ class x393Client(): def write(self, address, data): self.cmd.setWrite([address,data]) rslt = self.communicate(self.cmd.toJSON()) print("write->",rslt) # print("write->",rslt) def waitIrq(self, irqMask,wait_ns): self.cmd.setWait([irqMask,wait_ns]) rslt = self.communicate(self.cmd.toJSON()) # print("waitIrq->",rslt) def flush(self): self.cmd.setFlush() # print("flush->",self.communicate(self.cmd.toJSON())) def read(self, address): self.cmd.setRead(address) # print("read->args",self.cmd.getArgs()) Loading cocotb/x393_cocotb_02.sav +493 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes cocotb/x393_cocotb_server.py +193 −46 Original line number Diff line number Diff line Loading @@ -28,43 +28,126 @@ import select from socket_command import SocketCommand from cocotb.triggers import Timer from x393interfaces import MAXIGPMaster from x393interfaces import MAXIGPMaster, PSBus, SAXIRdSim, SAXIWrSim from cocotb.drivers import BitDriver from cocotb.triggers import Timer, RisingEdge, ReadOnly from cocotb.result import ReturnValue, TestFailure, TestError, TestSuccess import logging import re import struct def hex_list(lst, max_items=0, frmt="0x%08x"): if (max_items == 0) or (len(lst) <= max_items): hs="[" for d in lst: hs+=frmt%(d)+", " return hs[:-2]+"]" hs = "%d ["%len(lst) fi = max_items-1 if max_items > 1 else max_items for d in lst[:fi]: hs+=frmt%(d)+", " hs += "..." if fi < max_items: hs += " "+frmt%(d) return hs+"]" class X393_cocotb_server(object): INTR_ADDRESS = 0xfffffff0 #temporary address INTM_ADDRESS = 0xfffffff4 #temporary address RESERVED = (INTR_ADDRESS,INTM_ADDRESS) writeIDMask = (1 <<12) -1 readIDMask = (1 <<12) -1 started=False def __init__(self, dut, port, host, mempath="memfile", autoflush=True): # , debug=False): int_mask = 0 # all disabled def __init__(self, dut, port, host, mempath=None, autoflush=True): # , debug=False): self.ACLK_FREQ=50000000 # 50 MHz debug = os.getenv('COCOTB_DEBUG') # None/1 if mempath is None: mempath = os.getenv('SIMULATION_PATH')+"/"+"memfile" self.mempath = mempath self.memlow = 0 self.memhigh = 0x40000000 self.autoflush = autoflush self.cmd= SocketCommand() self.dut = dut #Open file to use as system memory try: self._memfile=open(mempath, 'r+') #keep old file if it exists already except: self._memfile=open(mempath, 'w+') #create a new file if it does not exist self.dut._log.info ("Created a new 'memory' file %s"%(mempath)) # #Extend to full size self._memfile.seek(self.memhigh-1) readOK=False try: readOK = len(self._memfile.read(1))>0 self.dut._log.info ("Read from 0x%08x"%(self.memhigh-1)) # except: pass if not readOK: self._memfile.seek(self.memhigh-1) self._memfile.write(chr(0)) self._memfile.flush() self.dut._log.info("Wrote to 0x%08x to extend file to full size"%(self.memhigh-1)) # #initialize MAXIGP0 interface (main control/status registers, TODO: add MAXIGP1 for SATA) self.maxigp0 = MAXIGPMaster(entity=dut, name="dutm0", clock=dut.dutm0_aclk, rdlag=0, blag=0) self.maxigp0 = MAXIGPMaster(entity = dut, name = "dutm0", clock = dut.dutm0_aclk, rdlag = 0, blag=0) self.writeID=0 self.readID=0 #initialize Zynq register access, has methods write_reg(a,d) and read_reg(a) self.ps_sbus = PSBus(entity=dut, name="ps_sbus", clock=dut.ps_sbus_clk) self.ps_sbus = PSBus (entity = dut, name = "ps_sbus", clock = dut.ps_sbus_clk) #Bus masters (communicated over mempath file #Membridge to FPGA self.saxihp0r = SAXIRdSim(entity=dut, name="saxihp0", clock=dut.axi_hclk, mempath = mempath, memhigh=0x40000000, data_bytes=8) self.saxihp0r = SAXIRdSim (entity = dut, name = "saxihp0", clock = dut.axi_hclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 8) #Membridge from FPGA self.saxihp0w = SAXIWrSim(entity=dut, name="saxihp0", clock=dut.axi_hclk, mempath = mempath, memhigh=0x40000000, data_bytes=8, autoflush = autoflush, blatency=5) self.saxihp0w = SAXIWrSim (entity = dut, name = "saxihp0", clock = dut.axi_hclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 8, autoflush = self.autoflush, blatency = 5) #Compressors from FPGA self.saxihp1w = SAXIWrSim(entity=dut, name="saxihp1", clock=dut.axi_hclk, mempath = mempath, memhigh=0x40000000, data_bytes=8, autoflush = autoflush, blatency=5) self.saxihp1w = SAXIWrSim (entity = dut, name = "saxihp1", clock = dut.axi_hclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 8, autoflush = self.autoflush, blatency = 5) #histograms from FPGA self.saxigp0 = SAXIWrSim(entity=dut, name="saxigp0", clock=dut.saxigp0, mempath = mempath, memhigh=0x40000000, data_bytes=4, autoflush = autoflush, blatency=5) self.saxigp0 = SAXIWrSim (entity = dut, name = "saxigp0", clock = dut.saxi0_aclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 4, autoflush = self.autoflush, blatency = 5) level = logging.DEBUG if debug else logging.WARNING self.dut._log.info('Set debug level '+str(level)+", debug="+str(debug)) self.maxigp0.log.setLevel(level) self.ps_sbus.log.setLevel(level) self.saxihp0r.log.setLevel(level) self.saxihp0w.log.setLevel(level) self.saxihp1w.log.setLevel(level) self.saxigp0.log.setLevel(level) #Initialize socket self.PORT = port self.HOST = host # Symbolic name meaning all available interfaces Loading @@ -76,11 +159,10 @@ class X393_cocotb_server(object): self.socket_conn.listen(1) # just a single request (may increase to 5 (backlog) self.dut._log.info ('Socket now listening to a single request on port %d: send command, receive response, close'%(self.PORT)) except socket.error as msg: self.dut._log.info ("Maybe you need to run 'killall vvp' to close previously opened socket?" ) self.logErrorTerminate('Bind failed. Error Code : %s Message %s'%( str(msg[0]),msg[1])) def logErrorTerminate(self, msg): self.dut._log.error(msg) cocotb.regression.tear_down() Loading Loading @@ -116,15 +198,13 @@ class X393_cocotb_server(object): while self.dut.reset_out.value.get_binstr() != "1": yield Timer(10000) while self.dut.reset_out.value: yield Timer(10000) # Launch all bus masters (no need to join ever, preserving just in case self.self.saxihp0r_thread = cocotb.fork(saxihp0r.saxi_rd_run) self.self.saxihp0w_thread = cocotb.fork(saxihp0w.saxi_wr_run) self.self.saxihp1w_thread = cocotb.fork(saxihp1w.saxi_wr_run) self.self.saxihp2w_thread = cocotb.fork(saxihp2w.saxi_wr_run) self.saxihp0r_thread = cocotb.fork(self.saxihp0r.saxi_rd_run()) self.saxihp0w_thread = cocotb.fork(self.saxihp0w.saxi_wr_run()) self.saxihp1w_thread = cocotb.fork(self.saxihp1w.saxi_wr_run()) self.saxigp0_thread = cocotb.fork(self.saxigp0.saxi_wr_run()) self.soc_conn.send(self.cmd.toJSON(0)+"\n") self.dut._log.debug('Sent 0 to the socket') started=True Loading @@ -143,9 +223,20 @@ class X393_cocotb_server(object): #For now write - one at a time, TODO: a) consolidate, b) decode address (some will be just a disk file) elif self.cmd.getWrite(): ad = self.cmd.getWrite() self.dut._log.info('Received WRITE, 0x%0x: %s'%(ad[0],str(ad[1]))) if ad[0] < 0x40000000: pass self.dut._log.debug('Received WRITE, 0x%0x: %s'%(ad[0],hex_list(ad[1]))) if ad[0]in self.RESERVED: if ad[0] == self.INTM_ADDRESS: self.int_mask = ad[1][0] rslt = 0 elif (ad[0] >= self.memlow) and (ad[0] < self.memhigh): addr = ad[0] self._memfile.seek(addr) for data in ad[1]: # currently only single word is supported sdata=struct.pack("<L",data) # little-endian, u32 self._memfile.write(sdata) self.dut._log.debug("Written 'system memory': 0x%08x => 0x%08x"%(data,addr)) addr += 4 rslt = 0 elif(ad[0] >= 0x40000000) and (ad[0] < 0x80000000): rslt = yield self.maxigp0.axi_write(address = ad[0], value = ad[1], Loading @@ -155,42 +246,98 @@ class X393_cocotb_server(object): burst = 1, address_latency = 0, data_latency = 0) self.dut._log.info('maxigp0.axi_write yielded %s'%(str(rslt))) self.dut._log.debug('maxigp0.axi_write yielded %s'%(str(rslt))) self.writeID = (self.writeID+1) & self.writeIDMask elif ad[0] >= 0xc0000000: elif (ad[0] >= 0xc0000000) and (ad[0] < 0xfffffffc): self.ps_sbus.write_reg(ad[0],ad[1][0]) rslt = 0 else: self.dut._log.info('Write address 0x%08x is outside of maxgp0, not yet supported'%(ad[0])) rslt = 0 self.dut._log.info('WRITE 0x%08x <= %s'%(ad[0],hex_list(ad[1], max_items = 4))) self.soc_conn.send(self.cmd.toJSON(rslt)+"\n") self.dut._log.debug('Sent rslt to the socket') elif self.cmd.getRead(): a = self.cmd.getRead() if a < 0x40000000: pass if(a >= 0x40000000) and (a < 0x80000000): dval = yield self.maxigp0.axi_read(address = a, ad = self.cmd.getRead() self.dut._log.debug(str(ad)) if not isinstance(ad,(list,tuple)): ad=(ad,1) elif len(ad) < 2: ad=(ad[0],1) self.dut._log.debug(str(ad)) if ad[0]in self.RESERVED: if ad[0] == self.INTR_ADDRESS: try: dval=[self.dut.irq_r.value.integer] except: bv = self.dut.irq_r.value bv.binstr = re.sub("[^1]","0",bv.binstr) dval=[bv.integer] elif ad[0] == self.INTM_ADDRESS: dval = [self.int_mask] else: dval = [0] elif (ad[0] >= self.memlow) and (ad[0] < self.memhigh): addr = ad[0] self._memfile.seek(addr) self.dut._log.debug("read length="+str(len(self._memfile.read(4*ad[1])))) self._memfile.seek(addr) self.dut._log.debug(str(ad)) dval = list(struct.unpack("<"+"L"*ad[1],self._memfile.read(4*ad[1]))) msg="'Written 'system memory: 0x%08x => "%(addr) for d in dval: msg += "0x%08x "%(d) self.dut._log.debug(msg) elif(ad[0] >= 0x40000000) and (ad[0] < 0x80000000): dval = yield self.maxigp0.axi_read(address = ad[0], id = self.readID, dlen = 1, dlen = ad[1], dsize = 2, address_latency = 0, data_latency = 0 ) self.dut._log.info("axi_read returned => " +str(dval)) self.dut._log.debug("axi_read returned 0x%08x => %s"%(ad[0],hex_list(dval, max_items = 4))) self.readID = (self.readID+1) & self.readIDMask elif ad[0] >= 0xc0000000: elif (ad[0]>= 0xc0000000) and (ad[0] < 0xfffffffc): dval = yield self.ps_sbus.read_reg(ad[0]) else: self.dut._log.info('Read address 0x%08x is outside of maxgp0, not yet supported'%(a)) self.dut._log.info('Read address 0x%08x is outside of maxgp0, not yet supported'%(ad[0])) dval = [0] self.soc_conn.send(self.cmd.toJSON(dval)+"\n") self.dut._log.debug('Sent dval to the socket') self.dut._log.info("READ 0x%08x =>%s"%(ad[0],hex_list(dval, max_items = 4))) elif self.cmd.getFlush(): self.dut._log.info('Received flush') self.flush_all() self.soc_conn.send(self.cmd.toJSON(0)+"\n") self.dut._log.debug('Sent 0 to the socket') def flush_all(self): self.self.saxihp0w.flush() self.self.saxihp1w.flush() self.self.saxihp2w.flush() elif self.cmd.getWait(): #self.MAXIGP0_CLK_FREQ int_dly = self.cmd.getWait() self.int_mask = int_dly[0] num_clk= (int_dly[1] * self.ACLK_FREQ) // 1000000000 self.dut._log.info('Received WAIT, interrupt mask = 0x%0x, timeout = %d ns, %d clocks'%(self.int_mask,int_dly[1], num_clk)) n = 0 for _ in range(num_clk): yield RisingEdge(self.dut.dutm0_aclk) try: irq_r=self.dut.irq_r.value.integer except: bv = self.dut.irq_r.value bv.binstr = re.sub("[^1]","0",bv.binstr) irq_r=bv.integer if (self.int_mask & irq_r): break n += 1 self.soc_conn.send(self.cmd.toJSON(n)+"\n") self.dut._log.debug('Sent %d to the socket'%(n)) self.dut._log.info(' WAIT over, passed %d ns'%((n * 1000000000)//self.ACLK_FREQ)) else: self.dut._log.warning('Received unknown command: '+str(self.cmd)) self.soc_conn.send(self.cmd.toJSON(1)+"\n") self.dut._log.debug('Sent 1 to the socket') def convert_string(txt): number=0 Loading Loading
.settings/com.elphel.vdt.cocotb.prefs +2 −1 Original line number Diff line number Diff line Loading @@ -7,8 +7,9 @@ cocotb_@_CocotbTESTCASE=run_test<-@\#\#@-> cocotb_@_GTKWaveSavFile=x393_cocotb_02.sav cocotb_@_GrepFindErr=error|ERROR cocotb_@_GrepFindErrWarn=error|warning|ERROR|WARNING cocotb_@_PatternInfo=.*[\\s.](\\w*\\.py)\:([0-9]+)\\s*\\S*\\s*\\S*\\s*(.*) cocotb_@_SaveLogsPreprocessor=true cocotb_@_SaveLogsSimulator=true com.elphel.store.context.cocotb=cocotb_@_CocotbExtraFiles<-@\#\#@->cocotb_@_CocotbMODULE<-@\#\#@->cocotb_@_GTKWaveSavFile<-@\#\#@->cocotb_@_CocotbIncludeDir<-@\#\#@->cocotb_@_CocotbDutTopFile<-@\#\#@->cocotb_@_CocotbTESTCASE<-@\#\#@->cocotb_@_GrepFindErrWarn<-@\#\#@->cocotb_@_COCOTB_DEBUG<-@\#\#@->cocotb_@_SaveLogsPreprocessor<-@\#\#@->cocotb_@_SaveLogsSimulator<-@\#\#@->cocotb_@_GrepFindErr<-@\#\#@-> com.elphel.store.context.cocotb=cocotb_@_CocotbExtraFiles<-@\#\#@->cocotb_@_CocotbMODULE<-@\#\#@->cocotb_@_GTKWaveSavFile<-@\#\#@->cocotb_@_CocotbIncludeDir<-@\#\#@->cocotb_@_CocotbDutTopFile<-@\#\#@->cocotb_@_CocotbTESTCASE<-@\#\#@->cocotb_@_GrepFindErrWarn<-@\#\#@->cocotb_@_SaveLogsPreprocessor<-@\#\#@->cocotb_@_SaveLogsSimulator<-@\#\#@->cocotb_@_GrepFindErr<-@\#\#@->cocotb_@_PatternInfo<-@\#\#@->cocotb_@_COCOTB_DEBUG<-@\#\#@-> com.elphel.store.version.cocotb=0.8 eclipse.preferences.version=1
axi/cmprs_afi_mux.v +11 −8 Original line number Diff line number Diff line Loading @@ -170,6 +170,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), //`endif reg en; // enable mux reg en_d; // or use it to reset all channels? wire en_nrst = en && ! hrst; // when hclk is not yet available reg [3:0] en_chn; // per-channel enable wire [31:0] cmd_data; Loading Loading @@ -272,6 +273,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), wire [1:0] want_wleft32 = (|items_left[7:2])? 2'b11 : items_left[1:0]; // want to set wleft[3:2] if not roll-over (actually "3" means 2) wire rollover_limited_w = max_wlen[1:0] < want_wleft32; wire afi_wvalid_w; assign cmd_we_status_w = cmd_we && ((cmd_a & 'hc) == CMPRS_AFIMUX_STATUS_CNTRL); Loading @@ -280,7 +282,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), assign cmd_we_sa_len_w = cmd_we && ((cmd_a & 'h8) == CMPRS_AFIMUX_SA_LEN); assign cmd_we_en_w = cmd_we && (cmd_a == CMPRS_AFIMUX_EN); assign cmd_we_rst_w = cmd_we && (cmd_a == CMPRS_AFIMUX_RST); assign afi_wvalid = afi_wvalid_w && !hrst; // use last_chunk_w to apply a special id to waddr and wdata and watch for it during readout Loading @@ -300,7 +302,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), assign afi_awaddr = {chunk_addr,5'b0}; assign afi_awid = afi_awid_r; // {1'b0,wleft[3:2],last_burst_in_frame,cur_chn}; assign afi_awvalid = awvalid[1]; assign afi_awvalid = awvalid[1] && !hrst; // assign afi_awlen = {wleft[3:2],2'b11}; assign afi_wdata = wdata; // assign afi_bready = 1'b1; // always ready Loading Loading @@ -371,7 +373,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), always @ (posedge hclk) begin en_d <= en; en_d <= en && !hrst; ready_to_start <= en && // ready to strta a burst !afi_wacount[5] && !(&afi_wacount[4:1]) && // >=2 free Loading Loading @@ -472,7 +474,8 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), else if (wleft != 0) wleft <= wleft - 1; if (!en) wvalid <= 0; // if (!en) wvalid <= 0; if (!en_nrst) wvalid <= 0; else if (pre_busy_w) wvalid <= 1; else if (wlast) wvalid <= 0; // should be after pre_busy_w as both can happen simultaneously Loading @@ -489,8 +492,8 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), awvalid <= {awvalid[0],pre_busy_w}; // no need to wait for afi_awready, will use fifo levels to enable pre_busy_w if (hrst) awvalid <= 0; else awvalid <= {awvalid[0],pre_busy_w}; // no need to wait for afi_awready, will use fifo levels to enable pre_busy_w if (pre_busy_w) begin cur_chn <= winner2; Loading Loading @@ -523,7 +526,7 @@ each group of 4 bits per channel : bits [1:0] - select, bit[2] - sset (0 - nop), .rst (!en), // input .dly (AFI_MUX_BUF_LATENCY), // input[3:0] will delay by AFI_MUX_BUF_LATENCY+1 (normally 3) .din ({ wvalid, wlast}), // , afi_awid_r}), // afi_awid}), // input[0:0] .dout ({afi_wvalid, afi_wlast}) //, afi_wid}) // output[0:0] .dout ({afi_wvalid_w, afi_wlast}) //, afi_wid}) // output[0:0] ); localparam [3:0] AFI_MUX_BUF_LATENCYM1 = AFI_MUX_BUF_LATENCY - 1; dly_16 #( Loading
cocotb/socket_command.py +18 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,10 @@ class SocketCommand(): return self.command == "stop" def getWrite(self): return self.arguments if self.command == "write" else None def getWait(self): return self.arguments if self.command == "wait" else None def getFlush(self): return self.command == "flush" def getRead(self): return self.arguments if self.command == "read" else None def setStart(self): Loading @@ -48,6 +52,11 @@ class SocketCommand(): def setWrite(self,arguments): self.command = "write" self.arguments=arguments def setWait(self,arguments): # wait irq mask, timeout (ns) self.command = "wait" self.arguments=arguments def setFlush(self): #flush memory file (use when sync_for_* self.command = "flush" def setRead(self,arguments): self.command = "read" self.arguments=arguments Loading Loading @@ -88,7 +97,15 @@ class x393Client(): def write(self, address, data): self.cmd.setWrite([address,data]) rslt = self.communicate(self.cmd.toJSON()) print("write->",rslt) # print("write->",rslt) def waitIrq(self, irqMask,wait_ns): self.cmd.setWait([irqMask,wait_ns]) rslt = self.communicate(self.cmd.toJSON()) # print("waitIrq->",rslt) def flush(self): self.cmd.setFlush() # print("flush->",self.communicate(self.cmd.toJSON())) def read(self, address): self.cmd.setRead(address) # print("read->args",self.cmd.getArgs()) Loading
cocotb/x393_cocotb_02.sav +493 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes
cocotb/x393_cocotb_server.py +193 −46 Original line number Diff line number Diff line Loading @@ -28,43 +28,126 @@ import select from socket_command import SocketCommand from cocotb.triggers import Timer from x393interfaces import MAXIGPMaster from x393interfaces import MAXIGPMaster, PSBus, SAXIRdSim, SAXIWrSim from cocotb.drivers import BitDriver from cocotb.triggers import Timer, RisingEdge, ReadOnly from cocotb.result import ReturnValue, TestFailure, TestError, TestSuccess import logging import re import struct def hex_list(lst, max_items=0, frmt="0x%08x"): if (max_items == 0) or (len(lst) <= max_items): hs="[" for d in lst: hs+=frmt%(d)+", " return hs[:-2]+"]" hs = "%d ["%len(lst) fi = max_items-1 if max_items > 1 else max_items for d in lst[:fi]: hs+=frmt%(d)+", " hs += "..." if fi < max_items: hs += " "+frmt%(d) return hs+"]" class X393_cocotb_server(object): INTR_ADDRESS = 0xfffffff0 #temporary address INTM_ADDRESS = 0xfffffff4 #temporary address RESERVED = (INTR_ADDRESS,INTM_ADDRESS) writeIDMask = (1 <<12) -1 readIDMask = (1 <<12) -1 started=False def __init__(self, dut, port, host, mempath="memfile", autoflush=True): # , debug=False): int_mask = 0 # all disabled def __init__(self, dut, port, host, mempath=None, autoflush=True): # , debug=False): self.ACLK_FREQ=50000000 # 50 MHz debug = os.getenv('COCOTB_DEBUG') # None/1 if mempath is None: mempath = os.getenv('SIMULATION_PATH')+"/"+"memfile" self.mempath = mempath self.memlow = 0 self.memhigh = 0x40000000 self.autoflush = autoflush self.cmd= SocketCommand() self.dut = dut #Open file to use as system memory try: self._memfile=open(mempath, 'r+') #keep old file if it exists already except: self._memfile=open(mempath, 'w+') #create a new file if it does not exist self.dut._log.info ("Created a new 'memory' file %s"%(mempath)) # #Extend to full size self._memfile.seek(self.memhigh-1) readOK=False try: readOK = len(self._memfile.read(1))>0 self.dut._log.info ("Read from 0x%08x"%(self.memhigh-1)) # except: pass if not readOK: self._memfile.seek(self.memhigh-1) self._memfile.write(chr(0)) self._memfile.flush() self.dut._log.info("Wrote to 0x%08x to extend file to full size"%(self.memhigh-1)) # #initialize MAXIGP0 interface (main control/status registers, TODO: add MAXIGP1 for SATA) self.maxigp0 = MAXIGPMaster(entity=dut, name="dutm0", clock=dut.dutm0_aclk, rdlag=0, blag=0) self.maxigp0 = MAXIGPMaster(entity = dut, name = "dutm0", clock = dut.dutm0_aclk, rdlag = 0, blag=0) self.writeID=0 self.readID=0 #initialize Zynq register access, has methods write_reg(a,d) and read_reg(a) self.ps_sbus = PSBus(entity=dut, name="ps_sbus", clock=dut.ps_sbus_clk) self.ps_sbus = PSBus (entity = dut, name = "ps_sbus", clock = dut.ps_sbus_clk) #Bus masters (communicated over mempath file #Membridge to FPGA self.saxihp0r = SAXIRdSim(entity=dut, name="saxihp0", clock=dut.axi_hclk, mempath = mempath, memhigh=0x40000000, data_bytes=8) self.saxihp0r = SAXIRdSim (entity = dut, name = "saxihp0", clock = dut.axi_hclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 8) #Membridge from FPGA self.saxihp0w = SAXIWrSim(entity=dut, name="saxihp0", clock=dut.axi_hclk, mempath = mempath, memhigh=0x40000000, data_bytes=8, autoflush = autoflush, blatency=5) self.saxihp0w = SAXIWrSim (entity = dut, name = "saxihp0", clock = dut.axi_hclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 8, autoflush = self.autoflush, blatency = 5) #Compressors from FPGA self.saxihp1w = SAXIWrSim(entity=dut, name="saxihp1", clock=dut.axi_hclk, mempath = mempath, memhigh=0x40000000, data_bytes=8, autoflush = autoflush, blatency=5) self.saxihp1w = SAXIWrSim (entity = dut, name = "saxihp1", clock = dut.axi_hclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 8, autoflush = self.autoflush, blatency = 5) #histograms from FPGA self.saxigp0 = SAXIWrSim(entity=dut, name="saxigp0", clock=dut.saxigp0, mempath = mempath, memhigh=0x40000000, data_bytes=4, autoflush = autoflush, blatency=5) self.saxigp0 = SAXIWrSim (entity = dut, name = "saxigp0", clock = dut.saxi0_aclk, mempath = self.mempath, memhigh = self.memhigh, data_bytes = 4, autoflush = self.autoflush, blatency = 5) level = logging.DEBUG if debug else logging.WARNING self.dut._log.info('Set debug level '+str(level)+", debug="+str(debug)) self.maxigp0.log.setLevel(level) self.ps_sbus.log.setLevel(level) self.saxihp0r.log.setLevel(level) self.saxihp0w.log.setLevel(level) self.saxihp1w.log.setLevel(level) self.saxigp0.log.setLevel(level) #Initialize socket self.PORT = port self.HOST = host # Symbolic name meaning all available interfaces Loading @@ -76,11 +159,10 @@ class X393_cocotb_server(object): self.socket_conn.listen(1) # just a single request (may increase to 5 (backlog) self.dut._log.info ('Socket now listening to a single request on port %d: send command, receive response, close'%(self.PORT)) except socket.error as msg: self.dut._log.info ("Maybe you need to run 'killall vvp' to close previously opened socket?" ) self.logErrorTerminate('Bind failed. Error Code : %s Message %s'%( str(msg[0]),msg[1])) def logErrorTerminate(self, msg): self.dut._log.error(msg) cocotb.regression.tear_down() Loading Loading @@ -116,15 +198,13 @@ class X393_cocotb_server(object): while self.dut.reset_out.value.get_binstr() != "1": yield Timer(10000) while self.dut.reset_out.value: yield Timer(10000) # Launch all bus masters (no need to join ever, preserving just in case self.self.saxihp0r_thread = cocotb.fork(saxihp0r.saxi_rd_run) self.self.saxihp0w_thread = cocotb.fork(saxihp0w.saxi_wr_run) self.self.saxihp1w_thread = cocotb.fork(saxihp1w.saxi_wr_run) self.self.saxihp2w_thread = cocotb.fork(saxihp2w.saxi_wr_run) self.saxihp0r_thread = cocotb.fork(self.saxihp0r.saxi_rd_run()) self.saxihp0w_thread = cocotb.fork(self.saxihp0w.saxi_wr_run()) self.saxihp1w_thread = cocotb.fork(self.saxihp1w.saxi_wr_run()) self.saxigp0_thread = cocotb.fork(self.saxigp0.saxi_wr_run()) self.soc_conn.send(self.cmd.toJSON(0)+"\n") self.dut._log.debug('Sent 0 to the socket') started=True Loading @@ -143,9 +223,20 @@ class X393_cocotb_server(object): #For now write - one at a time, TODO: a) consolidate, b) decode address (some will be just a disk file) elif self.cmd.getWrite(): ad = self.cmd.getWrite() self.dut._log.info('Received WRITE, 0x%0x: %s'%(ad[0],str(ad[1]))) if ad[0] < 0x40000000: pass self.dut._log.debug('Received WRITE, 0x%0x: %s'%(ad[0],hex_list(ad[1]))) if ad[0]in self.RESERVED: if ad[0] == self.INTM_ADDRESS: self.int_mask = ad[1][0] rslt = 0 elif (ad[0] >= self.memlow) and (ad[0] < self.memhigh): addr = ad[0] self._memfile.seek(addr) for data in ad[1]: # currently only single word is supported sdata=struct.pack("<L",data) # little-endian, u32 self._memfile.write(sdata) self.dut._log.debug("Written 'system memory': 0x%08x => 0x%08x"%(data,addr)) addr += 4 rslt = 0 elif(ad[0] >= 0x40000000) and (ad[0] < 0x80000000): rslt = yield self.maxigp0.axi_write(address = ad[0], value = ad[1], Loading @@ -155,42 +246,98 @@ class X393_cocotb_server(object): burst = 1, address_latency = 0, data_latency = 0) self.dut._log.info('maxigp0.axi_write yielded %s'%(str(rslt))) self.dut._log.debug('maxigp0.axi_write yielded %s'%(str(rslt))) self.writeID = (self.writeID+1) & self.writeIDMask elif ad[0] >= 0xc0000000: elif (ad[0] >= 0xc0000000) and (ad[0] < 0xfffffffc): self.ps_sbus.write_reg(ad[0],ad[1][0]) rslt = 0 else: self.dut._log.info('Write address 0x%08x is outside of maxgp0, not yet supported'%(ad[0])) rslt = 0 self.dut._log.info('WRITE 0x%08x <= %s'%(ad[0],hex_list(ad[1], max_items = 4))) self.soc_conn.send(self.cmd.toJSON(rslt)+"\n") self.dut._log.debug('Sent rslt to the socket') elif self.cmd.getRead(): a = self.cmd.getRead() if a < 0x40000000: pass if(a >= 0x40000000) and (a < 0x80000000): dval = yield self.maxigp0.axi_read(address = a, ad = self.cmd.getRead() self.dut._log.debug(str(ad)) if not isinstance(ad,(list,tuple)): ad=(ad,1) elif len(ad) < 2: ad=(ad[0],1) self.dut._log.debug(str(ad)) if ad[0]in self.RESERVED: if ad[0] == self.INTR_ADDRESS: try: dval=[self.dut.irq_r.value.integer] except: bv = self.dut.irq_r.value bv.binstr = re.sub("[^1]","0",bv.binstr) dval=[bv.integer] elif ad[0] == self.INTM_ADDRESS: dval = [self.int_mask] else: dval = [0] elif (ad[0] >= self.memlow) and (ad[0] < self.memhigh): addr = ad[0] self._memfile.seek(addr) self.dut._log.debug("read length="+str(len(self._memfile.read(4*ad[1])))) self._memfile.seek(addr) self.dut._log.debug(str(ad)) dval = list(struct.unpack("<"+"L"*ad[1],self._memfile.read(4*ad[1]))) msg="'Written 'system memory: 0x%08x => "%(addr) for d in dval: msg += "0x%08x "%(d) self.dut._log.debug(msg) elif(ad[0] >= 0x40000000) and (ad[0] < 0x80000000): dval = yield self.maxigp0.axi_read(address = ad[0], id = self.readID, dlen = 1, dlen = ad[1], dsize = 2, address_latency = 0, data_latency = 0 ) self.dut._log.info("axi_read returned => " +str(dval)) self.dut._log.debug("axi_read returned 0x%08x => %s"%(ad[0],hex_list(dval, max_items = 4))) self.readID = (self.readID+1) & self.readIDMask elif ad[0] >= 0xc0000000: elif (ad[0]>= 0xc0000000) and (ad[0] < 0xfffffffc): dval = yield self.ps_sbus.read_reg(ad[0]) else: self.dut._log.info('Read address 0x%08x is outside of maxgp0, not yet supported'%(a)) self.dut._log.info('Read address 0x%08x is outside of maxgp0, not yet supported'%(ad[0])) dval = [0] self.soc_conn.send(self.cmd.toJSON(dval)+"\n") self.dut._log.debug('Sent dval to the socket') self.dut._log.info("READ 0x%08x =>%s"%(ad[0],hex_list(dval, max_items = 4))) elif self.cmd.getFlush(): self.dut._log.info('Received flush') self.flush_all() self.soc_conn.send(self.cmd.toJSON(0)+"\n") self.dut._log.debug('Sent 0 to the socket') def flush_all(self): self.self.saxihp0w.flush() self.self.saxihp1w.flush() self.self.saxihp2w.flush() elif self.cmd.getWait(): #self.MAXIGP0_CLK_FREQ int_dly = self.cmd.getWait() self.int_mask = int_dly[0] num_clk= (int_dly[1] * self.ACLK_FREQ) // 1000000000 self.dut._log.info('Received WAIT, interrupt mask = 0x%0x, timeout = %d ns, %d clocks'%(self.int_mask,int_dly[1], num_clk)) n = 0 for _ in range(num_clk): yield RisingEdge(self.dut.dutm0_aclk) try: irq_r=self.dut.irq_r.value.integer except: bv = self.dut.irq_r.value bv.binstr = re.sub("[^1]","0",bv.binstr) irq_r=bv.integer if (self.int_mask & irq_r): break n += 1 self.soc_conn.send(self.cmd.toJSON(n)+"\n") self.dut._log.debug('Sent %d to the socket'%(n)) self.dut._log.info(' WAIT over, passed %d ns'%((n * 1000000000)//self.ACLK_FREQ)) else: self.dut._log.warning('Received unknown command: '+str(self.cmd)) self.soc_conn.send(self.cmd.toJSON(1)+"\n") self.dut._log.debug('Sent 1 to the socket') def convert_string(txt): number=0 Loading