diff --git a/examples/apb/3.1_write_transfer_with_no_wait_states.wave b/examples/apb/3.1_write_transfer_with_no_wait_states.wave new file mode 100644 index 00000000..bb1adb88 --- /dev/null +++ b/examples/apb/3.1_write_transfer_with_no_wait_states.wave @@ -0,0 +1,25 @@ +// https://support.arm.com/documentation/ihi0024/e/ +// Figure 3-1 "Write transfer with no wait states" (section 3.1.1) + +// Note: we assume that PENABLE is 0 during idle (i.e. before/after the write transaction), +// as Appendix A.1 of the APB spec recommends that "signals which are not required to be valid (meaningful) +// are driven to zero". + +// The figure in the spec omits the following signals: +// - PSLVERR (there is no error, so it is 0 throughout) +// - PRESETn (this is a write operation, not a reset, so we set it to 1 as it is active-low) +// - PSTRB (we assume all 4 bytes of PWDATA are valid, so we set this to 0xF) +// - PPROT (we assume this is a normal data access, so we set this to 0) +// - PRDATA (this is a write operation, so read data is DontCare) + +PRESETn 1 1 1 1 +PSEL 0 1 1 0 +PENABLE 0 0 1 0 +PWRITE x 1 1 x +PADDR[31:0] x 0x1 0x1 x // "Addr 1" +PWDATA[31:0] x 0x1 0x1 x // "Data 1" +PSTRB[3:0] x 0xf 0xf x +PPROT[2:0] x 0 0 x +PRDATA[31:0] x x x x +PREADY x x 1 x +PSLVERR 0 0 0 0 diff --git a/examples/apb/3.2_write_transfer_with_wait_states.wave b/examples/apb/3.2_write_transfer_with_wait_states.wave new file mode 100644 index 00000000..b56c646f --- /dev/null +++ b/examples/apb/3.2_write_transfer_with_wait_states.wave @@ -0,0 +1,28 @@ +// https://support.arm.com/documentation/ihi0024/e/ +// Figure 3-2 "Write transfer with wait states" (section 3.1.2) + +// This is largely the same as figure 3-1, except +// the subordinate exerts backpressure for two cycles by setting PREADY to 0. + +// Note: we assume that PENABLE is 0 during idle (i.e. before/after the write transaction), +// as Appendix A.1 of the APB spec recommends that "signals which are not required to be valid (meaningful) +// are driven to zero". + +// The figure in the spec omits the following signals: +// - PSLVERR (there is no error, so it is 0 throughout) +// - PRESETn (this is a write operation, not a reset, so we set it to 1 as it is active-low) +// - PSTRB (we assume all 4 bytes of PWDATA are valid, so we set this to 0xF) +// - PPROT (we assume this is a normal data access, so we set this to 0) +// - PRDATA (this is a write operation, so read data is DontCare) + +PRESETn 1 1 1 1 1 1 +PSEL 0 1 1 1 1 0 +PENABLE 0 0 1 1 1 0 +PWRITE x 1 1 1 1 x +PADDR[31:0] x 0x1 0x1 0x1 0x1 x // "Addr 1" +PWDATA[31:0] x 0x1 0x1 0x1 0x1 x // "Data 1" +PSTRB[3:0] x 0xf 0xf 0xf 0xf x +PPROT[2:0] x 0 0 0 0 x +PRDATA[31:0] x x x x x x +PREADY x x 0 0 1 x +PSLVERR 0 0 0 0 0 0 diff --git a/examples/apb/3.4_read_transfer_with_no_wait_states.wave b/examples/apb/3.4_read_transfer_with_no_wait_states.wave new file mode 100644 index 00000000..1145ce71 --- /dev/null +++ b/examples/apb/3.4_read_transfer_with_no_wait_states.wave @@ -0,0 +1,25 @@ +// https://support.arm.com/documentation/ihi0024/e/ +// Figure 3-4 "Read transfer with no wait states" (section 3.3.1) + +// Note: we assume that PENABLE is 0 during idle (i.e. before/after the read transaction), +// as Appendix A.1 of the APB spec recommends that "signals which are not required to be valid (meaningful) +// are driven to zero". + +// The figure in the spec omits the following signals: +// - PSLVERR (there is no error, so it is 0 throughout) +// - PRESETn (this is a read operation, not a reset, so we set it to 1 as it is active-low) +// - PSTRB (section 3.2 requires all bits of PSTRB to be LOW for reads, so we set this to 0) +// - PPROT (we assume this is a normal data access, so we set this to 0) +// - PWDATA (this is a read operation, so write data is DontCare) + +PRESETn 1 1 1 1 +PSEL 0 1 1 0 +PENABLE 0 0 1 0 +PWRITE x 0 0 x +PADDR[31:0] x 0x1 0x1 x // "Addr 1" +PWDATA[31:0] x x x x +PSTRB[3:0] x 0 0 x +PPROT[2:0] x 0 0 x +PRDATA[31:0] x x 0x1 x // "Data 1" +PREADY x x 1 x +PSLVERR 0 0 0 0 diff --git a/examples/apb/3.5_read_transfer_with_wait_states.wave b/examples/apb/3.5_read_transfer_with_wait_states.wave new file mode 100644 index 00000000..a96c2f46 --- /dev/null +++ b/examples/apb/3.5_read_transfer_with_wait_states.wave @@ -0,0 +1,25 @@ +// https://support.arm.com/documentation/ihi0024/e/ +// Figure 3-5 "Read transfer with wait states" (section 3.3.2) + +// Note: we assume that PENABLE is 0 during idle (i.e. before/after the read transaction), +// as Appendix A.1 of the APB spec recommends that "signals which are not required to be valid (meaningful) +// are driven to zero". + +// The figure in the spec omits the following signals: +// - PSLVERR (there is no error, so it is 0 throughout) +// - PRESETn (this is a read operation, not a reset, so we set it to 1 as it is active-low) +// - PSTRB (section 3.2 requires all bits of PSTRB to be LOW for reads, so we set this to 0) +// - PPROT (we assume this is a normal data access, so we set this to 0) +// - PWDATA (this is a read operation, so write data is DontCare) + +PRESETn 1 1 1 1 1 1 +PSEL 0 1 1 1 1 0 +PENABLE 0 0 1 1 1 0 +PWRITE x 0 0 0 0 x +PADDR[31:0] x 0x1 0x1 0x1 0x1 x // "Addr 1" +PWDATA[31:0] x x x x x x +PSTRB[3:0] x 0 0 0 0 x +PPROT[2:0] x 0 0 0 0 x +PRDATA[31:0] x x x x 0x1 x // "Data 1" (from cycles 1-4, PRDATA is grey in the waveform, so we assume it is DontCare for those cycles) +PREADY x x 0 0 1 x +PSLVERR 0 0 0 0 0 0 diff --git a/examples/apb/3.6_example_failing_write_transfer.wave b/examples/apb/3.6_example_failing_write_transfer.wave new file mode 100644 index 00000000..9f846c5f --- /dev/null +++ b/examples/apb/3.6_example_failing_write_transfer.wave @@ -0,0 +1,25 @@ +// https://support.arm.com/documentation/ihi0024/e/ +// Figure 3-6 "Example failing write transfer" (section 3.4.1) + +// Note: we assume that PENABLE and PLSVERR are 0 during idle (i.e. before/after the write transaction), +// as Appendix A.1 of the APB spec recommends that "signals which are not required to be valid (meaningful) +// are driven to zero". + + +// The figure in the spec omits the following signals: +// - PRESETn (this is a write operation, not a reset, so we set it to 1 as it is active-low) +// - PSTRB (we assume all 4 bytes of PWDATA are valid, so we set this to 0xF) +// - PPROT (we assume this is a normal data access, so we set this to 0) +// - PRDATA (this is a write operation, so read data is DontCare) + +PRESETn 1 1 1 1 1 +PSEL 0 1 1 1 0 +PENABLE 0 0 1 1 0 +PWRITE x 1 1 1 x +PADDR[31:0] x 0x1 0x1 0x1 x // "Addr 1" +PWDATA[31:0] x 0x1 0x1 0x1 x // "Data 1" +PSTRB[3:0] x 0xf 0xf 0xf x +PPROT[2:0] x 0 0 0 x +PRDATA[31:0] x x x x x +PREADY x x 0 1 x +PSLVERR 0 0 0 1 0 diff --git a/examples/apb/3.7_example_failing_read_transfer.wave b/examples/apb/3.7_example_failing_read_transfer.wave new file mode 100644 index 00000000..b55ee8c9 --- /dev/null +++ b/examples/apb/3.7_example_failing_read_transfer.wave @@ -0,0 +1,30 @@ +// https://support.arm.com/documentation/ihi0024/e/ +// Figure 3-7 "Example failing read transfer" (section 3.4.2) + +// Note: we assume that PENABLE and PLSVERR are 0 during idle (i.e. before/after the read transaction), +// as Appendix A.1 of the APB spec recommends that "signals which are not required to be valid (meaningful) +// are driven to zero" + +// The figure doesn't specify a value fo PRDATA: the spec says that a read transaction +// that errors "can return invalid error" and that there is +// "no requirement for the peripheral to drive the +// data bus to all 0s for a read error", so we give `PRDATA` an arbitrary value +// 0x0badda7a in this waveform. + +// The figure in the spec omits the following signals: +// - PRESETn (this is a read operation, not a reset, so we set it to 1 as it is active-low) +// - PSTRB (section 3.2 requires all bits of PSTRB to be LOW for reads, so we set this to 0) +// - PPROT (we assume this is a normal data access, so we set this to 0) +// - PWDATA (this is a read operation, so write data is DontCare) + +PRESETn 1 1 1 1 1 1 +PSEL 0 1 1 1 1 0 +PENABLE 0 0 1 1 1 0 +PWRITE x 0 0 0 0 x +PADDR[31:0] x 0x1 0x1 0x1 0x1 x // "Addr 1" +PWDATA[31:0] x x x x x x +PSTRB[3:0] x 0 0 0 0 x +PPROT[2:0] x 0 0 0 0 x +PRDATA[31:0] x x x x 0x0badda7a x // no valid read data +PREADY x x 0 0 1 x +PSLVERR 0 0 0 0 1 0 diff --git a/examples/apb/apb.prot b/examples/apb/apb.prot new file mode 100644 index 00000000..3ea8dc0d --- /dev/null +++ b/examples/apb/apb.prot @@ -0,0 +1,139 @@ +// Key points from the APB spec: +// - "Every transfer takes at least two cycles to complete" (sec. 1.1) +// - "Data transfers cannot occur concurrently because the read data and write data buses do not have their own individual +// handshake signal" (sec. 2.1.2) + +struct APB { + // active-low reset + in PRESETn: u1, + + // PSEL is 1 when the subordinate is selected + // (When there are multiple subordinates, each subordinate gets its own `PSEL` + // signal to indicate if it has been selected. Here we only have one subordinate, + // so only one `PSEL` signal) + in PSEL: u1, + + // Indicates the start of a data transfer (APB spec calls this the "access" state) + // (Note: per the spec, when `PENABLE` is low, `PREADY` is meaningless) + in PENABLE: u1, + + // 1 = write, 0 = read + in PWRITE: u1, + + // Address for reads/writes + in PADDR: u32, + + // Data to be written (this is DontCare during reads) + in PWDATA: u32, + + // Bitmask indicating which bytes of `PWDATA` contain valid data for writes. + // (APB spec calls this signal the "write strobe".) + // For reads, `PSTRB` is `DontCare`. + // APB spec says this signal is optional. + in PSTRB: u4, + + // "Protection attributes": 3-bit signal used to indicate if the data access + // is normal/privileged/secure, and if it is accessing data/an instruction + in PPROT: u3, + + // Read data (supplied by subordinate) + out PRDATA: u32, + + // Ready signal issued from subordinate + out PREADY: u1, + + // Optional signal indicating if an error occurred during data transfer + // Notes from APB spec section 3.4: + // - PSLVERR should be 0 when either one of PSEL, PENABLE or PREADY are low + // - PSLVERR is only meaningful when all three of PSEL, PENABLE and PREADY are high + out PSLVERR: u1, +} + +#[idle] +prot idle() { + // PSEL must be 0 during idle state (sec. 4.1) + DUT.PSEL := 1'b0; + + // Reset is active-low, so reset = 1 during idle (No reset) + DUT.PRESETn := 1'b1; + + // Idle means we're not in the Access state, so PENABLE = 0 + DUT.PENABLE := 1'b0; + + DUT.PWRITE := X; + DUT.PADDR := X; + DUT.PWDATA := X; + DUT.PSTRB := X; + DUT.PPROT := X; + assert_eq(DUT.PSLVERR, 1'b0); + step(); +} + +prot reset() { + // Reset is active-low + DUT.PRESETn := 1'b0; + + // These are 0, because during reset, we are not in the access state + // and the subordinate is not selected + DUT.PSEL := 1'b0; + DUT.PENABLE := 1'b0; + step(); +} + + +prot write(addr: u32, data: u32, strb: u4, pprot: u3, slverr: u1) { + DUT.PRESETn := 1'b1; + + // SETUP phase + DUT.PSEL := 1'b1; + DUT.PENABLE := 1'b0; + DUT.PWRITE := 1'b1; + DUT.PADDR := addr; + DUT.PWDATA := data; + DUT.PSTRB := strb; + DUT.PPROT := pprot; + assert_eq(DUT.PSLVERR, 1'b0); + + step(); + + // ACCESS phase: hold everything, wait out the subordinate's wait states + DUT.PENABLE := 1'b1; + while !(DUT.PREADY == 1'b1) { + assert_eq(DUT.PSLVERR, 1'b0); + step(); + } + assert_eq(DUT.PSLVERR, slverr); + step(); +} + +prot read(addr: u32, data: u32, pprot: u3, slverr: u1) { + DUT.PRESETn := 1'b1; + + // SETUP phase + DUT.PSEL := 1'b1; + DUT.PENABLE := 1'b0; + DUT.PWRITE := 1'b0; + DUT.PADDR := addr; + DUT.PPROT := pprot; + + // For read operations, PWDATA is meaningless + // and PSTRB must be set to all zeroes (sec. 3.2) + DUT.PWDATA := X; + DUT.PSTRB := 4'b0000; + assert_eq(DUT.PSLVERR, 1'b0); + + step(); + + // ACCESS phase + DUT.PENABLE := 1'b1; + + // Wait till subordinate becomes ready + while !(DUT.PREADY == 1'b1) { + assert_eq(DUT.PSLVERR, 1'b0); + step(); + } + + assert_eq(DUT.PRDATA, data); + assert_eq(DUT.PSLVERR, slverr); + step(); +} diff --git a/examples/apb/ch_apb.tx b/examples/apb/ch_apb.tx new file mode 100644 index 00000000..2a42ede4 --- /dev/null +++ b/examples/apb/ch_apb.tx @@ -0,0 +1,10 @@ +// Arguments for read & write transactions: +// write(addr, data, strb, pprot, slverr) +// read (addr, data, pprot, slverr) +trace { + reset(); + idle(); + write(0x00, 0x12345678, 0xF, 0x0, 0x0); + read(0x00, 0x12345678, 0x0, 0x0); + idle(); +} diff --git a/examples/apb/ch_apb_actual.tx b/examples/apb/ch_apb_actual.tx new file mode 100644 index 00000000..f0ac6c6e --- /dev/null +++ b/examples/apb/ch_apb_actual.tx @@ -0,0 +1,14 @@ +// Same as ch_apb.tx, but with an extra `read` transaction in the middle to show + +// Arguments for read & write transactions: +// write(addr, data, strb, pprot, slverr) +// read (addr, data, pprot, slverr) +trace { + reset(); + idle(); + write(0x00, 0x12345678, 0xF, 0x0, 0x0); + read(0x00, 0x00000000, 0x0, 0x0); // We add this extra "buggy" transaction here to show that `PRDATA` doesn't contain `0x12345678 + read(0x00, 0x12345678, 0x0, 0x0); // Read data arrives one cycle too late + idle(); +} + diff --git a/examples/apb/ch_apb_actual_0.fst b/examples/apb/ch_apb_actual_0.fst new file mode 100644 index 00000000..6d68564b Binary files /dev/null and b/examples/apb/ch_apb_actual_0.fst differ diff --git a/examples/apb/ch_apb_buggy_0.fst b/examples/apb/ch_apb_buggy_0.fst new file mode 100644 index 00000000..aa85a584 Binary files /dev/null and b/examples/apb/ch_apb_buggy_0.fst differ diff --git a/examples/apb/expects/3_1_write_transfer_with_no_wait_states.bi.expect b/examples/apb/expects/3_1_write_transfer_with_no_wait_states.bi.expect new file mode 100644 index 00000000..cf88d6a2 --- /dev/null +++ b/examples/apb/expects/3_1_write_transfer_with_no_wait_states.bi.expect @@ -0,0 +1,6 @@ +// trace 0 +trace { + idle(); [0] + write(0x00000001, 0x00000001, 0xf, 0x0, 0x0); [1 .. 2] + idle(); [3] +} diff --git a/examples/apb/expects/3_2_write_transfer_with_wait_states.bi.expect b/examples/apb/expects/3_2_write_transfer_with_wait_states.bi.expect new file mode 100644 index 00000000..cbce2e28 --- /dev/null +++ b/examples/apb/expects/3_2_write_transfer_with_wait_states.bi.expect @@ -0,0 +1,6 @@ +// trace 0 +trace { + idle(); [0] + write(0x00000001, 0x00000001, 0xf, 0x0, 0x0); [1 .. 4] + idle(); [5] +} diff --git a/examples/apb/expects/3_4_read_transfer_with_no_wait_states.bi.expect b/examples/apb/expects/3_4_read_transfer_with_no_wait_states.bi.expect new file mode 100644 index 00000000..f82122c7 --- /dev/null +++ b/examples/apb/expects/3_4_read_transfer_with_no_wait_states.bi.expect @@ -0,0 +1,6 @@ +// trace 0 +trace { + idle(); [0] + read(0x00000001, 0x00000001, 0x0, 0x0); [1 .. 2] + idle(); [3] +} diff --git a/examples/apb/expects/3_5_read_transfer_with_wait_states.bi.expect b/examples/apb/expects/3_5_read_transfer_with_wait_states.bi.expect new file mode 100644 index 00000000..5a3a0847 --- /dev/null +++ b/examples/apb/expects/3_5_read_transfer_with_wait_states.bi.expect @@ -0,0 +1,6 @@ +// trace 0 +trace { + idle(); [0] + read(0x00000001, 0x00000001, 0x0, 0x0); [1 .. 4] + idle(); [5] +} diff --git a/examples/apb/expects/3_6_example_failing_write_transfer.bi.expect b/examples/apb/expects/3_6_example_failing_write_transfer.bi.expect new file mode 100644 index 00000000..49ee55a8 --- /dev/null +++ b/examples/apb/expects/3_6_example_failing_write_transfer.bi.expect @@ -0,0 +1,6 @@ +// trace 0 +trace { + idle(); [0] + write(0x00000001, 0x00000001, 0xf, 0x0, 0x1); [1 .. 3] + idle(); [4] +} diff --git a/examples/apb/expects/3_7_example_failing_read_transfer.bi.expect b/examples/apb/expects/3_7_example_failing_read_transfer.bi.expect new file mode 100644 index 00000000..ed582171 --- /dev/null +++ b/examples/apb/expects/3_7_example_failing_read_transfer.bi.expect @@ -0,0 +1,6 @@ +// trace 0 +trace { + idle(); [0] + read(0x00000001, 0x0badda7a, 0x0, 0x1); [1 .. 4] + idle(); [5] +} diff --git a/examples/apb/expects/ch_apb.fail.expect b/examples/apb/expects/ch_apb.fail.expect new file mode 100644 index 00000000..1fc655f7 --- /dev/null +++ b/examples/apb/expects/ch_apb.fail.expect @@ -0,0 +1 @@ +Assertion failure in cycle 5. diff --git a/examples/apb/expects/ch_apb.interp.expect b/examples/apb/expects/ch_apb.interp.expect new file mode 100644 index 00000000..591feaed --- /dev/null +++ b/examples/apb/expects/ch_apb.interp.expect @@ -0,0 +1,9 @@ +error: The two expressions did not evaluate to the same value (in transaction `read(0, 305419896, 0, 0)`) + ┌─ examples/apb/apb.prot:136:15 + │ +136 │ assert_eq(DUT.PRDATA, data); + │ ^^^^^^^^^^^^^^^^ LHS Value: 0, RHS Value: 305419896 + +Trace 0 execution failed. +---CODE--- +101 diff --git a/examples/apb/expects/ch_apb_0.bi.expect b/examples/apb/expects/ch_apb_0.bi.expect new file mode 100644 index 00000000..1e265254 --- /dev/null +++ b/examples/apb/expects/ch_apb_0.bi.expect @@ -0,0 +1,6 @@ + +thread 'main' (14916314) panicked at /Users/eyn5/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wellen-0.25.6/src/viewers.rs:157:52: +failed to open input file!: Os { code: 2, kind: NotFound, message: "No such file or directory" } +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +---CODE--- +101 diff --git a/examples/apb/expects/ch_apb_actual.graph_interp.expect b/examples/apb/expects/ch_apb_actual.graph_interp.expect new file mode 100644 index 00000000..f5f6cb49 --- /dev/null +++ b/examples/apb/expects/ch_apb_actual.graph_interp.expect @@ -0,0 +1 @@ +Trace 0 executed successfully! diff --git a/examples/apb/expects/ch_apb_actual.interp.expect b/examples/apb/expects/ch_apb_actual.interp.expect new file mode 100644 index 00000000..f5f6cb49 --- /dev/null +++ b/examples/apb/expects/ch_apb_actual.interp.expect @@ -0,0 +1 @@ +Trace 0 executed successfully! diff --git a/examples/apb/expects/ch_apb_actual.waveform.expect b/examples/apb/expects/ch_apb_actual.waveform.expect new file mode 100644 index 00000000..478f95e8 --- /dev/null +++ b/examples/apb/expects/ch_apb_actual.waveform.expect @@ -0,0 +1,4 @@ +---CODE--- +134 +---STDERR--- +sh: line 1: 77452 Abort trap: 6 target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --bound 6 --ascii-waveform --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2> /dev/null diff --git a/examples/apb/expects/ip_apb.graph_interp.expect b/examples/apb/expects/ip_apb.graph_interp.expect new file mode 100644 index 00000000..f5f6cb49 --- /dev/null +++ b/examples/apb/expects/ip_apb.graph_interp.expect @@ -0,0 +1 @@ +Trace 0 executed successfully! diff --git a/examples/apb/expects/ip_apb.interp.expect b/examples/apb/expects/ip_apb.interp.expect new file mode 100644 index 00000000..f5f6cb49 --- /dev/null +++ b/examples/apb/expects/ip_apb.interp.expect @@ -0,0 +1 @@ +Trace 0 executed successfully! diff --git a/examples/apb/expects/ip_apb.waveform.expect b/examples/apb/expects/ip_apb.waveform.expect new file mode 100644 index 00000000..0517ed87 --- /dev/null +++ b/examples/apb/expects/ip_apb.waveform.expect @@ -0,0 +1,4 @@ +---CODE--- +134 +---STDERR--- +sh: line 1: 77598 Abort trap: 6 target/debug/graph-interp --transactions examples/apb/ip_apb.tx --bound 7 --ascii-waveform --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2> /dev/null diff --git a/examples/apb/expects/ip_apb_0.bi.expect b/examples/apb/expects/ip_apb_0.bi.expect new file mode 100644 index 00000000..099acb42 --- /dev/null +++ b/examples/apb/expects/ip_apb_0.bi.expect @@ -0,0 +1,8 @@ +// trace 0 +trace { + reset(); [0] + write(0, 3735929054, 15, 0, 0); [2 .. 3] + read(0, 3735929054, 0, 0); [4 .. 6] + write(8, 48879, 15, 0, 0); [7 .. 8] + read(8, 48879, 0, 0); [9 .. 11] +} diff --git a/examples/apb/ip_apb.tx b/examples/apb/ip_apb.tx new file mode 100644 index 00000000..c63d647a --- /dev/null +++ b/examples/apb/ip_apb.tx @@ -0,0 +1,17 @@ +// Arguments for read & write transactions: +// write(addr, data, strb, pprot, slverr) +// read (addr, data, pprot, slverr) +trace { + reset(); + idle(); + + // Write and read to the same address + write(0x00, 0xDEADC0DE, 0xF, 0x0, 0x0); + read(0x00, 0xDEADC0DE, 0x0, 0x0); + + // Write & read to another address + write(0x08, 0x0000BEEF, 0xF, 0x0, 0x0); + read(0x08, 0x0000BEEF, 0x0, 0x0); + + idle(); +} diff --git a/examples/apb/ip_apb_0.fst b/examples/apb/ip_apb_0.fst new file mode 100644 index 00000000..ca943fcb Binary files /dev/null and b/examples/apb/ip_apb_0.fst differ diff --git a/examples/apb/rtl/ch_apb_dut.v b/examples/apb/rtl/ch_apb_dut.v new file mode 100644 index 00000000..f81be9bb --- /dev/null +++ b/examples/apb/rtl/ch_apb_dut.v @@ -0,0 +1,38 @@ +`timescale 1ns/1ps +// This Verilog file is only used for renaming pins (renaming `PCLK` to `clk`) +// and for setting the size of the memory. +module ch_apb_dut( + input wire clk, + input wire PRESETn, + input wire PSEL, + input wire PENABLE, + input wire PWRITE, + input wire [31:0] PADDR, + input wire [31:0] PWDATA, + input wire [3:0] PSTRB, + input wire [2:0] PPROT, + output wire [31:0] PRDATA, + output wire PREADY, + output wire PSLVERR +); + + apb_slave #( + .ADDR_BUS_WIDTH(32), + .DATA_BUS_WIDTH(32), + .MEMSIZE(64), + .MEM_BLOCK_SIZE(32), + .RESET_VAL(0), + .EN_WAIT_DELAY_FUNC(0) + ) inst ( + .PRESETn (PRESETn), + .PCLK (clk), + .PSEL (PSEL), + .PENABLE (PENABLE), + .PWRITE (PWRITE), + .PADDR (PADDR), + .PWDATA (PWDATA), + .PRDATA (PRDATA), + .PREADY (PREADY), + .PSLVERR (PSLVERR) + ); +endmodule diff --git a/examples/apb/rtl/ch_apb_slave.sv b/examples/apb/rtl/ch_apb_slave.sv new file mode 100644 index 00000000..f6ab406a --- /dev/null +++ b/examples/apb/rtl/ch_apb_slave.sv @@ -0,0 +1,274 @@ +// Implementation taken from: +// https://github.com/courageheart/AMBA_APB_SRAM/blob/master/rtl/apb_v3_sram.v + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Module Name: apb_v3_sram +// Author: Farshad +// Email: farshad112@gmail.com +// Date Created: 1-June-2018 +// Description: Synchronous RAM (SRAM) core with APB interface. +// Address and data bus widths are configurable using ADDR_BUS_WIDTH and DATA_BUS_WIDTH parameters +// and RAM Size can also be configured using MEMSIZE, MEM_BLOCK_SIZE parameter. +// +// Version: 0.1 +// License: This project is licensed under MIT opensource license 3.0 available @ https://opensource.org/licenses/MIT +/******************************************* LICENSE BEGIN ************************************** +Copyright (c) 2018, Farshad + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************* LICENSE END **************************************/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +`timescale 1ns / 1ps + +module apb_slave #( + // device parameters + parameter ADDR_BUS_WIDTH=32, // Width of Address bus i.e. PADDR + parameter DATA_BUS_WIDTH=32, // Width of Data bus (i.e. PWDATA and PRDATA) + parameter MEMSIZE=64, // RAM memory Size + parameter MEM_BLOCK_SIZE=8, // RAM memory block size + parameter RESET_VAL=0, // Default Reset value of DUT + parameter EN_WAIT_DELAY_FUNC=0, // Enable Random Delay Assertion in read or write operation + parameter MIN_RAND_WAIT_CYC=0, // Minimum cycle delay for read and write operation + parameter MAX_RAND_WAIT_CYC=1)( // Maximum cycle delay for read and write operation + // IO ports + input wire PRESETn, + input wire PCLK, + input wire PSEL, + input wire PENABLE, + input wire PWRITE, + input wire [ADDR_BUS_WIDTH-1:0] PADDR, + input wire [DATA_BUS_WIDTH-1:0] PWDATA, + output reg [DATA_BUS_WIDTH-1:0] PRDATA, + output reg PREADY, + output reg PSLVERR + ); + + // RAM memory declaration + reg [MEM_BLOCK_SIZE-1:0] memory[MEMSIZE-1:0]; + + // APB State declaration + localparam IDLE = 0; + localparam SETUP = 1; + localparam ACCESS = 2; + localparam WAIT = 3; + + // APB operation states + localparam WRITE = 1; + localparam READ = 0; + + // State variable declaration + reg [1:0] state; + + // wait state variable declaration + integer wait_cyc_cntr=0; + integer wait_cyc_limit; + + /////////////////////////////////////////////// + // Task Name: reset_ram + // Parameter: none + // Return type: none + // Description: Write reset value in the RAM + /////////////////////////////////////////////// + task reset_ram; + input integer reset_value; + integer i; + begin + for(i=0; i< MEMSIZE; i=i+1) begin + memory[i] = reset_value; + end + end + endtask + + /////////////////////////////////////////////// + // Task Name: wr_data2mem + // Parameter: none + // Return type: none + // Description: Write data in the RAM + /////////////////////////////////////////////// + task wr_data2mem; + input integer mem_block_size; + input integer data_bus_width; + integer rqrd_tx_num; + integer i; + begin + // compute total number of memory required to hold the data + rqrd_tx_num = data_bus_width / mem_block_size; + if(data_bus_width == mem_block_size) begin + memory[PADDR] = PWDATA; + end + // Note: This is dead code that is commented out + // else begin + // for(i=0; i< rqrd_tx_num; i=i+1) begin + // memory[i] = PWDATA[((i+1)*MEM_BLOCK_SIZE)-1 +: (MEM_BLOCK_SIZE)]; + // end + // end + end + endtask + + // Note: This is dead code that is commented out because Yosys cannot resolve `$urandom_range`. + // initial begin + // state = IDLE; + // // compute random wait delay + // wait_cyc_limit = $urandom_range(MIN_RAND_WAIT_CYC, MAX_RAND_WAIT_CYC); + // $display("wait_cyc_limit:%0h", wait_cyc_limit); + // end + + // MINIMAL FIX: edge-sensitive async reset; remove inner event controls + always @(posedge PCLK or negedge PRESETn) begin + if(!PRESETn) begin + PREADY = 0; + PSLVERR = 0; + PRDATA = 0; + wait_cyc_cntr = 0; + // Reset SRAM + reset_ram(RESET_VAL); + end + else begin + if(!PSEL && !PENABLE) begin + PREADY = 0; + PSLVERR = 0; + wait_cyc_cntr = 0; + end + else if(PSEL && !PENABLE) begin + if(EN_WAIT_DELAY_FUNC == 1) begin + PREADY = 0; + PSLVERR = 0; + end + else begin + PREADY = 1; + PSLVERR = 0; + end + wait_cyc_cntr = 0; + end + else if(PSEL && PENABLE) begin + if(EN_WAIT_DELAY_FUNC) begin + // Use counter instead of "repeat @(posedge PCLK)" + if (wait_cyc_cntr < wait_cyc_limit) begin + wait_cyc_cntr = wait_cyc_cntr + 1; + PREADY = 0; + end + else begin + PREADY = 1; + end + end + if(PWRITE == WRITE) begin + if(PADDR < MEMSIZE) begin + wr_data2mem(MEM_BLOCK_SIZE, DATA_BUS_WIDTH); + PSLVERR = 0; + end + else begin + PSLVERR = 1; + end + end + else if(PWRITE == READ) begin + if(PADDR < MEMSIZE) begin // check if read memory is valid + PRDATA = memory[PADDR]; + PSLVERR = 0; + end + else begin + PSLVERR = 1; + end + end + + // PREADY deasserts in SETUP/IDLE branches above + end + end + end +/* + always @(posedge PCLK or PRESETn) begin + if(!PRESETn) begin + state = IDLE; + PRDATA = 0; + reset_ram(RESET_VAL); + end + else begin + if(!PSEL && !PENABLE) begin + state = IDLE; + wait_cyc_cntr = 0; + end + else if(PSEL && !PENABLE) begin + if(EN_WAIT_DELAY_FUNC==1) begin + state = WAIT; + end + else begin + state = SETUP; + end + end + else if(PSEL && PENABLE) begin + if(EN_WAIT_DELAY_FUNC == 1) begin + if(wait_cyc_cntr < wait_cyc_limit) begin + $display("@:%0t wait_cyc_cntr:%0d, wait_cyc_limit:%0d", $time, wait_cyc_cntr, wait_cyc_limit); + wait_cyc_cntr = wait_cyc_cntr + 1; + if(wait_cyc_cntr == wait_cyc_limit) begin + $display("@:%0t Setting PREADY HIGH", $time); + PREADY = 1; + $display("@:%0t wait_cyc_cntr:%0d, wait_cyc_limit:%0d", $time, wait_cyc_cntr, wait_cyc_limit); + $display("Starting ACCESS state"); + state = ACCESS; + end + else begin + state = WAIT; + end + end + end + else begin + state = ACCESS; + end + end + else begin + state = IDLE; + end + end + + end +*/ + /* + always @(state) begin + case(state) + IDLE: begin + PREADY = 0; + PSLVERR = 0; + end + SETUP: begin + PREADY = 1; + PSLVERR = 0; + end + ACCESS: begin + if(PWRITE == WRITE) begin + if(PADDR < MEMSIZE) begin + wr_data2mem(MEM_BLOCK_SIZE, DATA_BUS_WIDTH); + PSLVERR = 0; + end + else begin + PSLVERR = 1; + end + end + else if(PWRITE == READ) begin + if(PADDR < MEMSIZE) begin // check if read memory is valid + PRDATA = memory[PADDR]; + PSLVERR = 0; + end + else begin + PSLVERR = 1; + end + end + PREADY = 0; + end + WAIT: begin + PREADY = 0; + PSLVERR = 0; + end + default: begin + PREADY = 0; + PRDATA = 0; + PSLVERR = 0; + end + endcase + end + */ +endmodule diff --git a/examples/apb/rtl/ip_apb_dut.v b/examples/apb/rtl/ip_apb_dut.v new file mode 100644 index 00000000..ac2cf7c2 --- /dev/null +++ b/examples/apb/rtl/ip_apb_dut.v @@ -0,0 +1,33 @@ +`timescale 1ns/1ps +// This Verilog file is only used for renaming pins. +module ip_apb_dut( + input wire clk, + input wire PRESETn, + input wire PSEL, + input wire PENABLE, + input wire PWRITE, + input wire [31:0] PADDR, + input wire [31:0] PWDATA, + input wire [3:0] PSTRB, + input wire [2:0] PPROT, + output wire [31:0] PRDATA, + output wire PREADY, + output wire PSLVERR +); + + apb_slave #(.DW(32), .AW(5)) inst ( + .pclk (clk), + .presetn (PRESETn), + .i_paddr (PADDR[4:0]), + .i_pwrite (PWRITE), + .i_psel (PSEL), + .i_penable (PENABLE), + .i_pwdata (PWDATA), + .i_pstrb (PSTRB), + .o_prdata (PRDATA), + .o_pslverr (PSLVERR), + .o_pready (PREADY), + .o_hw_ctl (), + .i_hw_sts (1'b0) + ); +endmodule diff --git a/examples/apb/rtl/ip_apb_slave.sv b/examples/apb/rtl/ip_apb_slave.sv new file mode 100644 index 00000000..adb779fc --- /dev/null +++ b/examples/apb/rtl/ip_apb_slave.sv @@ -0,0 +1,197 @@ +// Implementation taken from: +// https://github.com/iammituraj/apb/blob/main/apb_slave.sv + + +//----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//----%% ╔═╦╗╔╗─────────╔╗─╔╗────╔╗ +//----%% ║╔╣╚╬╬═╦══╦╦╦═╦╣╠╗║║╔═╦═╬╬═╗ +//----%% ║╚╣║║║╬║║║║║║║║║═╣║╚╣╬║╬║║═╣ +//----%% ╚═╩╩╩╣╔╩╩╩╩═╩╩═╩╩╝╚═╩═╬╗╠╩═╝ +//----%% ─────╚╝───────────────╚═╝ Chipmunk Logic™ , https://chipmunklogic.com +//----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +//----%% Module Name : APB Slave +//----%% Developer : Mitu Raj, chip@chipmunklogic.com +//----%% +//----%% Description : APB slave which implements register address map for a HW. Read access has one wait state. Write access has 0 wait state. +//----%% Write access: 2-cycle +//----%% Read access : 3-cycle +//----%% +//----%% Last modified on : July-2024 +//----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +//################################################################################################################################################### +// A P B S L A V E +//################################################################################################################################################### +module apb_slave #( + // Configurable Parameters + parameter DW = 32 , // Data width + parameter AW = 5 , // Address width; max. 32 as per APB spec + + // Derived Parameters + localparam SW = DW/8 // Strobe width (yosys-friendly rewrite of int'($ceil(DW/8))) +) +( + // Clock and Reset + input logic pclk , // Clock + input logic presetn , // Reset + + // APB Interface + input logic [AW-1:0] i_paddr , // Address + input logic i_pwrite , // Write enable + input logic i_psel , // Select + input logic i_penable , // Enable + input logic [DW-1:0] i_pwdata , // Write data + input logic [SW-1:0] i_pstrb , // Write strobe + output logic [DW-1:0] o_prdata , // Read data + output logic o_pslverr , // Slave error + output logic o_pready , // Ready + + // HW interface + output logic o_hw_ctl , // Some control signal from APB registers to external HW... + input logic i_hw_sts // Some status signal from external HW to APB registers... +); + +// States +typedef enum logic [1:0] +{ + IDLE = 2'b00 , + W_ACCESS = 2'b01 , + R_ACCESS = 2'b10 , + R_FINISH = 2'b11 +} state_t ; +// State register +state_t state_ff ; + +// Address LSb index, assuming address space with byte-addressing scheme... +// 8-bit => addr[AW-1:0] +// 16-bit => addr[AW-1:1], ie., ignore addr[0:0] bits +// 32-bit => addr[AW-1:2], ie., ignore addr[1:0] bits +localparam ADDR_LSB = $clog2(DW/8) ; +localparam N_REG = 2**(AW-ADDR_LSB) ; // Max. no of registers supported in the address space + +//----------------------------------------------------------------------------------- +// Register Address Map +//----------------------------------------------------------------------------------- +// 1) 0x00 : apb_reg[0] - (RW) // read-write; drives HW interface +// 2) 0x04 : apb_reg[1] - (WO) // write-only +// 3) 0x08 : apb_reg[2] - (RW) // read-write +// 4) 0x0C : apb_reg[3] - (RO) // read-only +// 5) 0x10 : apb_reg[4] - (RO+) // read-only; HW interface drives this +// 6) +// ... +//----------------------------------------------------------------------------------- +logic [DW-1:0] apb_reg[5] ; + +// Read/write errors +logic wr_err, rd_err ; + +// Read/write requests +logic req_rd, req_wr ; +assign req_rd = i_psel && ~i_pwrite ; +assign req_wr = i_psel && i_pwrite ; + +// Synchronous logic to read/write registers +always @(posedge pclk) begin + // Reset + if (!presetn) begin + state_ff <= IDLE ; + // RW/WO registers + apb_reg[0] <= '0 ; + apb_reg[1] <= '0 ; + apb_reg[2] <= '0 ; + // APB read ports + o_prdata <= '0 ; + o_pready <= 1'b0 ; + end + // Out of reset + else begin + // APB control FSM + case (state_ff) + + // Idle State : waits for psel signal and decodes access type + IDLE : begin + if (req_wr) begin + o_pready <= 1'b1 ; // Write access has no wait states + state_ff <= W_ACCESS ; // Write access required + end + else if (req_rd) begin + o_pready <= 1'b0 ; // Read access has wait states + state_ff <= R_ACCESS ; // Read access required + end + end + + // Write Access State : writes addressed-register + W_ACCESS : begin + // psel and pwrite expected to be stable and penable to be asserted for successful write + if (req_wr && i_penable) begin + // Address decoding with LSbs masked + case (i_paddr [AW-1:ADDR_LSB]) + 0 : apb_reg[0] <= i_pwdata ; + 1 : apb_reg[1] <= i_pwdata ; + 2 : apb_reg[2] <= i_pwdata ; + default : ; + endcase + end + o_pready <= 1'b0 ; + state_ff <= IDLE ; + end + + // Read Access State : reads addressed-register + R_ACCESS : begin + // psel and pwrite expected to be stable and penable to be asserted for successful read + if (req_rd && i_penable) begin + // Address decoding with LSbs masked + case (i_paddr [AW-1:ADDR_LSB]) + 0 : o_prdata <= apb_reg[0] ; + 2 : o_prdata <= apb_reg[2] ; + 3 : o_prdata <= apb_reg[3] ; + 4 : o_prdata <= apb_reg[4] ; + default : o_prdata <= '0 ; // All invalid addresses, write-only registers are read as 0 + endcase + end + else begin + o_prdata <= '0 ; // Send 0s on unsuccessful read + end + o_pready <= 1'b1 ; // Induces one wait state + state_ff <= R_FINISH ; + end + + // Read Finish state : All read accesses finish here + R_FINISH : begin + o_pready <= 1'b0 ; + state_ff <= IDLE ; + end + + default : ; + + endcase + end +end + +// Assign all RO/RO+ registers +assign apb_reg[3] = 32'hDEAD_BEEF ; // Constant value +assign apb_reg[4] = i_hw_sts ; // Driven by HW interface status signal... + +// Drive all HW interface control signals +assign o_hw_ctl = apb_reg[0] ; + +// Slave error conditions +assign wr_err = (state_ff == IDLE) && req_wr && (i_paddr[AW-1:ADDR_LSB] == 3 || i_paddr[AW-1:ADDR_LSB] == 4); // Write request to read-only registers = ERROR +assign rd_err = (state_ff == R_ACCESS) && req_rd && (i_paddr[AW-1:ADDR_LSB] == 1); // Read request to write-only registers = ERROR + +// Register the Slave error +always @(posedge pclk) begin + // Reset + if (!presetn) begin + o_pslverr <= 1'b0 ; + end + // Out of reset + else begin + o_pslverr <= wr_err | rd_err ; + end +end + +endmodule +//################################################################################################################################################### +// A P B S L A V E +//################################################################################################################################################### diff --git a/runt/bi/runt.toml b/runt/bi/runt.toml index 7554d261..02ebd6f4 100644 --- a/runt/bi/runt.toml +++ b/runt/bi/runt.toml @@ -1,5 +1,68 @@ ver = "0.4.1" +[[tests]] +name = "bi.examples_apb_apb.3_1_write_transfer_with_no_wait_states_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "3_1_write_transfer_with_no_wait_states.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/3.1_write_transfer_with_no_wait_states.wave --instances :APB --show-steps --include-idle --display-hex 2>&1" + +[[tests]] +name = "bi.examples_apb_apb.3_2_write_transfer_with_wait_states_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "3_2_write_transfer_with_wait_states.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/3.2_write_transfer_with_wait_states.wave --instances :APB --show-steps --include-idle --display-hex 2>&1" + +[[tests]] +name = "bi.examples_apb_apb.3_4_read_transfer_with_no_wait_states_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "3_4_read_transfer_with_no_wait_states.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/3.4_read_transfer_with_no_wait_states.wave --instances :APB --show-steps --include-idle --display-hex 2>&1" + +[[tests]] +name = "bi.examples_apb_apb.3_5_read_transfer_with_wait_states_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "3_5_read_transfer_with_wait_states.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/3.5_read_transfer_with_wait_states.wave --instances :APB --show-steps --include-idle --display-hex 2>&1" + +[[tests]] +name = "bi.examples_apb_apb.3_6_example_failing_write_transfer_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "3_6_example_failing_write_transfer.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/3.6_example_failing_write_transfer.wave --instances :APB --show-steps --include-idle --display-hex 2>&1" + +[[tests]] +name = "bi.examples_apb_apb.3_7_example_failing_read_transfer_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "3_7_example_failing_read_transfer.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/3.7_example_failing_read_transfer.wave --instances :APB --show-steps --include-idle --display-hex 2>&1" + +[[tests]] +name = "bi.examples_apb_apb.ip_apb_0_bi" +paths = [ + "../../examples/apb/apb.prot", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb_0.bi.expect" +cmd = "cd ../.. && target/debug/bi --color never --protocol examples/apb/apb.prot --wave examples/apb/ip_apb_0.fst --instances dut:APB --show-steps 2>&1" + [[tests]] name = "bi.examples_wishbone_wishbone.ethmac_first_62us_bi" paths = [ diff --git a/runt/fail/runt.toml b/runt/fail/runt.toml index f3e88462..84d65afe 100644 --- a/runt/fail/runt.toml +++ b/runt/fail/runt.toml @@ -1,5 +1,23 @@ ver = "0.4.1" +[[tests]] +name = "fail.examples_apb_ch_apb.ch_apb_fail.graph" +paths = [ + "../../examples/apb/ch_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb.fail.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb.tx --respect-forks --determinize --brief-graph-errors --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + +[[tests]] +name = "fail.examples_apb_ch_apb.ch_apb_fail.ts" +paths = [ + "../../examples/apb/ch_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb.fail.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb.tx --transition-system --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + [[tests]] name = "fail.tests_adders_adder_d1_add_incorrect.add_incorrect_fail.graph" paths = [ diff --git a/runt/graph_interp/runt.toml b/runt/graph_interp/runt.toml index 373c5075..50d11191 100644 --- a/runt/graph_interp/runt.toml +++ b/runt/graph_interp/runt.toml @@ -1,5 +1,59 @@ ver = "0.4.1" +[[tests]] +name = "graph_interp.examples_apb_ch_apb_actual.ch_apb_actual_graph_interp" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.graph_interp.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + +[[tests]] +name = "graph_interp.examples_apb_ch_apb_actual.ch_apb_actual_graph_interp.contract_edges" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.graph_interp.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut --contract-edges 2>/dev/null" + +[[tests]] +name = "graph_interp.examples_apb_ch_apb_actual.ch_apb_actual_graph_interp.respect_forks" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.graph_interp.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut --respect-forks --determinize 2>/dev/null" + +[[tests]] +name = "graph_interp.examples_apb_ip_apb.ip_apb_graph_interp" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.graph_interp.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ip_apb.tx --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2>/dev/null" + +[[tests]] +name = "graph_interp.examples_apb_ip_apb.ip_apb_graph_interp.contract_edges" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.graph_interp.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ip_apb.tx --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut --contract-edges 2>/dev/null" + +[[tests]] +name = "graph_interp.examples_apb_ip_apb.ip_apb_graph_interp.respect_forks" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.graph_interp.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ip_apb.tx --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut --respect-forks --determinize 2>/dev/null" + [[tests]] name = "graph_interp.examples_picorv32_unsigned_mul.unsigned_mul_graph_interp" paths = [ diff --git a/runt/interp/runt.toml b/runt/interp/runt.toml index a06c977b..39efb5ff 100644 --- a/runt/interp/runt.toml +++ b/runt/interp/runt.toml @@ -1,5 +1,32 @@ ver = "0.4.1" +[[tests]] +name = "interp.examples_apb_ch_apb.ch_apb_interp" +paths = [ + "../../examples/apb/ch_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb.interp.expect" +cmd = "cd ../.. && target/debug/protocols-interp --color never --transactions examples/apb/ch_apb.tx --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>&1" + +[[tests]] +name = "interp.examples_apb_ch_apb_actual.ch_apb_actual_interp" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.interp.expect" +cmd = "cd ../.. && target/debug/protocols-interp --color never --transactions examples/apb/ch_apb_actual.tx --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>&1" + +[[tests]] +name = "interp.examples_apb_ip_apb.ip_apb_interp" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.interp.expect" +cmd = "cd ../.. && target/debug/protocols-interp --color never --transactions examples/apb/ip_apb.tx --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2>&1" + [[tests]] name = "interp.examples_picorv32_unsigned_mul.unsigned_mul_interp" paths = [ diff --git a/runt/waveform/runt.toml b/runt/waveform/runt.toml index 579c1232..916a4e87 100644 --- a/runt/waveform/runt.toml +++ b/runt/waveform/runt.toml @@ -1,5 +1,77 @@ ver = "0.4.1" +[[tests]] +name = "waveform.examples_apb_ch_apb_actual.ch_apb_actual_waveform.ast" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.waveform.expect" +cmd = "cd ../.. && target/debug/protocols-interp --color never --transactions examples/apb/ch_apb_actual.tx --ascii-waveform --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ch_apb_actual.ch_apb_actual_waveform.graph" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.waveform.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --respect-forks --determinize --ascii-waveform --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ch_apb_actual.ch_apb_actual_waveform.ts" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.waveform.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --transition-system --ascii-waveform --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ch_apb_actual.ch_apb_actual_waveform.bmc" +paths = [ + "../../examples/apb/ch_apb_actual.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ch_apb_actual.waveform.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ch_apb_actual.tx --bound 6 --ascii-waveform --verilog examples/apb/rtl/ch_apb_slave.sv examples/apb/rtl/ch_apb_dut.v --protocol examples/apb/apb.prot --module ch_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ip_apb.ip_apb_waveform.ast" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.waveform.expect" +cmd = "cd ../.. && target/debug/protocols-interp --color never --transactions examples/apb/ip_apb.tx --ascii-waveform --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ip_apb.ip_apb_waveform.graph" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.waveform.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ip_apb.tx --respect-forks --determinize --ascii-waveform --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ip_apb.ip_apb_waveform.ts" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.waveform.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ip_apb.tx --transition-system --ascii-waveform --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2>/dev/null" + +[[tests]] +name = "waveform.examples_apb_ip_apb.ip_apb_waveform.bmc" +paths = [ + "../../examples/apb/ip_apb.tx", +] +expect_dir = "../../examples/apb/expects" +expect_name = "ip_apb.waveform.expect" +cmd = "cd ../.. && target/debug/graph-interp --transactions examples/apb/ip_apb.tx --bound 7 --ascii-waveform --verilog examples/apb/rtl/ip_apb_slave.sv examples/apb/rtl/ip_apb_dut.v --protocol examples/apb/apb.prot --module ip_apb_dut 2>/dev/null" + [[tests]] name = "waveform.examples_picorv32_unsigned_mul.unsigned_mul_waveform.ast" paths = [ diff --git a/scripts/generate_runt_configs.py b/scripts/generate_runt_configs.py index 96c0dc22..d39c2e94 100644 --- a/scripts/generate_runt_configs.py +++ b/scripts/generate_runt_configs.py @@ -74,12 +74,17 @@ def replace_non_alphanumerics(value: object) -> str: def case_stem(case: dict) -> str: - # Antmicro & Brave New World test cases for the BI share the same `.prot` - # file but have multiple waveforms, so we use the waveform files' + # Antmicro, Brave New World & APB test cases for the BI share the same + # `.prot` file but have multiple waveforms, so we use the waveform files' # names to identify a particular test, otherwise we use the `.prot` file's stem # to identify a test wave = case.get("wave") - if wave and ("antmicro" in wave or "fpga-debugging" in wave or "ethmac" in wave): + if wave and ( + "antmicro" in wave + or "fpga-debugging" in wave + or "ethmac" in wave + or "apb" in wave + ): return Path(wave).stem # for all the .wave bi benchmarks, we use the id if wave and wave.endswith(".wave"): diff --git a/scripts/test_catalog.py b/scripts/test_catalog.py index 95480ab6..04ae4d75 100644 --- a/scripts/test_catalog.py +++ b/scripts/test_catalog.py @@ -4,6 +4,33 @@ # TX_CASES are keyed by their .tx path. BI_CASES are keyed by a unique id TX_CASES = { + "examples/apb/ip_apb.tx": { + "protocol": "examples/apb/apb.prot", + "verilog": ( + "examples/apb/rtl/ip_apb_slave.sv", + "examples/apb/rtl/ip_apb_dut.v", + ), + "top": "ip_apb_dut", + "expect": "pass", + }, + "examples/apb/ch_apb_actual.tx": { + "protocol": "examples/apb/apb.prot", + "verilog": ( + "examples/apb/rtl/ch_apb_slave.sv", + "examples/apb/rtl/ch_apb_dut.v", + ), + "top": "ch_apb_dut", + "expect": "pass", + }, + "examples/apb/ch_apb.tx": { + "protocol": "examples/apb/apb.prot", + "verilog": ( + "examples/apb/rtl/ch_apb_slave.sv", + "examples/apb/rtl/ch_apb_dut.v", + ), + "top": "ch_apb_dut", + "expect": "assertion_mismatch", + }, "examples/picorv32/unsigned_mul.tx": { "protocol": "examples/picorv32/pcpi_mul.prot", "verilog": ("examples/picorv32/picorv32.v",), @@ -476,6 +503,55 @@ } BI_CASES = { + "examples.apb.ip_apb_interp_fst": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/ip_apb_0.fst", + "instances": ("dut:APB",), + "expect": "pass", + "extra_args": ("--show-steps",), + }, + "examples.apb.spec_fig_3_1": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/3.1_write_transfer_with_no_wait_states.wave", + "instances": (":APB",), + "expect": "pass", + "extra_args": ("--show-steps", "--include-idle", "--display-hex"), + }, + "examples.apb.spec_fig_3_2": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/3.2_write_transfer_with_wait_states.wave", + "instances": (":APB",), + "expect": "pass", + "extra_args": ("--show-steps", "--include-idle", "--display-hex"), + }, + "examples.apb.spec_fig_3_4": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/3.4_read_transfer_with_no_wait_states.wave", + "instances": (":APB",), + "expect": "pass", + "extra_args": ("--show-steps", "--include-idle", "--display-hex"), + }, + "examples.apb.spec_fig_3_5": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/3.5_read_transfer_with_wait_states.wave", + "instances": (":APB",), + "expect": "pass", + "extra_args": ("--show-steps", "--include-idle", "--display-hex"), + }, + "examples.apb.spec_fig_3_6": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/3.6_example_failing_write_transfer.wave", + "instances": (":APB",), + "expect": "pass", + "extra_args": ("--show-steps", "--include-idle", "--display-hex"), + }, + "examples.apb.spec_fig_3_7": { + "protocol": "examples/apb/apb.prot", + "wave": "examples/apb/3.7_example_failing_read_transfer.wave", + "instances": (":APB",), + "expect": "pass", + "extra_args": ("--show-steps", "--include-idle", "--display-hex"), + }, "tests.adders.add_d1": { "protocol": "tests/adders/add_d1.prot", "wave": "tests/adders/add_d1.fst",