SPI core: Basic testbench working

This commit is contained in:
jaseg 2021-06-22 20:18:27 +02:00
parent f46c6a2a41
commit 1daef761b6
4 changed files with 363 additions and 105 deletions

View file

@ -42,7 +42,7 @@
<Option Name="IPUserFilesDir" Val="$PIPUSERFILESDIR"/>
<Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/>
<Option Name="EnableBDX" Val="FALSE"/>
<Option Name="WTXSimLaunchSim" Val="375"/>
<Option Name="WTXSimLaunchSim" Val="435"/>
<Option Name="WTModelSimLaunchSim" Val="0"/>
<Option Name="WTQuestaLaunchSim" Val="0"/>
<Option Name="WTIesLaunchSim" Val="0"/>
@ -237,6 +237,14 @@
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<File Path="$PPRDIR/src/spi_core.v">
<FileInfo>
<Attr Name="AutoDisabled" Val="1"/>
<Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="implementation"/>
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<Config>
<Option Name="DesignMode" Val="RTL"/>
<Option Name="TopModule" Val="hdmi_design"/>
@ -258,8 +266,16 @@
</FileSet>
<FileSet Name="sim_1" Type="SimulationSrcs" RelSrcDir="$PSRCDIR/sim_1">
<Filter Type="Srcs"/>
<File Path="$PPRDIR/test_bench/spi_core_tb.v">
<FileInfo>
<Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="implementation"/>
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<File Path="$PPRDIR/test_bench/term_emu_tb.v">
<FileInfo>
<Attr Name="AutoDisabled" Val="1"/>
<Attr Name="UsedIn" Val="synthesis"/>
<Attr Name="UsedIn" Val="implementation"/>
<Attr Name="UsedIn" Val="simulation"/>
@ -352,9 +368,14 @@
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<File Path="$PPRDIR/spi_core_tb_behav.wcfg">
<FileInfo>
<Attr Name="UsedIn" Val="simulation"/>
</FileInfo>
</File>
<Config>
<Option Name="DesignMode" Val="RTL"/>
<Option Name="TopModule" Val="term_emu_tb"/>
<Option Name="TopModule" Val="spi_core_tb"/>
<Option Name="TopLib" Val="xil_defaultlib"/>
<Option Name="TransportPathDelay" Val="0"/>
<Option Name="TransportIntDelay" Val="0"/>
@ -368,6 +389,7 @@
<Option Name="XSimWcfgFile" Val="$PPRDIR/window_matcher_tb_behav.wcfg"/>
<Option Name="XSimWcfgFile" Val="$PPRDIR/term_renderer_tb_behav.wcfg"/>
<Option Name="XSimWcfgFile" Val="$PPRDIR/term_emu_tb_behav.wcfg"/>
<Option Name="XSimWcfgFile" Val="$PPRDIR/spi_core_tb_behav.wcfg"/>
<Option Name="xsim.simulate.runtime" Val="10ms"/>
<Option Name="NLNetlistMode" Val="funcsim"/>
</Config>

128
spi_core_tb_behav.wcfg Normal file
View file

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<wave_config>
<wave_state>
</wave_state>
<db_ref_list>
<db_ref path="spi_core_tb_behav.wdb" id="1">
<top_modules>
<top_module name="glbl" />
<top_module name="spi_core_tb" />
</top_modules>
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="2358333fs"></ZoomStartTime>
<ZoomEndTime time="16508334fs"></ZoomEndTime>
<Cursor1Time time="14150000fs"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="175"></NameColumnWidth>
<ValueColumnWidth column_width="146"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="24" />
<wvobject fp_name="/spi_core_tb/spi_core_dut/clk" type="logic">
<obj_property name="ElementShortName">clk</obj_property>
<obj_property name="ObjectShortName">clk</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/rst" type="logic">
<obj_property name="ElementShortName">rst</obj_property>
<obj_property name="ObjectShortName">rst</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/ncs" type="logic">
<obj_property name="ElementShortName">ncs</obj_property>
<obj_property name="ObjectShortName">ncs</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/sck" type="logic">
<obj_property name="ElementShortName">sck</obj_property>
<obj_property name="ObjectShortName">sck</obj_property>
<obj_property name="CustomSignalColor">#FFFF00</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/sdi" type="logic">
<obj_property name="ElementShortName">sdi</obj_property>
<obj_property name="ObjectShortName">sdi</obj_property>
<obj_property name="CustomSignalColor">#FFFF00</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/sdo" type="logic">
<obj_property name="ElementShortName">sdo</obj_property>
<obj_property name="ObjectShortName">sdo</obj_property>
<obj_property name="CustomSignalColor">#FFFF00</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/cs_rising" type="logic">
<obj_property name="ElementShortName">cs_rising</obj_property>
<obj_property name="ObjectShortName">cs_rising</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/cs_falling" type="logic">
<obj_property name="ElementShortName">cs_falling</obj_property>
<obj_property name="ObjectShortName">cs_falling</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/data_out" type="array">
<obj_property name="ElementShortName">data_out[15:0]</obj_property>
<obj_property name="ObjectShortName">data_out[15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/data_out_valid" type="logic">
<obj_property name="ElementShortName">data_out_valid</obj_property>
<obj_property name="ObjectShortName">data_out_valid</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/data_in" type="array">
<obj_property name="ElementShortName">data_in[15:0]</obj_property>
<obj_property name="ObjectShortName">data_in[15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/data_in_valid" type="logic">
<obj_property name="ElementShortName">data_in_valid</obj_property>
<obj_property name="ObjectShortName">data_in_valid</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/sim_txbuf" type="array">
<obj_property name="ElementShortName">sim_txbuf[15:0]</obj_property>
<obj_property name="ObjectShortName">sim_txbuf[15:0]</obj_property>
<obj_property name="CustomSignalColor">#FAAFBE</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/last_cs" type="logic">
<obj_property name="ElementShortName">last_cs</obj_property>
<obj_property name="ObjectShortName">last_cs</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/last_sck" type="array">
<obj_property name="ElementShortName">last_sck[1:0]</obj_property>
<obj_property name="ObjectShortName">last_sck[1:0]</obj_property>
<obj_property name="Radix">BINARYRADIX</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/rx_buf" type="array">
<obj_property name="ElementShortName">rx_buf[15:0]</obj_property>
<obj_property name="ObjectShortName">rx_buf[15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/tx_buf" type="array">
<obj_property name="ElementShortName">tx_buf[15:0]</obj_property>
<obj_property name="ObjectShortName">tx_buf[15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/tx_buf_next" type="array">
<obj_property name="ElementShortName">tx_buf_next[15:0]</obj_property>
<obj_property name="ObjectShortName">tx_buf_next[15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/sck_rising" type="logic">
<obj_property name="ElementShortName">sck_rising</obj_property>
<obj_property name="ObjectShortName">sck_rising</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/spi_core_dut/sck_falling" type="logic">
<obj_property name="ElementShortName">sck_falling</obj_property>
<obj_property name="ObjectShortName">sck_falling</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/i" type="array">
<obj_property name="ElementShortName">i[31:0]</obj_property>
<obj_property name="ObjectShortName">i[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/sim_rxdata" type="array">
<obj_property name="ElementShortName">sim_rxdata[1:4][15:0]</obj_property>
<obj_property name="ObjectShortName">sim_rxdata[1:4][15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/sim_txdata" type="array">
<obj_property name="ElementShortName">sim_txdata[1:4][15:0]</obj_property>
<obj_property name="ObjectShortName">sim_txdata[1:4][15:0]</obj_property>
</wvobject>
<wvobject fp_name="/spi_core_tb/testcase" type="array">
<obj_property name="ElementShortName">testcase[31:0]</obj_property>
<obj_property name="ObjectShortName">testcase[31:0]</obj_property>
</wvobject>
</wave_config>

View file

@ -2,124 +2,87 @@
module spi_core(
input clk, rst,
input sck, sdi, sdo, ncs,
input sck, sdi, ncs,
output reg sdo,
output reg cs_rising,
output reg cs_falling,
output reg data[15:0],
output reg data_valid
output reg [WORDSIZE-1:0] data_out,
output reg data_out_valid,
input [WORDSIZE-1:0] data_in,
input data_in_valid
);
reg data_release_flag_sysclk;
parameter WORDSIZE = 16;
parameter SPI_CPOL = 0;
parameter SPI_CPHA = 0;
reg [15:0] rxbuf_sck;
reg [15:0] data_reg_sck;
reg data_good_flag_sck;
always @(posedge sck or posedge ncs) begin
if (ncs) begin /* asynchronous reset */
data_reg_sck <= 16'h0001;
data_good_flag_sck <= 0;
end else begin
if (data_reg_sck[15]) begin
rxbuf_sck <= {data_reg_sck[14:0], sdi};
data_reg_sck <= 16'h0001;
data_good_flag_sck <= 1;
end else begin
data_reg_sck <= {data_reg_sck[14:0], sdi};
end
end
end
/* Receiver */
reg last_cs;
reg [1:0] last_sck;
reg [WORDSIZE-1:0] rx_buf;
reg [WORDSIZE-1:0] tx_buf;
reg [WORDSIZE-1:0] tx_buf_next;
wire sck_rising = !last_sck[1] && last_sck[0];
wire sck_falling = last_sck[1] && !last_sck[0];
reg cs_rising_sysclk;
reg cs_falling_sysclk;
reg last_cs_sysclk;
reg [1:0] data_good_flag_sysclk;
always @(posedge clk) begin
last_cs <= ncs;
last_sck = {last_sck[0], sck};
data_out_valid <= 0;
if (rst) begin
last_cs_sysclk <= cs;
cs_rising <= 0;
cs_falling <= 0;
data_valid <= 0;
data <= 0;
data_release_flag_sysclk <= 0;
data_good_flag_sysclk <= 0;
end else begin
data_good_flag_sysclk <= {data-good_flag_sysclk[0], data_good_flag_sck};
rx_buf[WORDSIZE-1:1] <= 0;
rx_buf[0] <= 1;
tx_buf <= 0;
tx_buf_next <= 0;
sdo <= 0;
data_out <= 0;
data_out_valid <= 0;
if (last_cs_sysclk = 0 && cs == 1) begin
cs_rising <= 1;
cs_falling <= 0;
end else begin if (last_cs_sysclk = 1 && cs == 0) begin
cs_rising <= 0;
end else begin
if (last_cs && !ncs) begin /* cs falling, device asserted */
cs_falling <= 1;
cs_rising <= 0;
sdo <= tx_buf_next[WORDSIZE-1];
tx_buf <= {tx_buf_next[WORDSIZE-2:0], 1'b0};
tx_buf_next <= 0;
end else if (!last_cs && ncs) begin /* cs rising, device de-asserted */
cs_falling <= 0;
cs_rising <= 1;
end else begin /* cs unchanged */
cs_falling <= 0;
cs_rising <= 0;
end
if (!last_cs_sysclk && data_good_flag_sysclk[0] && data_good_flag_sysclk[1]) begin
data <= rxbuf_sck;
data_release_flag_sysclk <= 1;
if(!ncs) begin
if (((SPI_CPOL == SPI_CPHA) && sck_rising) || ((SPI_CPOL != SPI_CPHA) && sck_falling)) begin /* sampling edge */
if (rx_buf[WORDSIZE-1]) begin
data_out <= {rx_buf[WORDSIZE-2:0], sdi};
data_out_valid <= 1;
rx_buf[WORDSIZE-1:1] <= 0;
rx_buf[0] <= 1;
tx_buf <= tx_buf_next;
tx_buf_next <= 0;
end else begin
rx_buf <= {rx_buf[WORDSIZE-2:0], sdi};
end
end else if (((SPI_CPOL == SPI_CPHA) && sck_falling) || ((SPI_CPOL != SPI_CPHA) && sck_rising)) begin /* driving edge */
sdo <= tx_buf[WORDSIZE-1];
tx_buf <= {tx_buf[WORDSIZE-2:0], 1'b0};
end
end
if (data_in_valid) begin
tx_buf_next <= data_in;
end
end
end
endmodule
module cdc_reg (
input in_clk, in_rst,
input [WORDSIZE-1:0] in_data,
input in_data_valid,
input out_clk, out_rst,
output reg [WORDSIZE-1:0] out_data,
output reg out_data_valid,
);
parameter WORDSIZE = 16;
reg [2:0] wr_flags_in;
reg [WORDSIZE-1:0] reg_in [0:2];
always @(posedge in_clk, posedge in_rst) begin
if (in_rst) begin
wr_flags_in <= 3'b000;
regs_in[0] <= 0;
regs_in[1] <= 0;
regs_in[2] <= 0;
end else begin
case (regs_in)
3'b001: begin regs_in[1] <= in_data; wr_flags_in <= 3'b010; end
3'b010: begin regs_in[2] <= in_data; wr_flags_in <= 3'b100; end
3'b100, 3'b000: begin regs_in[0] <= in_data; wr_flags_in <= 3'b001; end
endcase
end
end
reg [2:0] wr_flags_out [0:1];
always @(posedge out_clk) begin
if (out_rst) begin
wr_flags_out[0] <= 3'b000;
wr_flags_out[1] <= 3'b000;
end else begin
wr_flags_out[0] <= wr_flags_in;
wr_flags_out[1] <= wr_flags_out[0];
out_data_valid <= 0;
if (wr_flags_out[0][0] && !wr_flags_out[1][0]) begin
out_data <= regs_in[0];
out_data_valid <= 1;
end else if (wr_flags_out[0][1] && !wr_flags_out[1][1]) begin
out_data <= regs_in[1];
out_data_valid <= 1;
end else if (wr_flags_out[0][2] && !wr_flags_out[1][2]) begin
out_data <= regs_in[2];
out_data_valid <= 1;
end
end
end
endmodule

View file

@ -0,0 +1,145 @@
module spi_core_tb();
localparam period = 10;
parameter WORDSIZE = 16;
reg clk, rst;
reg sck, sdi, ncs;
wire sdo;
wire cs_rising, cs_falling;
wire [WORDSIZE-1:0] data_out;
wire data_out_valid;
reg [WORDSIZE-1:0] data_in;
reg data_in_valid;
initial begin
clk = 0;
/* rst set below */
sck = 0;
sdi = 0;
ncs = 1;
data_in = 0;
data_in_valid = 0;
forever #period clk = ~clk;
end
integer i;
integer j;
integer k;
integer testcase;
reg [WORDSIZE-1:0] sim_rxdata [1:4];
reg [WORDSIZE-1:0] sim_txdata [1:4];
reg [WORDSIZE-1:0] sim_txbuf;
initial begin
sim_rxdata[1] = 16'h523a;
sim_rxdata[2] = 16'hbeef;
sim_rxdata[3] = 16'h7721;
sim_rxdata[4] = 16'h0108;
sim_txdata[1] = 16'h1234;
sim_txdata[2] = 16'h5678;
sim_txdata[3] = 16'h9abc;
sim_txdata[4] = 16'hdef9;
for (j=1; j<=4; j=j+1) begin
$display("TC-SIMPLE-%d: rx/tx %d word", j, j);
testcase = j;
rst = 1;
repeat(2) @(posedge clk);
rst = 0;
@(posedge clk);
data_in = sim_txdata[1];
data_in_valid = 1;
@(posedge clk);
data_in_valid = 0;
ncs = 0;
@(posedge clk);
if (cs_rising || !cs_falling || data_out_valid) $finish;
for (k=0; k<j; k=k+1) begin
sim_txbuf = 0;
data_in = 16'h0000;
data_in_valid = 0;
for (i=0; i<WORDSIZE; i=i+1) begin
sdi = sim_rxdata[k+1][WORDSIZE-1-i];
sck = 0;
@(posedge clk);
if (cs_rising || cs_falling || (i < WORDSIZE-1 && data_out_valid)) $finish;
@(posedge clk);
if (cs_rising || cs_falling || data_out_valid) $finish;
sck = 1;
sim_txbuf[WORDSIZE-1-i] = sdo;
if (i == WORDSIZE-1) begin
data_in = sim_txdata[k+2];
data_in_valid = 1;
end
@(posedge clk);
data_in_valid = 0;
if (cs_rising || cs_falling || (i < WORDSIZE-1 && data_out_valid)) $finish;
@(posedge clk);
if (cs_rising || cs_falling || (i < WORDSIZE-1 && data_out_valid)) $finish;
end
if (!data_out_valid) $finish;
if (data_out != sim_rxdata[k+1]) $finish;
if (!sim_txbuf == sim_txdata[k+1]) $finish;
end
sck = 0;
@(posedge clk);
ncs = 1;
@(posedge clk);
if (!cs_rising || cs_falling || data_out_valid) $finish;
repeat(10) @(posedge clk);
end
$finish;
end
reg cs_rising_last, cs_falling_last;
always @(posedge clk) begin
/* Only one signal can be active at the same time */
if (cs_rising && cs_falling) $finish;
/* Both signals must be one-cycle pulses */
if (cs_rising == 1 && cs_rising_last == 1) $finish;
if (cs_falling == 1 && cs_falling_last == 1) $finish;
cs_rising_last <= cs_rising;
cs_falling_last <= cs_falling;
end
reg sck_last, sdo_last;
always @(posedge clk) begin
//if (sck_last == sck && sdo_last != sdo) $finish; /* SDO can only change on SCK edges */
sck_last <= sck;
sdo_last <= sdo;
end
spi_core #(.WORDSIZE(WORDSIZE)) spi_core_dut (
.clk(clk), .rst(rst),
.sck(sck), .sdi(sdi), .sdo(sdo), .ncs(ncs),
.cs_rising(cs_rising),
.cs_falling(cs_falling),
.data_out(data_out),
.data_out_valid(data_out_valid),
.data_in(data_in),
.data_in_valid(data_in_valid)
);
endmodule