Add interrupt tests!
This commit is contained in:
@@ -105,12 +105,13 @@ X sticky=true + "(posedge|negedge|bothedge) intr"
|
||||
X we/wel + implied or explicit "sticky"/"stickybit"
|
||||
we/wel modifier doesn't make sense here.
|
||||
|
||||
! hwclr/hwset/we/wel probably shouldn't be able to reference itself
|
||||
y->hwclr = y;
|
||||
y->we = y;
|
||||
... it works, but should it be allowed? Seems like user-error
|
||||
X sticky/stickybit shall be hw writable
|
||||
|
||||
! counter field that saturates should not set overflow
|
||||
X Illegal to use enable/mask/haltenable/haltmask on non-intr fields
|
||||
|
||||
X incrwidth/decrwidth must be between 1 and the width of the counter
|
||||
|
||||
X counter field that saturates should not set overflow
|
||||
counter; incrsaturate; overflow;
|
||||
counter; decrsaturate; underflow;
|
||||
|
||||
@@ -119,11 +120,10 @@ X we/wel + implied or explicit "sticky"/"stickybit"
|
||||
|
||||
Same goes to prop references to overflow/underflow
|
||||
|
||||
! incrwidth/decrwidth must be between 1 and the width of the counter
|
||||
|
||||
! Illegal to use enable/mask/haltenable/haltmask on non-intr fields
|
||||
|
||||
! sticky/stickybit shall be hw writable
|
||||
! hwclr/hwset/we/wel probably shouldn't be able to reference itself
|
||||
y->hwclr = y;
|
||||
y->we = y;
|
||||
... it works, but should it be allowed? Seems like user-error
|
||||
|
||||
================================================================================
|
||||
Things that need validation by this exporter
|
||||
@@ -148,7 +148,7 @@ X Warn/error on any signal with cpuif_reset set, that is not in the top-level
|
||||
|
||||
! async data signals
|
||||
Only supporting async signals if they are exclusively used in resets.
|
||||
Anyhting else declared as "async" shall emit a warning that it is ignored
|
||||
Anything else declared as "async" shall emit a warning that it is ignored
|
||||
I have zero interest in implementing resynchronizers
|
||||
|
||||
! Error if a property references a non-signal component, or property reference from
|
||||
|
||||
@@ -53,7 +53,7 @@ TODO:
|
||||
Provide a mechanism for users to extend/override field behavior
|
||||
|
||||
TODO:
|
||||
Does the endinness the user sets matter anywhere?
|
||||
Does the endianness the user sets matter anywhere?
|
||||
|
||||
Implementation
|
||||
Makes sense to use a listener class
|
||||
@@ -63,7 +63,7 @@ Be sure to skip alias registers
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
NextStateConditional Class
|
||||
Decribes a single conditional action that determines the next state of a field
|
||||
Describes a single conditional action that determines the next state of a field
|
||||
Provides information to generate the following content:
|
||||
if(<conditional>) begin
|
||||
<assignments>
|
||||
@@ -110,22 +110,22 @@ FieldBuilder Class
|
||||
NextStateConditional objects are stored in a dictionary as follows:
|
||||
_conditionals {
|
||||
assignment_precedence: [
|
||||
conditional_option_3,
|
||||
conditional_option_2,
|
||||
conditional_option_1,
|
||||
conditional_option_2,
|
||||
conditional_option_3,
|
||||
]
|
||||
}
|
||||
|
||||
add_conditional(self, conditional, assignment_precedence):
|
||||
Inserts the NextStateConditional into the given assignment precedence bin
|
||||
The last one added to a precedence bin is first in that bin's search order
|
||||
The first one added to a precedence bin is first in that bin's search order
|
||||
|
||||
init_conditionals(self) -> None:
|
||||
Called from __init__.
|
||||
loads all possible conditionals into self.conditionals list
|
||||
This function is to provide a hook for the user to add their own.
|
||||
|
||||
Do not do fancy class intospection. Load them explicitly by name like so:
|
||||
Do not do fancy class introspection. Load them explicitly by name like so:
|
||||
self.add_conditional(MyNextState(), AssignmentPrecedence.SW_ACCESS)
|
||||
|
||||
If user wants to extend this class, they can pile onto the bins of conditionals freely!
|
||||
|
||||
@@ -44,6 +44,7 @@ Links
|
||||
:hidden:
|
||||
:caption: CPU Interfaces
|
||||
|
||||
cpuif/addressing
|
||||
cpuif/apb3
|
||||
cpuif/advanced
|
||||
|
||||
|
||||
@@ -402,46 +402,113 @@ that an interrupt is active. This is an or-reduction of all interrupt fields
|
||||
after applying the appropriate ``enable`` or ``mask`` to the field value.
|
||||
|
||||
level (default)
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
Interrupt is level-sensitive.
|
||||
Interrupt is level-sensitive. If a bit on the field's ``hwif_in..next`` input
|
||||
is '1', it will trigger an interrupt event.
|
||||
|
||||
posedge
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
If a bit on the field's ``hwif_in..next`` input transitions from '0' to '1',
|
||||
it will trigger an interrupt event. This transition shall still be synchronous
|
||||
to the register block's clock.
|
||||
|
||||
negedge
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
If a bit on the field's ``hwif_in..next`` input transitions from '1' to '0',
|
||||
it will trigger an interrupt event. This transition shall still be synchronous
|
||||
to the register block's clock.
|
||||
|
||||
bothedge
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
If a bit on the field's ``hwif_in..next`` input transitions from '0' to '1' or '1' to '0',
|
||||
it will trigger an interrupt event. This transition shall still be synchronous
|
||||
to the register block's clock.
|
||||
|
||||
nonsticky
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
|
||||
enable
|
||||
^^^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
Reference to a field or signal that, if set to 1, define which bits in the field
|
||||
are used to assert an interrupt.
|
||||
|
||||
|
||||
mask
|
||||
^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
Reference to a field or signal that, if set to 1, define which bits in the field
|
||||
are *not* used to assert an interrupt.
|
||||
|
||||
|
||||
haltenable
|
||||
^^^^^^^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
Reference to a field or signal that, if set to 1, define which bits in the field
|
||||
are used to assert the halt output.
|
||||
|
||||
If this property is set, the enclosing register will infer a ``hwif_out..halt`` output.
|
||||
|
||||
|
||||
haltmask
|
||||
^^^^^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
Reference to a field or signal that, if set to 1, define which bits in the field
|
||||
are *not* used to assert the halt output.
|
||||
|
||||
If this property is set, the enclosing register will infer a ``hwif_out..halt`` output.
|
||||
|
||||
sticky
|
||||
^^^^^^
|
||||
|EX|
|
||||
|
||||
stickybit
|
||||
^^^^^^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
When an interrupt trigger occurs, a stickybit field will set the corresponding
|
||||
bit to '1' and hold it until it is cleared by a software access.
|
||||
|
||||
The interrupt trigger depends on the interrupt type. By default, interrupts are
|
||||
level-sensitive, but the interrupt modifiers allow for edge-sensitive triggers as
|
||||
well.
|
||||
|
||||
The waveform below demonstrates a level-sensitive interrupt:
|
||||
|
||||
.. wavedrom::
|
||||
|
||||
{
|
||||
signal: [
|
||||
{name: 'clk', wave: 'p.....'},
|
||||
{name: 'hwif_in..next', wave: '010...'},
|
||||
{name: '<field value>', wave: '0.1...'}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
sticky
|
||||
^^^^^^
|
||||
|OK|
|
||||
|
||||
Unlike ``stickybit`` fields, a sticky field will latch an entire value. The
|
||||
value is latched as soon as ``hwif_in..next`` is nonzero, and is held until the
|
||||
field contents are cleared back to 0 by a software access.
|
||||
|
||||
.. wavedrom::
|
||||
|
||||
{
|
||||
signal: [
|
||||
{name: 'clk', wave: 'p.....'},
|
||||
{name: 'hwif_in..next', wave: '23.22.', data: [0,10,20,30]},
|
||||
{name: '<field value>', wave: '2.3...', data: [0, 10]}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -206,8 +206,12 @@ Register
|
||||
|
||||
reg -> intr
|
||||
^^^^^^^^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
References the register's ``hwif_out..intr`` signal.
|
||||
|
||||
reg -> halt
|
||||
^^^^^^^^^^^
|
||||
|EX|
|
||||
|OK|
|
||||
|
||||
References the register's ``hwif_out..halt`` signal.
|
||||
|
||||
@@ -235,7 +235,6 @@ class FieldLogic:
|
||||
|
||||
If multiple conditionals of the same precedence are registered, they are
|
||||
searched sequentially and only the first to match the given field is used.
|
||||
Conditionals are searched in reverse order that they were registered.
|
||||
"""
|
||||
if precedence not in self._hw_conditionals:
|
||||
self._hw_conditionals[precedence] = []
|
||||
@@ -253,7 +252,6 @@ class FieldLogic:
|
||||
|
||||
If multiple conditionals of the same precedence are registered, they are
|
||||
searched sequentially and only the first to match the given field is used.
|
||||
Conditionals are searched in reverse order that they were registered.
|
||||
"""
|
||||
if precedence not in self._sw_conditionals:
|
||||
self._sw_conditionals[precedence] = []
|
||||
@@ -272,29 +270,29 @@ class FieldLogic:
|
||||
self.add_sw_conditional(sw_onread.ClearOnRead(self.exp), AssignmentPrecedence.SW_ONREAD)
|
||||
self.add_sw_conditional(sw_onread.SetOnRead(self.exp), AssignmentPrecedence.SW_ONREAD)
|
||||
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneToggle(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroToggle(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.Write(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroToggle(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteZeroSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneToggle(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneClear(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
self.add_sw_conditional(sw_onwrite.WriteOneSet(self.exp), AssignmentPrecedence.SW_ONWRITE)
|
||||
|
||||
self.add_sw_conditional(sw_singlepulse.Singlepulse(self.exp), AssignmentPrecedence.SW_SINGLEPULSE)
|
||||
|
||||
self.add_hw_conditional(hw_write.AlwaysWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.WELWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.WEWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.Sticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.Stickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.PosedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.NegedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.BothedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.PosedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.NegedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.BothedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.Sticky(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_interrupts.Stickybit(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.WEWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.WELWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
self.add_hw_conditional(hw_write.AlwaysWrite(self.exp), AssignmentPrecedence.HW_WRITE)
|
||||
|
||||
self.add_hw_conditional(hw_set_clr.HWClear(self.exp), AssignmentPrecedence.HWCLR)
|
||||
|
||||
@@ -308,6 +306,7 @@ class FieldLogic:
|
||||
for conditional in conditionals[precedence]:
|
||||
if conditional.is_match(field):
|
||||
result.append(conditional)
|
||||
break
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@@ -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