clean up tests

This commit is contained in:
Peter McGoron 2024-01-23 14:05:26 -05:00
parent 90b74593e9
commit bf78682e73
10 changed files with 115 additions and 140 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
simtop_* tests/test_*

View File

View File

@ -10,7 +10,7 @@ License, v.2.0. A copy of this license may be found in the file `COPYING`. You
can obtain one at https://mozilla.org/MPL/2.0/. can obtain one at https://mozilla.org/MPL/2.0/.
All Verilog source in this project is dual-licensed under the MPL v2.0 All Verilog source in this project is dual-licensed under the MPL v2.0
and the CERN-OHL-W v2.0 (or any later version). and the CERN-OHL-W v2.0.
## Tests ## Tests
@ -18,11 +18,6 @@ Run `./mk.sh` in `tests/` to generate and run tests.
## Modules ## Modules
"master_no_read" and "slave_no_write" have no Master In, Slave Out ("miso")
wires (and no corresponding shift registers), while "master_no_write"
and "slave_no_read" have no Master Out, Slave In ("mosi") wires. This
is for compatability for "SPI compatible" devices that are read only.
"master_ss" and others include a timer that will assert the Slave Select "master_ss" and others include a timer that will assert the Slave Select
pin and wait a set number of clock cycles before starting the SPI transfer. pin and wait a set number of clock cycles before starting the SPI transfer.

View File

@ -1,7 +1,7 @@
/* (c) Peter McGoron 2022 v0.4 /* (c) Peter McGoron 2022-2024 v0.4
* This Source Code Form is subject to the terms of the Mozilla Public *
* License, v.2.0. If a copy of the MPL was not distributed with this * This code is disjunctively dual-licensed under the MPL v2.0, or the
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * CERN-OHL-W v2.
*/ */
/* CYCLE_HALF_WAIT should take into account the setup time of the slave /* CYCLE_HALF_WAIT should take into account the setup time of the slave
@ -45,7 +45,7 @@ module spi_master #(
reg miso_hot = 0; reg miso_hot = 0;
reg read_miso = 0; reg read_miso = 0;
always @ (posedge clk) if (ENABLE_MISO) begin always @ (posedge clk) if (ENABLE_MISO == 1) begin
read_miso <= miso_hot; read_miso <= miso_hot;
miso_hot <= miso; miso_hot <= miso;
end end
@ -70,20 +70,20 @@ task idle_state();
end else begin end else begin
sck <= 1; sck <= 1;
end end
if (ENABLE_MOSI) mosi <= 0; if (ENABLE_MOSI == 1) mosi <= 0;
timer <= 0; timer <= 0;
bit_counter <= 0; bit_counter <= 0;
endtask endtask
task read_data(); task read_data();
if (ENABLE_MISO) begin if (ENABLE_MISO == 1) begin
from_slave <= from_slave << 1; from_slave <= from_slave << 1;
from_slave[0] <= read_miso; from_slave[0] <= read_miso;
end end
endtask endtask
task write_data(); task write_data();
if (ENABLE_MOSI) begin if (ENABLE_MOSI == 1) begin
mosi <= send_buf[WID-1]; mosi <= send_buf[WID-1];
send_buf <= send_buf << 1; send_buf <= send_buf << 1;
end end
@ -97,13 +97,13 @@ task setup_bits();
* For mode 01 and mode 10, the first action is a WRITE. * For mode 01 and mode 10, the first action is a WRITE.
*/ */
if (POLARITY == PHASE) begin if (POLARITY == PHASE) begin
if (ENABLE_MOSI) begin if (ENABLE_MOSI == 1) begin
mosi <= to_slave[WID-1]; mosi <= to_slave[WID-1];
send_buf <= to_slave << 1; send_buf <= to_slave << 1;
end end
state <= CYCLE_WAIT; state <= CYCLE_WAIT;
end else begin end else begin
if (ENABLE_MISO) begin if (ENABLE_MISO == 1) begin
send_buf <= to_slave; send_buf <= to_slave;
end end
state <= ON_CYCLE; state <= ON_CYCLE;
@ -128,8 +128,8 @@ always @ (posedge clk) begin
finished <= 0; finished <= 0;
state <= WAIT_ON_ARM; state <= WAIT_ON_ARM;
ready_to_arm <= 1; ready_to_arm <= 1;
if (ENABLE_MISO) from_slave <= 0; if (ENABLE_MISO == 1) from_slave <= 0;
if (ENABLE_MOSI) send_buf <= 0; if (ENABLE_MOSI == 1) send_buf <= 0;
end else case (state) end else case (state)
WAIT_ON_ARM: begin WAIT_ON_ARM: begin
`ifdef SIMULATION `ifdef SIMULATION

View File

@ -1,7 +1,7 @@
/* (c) Peter McGoron 2022 v0.4 /* (c) Peter McGoron 2022 v0.4
* This Source Code Form is subject to the terms of the Mozilla Public *
* License, v.2.0. If a copy of the MPL was not distributed with this * This code is disjunctively dual-licensed under the MPL v2.0, or the
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * CERN-OHL-W v2.
*/ */
/* spi master with integrated ability to wait a certain amount of cycles /* spi master with integrated ability to wait a certain amount of cycles

View File

@ -1,7 +1,7 @@
/* (c) Peter McGoron 2022 v0.4 /* (c) Peter McGoron 2022 v0.4
* This Source Code Form is subject to the terms of the Mozilla Public *
* License, v.2.0. If a copy of the MPL was not distributed with this * This code is disjunctively dual-licensed under the MPL v2.0, or the
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * CERN-OHL-W v2.
*/ */
module spi_slave #( module spi_slave #(
@ -32,7 +32,7 @@ module spi_slave #(
reg mosi_hot = 0; reg mosi_hot = 0;
reg read_mosi = 0; reg read_mosi = 0;
always @ (posedge clk) if (ENABLE_MOSI) begin always @ (posedge clk) if (ENABLE_MOSI == 1) begin
read_mosi <= mosi_hot; read_mosi <= mosi_hot;
mosi_hot <= mosi; mosi_hot <= mosi;
end end
@ -48,21 +48,21 @@ reg [WID-1:0] send_buf = 0;
`endif `endif
task read_data(); task read_data();
if (ENABLE_MOSI) begin if (ENABLE_MOSI == 1) begin
from_master <= from_master << 1; from_master <= from_master << 1;
from_master[0] <= read_mosi; from_master[0] <= read_mosi;
end end
endtask endtask
task write_data(); task write_data();
if (ENABLE_MISO) begin if (ENABLE_MISO == 1) begin
send_buf <= send_buf << 1; send_buf <= send_buf << 1;
miso <= send_buf[WID-1]; miso <= send_buf[WID-1];
end end
endtask endtask
task setup_bits(); task setup_bits();
if (ENABLE_MISO) begin if (ENABLE_MISO == 1) begin
/* at Mode 00, the transmission starts with /* at Mode 00, the transmission starts with
* a rising edge, and at mode 11, it starts with a falling * a rising edge, and at mode 11, it starts with a falling
* edge. For both modes, these are READs. * edge. For both modes, these are READs.
@ -93,9 +93,9 @@ always @ (posedge clk) begin
ss_delay <= 0; ss_delay <= 0;
ready_at_start <= 0; ready_at_start <= 0;
if (ENABLE_MOSI) from_master <= 0; if (ENABLE_MOSI == 1) from_master <= 0;
if (ENABLE_MISO) begin if (ENABLE_MISO == 1) begin
miso <= 0; miso <= 0;
send_buf <= 0; send_buf <= 0;
end end

View File

@ -1,3 +1,3 @@
#!/bin/sh #!/bin/sh
rm -rf simtop_* rm -rf test_master* test_ss*

View File

@ -1,85 +0,0 @@
#!/bin/sh
run_test() {
POL=$1
PHASE=$2
MASTER_TYPE=$3
SLAVE_TYPE=$4
DIR=$5
WID=$6
MODS=$7
EXTARG=$8
WIDLEN=$(printf "import math\nprint(math.floor(math.log2($WID) + 1))" | python3 -)
echo "running $POL$PHASE $MASTER_TYPE"
verilator --cc --exe -I.. -Wall -Wno-unused --trace --trace-fst \
--top-module simtop \
-GPOLARITY=$POL -GPHASE=$PHASE -GWID=$WID -CFLAGS -DWID=$WID \
-GWID_LEN=$WIDLEN \
-DSPI_MASTER_TYPE=$MASTER_TYPE -DSPI_SLAVE_TYPE=$SLAVE_TYPE \
-DVCDFILE="\"$DIR.fst\"" \
-DSIMULATION \
--Mdir $DIR \
$EXTARG \
simtop.v write_read.cpp $MODS \
|| exit 1
cd "$DIR"
make -f Vsimtop.mk
./Vsimtop
}
for POL in 0 1; do
for PHASE in 0 1; do
( \
run_test $POL $PHASE \
spi_master spi_slave \
simtop_$POL$PHASE 24 \
"../spi_master.v ../spi_slave.v"
) || exit 1
( \
run_test $POL $PHASE \
spi_master_ss spi_slave \
simtop_ss$POL$PHASE 24 \
"../spi_master_ss.v ../spi_slave.v" \
"-DSPI_MASTER_SS -CFLAGS -DSPI_MASTER_SS"
) || exit 1
( \
run_test $POL $PHASE \
spi_master_no_write spi_slave_no_read \
simtop_no_write_$POL$PHASE 24 \
"../spi_master_no_write.v ../spi_slave_no_read.v" \
"-DSPI_MASTER_NO_WRITE -CFLAGS -DSPI_MASTER_NO_WRITE"
) || exit 1
( \
run_test $POL $PHASE \
spi_master_ss_no_write spi_slave_no_read \
simtop_ss_no_write_$POL$PHASE 24 \
"../spi_master_ss_no_write.v ../spi_slave_no_read.v" \
"-DSPI_MASTER_NO_WRITE -CFLAGS -DSPI_MASTER_NO_WRITE
-DSPI_MASTER_SS -CFLAGS -DSPI_MASTER_SS"
) || exit 1
( \
run_test $POL $PHASE \
spi_master_no_read spi_slave_no_write \
simtop_no_read_$POL$PHASE 24 \
"../spi_master_no_read.v ../spi_slave_no_write.v" \
"-DSPI_MASTER_NO_READ -CFLAGS -DSPI_MASTER_NO_READ"
) || exit 1
( \
run_test $POL $PHASE \
spi_master_ss_no_read spi_slave_no_write \
simtop_ss_no_read_$POL$PHASE 24 \
"../spi_master_ss_no_read.v ../spi_slave_no_write.v" \
"-DSPI_MASTER_NO_READ -CFLAGS -DSPI_MASTER_NO_READ
-DSPI_MASTER_SS -CFLAGS -DSPI_MASTER_SS"
) || exit 1
done
done

72
tests/runtests.py Executable file
View File

@ -0,0 +1,72 @@
#!/usr/bin/python3
import math
import subprocess
import sys
import os
from collections import namedtuple
class Case:
def __init__(self, master_name, defflags, params):
self.master_name = master_name
self.defflags = defflags
self.params = params
def run(self, dirname, pol, phase, wid):
dirname = f'{dirname}{pol}{phase}'
widlen = math.floor(math.log2(wid) + 1)
args = ["verilator", "--cc", "--exe", "-I..", "-Wall", "--trace",
"--trace-fst", "-Wno-unused",
"--top-module", "simtop",
f"-GPOLARITY={pol}", f"-GPHASE={phase}",
f"-GWID={wid}", f"-CFLAGS", f"-DWID={wid}",
f"-GWID_LEN={widlen}",
f"-DSPI_MASTER_TYPE={self.master_name}",
f'-DVCDFILE="{dirname}/trace.fst"',
f"-DSIMULATION",
f"--Mdir", dirname
]
for flag in self.defflags:
args.extend([f'-D{flag}', '-CFLAGS', f'-D{flag}'])
for param in self.params:
args.append(f'-G{param}={self.params[param]}')
args.extend(['simtop.v', 'write_read.cpp', '../spi_slave.v', f'../{self.master_name}.v'])
print(args)
proc = subprocess.run(args, stdout=sys.stdout, stderr=sys.stderr)
if proc.returncode != 0:
print("Verilator failed")
return False
os.chdir(dirname)
proc = subprocess.run(["make", "-f", "Vsimtop.mk"], stdout=sys.stdout, stderr=sys.stderr)
if proc.returncode != 0:
print("Make failed")
os.chdir("..")
return False
proc = subprocess.run("./Vsimtop", stdout=sys.stdout, stderr=sys.stderr)
os.chdir("..")
if proc.returncode != 0:
print("Vsimtop failed")
return False
return True
cases = {}
# Add basic cases
cases[f'test_master'] = Case("spi_master", [], {})
cases[f'test_ss'] = Case("spi_master_ss", ["SPI_MASTER_SS"], {})
cases[f'test_master_no_write'] = Case("spi_master", ['SPI_MASTER_NO_WRITE'], {'ENABLE_MOSI': 0})
cases[f'test_ss_no_write'] = Case("spi_master_ss", ["SPI_MASTER_SS", 'SPI_MASTER_NO_WRITE'], {'ENABLE_MOSI': 0})
cases[f'test_master_no_read'] = Case("spi_master", ['SPI_MASTER_NO_READ'], {'ENABLE_MISO': 1})
cases[f'test_ss_no_read'] = Case("spi_master_ss", ["SPI_MASTER_SS", 'SPI_MASTER_NO_READ'], {'ENABLE_MISO': 1})
failures=0
for polarity in [0, 1]:
for phase in [0, 1]:
for casename in cases:
if not cases[casename].run(casename, polarity, phase, 24):
failures += 1
print(f'Failures: {failures}')

View File

@ -1,11 +1,13 @@
/* (c) Peter McGoron 2022 /* (c) Peter McGoron 2022-2024 v0.4
* This Source Code Form is subject to the terms of the Mozilla Public *
* License, v.2.0. If a copy of the MPL was not distributed with this * This code is disjunctively dual-licensed under the MPL v2.0, or the
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * CERN-OHL-W v2.
*/ */
module simtop module simtop
#( #(
parameter ENABLE_MOSI = 1,
parameter ENABLE_MISO = 1,
parameter POLARITY = 0, parameter POLARITY = 0,
parameter PHASE = 0, parameter PHASE = 0,
parameter WID = 24, parameter WID = 24,
@ -13,14 +15,13 @@ module simtop
) ( ) (
input clk, input clk,
input rst_L, input rst_L,
`ifndef SPI_MASTER_NO_WRITE
input [WID-1:0] master_to_slave, input [WID-1:0] master_to_slave,
output [WID-1:0] from_master, output [WID-1:0] from_master,
`endif
`ifndef SPI_MASTER_NO_READ
input [WID-1:0] slave_to_master, input [WID-1:0] slave_to_master,
output [WID-1:0] from_slave, output [WID-1:0] from_slave,
`endif
input activate, input activate,
`ifndef SPI_MASTER_SS `ifndef SPI_MASTER_SS
input ss, input ss,
@ -31,13 +32,9 @@ module simtop
output err output err
); );
`ifndef SPI_MASTER_NO_READ
wire miso; wire miso;
`endif
`ifndef SPI_MASTER_NO_WRITE
wire mosi; wire mosi;
`endif
wire sck; wire sck;
wire ss_L; wire ss_L;
@ -46,8 +43,8 @@ wire ss_L;
assign ss_L = !ss; assign ss_L = !ss;
`endif `endif
reg slave_finished; wire slave_finished;
reg slave_error; wire slave_error;
`SPI_MASTER_TYPE `SPI_MASTER_TYPE
#( #(
@ -55,6 +52,8 @@ reg slave_error;
.SS_WAIT(5), .SS_WAIT(5),
.SS_WAIT_TIMER_LEN(3), .SS_WAIT_TIMER_LEN(3),
`endif `endif
.ENABLE_MOSI(ENABLE_MOSI),
.ENABLE_MISO(ENABLE_MISO),
.CYCLE_HALF_WAIT(5), .CYCLE_HALF_WAIT(5),
.TIMER_LEN(3), .TIMER_LEN(3),
.POLARITY(POLARITY), .POLARITY(POLARITY),
@ -64,14 +63,10 @@ reg slave_error;
) master ( ) master (
.clk(clk), .clk(clk),
.rst_L(rst_L), .rst_L(rst_L),
`ifndef SPI_MASTER_NO_WRITE
.to_slave(master_to_slave), .to_slave(master_to_slave),
.mosi(mosi), .mosi(mosi),
`endif
`ifndef SPI_MASTER_NO_READ
.from_slave(from_slave), .from_slave(from_slave),
.miso(miso), .miso(miso),
`endif
`ifdef SPI_MASTER_SS `ifdef SPI_MASTER_SS
.ss_L(ss_L), .ss_L(ss_L),
`endif `endif
@ -81,7 +76,9 @@ reg slave_error;
.arm(activate) .arm(activate)
); );
`SPI_SLAVE_TYPE #( spi_slave #(
.ENABLE_MOSI(ENABLE_MOSI),
.ENABLE_MISO(ENABLE_MISO),
.POLARITY(POLARITY), .POLARITY(POLARITY),
.PHASE(PHASE), .PHASE(PHASE),
.WID(WID), .WID(WID),
@ -91,14 +88,10 @@ reg slave_error;
.rst_L(rst_L), .rst_L(rst_L),
.sck(sck), .sck(sck),
.ss_L(ss_L), .ss_L(ss_L),
`ifndef SPI_MASTER_NO_WRITE
.from_master(from_master), .from_master(from_master),
.mosi(mosi), .mosi(mosi),
`endif
`ifndef SPI_MASTER_NO_READ
.to_master(slave_to_master), .to_master(slave_to_master),
.miso(miso), .miso(miso),
`endif
.finished(slave_finished), .finished(slave_finished),
.rdy(rdy), .rdy(rdy),
.err(err) .err(err)