Commit 05a118d9 authored by Andrey Filippov's avatar Andrey Filippov

working with cocotb simulation

parent ca6e4334
......@@ -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
......@@ -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;
......@@ -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);
......@@ -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
......@@ -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
......@@ -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
......@@ -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
......@@ -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;
......@@ -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 #(
......
......@@ -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):
......@@ -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
......@@ -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())
......
This diff is collapsed.
This diff is collapsed.
......@@ -357,19 +357,23 @@ module x393_dut#(
//`include "includes/x393_cur_params_sim.vh" // parameters that may need adjustment, should be before x393_localparams.vh
// *** Adjusting includes/x393_cur_params_target.vh by the hardware may break simulation, hard-wired parameters below are tested ***
/*
`ifdef USE_HARD_CURPARAMS
localparam DLY_LANE0_ODELAY = 80'hd85c1014141814181218;
localparam DLY_LANE0_IDELAY = 72'h2c7a8380897c807b88;
localparam DLY_LANE1_ODELAY = 80'hd8581812181418181814;
localparam DLY_LANE1_IDELAY = 72'h108078807a887c8280;
localparam DLY_CMDA = 256'hd3d3d3d4dcd1d8cc494949494949494949d4d3ccd3d3dbd4ccd4d2d3d1d2d8cc;
`include "includes/x393_cur_params_target_simulation.vh" // SuppressThisWarning VEditor - not used parameters that may need adjustment, should be before x393_localparams.vh
// localparam DLY_LANE0_ODELAY = 80'hd85c1014141814181218;
// localparam DLY_LANE0_IDELAY = 72'h2c7a8380897c807b88;
// localparam DLY_LANE1_ODELAY = 80'hd8581812181418181814;
// localparam DLY_LANE1_IDELAY = 72'h108078807a887c8280;
// localparam DLY_CMDA = 256'hd3d3d3d4dcd1d8cc494949494949494949d4d3ccd3d3dbd4ccd4d2d3d1d2d8cc;
// localparam DLY_PHASE = 8'h33;
`else
`include "includes/x393_cur_params_target.vh" // SuppressThisWarning VEditor - not used parameters that may need adjustment, should be before x393_localparams.vh
`endif
`include "includes/x393_localparams.vh" // SuppressThisWarning VEditor - not used
*/
// ========================== parameters from x353 ===================================
`ifdef SYNC_COMPRESS
......@@ -719,10 +723,10 @@ assign #10 gpio_pins[9] = gpio_pins[8];
// reg [639:0] TEST_TITLE="abcdef"; //S uppressThisWarning VEditor May use again later
// Simulation signals
wire CLK;
reg RST;
reg RST_CLEAN = 1;
// reg RST_CLEAN = 1;
/*
wire [NUM_INTERRUPTS-1:0] IRQ_R = {x393_i.sata_irq, x393_i.cmprs_irq[3:0], x393_i.frseq_irq[3:0]};
wire [NUM_INTERRUPTS-1:0] IRQ_ACKN;
wire [3:0] IRQ_FRSEQ_ACKN = IRQ_ACKN[3:0];
......@@ -742,7 +746,7 @@ assign #10 gpio_pins[9] = gpio_pins[8];
wire [3:0] IRQ_CMPRS_S = IRQ_S[7:4];
wire IRQ_SATA_S = IRQ_S[8];// SuppressThisWarning VEditor - not used
*/
assign reset_out = RST || x393_i.arst;
x393 #(
// TODO: Are these parameters needed? They are included in x393 from the save x393_parameters.vh
......@@ -1649,7 +1653,7 @@ simul_axi_hp_wr #(
.VACT (PX4_VACT), // output
.VACT1 () // output
);
/*
sim_soc_interrupts #(
.NUM_INTERRUPTS (NUM_INTERRUPTS)
) sim_soc_interrupts_i (
......@@ -1663,7 +1667,7 @@ simul_axi_hp_wr #(
.inta (IRQ_ACKN), // output[7:0]
.main_go (MAIN_GO) // output
);
*/
// Initilize simulation
`ifndef ROOTPATH
......@@ -1678,7 +1682,7 @@ simul_axi_hp_wr #(
$display(`ROOTPATH);
$display({`ROOTPATH,"/",`DATAPATH});
RST_CLEAN = 1;
// RST_CLEAN = 1;
RST = 1'bx;
$display("%t %s:%d RST=1'bx",$time,`__FILE__,`__LINE__);
#500;
......@@ -1689,14 +1693,16 @@ simul_axi_hp_wr #(
RST =1'b0;
$display("%t %s:%d RST=1'b0",$time,`__FILE__,`__LINE__);
@(posedge CLK) ;
RST_CLEAN = 0;
$display("%t %s:%d RST_CLEAN=1'b0",$time,`__FILE__,`__LINE__);
// RST_CLEAN = 0;
// $display("%t %s:%d RST_CLEAN=1'b0",$time,`__FILE__,`__LINE__);
// IRQ-related
/*
IRQ_EN = 1;
IRQ_M = 0;
IRQ_FRSEQ_DONE = 0;
IRQ_CMPRS_DONE = 0;
IRQ_SATA_DONE = 0;
*/
#5000;
// Need to killall vvp
// $finish;
......
......@@ -55,7 +55,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. '''
import cocotb
from cocotb.triggers import Timer, RisingEdge, ReadOnly, Lock
from cocotb.triggers import Timer, RisingEdge, FallingEdge, Edge, ReadOnly, Lock
from cocotb.drivers import BusDriver
from cocotb.result import ReturnValue
from cocotb.binary import BinaryValue
......@@ -64,6 +64,7 @@ import re
import binascii
import array
import struct
#import logging
#channels
AR_CHN="AR"
......@@ -72,7 +73,7 @@ R_CHN="R"
W_CHN="W"
B_CHN="B"
def _float_signals(self,signals):
def _float_signals(signals):
if not isinstance (signals,(list,tuple)):
signals = (signals,)
for signal in signals:
......@@ -80,6 +81,8 @@ def _float_signals(self,signals):
v.binstr = "z" * len(signal)
signal <= v
class MAXIGPReadError(Exception):
# print ("MAXIGPReadError")
pass
......@@ -89,18 +92,19 @@ class PSBus(BusDriver):
Small subset of Zynq registers, used to access SAXI_HP* registers
"""
_signals=[ # i/o from the DUT side
clk, # output
addr, # input [31:0]
wr, # input
rd, # input
din, # input [31:0]
dout] #output [31:0]
"clk", # output
"addr", # input [31:0]
"wr", # input
"rd", # input
"din", # input [31:0]
"dout"] #output [31:0]
def __init__(self, entity, name, clock):
BusDriver.__init__(self, entity, name, clock)
self.busy_channel = Lock("%s_busy"%(name))
self.bus.wr.setimmediatevalue(0)
self.bus.rd.setimmediatevalue(0)
_float_signals((self.bus.addr, self.bus.din))
self.name = name
@cocotb.coroutine
def write_reg(self,addr,data):
......@@ -167,20 +171,36 @@ class SAXIWrSim(BusDriver):
@param autoflush flush file after each write
@param blatency number of cycles to delay write response (b) channel
"""
# self.log.setLevel(logging.DEBUG)
BusDriver.__init__(self, entity, name, clock)
self.log.debug ("SAXIWrSim.__init__(): super done")
self._memfile=open(mempath, 'w+')
self.name = name
self.log.debug ("SAXIWrSim: name='%s', mempath='%s', memhigh=0x%08x, data_bytes=%d, autoflush=%s, blatency=%d"%
(name,mempath,memhigh,data_bytes, str(autoflush), blatency))
# self.log.debug ("SAXIWrSim.__init__(): super done")
#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.log.info ("SAXIWrSim(%s): created a new 'memory' file %s"%(name,mempath)) #
#Extend to full size
self._memfile.seek(memhigh-1)
readOK=False
try:
self._memfile.read(1)
readOK = len(self._memfile.read(1))>0
self.log.debug ("Read from 0x%08x"%(memhigh-1)) #
except:
pass
if not readOK:
self._memfile.seek(memhigh-1)
self._memfile.write(chr(0))
self._memfile.flush()
self.log.info("Wrote to 0x%08x to extend file to full size"%(memhigh-1)) #
self.autoflush=autoflush
self.bus.wr_ready.setimmediatevalue(1) # always ready
self.bresp_latency = blatency
self.bus.bresp_latency.setimmediatevalue(blatency)
if data_bytes > 4:
self._data_bytes = 8
self._address_lsb = 3
......@@ -197,12 +217,14 @@ class SAXIWrSim(BusDriver):
self._data_bytes = 1
self._address_lsb = 0
self._fmt= "<B"
self.log.debug ("SAXIWrSim(%s) init done"%(self.name))
def flush(self):
self._memfile.flush()
@cocotb.coroutine
def saxi_wr_run(self):
self.log.debug ("SAXIWrSim(%s).saxi_wr_run"%(self.name))
while True:
if not self.bus.wr_ready.value:
break #exit
......@@ -278,9 +300,33 @@ class SAXIRdSim(BusDriver):
@param data_bytes data width, in bytes
"""
# self.log.setLevel(logging.DEBUG)
BusDriver.__init__(self, entity, name, clock)
self.log.debug ("SAXIWrSim.__init__(): super done")
self._memfile=open(mempath, 'r+')
self.name = name
self.log.debug ("SAXIRdSim: name='%s', mempath='%s', memhigh=0x%08x, data_bytes=%d"%
(name,mempath,memhigh,data_bytes))
# self._memfile=open(mempath, 'r+')
#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.log.info ("SAXIRdSim(%s): created a new 'memory' file %s"%(name,mempath)) #
#Extend to full size
self._memfile.seek(memhigh-1)
readOK=False
try:
readOK = len(self._memfile.read(1))>0
self.log.debug ("Read from 0x%08x"%(memhigh-1)) #
except:
pass
if not readOK:
self._memfile.seek(memhigh-1)
self._memfile.write(chr(0))
self._memfile.flush()
self.log.info("Wrote to 0x%08x to extend file to full size"%(memhigh-1)) #
self.bus.rd_valid.setimmediatevalue(0)
if data_bytes > 4:
......@@ -299,9 +345,16 @@ class SAXIRdSim(BusDriver):
self._data_bytes = 1
self._address_lsb = 0
self._fmt= "<B"
self.log.debug("SAXIRdSim(%s) init done"%(self.name))
@cocotb.coroutine
def saxi_test(self):
self.log.info ("SAXIRdSim(%s).saxi_test"%(self.name))
yield Timer(1000)
@cocotb.coroutine
def saxi_rd_run(self):
self.log.info ("SAXIRdSim(%s).saxi_wr_run"%(self.name))
while True:
# if not self.bus.rd_valid.value:
# break #exit
......@@ -404,6 +457,8 @@ class MAXIGPMaster(BusDriver):
_channels = [AR_CHN,AW_CHN,R_CHN,W_CHN,B_CHN]
def __init__(self, entity, name, clock, rdlag=None, blag=None):
BusDriver.__init__(self, entity, name, clock)
# self.log.setLevel(logging.DEBUG)
self.name = name
# set read and write back channels simulation lag between AXI sets valid and host responds with
# ready. If None - drive these signals
self.log.debug ("MAXIGPMaster.__init__(): super done")
......@@ -429,7 +484,7 @@ class MAXIGPMaster(BusDriver):
self.bus.awprot.setimmediatevalue(0)
self.bus.awqos.setimmediatevalue(0)
self.busy_channels = {}
self.log.debug ("MAXIGPMaster.__init__(): pre-lcok done")
self.log.debug ("MAXIGPMaster.__init__(): pre-lock done")
#Locks on each subchannel
for chn in self._channels:
......
-d TARGET_MODE=1
-f system_defines.vh
-f includes/x393_parameters.vh includes/x393_cur_params_target.vh includes/x393_localparams.vh includes/x393_simulation_parameters.vh
-f includes/x393_parameters.vh includes/x393_cur_params_target_simulation.vh includes/x393_localparams.vh includes/x393_simulation_parameters.vh
-l includes/x393_cur_params_target_gen.vh
-l includes/x393_cur_params_target_gen.vh
-p PICKLE="includes/x393_mcntrl.pickle"
......
......@@ -267,6 +267,85 @@ class X393Cmprs(object):
focus_mode = focus_mode)
self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR + chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_CONTROL_REG,
data)
def compressor_interrupt_control (self,
chn,
cntrl = "clr"):
"""
Control compressor interrupts
@param chn - compressor channel number, "a" or "all" - same for all 4 channels
@param cntrl - "clr" - clear, "en" - enable, "dis" - disable
"""
# print("compressor_interrupt_control(",chn,", ",cntrl,")")
try:
if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
for chn in range(4):
self.compressor_interrupt_control (chn = chn,
cntrl = cntrl)
return
except:
pass
if cntrl.lower() == "clr":
data = 1
elif cntrl.lower() == "dis":
data = 2
elif cntrl.lower() == "en":
data = 3
else:
print ("compressor_interrupts(): invalid control mode: %s, only 'clr', 'en' and 'dis' are accepted"%(str(cntrl)))
return
self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR + chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_INTERRUPTS,
data)
def compressor_interrupt_acknowledge (self, enabledOnly=True):
"""
Clear (one of) raised compressor interrupts
@param enabledOnly consider only channels with interrupts enabled
@return number of cleared interrupt, None if none was set
"""
d = 0 if enabledOnly else 2
for chn in range(4):
if ((self.get_status_compressor(chn) | d) & 3) == 3: # both request and mask are set
self.compressor_interrupt_control(chn, "clr")
return chn
return None
def get_status_compressor ( self,
chn="All"):
"""
Read compressor status word
@param chn - compressor port (0..3)
@return status word
"""
try:
if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
rslt = []
for chn in range(4):
rslt.append(self.get_status_compressor (chn = chn))
return rslt
except:
pass
return self.x393_axi_tasks.read_status(
address=(vrlg.CMPRS_STATUS_REG_BASE + chn * vrlg.CMPRS_STATUS_REG_INC))
def get_highfreq_compressor ( self,
chn="All"):
"""
Read total high frequency amount from the compressor
@param chn - compressor port (0..3)
@return status word
"""
try:
if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
rslt = []
for chn in range(4):
rslt.append(self.get_highfreq_compressor (chn = chn))
return rslt
except:
pass
return self.x393_axi_tasks.read_status(
address=(vrlg.CMPRS_HIFREQ_REG_BASE + num_sensor * vrlg.CMPRS_STATUS_REG_INC))
def setup_compressor_memory (self,
num_sensor,
frame_sa,
......
......@@ -93,7 +93,7 @@ class X393CmprsAfi(object):
"""
# print ("status reg = 0x%x"%(((vrlg.CMPRS_AFIMUX_REG_ADDR0, vrlg.CMPRS_AFIMUX_REG_ADDR1)[port_afi]+channel) ))
# print ("status reg data = 0x%x"%(self.x393_axi_tasks.read_status((vrlg.CMPRS_AFIMUX_REG_ADDR0, vrlg.CMPRS_AFIMUX_REG_ADDR1)[port_afi]+channel) ))
if (self.DRY_MODE):
if self.DRY_MODE == True:
return None
return 32*(self.x393_axi_tasks.read_status((vrlg.CMPRS_AFIMUX_REG_ADDR0, vrlg.CMPRS_AFIMUX_REG_ADDR1)[port_afi]+channel) & 0x3ffffff)
......
......@@ -44,6 +44,7 @@ import x393_cmprs
import x393_cmprs_afi
import vrlg
import time
import os
STD_QUANT_TBLS = {
"Y_landscape":( 16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
......@@ -763,6 +764,11 @@ class X393Jpeg(object):
self.x393_sens_cmprs.specify_window(verbose = 2)
return numChannels
def _get_project_root(self):
"""
@return absolute path of the directory one above current script one
"""
return os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))
def jpeg_write(self,
file_path = "img.jpeg",
channel = 0,
......@@ -784,9 +790,29 @@ class X393Jpeg(object):
@param server_root - files ystem path to the web server root directory
@param verbose - verbose level
"""
useNextReady = False
try:
if (channel == next) or (channel[0].upper() == "N"): #next is a built-in function
useNextReady = True
except:
pass
if useNextReady:
channel = self.x393Cmprs.compressor_interrupt_acknowledge(enabledOnly=True)
if channel is None:
raise Exception ("No channels have new compressed images ready")
else:
schn="-"+str(channel)
if '@' in file_path:
file_path=file_path[:file_path.rindex('@')+1]+schn+file_path[file_path.rindex('@')+1:] #insert after after '@' (keep @ to be replaced by a timestamp)
elif '.' in file_path:
file_path=file_path[:file_path.rindex('.')]+schn+file_path[file_path.rindex('.'):] #insert before '.'
print("Channel %d has JPEG image ready, using path %s"%(channel, file_path))
#change image name
if server_root is None:
if (self.DRY_MODE):
server_root = "../www/"
server_root = self._get_project_root()+"/www/"
if not os.path.exists(server_root):
os.mkdir(server_root)
else:
server_root = "/www/pages/"
allFiles = False
......@@ -867,7 +893,7 @@ class X393Jpeg(object):
color_mode = window["cmode"], #color_mode,
byrshift = byrshift,
verbose = verbose - 1)
if self.DRY_MODE:
if self.DRY_MODE == True:
meta = self.x393_cmprs_afi.afi_mux_get_image_meta(
port_afi = SIMULATION_JPEG_DATA, # 0,
channel = channel,
......@@ -875,6 +901,8 @@ class X393Jpeg(object):
circbuf_len = 0, #x393_sens_cmprs.GLBL_CIRCBUF_ENDS[channel] - x393_sens_cmprs.GLBL_CIRCBUF_STARTS[channel],
verbose = verbose)
else:
if self.DRY_MODE: # only with socket connection
self.x393_mem.flush_simulation()# Same as sync_for_cpu() ?
meta = self.x393_cmprs_afi.afi_mux_get_image_meta(
port_afi = 0,
channel = channel,
......@@ -888,6 +916,9 @@ class X393Jpeg(object):
if verbose > 1 :
for s in meta["segments"]:
print ("start_address = 0x%x, length = 0x%x"%(s[0],s[1]))
if "@" in file_path:
fts=("%f"%(meta["timestamp"])).replace(".","_")
file_path=file_path[:file_path.rindex('@')]+fts+file_path[file_path.rindex('@')+1:] #replacing '@'
with open (server_root+file_path, "w+b") as bf:
bf.write(jpeg_data["header"])
for s in meta["segments"]:
......@@ -1064,6 +1095,31 @@ compressor_control all 2
jpeg_write "img.jpeg" 0 85
################## Simulate Serial ####################
measure_all "*DI"
setup_all_sensors True None 0xf
compressor_control all None None None None None 2
compressor_interrupt_control all clr
compressor_interrupt_control all en
compressor_control all 3
wait_irq 0xf0 100000
wait_irq 0x0 100
jpeg_write "img@.jpeg" next
jpeg_write "/home/eyesis/git/x393-neon/www/img.jpeg" next
x393 (localhost:7777) +107.289s--> compressor_control all None None None None None 2
x393 (localhost:7777) +0.647s--> compressor_interrupt_control all clr
x393 (localhost:7777) +0.150s--> compressor_interrupt_control all en
x393 (localhost:7777) +0.589s--> compressor_interrupt_control 0 en
x393 (localhost:7777) +0.153s--> compressor_interrupt_control 1 en
x393 (localhost:7777) +0.147s--> compressor_interrupt_control 2 en
x393 (localhost:7777) +0.150s--> compressor_interrupt_control 3 en
x393 (localhost:7777) +0.162s--> compressor_control all 3
################## Serial ####################
cd /usr/local/verilog/; test_mcntrl.py @hargs
bitstream_set_path /usr/local/verilog/x393_hispi.bit
......
......@@ -109,8 +109,8 @@ class X393McntrlMembridge(object):
except:
pass
if dry_mode:
BUFFER_ADDRESS=0x27900000
BUFFER_LEN= 0x6400000
BUFFER_ADDRESS=0x25500000
BUFFER_LEN= 0x19000000
print ("Running in simulated mode, using hard-coded addresses:")
else:
try:
......
......@@ -133,6 +133,34 @@ class X393Mem(object):
else:
X393_CLIENT.stop()
X393_CLIENT = True # just simulated mode
def flush_simulation(self):
"""
Flush simulation 'system memory" file
"""
global X393_CLIENT
if X393_CLIENT is None:
print ("flush_simulation(): Not running in simulated mode")
return
elif X393_CLIENT is True:
print ("flush_simulation(): Not running as a client to x393 simulation server")
return
else:
X393_CLIENT.flush()
def wait_irq(self,irq_mask= 0, wait_ns = 1000):
"""
Wait silation certain time, interruptible
@param irq_mask - mask to be AND-ed with interrupt vector
@param wait_ns - timeout in nanoseconds
"""
global X393_CLIENT
if X393_CLIENT is None:
print ("wait_irq(): Not running in simulated mode")
return
elif X393_CLIENT is True:
print ("wait_irq(): Not running as a client to x393 simulation server")
return
else:
X393_CLIENT.waitIrq(irq_mask, wait_ns)
def write_mem (self,addr, data,quiet=1):
"""
......@@ -149,7 +177,7 @@ class X393Mem(object):
if quiet < 1:
print ("remote: write_mem(0x%x,0x%x)"%(addr,data))
X393_CLIENT.write(addr, [data])
if quiet < 2:
if quiet < 1:
print ("remote: write_mem done" )
return
with open("/dev/mem", "r+b") as f:
......@@ -280,9 +308,26 @@ class X393Mem(object):
@param start_addr physical byte start address
@param length - number of bytes to save
'''
if self.DRY_MODE:
if self.DRY_MODE == True:
print ("Write memory to file is not implemented in non-target mode")
return
elif self.DRY_MODE: # Cocotb over socket
first_page = start_addr // self.PAGE_SIZE
last_page = (start_addr + length - 1) // self.PAGE_SIZE
for page_num in range(first_page, last_page+1):
start_offset = 0
if page_num == first_page:
start_offset = start_addr - self.PAGE_SIZE * page_num
end_offset = self.PAGE_SIZE
if page_num == last_page:
end_offset = start_addr + length - self.PAGE_SIZE * page_num
page_addr = page_num * self.PAGE_SIZE
page_data= X393_CLIENT.read((page_addr, self.PAGE_SIZE//4)) # always read memory page (as in mmap)
mm = struct.pack("<"+("L"*(self.PAGE_SIZE//4)),*page_data)
bf.write(mm[start_offset:end_offset])
# mm = self.wrap_mm(f, page_addr)
# bf.write(mm[start_offset:end_offset])
return
with open("/dev/mem", "r+b") as f:
first_page = start_addr // self.PAGE_SIZE
last_page = (start_addr + length - 1) // self.PAGE_SIZE
......
......@@ -154,11 +154,11 @@ class X393SensCmprs(object):
try:
if ":" in dry_mode:
print ("X393SensCmprs.__init__: setting SENSOR_DEFAULTS")
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_PARALLEL]["width"]= vrlg.WOI_WIDTH + 4
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_PARALLEL]["width"]= vrlg.WOI_WIDTH + 2 # 4
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_PARALLEL]["height"]= vrlg.WOI_HEIGHT + 4
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_PARALLEL]["top"]= 0
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_PARALLEL]["left"]= 0
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_HISPI]["width"]= vrlg.WOI_WIDTH + 4
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_HISPI]["width"]= vrlg.WOI_WIDTH + 2 #4
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_HISPI]["height"]= vrlg.WOI_HEIGHT + 4
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_HISPI]["top"]= 0
SENSOR_DEFAULTS[x393_sensor.SENSOR_INTERFACE_HISPI]["left"]= 0
......@@ -186,6 +186,7 @@ class X393SensCmprs(object):
except:
pass
if dry_mode:
"""
BUFFER_ADDRESS = 0x38100000
BUFFER_LEN = 0x06400000
BUFFER_ADDRESS_H2D = 0x38100000
......@@ -194,7 +195,18 @@ class X393SensCmprs(object):
BUFFER_LEN_D2H = 0x06400000
BUFFER_ADDRESS_BIDIR = 0x38100000
BUFFER_LEN_BIDIR = 0x06400000
print ("Running in simulated mode, using hard-coded addresses:")
"""
BUFFER_ADDRESS = 0x25500000
BUFFER_LEN = 0x19000000
BUFFER_ADDRESS_H2D = 0x25500000
BUFFER_LEN_H2D = 0x19000000
BUFFER_ADDRESS_D2H = 0x25500000
BUFFER_LEN_D2H = 0x19000000
BUFFER_ADDRESS_BIDIR = 0x25500000
BUFFER_LEN_BIDIR = 0x19000000
print ("Running in simulated mode, using hard-coded addresses:")
else:
......@@ -476,7 +488,7 @@ class X393SensCmprs(object):
if (window_top + window_height) % 8:
num8rows += 1
frame_start_address_inc = num8rows * frame_full_width
""" TODO: Calculate tiles and mov e to initial print """
""" TODO: Calculate tiles and move to initial print """
num_macro_cols_m1 = (window_width >> 4) - 1
num_macro_rows_m1 = (window_height >> 4) - 1
......@@ -499,7 +511,10 @@ class X393SensCmprs(object):
print ("frame_start_address_inc = 0x%x"%(frame_start_address_inc))
print ("histogram_start_phys_page = 0x%x"%(histogram_start_phys_page))
print ("histogram start address = 0x%x"%(histogram_start_phys_page * 4096))
print ("width_in_bursts = %d(0x%x)"%(width_in_bursts,width_in_bursts))
print ("num_burst_in_line = %d(0x%x)"%(num_burst_in_line,num_burst_in_line))
print ("num_pages_in_line = %d(0x%x)"%(num_pages_in_line,num_pages_in_line))
print ("num8rows = %d(0x%x)"%(num8rows,num8rows))
print ("last_buf_frame = ", last_buf_frame)
print ("num_macro_cols_m1 = ", num_macro_cols_m1)
print ("num_macro_rows_m1 = ", num_macro_rows_m1)
......@@ -531,7 +546,8 @@ class X393SensCmprs(object):
frame_sa_inc = frame_start_address_inc, # input [31:0] frame_sa_inc; # 22-bit frame start address increment ((3 CA LSBs==0. BA==0)
last_frame_num = last_buf_frame, # input [31:0] last_frame_num; # 16-bit number of the last frame in a buffer
frame_full_width = frame_full_width, # input [31:0] frame_full_width; # 13-bit Padded line length (8-row increment), in 8-bursts (16 bytes)
window_width = window_width >> 4, # input [31:0] window_width; # 13 bit - in 8*16=128 bit bursts
# window_width = window_width >> 4, # input [31:0] window_width; # 13 bit - in 8*16=128 bit bursts
window_width = num_burst_in_line, # input [31:0] window_width; # 13 bit - in 8*16=128 bit bursts
window_height = window_height, # input [31:0] window_height; # 16 bit
window_left = window_left >> 4, # input [31:0] window_left;
window_top = window_top); # input [31:0] window_top;
......@@ -1173,7 +1189,7 @@ class X393SensCmprs(object):
histogram_top = None,
histogram_width_m1 = None, # 2559, #0,
histogram_height_m1 = None, # 799, #0,
circbuf_chn_size= 0x4000000, # 64 Mib
circbuf_chn_size= 0x4000000, # 64 Mib - all 4 channels?
verbose = 1):
"""
Setup one sensor+compressor channel (for one sub-channel only)
......@@ -1691,6 +1707,13 @@ class X393SensCmprs(object):
num8rows= (window_top + window_height) // 8
if (window_top + window_height) % 8:
num8rows += 1
if verbose >0 :
print ("width_in_bursts = %d(0x%x)"%(width_in_bursts,width_in_bursts))
print ("num_burst_in_line = %d(0x%x)"%(num_burst_in_line,num_burst_in_line))
print ("num_pages_in_line = %d(0x%x)"%(num_pages_in_line,num_pages_in_line))
print ("num8rows = %d(0x%x)"%(num8rows,num8rows))
# frame_start_addr = 0 # for sensor 0
# frame_start_address_inc = num8rows * frame_full_width
# len64 = num_burst_in_line * 2 * window_height
......@@ -2131,18 +2154,21 @@ class X393SensCmprs(object):
return "_bidir"
def sync_for_cpu(self, direction, saddr=None, leng=None):
if self.DRY_MODE:
print ("Simulating sync_for_cpu(),",self.get_mem_buf_args(saddr, leng)," -> ",MEM_PATH + BUFFER_FOR_CPU + self._get_dma_dir_suffix(direction))
self.x393_mem.flush_simulation()
#print ("Simulating sync_for_cpu(),",self.get_mem_buf_args(saddr, leng)," -> ",MEM_PATH + BUFFER_FOR_CPU + self._get_dma_dir_suffix(direction))
return
with open (MEM_PATH + BUFFER_FOR_CPU + self._get_dma_dir_suffix(direction),"w") as f:
print (self.get_mem_buf_args(saddr, leng),file=f)
def sync_for_device(self, direction, saddr=None, leng=None):
if self.DRY_MODE:
print ("Simulating sync_for_device(),",self.get_mem_buf_args(saddr, leng)," -> ",MEM_PATH + BUFFER_FOR_DEVICE + self._get_dma_dir_suffix(direction))
self.x393_mem.flush_simulation()
#print ("Simulating sync_for_device(),",self.get_mem_buf_args(saddr, leng)," -> ",MEM_PATH + BUFFER_FOR_DEVICE + self._get_dma_dir_suffix(direction))
return
with open (MEM_PATH + BUFFER_FOR_DEVICE + self._get_dma_dir_suffix(direction),"w") as f:
print (self.get_mem_buf_args(saddr, leng),file=f)
"""
flush_simulation
cd /usr/local/verilog/; test_mcntrl.py @hargs
#fpga_shutdown
setupSensorsPower "PAR12"
......@@ -2276,7 +2302,7 @@ jpeg_write "img.jpeg" 0 100 None False 0 "/www/pages/" 3
# Above did not work, try disabling memory channel
self.x393_axi_tasks.enable_memcntrl_en_dis(8 + chn, False);
#Will restore defaulrt circbuf parameters
#Will restore default circbuf parameters
self.specify_phys_memory() # setup physical memory
#Overwrite CIRCBUF parameters for selected channel with D2H stream DMA buffer (shared with membridge)
......
......@@ -144,7 +144,7 @@ class X393Sensor(object):
if (num_sensor == all) or (num_sensor[0].upper() == "A"): #all is a built-in function
rslt = []
for num_sensor in range(4):
rslt.append(self.program_status_sensor_io (num_sensor = num_sensor))
rslt.append(self.get_status_sensor_io (num_sensor = num_sensor))
return rslt
except:
pass
......
......@@ -40,7 +40,9 @@
module level_cross_clocks#(
parameter WIDTH = 1,
parameter REGISTER = 2 // number of registers (>=12)
parameter REGISTER = 2, // number of registers (>=12)
parameter FAST0 = 1'b0,
parameter FAST1 = 1'b0
)(
input clk,
input [WIDTH-1:0] d_in,
......@@ -50,20 +52,20 @@ module level_cross_clocks#(
genvar i;
for (i = 0; i < WIDTH ; i = i+1) begin: level_cross_clock_block
if (REGISTER <= 1)
level_cross_clocks_ff_bit level_cross_clocks_single_i ( // just a single ff (if metastability is not a problem)
level_cross_clocks_ff_bit #(.FAST1(FAST1)) level_cross_clocks_single_i ( // just a single ff (if metastability is not a problem)
.clk (clk), // input
.d_in (d_in[i]), // input
.d_out (d_out[i]) // output
);
else if (REGISTER == 2)
level_cross_clocks_sync_bit level_cross_clocks_sync_i ( // classic 2-register synchronizer
level_cross_clocks_sync_bit #(.FAST0(FAST0),.FAST1(FAST1)) level_cross_clocks_sync_i ( // classic 2-register synchronizer
.clk (clk), // input
.d_in (d_in[i]), // input
.d_out (d_out[i]) // output
);
else
level_cross_clocks_single_bit #( // >2 bits (first two only are synchronizer)
.REGISTER(REGISTER)
.REGISTER(REGISTER), .FAST0(FAST0), .FAST1(FAST1)
) level_cross_clocks_single_i (
.clk (clk), // input
.d_in (d_in[i]), // input
......@@ -74,20 +76,24 @@ module level_cross_clocks#(
endmodule
module level_cross_clocks_single_bit#(
parameter REGISTER = 3 // number of registers (>=3)
parameter REGISTER = 3, // number of registers (>=3)
parameter FAST0 = 1'b0,
parameter FAST1 = 1'b0
)(
input clk,
input d_in,
output d_out
);
reg [REGISTER - 3 : 0] regs = 0;
reg [REGISTER - 3 : 0] regs = {REGISTER -2 {FAST1}};
wire d_sync; // after a 2-bit synchronizer
wire [REGISTER - 2 : 0] regs_next = {regs, d_sync};
assign d_out = regs[REGISTER -3];
always @ (posedge clk) begin
regs <= regs_next[REGISTER - 3 : 0]; // | d_in complains about widths mismatch
if (FAST0) regs <= {REGISTER - 3{d_in}} & regs_next[REGISTER - 3 : 0];
else if (FAST1) regs <= {REGISTER - 3{d_in}} | regs_next[REGISTER - 3 : 0];
else regs <= regs_next[REGISTER - 3 : 0]; // | d_in complains about widths mismatch
end
level_cross_clocks_sync_bit level_cross_clocks_sync_bit_i (
level_cross_clocks_sync_bit #(.FAST0(FAST0),.FAST1(FAST1)) level_cross_clocks_sync_bit_i (
.clk (clk), // input
.d_in (d_in), // input
.d_out (d_sync) // output
......@@ -95,7 +101,10 @@ module level_cross_clocks_single_bit#(
endmodule
// Classic 2-bit (exactly) synchronizer
module level_cross_clocks_sync_bit(
module level_cross_clocks_sync_bit #(
parameter FAST0 = 1'b0,
parameter FAST1 = 1'b0
)(
input clk,
input d_in,
output d_out
......@@ -106,17 +115,23 @@ module level_cross_clocks_sync_bit(
reg [1:0] sync_zer;
assign d_out = sync_zer [1];
always @ (posedge clk) begin
sync_zer <= {sync_zer[0],d_in};
if (FAST0) sync_zer <= {sync_zer[0] & d_in, d_in};
else if (FAST1) sync_zer <= {sync_zer[0] | d_in, d_in};
else sync_zer <= {sync_zer[0],d_in};
end
endmodule
module level_cross_clocks_ff_bit( // just a single FF if REGISTER == 1 (if metastability is not a problem)
module level_cross_clocks_ff_bit #( // just a single FF if REGISTER == 1 (if metastability is not a problem)
parameter FAST1 = 1'b0
) (
input clk,
input d_in,
output reg d_out
output d_out
);
reg d_out_r = FAST1;
assign d_out = d_out_r;
always @ (posedge clk) begin
d_out <= d_in;
d_out_r <= d_in;
end
endmodule
......
......@@ -63,7 +63,7 @@ module sync_resets#(
else mrst <= ~(locked[0] && en_locked);
end
always @(posedge clk[0]) begin
rst_early_master <= rst_early_master_w;
rst_early_master <= rst_early_master_w | mrst;
end
level_cross_clocks #(
.WIDTH (1),
......@@ -79,7 +79,9 @@ module sync_resets#(
for (i = 1; i < WIDTH; i = i + 1) begin: rst_block
level_cross_clocks #(
.WIDTH (1),
.REGISTER ((i==5) ? 1: REGISTER) // disable for aclk
.REGISTER ((i==5) ? 1: REGISTER), // disable for aclk
// .REGISTER (REGISTER), // disable for aclk - aclk is now (0)
.FAST1 (1) // Switch to next cycle, to 0 - regeisterd
) level_cross_clocks_rst_i (
.clk (clk[i]), // input
.d_in (mrst || rst_early_master || ~locked[i] ), // input[0:0]
......
......@@ -132,24 +132,26 @@ module mmcm_phase_cntr#(
// made a difference, so it doesn't seem Vivado extends bits of operands "+", "-"
wire [PHASE_WIDTH:0] diff= {ps_target[PHASE_WIDTH-1],ps_target}-{ps_dout_r[PHASE_WIDTH-1],ps_dout_r};
assign ps_dout = ps_dout_r;
wire reset_extended = rst || !locked;
always @ (posedge psclk) begin
if (rst) ps_start0 <= 0;
if (reset_extended) ps_start0 <= 0;
else ps_start0 <= ps_we && ps_ready;
if (rst) ps_dout_r <= 0;
if (reset_extended) ps_dout_r <= 0;
else if (psen && psincdec) ps_dout_r <= ps_dout_r +1; //SuppressThisWarning ISExst Result of 9-bit expression is truncated to fit in 8-bit target.
else if (psen && !psincdec) ps_dout_r <= ps_dout_r -1; //SuppressThisWarning ISExst Result of 32-bit expression is truncated to fit in 8-bit target.
if (rst) ps_target <= 0;
if (reset_extended) ps_target <= 0;
else if (ps_we && ps_ready) ps_target <= ps_din;
if (rst) ps_busy <= 1'b0;
if (reset_extended) ps_busy <= 1'b0;
else if (ps_start) ps_busy <= (diff!=0);
end
always @ (posedge psclk) begin
ps_start <= ps_start0 || psdone;
ps_start <= !reset_extended && (ps_start0 || psdone);
psincdec <= !diff[PHASE_WIDTH];
end
......
......@@ -2476,7 +2476,6 @@ assign axi_grst = axi_rst_pre;
.locked_pclk (locked_pclk), // output
.locked_hclk (locked_hclk) // output
);
sync_resets #(
.WIDTH(7),
.REGISTER(4)
......@@ -2487,6 +2486,19 @@ assign axi_grst = axi_rst_pre;
.rst ({hrst, arst, lrst, crst, xrst, prst, mrst}) // output[6:0]
);
// Changed aclk to master (itg is the source of most orthers)
/*
sync_resets #(
.WIDTH(7),
.REGISTER(4)
) sync_resets_i (
.arst (axi_rst_pre), // input
.locked ({locked_hclk, locked_sync_clk, locked_sync_clk, locked_xclk, locked_pclk, mcntrl_locked, 1'b1 }), // input
.clk ({hclk, logger_clk, camsync_clk, xclk, pclk, mclk, axi_aclk}), // input[6:0]
.rst ({hrst, lrst, crst, xrst, prst, mrst, arst}) // output[6:0]
);
*/
`ifdef DEBUG_RING
debug_master #(
.DEBUG_ADDR (DEBUG_ADDR),
......
......@@ -113,7 +113,7 @@ module x393_testbench03 #(
parameter TRIGGER_MODE = 0; // 1; // 0 - auto, 1 - triggered
parameter EXT_TRIGGER_MODE = 1 ; // 0 - internal, 1 - external trigger (camsync)
parameter EXTERNAL_TIMESTAMP = 0; // 1 ; // embed local timestamp, 1 - embed received timestamp
parameter NUM_INTERRUPTS = 9;
//parameter NUM_INTERRUPTS = 9;
`include "includes/x393_localparams.vh" // SuppressThisWarning VEditor - not used
// VDT - incorrect real number calculation
......@@ -1405,7 +1405,8 @@ end
initial begin
// after 1 frame compressed on all channels
// Debugging DCT Chen
//#20000;
//$finish;
`ifdef HISPI
#135000;
`else
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment