Add interrupt tests!

This commit is contained in:
Alex Mykyta
2022-01-25 21:24:17 -08:00
parent ae3714f4a4
commit 603484788a
12 changed files with 471 additions and 52 deletions

View File

@@ -105,12 +105,13 @@ X sticky=true + "(posedge|negedge|bothedge) intr"
X we/wel + implied or explicit "sticky"/"stickybit" X we/wel + implied or explicit "sticky"/"stickybit"
we/wel modifier doesn't make sense here. we/wel modifier doesn't make sense here.
! hwclr/hwset/we/wel probably shouldn't be able to reference itself X sticky/stickybit shall be hw writable
y->hwclr = y;
y->we = y;
... it works, but should it be allowed? Seems like user-error
! 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; incrsaturate; overflow;
counter; decrsaturate; underflow; counter; decrsaturate; underflow;
@@ -119,11 +120,10 @@ X we/wel + implied or explicit "sticky"/"stickybit"
Same goes to prop references to overflow/underflow Same goes to prop references to overflow/underflow
! incrwidth/decrwidth must be between 1 and the width of the counter ! hwclr/hwset/we/wel probably shouldn't be able to reference itself
y->hwclr = y;
! Illegal to use enable/mask/haltenable/haltmask on non-intr fields y->we = y;
... it works, but should it be allowed? Seems like user-error
! sticky/stickybit shall be hw writable
================================================================================ ================================================================================
Things that need validation by this exporter 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 ! async data signals
Only supporting async signals if they are exclusively used in resets. 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 I have zero interest in implementing resynchronizers
! Error if a property references a non-signal component, or property reference from ! Error if a property references a non-signal component, or property reference from

View File

@@ -53,7 +53,7 @@ TODO:
Provide a mechanism for users to extend/override field behavior Provide a mechanism for users to extend/override field behavior
TODO: TODO:
Does the endinness the user sets matter anywhere? Does the endianness the user sets matter anywhere?
Implementation Implementation
Makes sense to use a listener class Makes sense to use a listener class
@@ -63,7 +63,7 @@ Be sure to skip alias registers
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
NextStateConditional Class 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: Provides information to generate the following content:
if(<conditional>) begin if(<conditional>) begin
<assignments> <assignments>
@@ -110,22 +110,22 @@ FieldBuilder Class
NextStateConditional objects are stored in a dictionary as follows: NextStateConditional objects are stored in a dictionary as follows:
_conditionals { _conditionals {
assignment_precedence: [ assignment_precedence: [
conditional_option_3,
conditional_option_2,
conditional_option_1, conditional_option_1,
conditional_option_2,
conditional_option_3,
] ]
} }
add_conditional(self, conditional, assignment_precedence): add_conditional(self, conditional, assignment_precedence):
Inserts the NextStateConditional into the given assignment precedence bin 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: init_conditionals(self) -> None:
Called from __init__. Called from __init__.
loads all possible conditionals into self.conditionals list loads all possible conditionals into self.conditionals list
This function is to provide a hook for the user to add their own. 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) self.add_conditional(MyNextState(), AssignmentPrecedence.SW_ACCESS)
If user wants to extend this class, they can pile onto the bins of conditionals freely! If user wants to extend this class, they can pile onto the bins of conditionals freely!

View File

@@ -44,6 +44,7 @@ Links
:hidden: :hidden:
:caption: CPU Interfaces :caption: CPU Interfaces
cpuif/addressing
cpuif/apb3 cpuif/apb3
cpuif/advanced cpuif/advanced

View File

@@ -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. after applying the appropriate ``enable`` or ``mask`` to the field value.
level (default) 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 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 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 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 nonsticky
|EX| |OK|
enable 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 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 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 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 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]}
]
}
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -206,8 +206,12 @@ Register
reg -> intr reg -> intr
^^^^^^^^^^^ ^^^^^^^^^^^
|EX| |OK|
References the register's ``hwif_out..intr`` signal.
reg -> halt reg -> halt
^^^^^^^^^^^ ^^^^^^^^^^^
|EX| |OK|
References the register's ``hwif_out..halt`` signal.

View File

@@ -235,7 +235,6 @@ class FieldLogic:
If multiple conditionals of the same precedence are registered, they are If multiple conditionals of the same precedence are registered, they are
searched sequentially and only the first to match the given field is used. 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: if precedence not in self._hw_conditionals:
self._hw_conditionals[precedence] = [] self._hw_conditionals[precedence] = []
@@ -253,7 +252,6 @@ class FieldLogic:
If multiple conditionals of the same precedence are registered, they are If multiple conditionals of the same precedence are registered, they are
searched sequentially and only the first to match the given field is used. 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: if precedence not in self._sw_conditionals:
self._sw_conditionals[precedence] = [] 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.ClearOnRead(self.exp), AssignmentPrecedence.SW_ONREAD)
self.add_sw_conditional(sw_onread.SetOnRead(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.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_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.PosedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
self.add_hw_conditional(hw_interrupts.NegedgeStickybit(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.BothedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE)
self.add_hw_conditional(hw_interrupts.PosedgeNonsticky(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.NegedgeNonsticky(self.exp), AssignmentPrecedence.HW_WRITE)
self.add_hw_conditional(hw_interrupts.BothedgeNonsticky(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) self.add_hw_conditional(hw_set_clr.HWClear(self.exp), AssignmentPrecedence.HWCLR)
@@ -308,6 +306,7 @@ class FieldLogic:
for conditional in conditionals[precedence]: for conditional in conditionals[precedence]:
if conditional.is_match(field): if conditional.is_match(field):
result.append(conditional) result.append(conditional)
break
return result return result

View File

@@ -18,8 +18,8 @@ python3 -m pip install test/requirements.txt
# Running tests # Running tests
Tests can be launched from the test directory using `pytest``. Tests can be launched from the test directory using `pytest`.
Use ``pytest -n auto`` to run tests in parallel. Use `pytest -n auto` to run tests in parallel.
To run all tests: To run all tests:
```bash ```bash
@@ -36,12 +36,12 @@ pytest
# Test organization # 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 testcases, with minimal repetition/boilerplate code that is usually present in
SystemVerilog testbenches. SystemVerilog testbenches.
To accomplish this, Jinja templates are used extensively to generate the 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.

View File

View 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;
};

View 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 %}

View File

@@ -0,0 +1,5 @@
from ..lib.regblock_testcase import RegblockTestCase
class Test(RegblockTestCase):
def test_dut(self):
self.run_test()