Add interrupt tests!
This commit is contained in:
@@ -18,8 +18,8 @@ python3 -m pip install test/requirements.txt
|
||||
|
||||
# Running tests
|
||||
|
||||
Tests can be launched from the test directory using `pytest``.
|
||||
Use ``pytest -n auto`` to run tests in parallel.
|
||||
Tests can be launched from the test directory using `pytest`.
|
||||
Use `pytest -n auto` to run tests in parallel.
|
||||
|
||||
To run all tests:
|
||||
```bash
|
||||
@@ -36,12 +36,12 @@ pytest
|
||||
|
||||
# Test organization
|
||||
|
||||
The goal for this test infrastructre is to make it easy to add small-standalone
|
||||
The goal for this test infrastructure is to make it easy to add small-standalone
|
||||
testcases, with minimal repetition/boilerplate code that is usually present in
|
||||
SystemVerilog testbenches.
|
||||
|
||||
To accomplish this, Jinja templates are used extensively to generate the
|
||||
resulting ``tb.sv`` file, as well as assist in dynamic testcase parameterization.
|
||||
resulting `tb.sv` file, as well as assist in dynamic testcase parameterization.
|
||||
|
||||
|
||||
|
||||
|
||||
0
test/test_interrupts/__init__.py
Normal file
0
test/test_interrupts/__init__.py
Normal file
106
test/test_interrupts/regblock.rdl
Normal file
106
test/test_interrupts/regblock.rdl
Normal file
@@ -0,0 +1,106 @@
|
||||
addrmap top {
|
||||
//---------------------------------
|
||||
reg {
|
||||
field ctrl_t {
|
||||
sw=rw; hw=na;
|
||||
};
|
||||
ctrl_t irq0[8] = 0;
|
||||
ctrl_t irq1[1] = 0;
|
||||
}
|
||||
ctrl_enable @ 0x100,
|
||||
ctrl_mask @ 0x104,
|
||||
ctrl_haltenable @ 0x108,
|
||||
ctrl_haltmask @ 0x10c;
|
||||
//---------------------------------
|
||||
|
||||
reg {
|
||||
field intr_t {
|
||||
sw=rw; hw=w;
|
||||
level intr;
|
||||
woclr;
|
||||
};
|
||||
|
||||
intr_t irq0[8] = 0;
|
||||
intr_t irq1[1] = 0;
|
||||
}
|
||||
level_irqs_1 @ 0x0,
|
||||
level_irqs_2 @ 0x4,
|
||||
level_irqs_3 @ 0x8;
|
||||
|
||||
level_irqs_2.irq0->enable = ctrl_enable.irq0;
|
||||
level_irqs_2.irq1->enable = ctrl_enable.irq1;
|
||||
level_irqs_2.irq0->haltenable = ctrl_haltenable.irq0;
|
||||
level_irqs_2.irq1->haltenable = ctrl_haltenable.irq1;
|
||||
level_irqs_3.irq0->mask = ctrl_mask.irq0;
|
||||
level_irqs_3.irq1->mask = ctrl_mask.irq1;
|
||||
level_irqs_3.irq0->haltmask = ctrl_haltmask.irq0;
|
||||
level_irqs_3.irq1->haltmask = ctrl_haltmask.irq1;
|
||||
//---------------------------------
|
||||
|
||||
reg {
|
||||
field intr_t {
|
||||
sw=rw; hw=w;
|
||||
posedge intr;
|
||||
woclr;
|
||||
};
|
||||
|
||||
intr_t irq0[8] = 0;
|
||||
intr_t irq1[1] = 0;
|
||||
} posedge_irqs @ 0x10;
|
||||
|
||||
//---------------------------------
|
||||
|
||||
reg {
|
||||
field intr_t {
|
||||
sw=rw; hw=w;
|
||||
negedge intr;
|
||||
woclr;
|
||||
};
|
||||
|
||||
intr_t irq0[8] = 0;
|
||||
intr_t irq1[1] = 0;
|
||||
} negedge_irqs @ 0x20;
|
||||
|
||||
//---------------------------------
|
||||
|
||||
reg {
|
||||
field intr_t {
|
||||
sw=rw; hw=w;
|
||||
bothedge intr;
|
||||
woclr;
|
||||
};
|
||||
|
||||
intr_t irq0[8] = 0;
|
||||
intr_t irq1[1] = 0;
|
||||
} bothedge_irqs @ 0x30;
|
||||
|
||||
//---------------------------------
|
||||
|
||||
reg {
|
||||
field intr_t {
|
||||
sw=r; hw=w;
|
||||
nonsticky intr;
|
||||
};
|
||||
|
||||
intr_t level_active[1];
|
||||
intr_t posedge_active[1];
|
||||
intr_t negedge_active[1];
|
||||
intr_t bothedge_active[1];
|
||||
intr_t level_halt_active[1];
|
||||
} top_irq @ 0x40;
|
||||
|
||||
top_irq.level_active->next = level_irqs_1->intr;
|
||||
top_irq.posedge_active->next = posedge_irqs->intr;
|
||||
top_irq.negedge_active->next = negedge_irqs->intr;
|
||||
top_irq.bothedge_active->next = bothedge_irqs->intr;
|
||||
top_irq.level_halt_active->next = level_irqs_2->halt;
|
||||
|
||||
//---------------------------------
|
||||
reg {
|
||||
field {
|
||||
sw=rw; hw=w;
|
||||
sticky;
|
||||
} stickyfield[8] = 0;
|
||||
} stickyreg @ 0x50;
|
||||
|
||||
};
|
||||
237
test/test_interrupts/tb_template.sv
Normal file
237
test/test_interrupts/tb_template.sv
Normal file
@@ -0,0 +1,237 @@
|
||||
{% extends "lib/tb_base.sv" %}
|
||||
|
||||
{% block seq %}
|
||||
{% sv_line_anchor %}
|
||||
##1;
|
||||
cb.rst <= '0;
|
||||
##1;
|
||||
|
||||
// Enable all interrupts
|
||||
cpuif.write('h100, 'h1FF); // ctrl_enable
|
||||
cpuif.write('h104, 'h000); // ctrl_mask
|
||||
cpuif.write('h108, 'h1FF); // ctrl_haltenable
|
||||
cpuif.write('h10C, 'h000); // ctrl_haltmask
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test level_irqs_1
|
||||
cpuif.assert_read('h0, 'h000);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b0);
|
||||
cb.hwif_in.level_irqs_1.irq0.next <= 'h0F;
|
||||
@cb;
|
||||
cb.hwif_in.level_irqs_1.irq0.next <= 'h00;
|
||||
cpuif.assert_read('h0, 'h00F);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b1);
|
||||
cpuif.write('h0, 'h3);
|
||||
cpuif.assert_read('h0, 'h00C);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b1);
|
||||
cpuif.write('h0, 'hC);
|
||||
cpuif.assert_read('h0, 'h000);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b0);
|
||||
|
||||
cb.hwif_in.level_irqs_1.irq1.next <= 'b1;
|
||||
@cb;
|
||||
cb.hwif_in.level_irqs_1.irq1.next <= 'b0;
|
||||
cpuif.assert_read('h0, 'h100);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b1);
|
||||
cpuif.write('h0, 'h100);
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b0);
|
||||
cpuif.assert_read('h0, 'h0);
|
||||
|
||||
cb.hwif_in.level_irqs_1.irq1.next <= 'b1;
|
||||
cpuif.assert_read('h0, 'h100);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b1);
|
||||
cpuif.write('h0, 'h100);
|
||||
cpuif.assert_read('h0, 'h100);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b1);
|
||||
cb.hwif_in.level_irqs_1.irq1.next <= 'b0;
|
||||
cpuif.assert_read('h0, 'h100);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b1);
|
||||
cpuif.write('h0, 'h100);
|
||||
cpuif.assert_read('h0, 'h000);
|
||||
assert(cb.hwif_out.level_irqs_1.intr == 1'b0);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test level_irqs_2
|
||||
cpuif.assert_read('h4, 'h000);
|
||||
assert(cb.hwif_out.level_irqs_2.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_2.halt == 1'b0);
|
||||
cb.hwif_in.level_irqs_2.irq0.next <= 'h0F;
|
||||
@cb;
|
||||
cb.hwif_in.level_irqs_2.irq0.next <= 'h00;
|
||||
cpuif.assert_read('h4, 'h00F);
|
||||
assert(cb.hwif_out.level_irqs_2.intr == 1'b1);
|
||||
assert(cb.hwif_out.level_irqs_2.halt == 1'b1);
|
||||
cpuif.write('h100, 'h0); // ctrl_enable
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_2.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_2.halt == 1'b1);
|
||||
cpuif.write('h108, 'h0); // ctrl_haltenable
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_2.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_2.halt == 1'b0);
|
||||
cpuif.write('h100, 'h1FF); // ctrl_enable
|
||||
cpuif.write('h108, 'h1FF); // ctrl_haltenable
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_2.intr == 1'b1);
|
||||
assert(cb.hwif_out.level_irqs_2.halt == 1'b1);
|
||||
cpuif.write('h4, 'h1FF);
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_2.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_2.halt == 1'b0);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test level_irqs_3
|
||||
cpuif.assert_read('h8, 'h000);
|
||||
assert(cb.hwif_out.level_irqs_3.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_3.halt == 1'b0);
|
||||
cb.hwif_in.level_irqs_3.irq0.next <= 'h0F;
|
||||
@cb;
|
||||
cb.hwif_in.level_irqs_3.irq0.next <= 'h00;
|
||||
cpuif.assert_read('h8, 'h00F);
|
||||
assert(cb.hwif_out.level_irqs_3.intr == 1'b1);
|
||||
assert(cb.hwif_out.level_irqs_3.halt == 1'b1);
|
||||
cpuif.write('h104, 'h0F); // ctrl_mask
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_3.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_3.halt == 1'b1);
|
||||
cpuif.write('h10C, 'hF); // ctrl_haltmask
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_3.intr == 1'b0);
|
||||
assert(cb.hwif_out.level_irqs_3.halt == 1'b0);
|
||||
cpuif.write('h104, 'h0); // ctrl_mask
|
||||
cpuif.write('h10C, 'h0); // ctrl_haltmask
|
||||
@cb;
|
||||
assert(cb.hwif_out.level_irqs_3.intr == 1'b1);
|
||||
assert(cb.hwif_out.level_irqs_3.halt == 1'b1);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test posedge_irqs
|
||||
cpuif.assert_read('h10, 'h000);
|
||||
assert(cb.hwif_out.posedge_irqs.intr == 1'b0);
|
||||
cb.hwif_in.posedge_irqs.irq1.next <= 1'b1;
|
||||
@cb;
|
||||
cpuif.assert_read('h10, 'h100);
|
||||
assert(cb.hwif_out.posedge_irqs.intr == 1'b1);
|
||||
cpuif.write('h10, 'h100);
|
||||
cpuif.assert_read('h10, 'h000);
|
||||
assert(cb.hwif_out.posedge_irqs.intr == 1'b0);
|
||||
cpuif.assert_read('h10, 'h000);
|
||||
|
||||
cb.hwif_in.posedge_irqs.irq1.next <= 1'b0;
|
||||
cpuif.assert_read('h10, 'h000);
|
||||
assert(cb.hwif_out.posedge_irqs.intr == 1'b0);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test negedge_irqs
|
||||
cpuif.assert_read('h20, 'h000);
|
||||
assert(cb.hwif_out.negedge_irqs.intr == 1'b0);
|
||||
cb.hwif_in.negedge_irqs.irq1.next <= 1'b1;
|
||||
@cb;
|
||||
cpuif.assert_read('h20, 'h000);
|
||||
assert(cb.hwif_out.negedge_irqs.intr == 1'b0);
|
||||
cb.hwif_in.negedge_irqs.irq1.next <= 1'b0;
|
||||
cpuif.assert_read('h20, 'h100);
|
||||
assert(cb.hwif_out.negedge_irqs.intr == 1'b1);
|
||||
cpuif.write('h20, 'h100);
|
||||
cpuif.assert_read('h20, 'h000);
|
||||
assert(cb.hwif_out.negedge_irqs.intr == 1'b0);
|
||||
cpuif.assert_read('h20, 'h000);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test bothedge_irqs
|
||||
cpuif.assert_read('h30, 'h000);
|
||||
assert(cb.hwif_out.bothedge_irqs.intr == 1'b0);
|
||||
|
||||
cb.hwif_in.bothedge_irqs.irq1.next <= 1'b1;
|
||||
cpuif.assert_read('h30, 'h100);
|
||||
assert(cb.hwif_out.bothedge_irqs.intr == 1'b1);
|
||||
cpuif.write('h30, 'h100);
|
||||
cpuif.assert_read('h30, 'h000);
|
||||
assert(cb.hwif_out.bothedge_irqs.intr == 1'b0);
|
||||
cpuif.assert_read('h30, 'h000);
|
||||
|
||||
cb.hwif_in.bothedge_irqs.irq1.next <= 1'b0;
|
||||
cpuif.assert_read('h30, 'h100);
|
||||
assert(cb.hwif_out.bothedge_irqs.intr == 1'b1);
|
||||
cpuif.write('h30, 'h100);
|
||||
cpuif.assert_read('h30, 'h000);
|
||||
assert(cb.hwif_out.bothedge_irqs.intr == 1'b0);
|
||||
cpuif.assert_read('h30, 'h000);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
cpuif.assert_read('h40, 'h000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
cb.hwif_in.level_irqs_1.irq0.next <= 'h01;
|
||||
@cb;
|
||||
cb.hwif_in.level_irqs_1.irq0.next <= 'h00;
|
||||
cpuif.assert_read('h40, 'b0001);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b1);
|
||||
cpuif.write('h0, 'h01);
|
||||
cpuif.assert_read('h40, 'b0000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
cb.hwif_in.posedge_irqs.irq0.next <= 'h01;
|
||||
@cb;
|
||||
cb.hwif_in.posedge_irqs.irq0.next <= 'h00;
|
||||
cpuif.assert_read('h40, 'b0010);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b1);
|
||||
cpuif.write('h10, 'h01);
|
||||
cpuif.assert_read('h40, 'b0000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
cb.hwif_in.negedge_irqs.irq0.next <= 'h01;
|
||||
@cb;
|
||||
cb.hwif_in.negedge_irqs.irq0.next <= 'h00;
|
||||
@cb;
|
||||
cpuif.assert_read('h40, 'b0100);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b1);
|
||||
cpuif.write('h20, 'h01);
|
||||
cpuif.assert_read('h40, 'b0000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
cb.hwif_in.bothedge_irqs.irq0.next <= 'h01;
|
||||
@cb;
|
||||
cb.hwif_in.bothedge_irqs.irq0.next <= 'h00;
|
||||
cpuif.assert_read('h40, 'b1000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b1);
|
||||
cpuif.write('h30, 'h01);
|
||||
cpuif.assert_read('h40, 'b0000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
cpuif.write('h108, 'h000); // ctrl_haltenable
|
||||
cb.hwif_in.level_irqs_2.irq0.next <= 'h01;
|
||||
@cb;
|
||||
cb.hwif_in.level_irqs_2.irq0.next <= 'h00;
|
||||
@cb;
|
||||
cpuif.assert_read('h40, 'b00000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
cpuif.write('h108, 'h001); // ctrl_haltenable
|
||||
cpuif.assert_read('h40, 'b10000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b1);
|
||||
|
||||
cpuif.write('h4, 'h01);
|
||||
cpuif.assert_read('h40, 'b00000);
|
||||
assert(cb.hwif_out.top_irq.intr == 1'b0);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Test multi-bit sticky reg
|
||||
cpuif.assert_read('h50, 'h00);
|
||||
cb.hwif_in.stickyreg.stickyfield.next <= 'h12;
|
||||
@cb;
|
||||
cb.hwif_in.stickyreg.stickyfield.next <= 'h34;
|
||||
@cb;
|
||||
cb.hwif_in.stickyreg.stickyfield.next <= 'h56;
|
||||
@cb;
|
||||
cpuif.assert_read('h50, 'h12);
|
||||
cpuif.write('h50, 'h00);
|
||||
@cb;
|
||||
cb.hwif_in.stickyreg.stickyfield.next <= 'h78;
|
||||
@cb;
|
||||
cpuif.assert_read('h50, 'h56);
|
||||
|
||||
|
||||
{% endblock %}
|
||||
5
test/test_interrupts/testcase.py
Normal file
5
test/test_interrupts/testcase.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from ..lib.regblock_testcase import RegblockTestCase
|
||||
|
||||
class Test(RegblockTestCase):
|
||||
def test_dut(self):
|
||||
self.run_test()
|
||||
Reference in New Issue
Block a user