Add counter support

This commit is contained in:
Alex Mykyta
2021-12-11 20:41:49 -08:00
parent f5b12253ad
commit 9eddc9b60f
40 changed files with 1133 additions and 349 deletions

View File

@@ -1,33 +1,4 @@
================================================================================
Overarching philosophy
================================================================================
Encourage users to be able to tweak the design
Templating:
Design templates to be small bite-size snippets, each with clear intent
Templates shall be extendable
Templates shall be easy/intuitive
Output:
Output shall be beautiful. Consistent and clean formatting/whitespace builds trust
Output has comments. Users will be looking at it.
================================================================================
On templating...
================================================================================
Everything should be written out to a single file
The only exception is if a struct port interface is used, then the appropriate
struct package is also written out (or lumped into the same file?)
Each layer should actually be its own separate template.
Use helper functions to abstract away details about identifier implementation.
Similarly, some fields will end up with additional port-level signals inferred.
For example, if the user set the field's "anded=true" property
the template would do something like:
{{output_signal(field, "anded")}} = &{{field_value(field)}};
Basically, i'd define a ton of helper functions that return the signal identifier.
================================================================================
Accesswidth vs Regwidth
================================================================================
@@ -46,7 +17,7 @@ Changes to this tool this new understanding imposes:
- derive the CPU bus width based on the largest regwidth
this seems like a reasonable & easy thing to implement
- CPUIF should make sure to always present an aligned address!
if bus width is 32-bits, decoder logic shall recieve an address with bits [1:0] ALWAYS zeroed
if bus width is 32-bits, decoder logic shall receive an address with bits [1:0] ALWAYS zeroed
Codify this in the internal specification!
- address decode may produce multiple strobes if registers are packed.
Eg: if bus width is 32, and there is a region of 8-bit registers that are tightly packed,
@@ -75,77 +46,49 @@ Write about this in the SystemRDL errata?
Maybe not so much in other protocols...
Maybe add some words to the "clarifications" section
================================================================================
Unit Testing
================================================================================
I NEED to start building a suite of unit-tests!
Goal:
- Small easy-to-understand testcases
- Parameterized testcases to rerun testcases with different cpuifs, etc.
- coverage
Split it into the following components:
Common testbench SV infrastructure
Make a generic SV framework that can be re-used everywhere
Use SV interfaces/classes and even `include preprocessor tricks to make it possible
to swap out for specific testcases:
- cpuif abstraction layer
Need to be able to swap out to different CPU interfaces easily
- Clocks/resets
- DUT instantiation
Will need to account for minor variations in port list somehow
Maybe a good time to use the .* method?
- Helper functions, assertion library, etc.
Testcase-specific
SV sequence file that issues transactions and asserts things
Dispatch tests completely through pytest
- Each testcase has its own folder with:
testcase-specific SV file(s)
RDL file
pytest entry point .py file
- build up py utility functions that will:
Export the testcase-specific RDL --> SV
Compile and run the simulation
need to deal with timeouts if the RTL deadlocks somehow. Limit of how many uS to run?
Query sim result for pass/fail
- Each testcase folder will likely have multiple subtests
- Variations to RDL export:
- different cpuif
- pipe stages
- etc.
- Different test sequences
may be necessary to test the same compilation in different ways
I can imagine it may not be possible to do everything from a single test sequence.
May require the sim to reset to T-0 for fresh-slate.
- Handle these variations using pytest testcases & parameterizations as appropriate.
Possibly something like:
- Each pytest class --> unique compilation/elaboration
pytest parameters to expand this for export variations
- Each pytest class method --> simulation sequence
- Collect coverage!
install the tool in a venv, collect exporter coverage, etc.
TBD if i want to deal with SV coverage (is that even allowed in modelsim free?)
================================================================================
Dev Todo list
================================================================================
- Signals - clean them up and add proper support
Generate these in the hwif_in struct? I forget what I decided
- FIXME: cpuif reset inside top-level addrmap results in two input signals:
- one popped out to top
- another inside the input struct
- Interrupt properties
i think my docs are missing a property or something...
- Rework TB CPUIF driver a bit
Split test API into a class
class receives a vif to the driver
make this more proper w.r.t extending stuff.
- Add more CPUIF protocols
- AXI-Lite
- cpuif interface passthrough?
- Add synthesis tests
Create a new testcase base class
Similar concept as before with testcases & parameterization.
Launch Vivado and do out-of-context synthesis
Override message severities to highlight:
- undriven nets
- multi-driven nets
- combo loops
Figure out a way to test these separately from other testcases
maybe rearrange folders so:
test/test_behav/...
test/test_synth/...
- break out 'next' and singlepulse into a separate section of their own.
these should always be lowest priority regardless of precedence
and always end up as the "else" clause in the conditional list.
- Link more functions to the dereferencer
I shouldn't have to go to the hwif or whatever
dereferencer should have all the query functions
- Start a sphinx docs thing
I need to keep better track of everything!
Diagrams of each layer in an architecture overview
transcribe logbook into dev notes
Define strict interface expectations for each layer!
Including latency/etc
endianness controls byte order of the CPU bus
controls byteswap at the CPUIF layer
Internally, use little endian ordering.
@@ -155,16 +98,3 @@ endianness controls byte order of the CPU bus
Do something about cpuif byte strobes?
Remove for now?
Demote to APB3?
- Other field output assignments
- HWIF layer
- User Signals
Generate these in the io struct? I forget what I decided
- dereferencer has some remaining todos that depend on field logic
- FIXME: cpuif reset inside top-level addrmap results in two input signals:
- one popped out to top
- another inside the input struct

View File

@@ -93,15 +93,29 @@ X Flag illegal sw actions if not readable/writable
X Signals marked as field_reset or cpuif_reset need to have activehigh/activelow
specified. (8.2.1-d states that activehigh/low does not have an implied default state if unset!)
Also aplies to signals referenced by resetsignal
Also applies to signals referenced by resetsignal
! 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 incrvalue/decrvalue needs to be the same or narrower than counter itself
! singlepulse and next properties cannot both be used.
Both are hard overrides of the field's next value.
singlepulse is basically an alias for next=0 that takes lowest priority
! counter field that saturates should not set overflow
counter; incrsaturate; overflow;
counter; decrsaturate; underflow;
Flag this as an error on the overflow/underflow property.
overflow/underflow property is meaningless since it can never happen.
Same goes to prop references to overflow/underflow
! incrwidth/decrwidth must be between 1 and the width of the counter
================================================================================
Things that need validation by this exporter

View File

@@ -23,10 +23,6 @@ bigendian/littleendian
----------------------
|NO|
bridge
------
|NO|
rsvdset
-------
|NO|

View File

@@ -19,6 +19,16 @@ singlepulse
^^^^^^^^^^^
|OK|
If set, field will get cleared back to zero after being written.
.. wavedrom::
{signal: [
{name: 'clk', wave: 'p.....'},
{name: '<swmod>', wave: '0.10..'},
{name: 'hwif_out..value', wave: '0..10.'}
]}
sw
^^^
|OK|
@@ -143,93 +153,228 @@ Counter Properties
counter
^^^^^^^
|NO|
|OK|
decr
^^^^
reference
|NO|
If true, marks this field as a counter. The counter direction is inferred based
based on which properties are assigned. By default, an up-counter is implemented.
If any of the properties associated with an up-counter are used, then up-counting
capabilities will be implemented. The same is true for down-counters and up/down
counters.
decrthreshold
^^^^^^^^^^^^^
boolean
|NO|
Unless alternate control signals are specified, the existence of input signals
``hwif_in..incr`` and ``hwif_in..decr`` will be inferred depending on the type
of counter described.
bit
|NO|
reference
|NO|
decrsaturate
^^^^^^^^^^^^
boolean
|NO|
bit
|NO|
reference
|NO|
decrvalue
^^^^^^^^^
bit
|NO|
reference
|NO|
decrwidth
^^^^^^^^^
|NO|
incr
^^^^
|NO|
|OK|
Assign a reference to an alternate control signal to increment the counter.
If assigned, the inferred ``hwif_in..incr`` input will not be generated.
incrsaturate/saturate
^^^^^^^^^^^^^^^^^^^^^
boolean
|NO|
If assigned, indicates that the counter will saturate instead of wrapping.
If an alternate saturation point is specified, the counter value will be
adjusted so that it does not exceed that limit, even after non-increment actions.
bit
|NO|
boolean
|OK|
If true, saturation point is at the counter's maximum count value. (2^width - 1)
integer
|OK|
Specify a static saturation value.
reference
|NO|
|OK|
Specify a dynamic saturation value.
incrthreshold/threshold
^^^^^^^^^^^^^^^^^^^^^^^
boolean
|NO|
bit
|NO|
If assigned, infers a ``hwif_out..incrthreshold`` output signal. This signal is
asserted if the counter value is greater or equal to the threshold.
.. wavedrom::
{
signal: [
{name: 'clk', wave: 'p......'},
{name: 'hwif_in..incr', wave: '01...0.'},
{name: '<counter>', wave: '=.=3==..', data: [4,5,6,7,8,9]},
{name: 'hwif_out..incrthreshold', wave: '0..1....'}
],
foot: {
text: "Example where incrthreshold = 6"
}
}
boolean
|EX|
If true, threshold is the counter's maximum count value. (2^width - 1)
integer
|EX|
Specify a static threshold value.
reference
|NO|
|EX|
Specify a dynamic threshold value.
incrvalue
^^^^^^^^^
bit
|NO|
Override the counter's increment step size.
integer
|OK|
reference
|NO|
|OK|
incrwidth
^^^^^^^^^
|NO|
|OK|
If assigned, infers an input signal ``hwif_in..incrvalue``. The value of this
property defines the signal's width.
overflow
^^^^^^^^
|NO|
|EX|
If true, infers an output signal ``hwif_out..overflow`` that is asserted when
the counter is about to wrap.
.. wavedrom::
{
signal: [
{name: 'clk', wave: 'p.......'},
{name: 'hwif_in..incr', wave: '0101010.'},
{name: '<counter>', wave: '=.=.=.=.', data: [14,15,0,1]},
{name: 'hwif_out..overflow', wave: '0..10...'}
],
foot: {
text: "A 4-bit counter overflowing"
}
}
decr
^^^^
|OK|
Assign a reference to an alternate control signal to decrement the counter.
If assigned, the inferred ``hwif_in..decr`` input will not be generated.
decrsaturate
^^^^^^^^^^^^
If assigned, indicates that the counter will saturate instead of wrapping.
If an alternate saturation point is specified, the counter value will be
adjusted so that it does not exceed that limit, even after non-decrement actions.
boolean
|OK|
If true, saturation point is when the counter reaches 0.
integer
|OK|
Specify a static saturation value.
reference
|OK|
Specify a dynamic saturation value.
decrthreshold
^^^^^^^^^^^^^
If assigned, infers a ``hwif_out..decrthreshold`` output signal. This signal is
asserted if the counter value is less than or equal to the threshold.
.. wavedrom::
{
signal: [
{name: 'clk', wave: 'p......'},
{name: 'hwif_in..decr', wave: '01...0.'},
{name: '<counter>', wave: '=.=3==..', data: [9,8,7,6,5,4]},
{name: 'hwif_out..decrthreshold', wave: '0..1....'}
],
foot: {
text: "Example where incrthreshold = 7"
}
}
boolean
|EX|
If true, threshold is 0.
integer
|EX|
Specify a static threshold value.
reference
|EX|
Specify a dynamic threshold value.
decrvalue
^^^^^^^^^
Override the counter's decrement step size.
integer
|OK|
reference
|OK|
decrwidth
^^^^^^^^^
|OK|
If assigned, infers an input signal ``hwif_in..decrvalue``. The value of this
property defines the signal's width.
underflow
^^^^^^^^^
|NO|
|EX|
If true, infers an output signal ``hwif_out..underflow`` that is asserted when
the counter is about to wrap.
.. wavedrom::
{
signal: [
{name: 'clk', wave: 'p.......'},
{name: 'hwif_in..decr', wave: '0101010.'},
{name: '<counter>', wave: '=.=.=.=.', data: [1,0,15,14]},
{name: 'hwif_out..underflow', wave: '0..10...'}
],
foot: {
text: "A 4-bit counter underflowing"
}
}
--------------------------------------------------------------------------------
@@ -288,7 +433,7 @@ precedence
reset
^^^^^
bit
integer
|OK|
reference

View File

@@ -13,7 +13,3 @@ Only ``accesswidth`` that is equal to the ``regwidth`` is supported (default if
regwidth
--------
|OK|
shared
------
|NO|

View File

@@ -6,7 +6,7 @@ property assignment expressions:
.. code-block:: systemrdl
some_property = my_reg.my_field->some_property;
some_property = my_reg.my_field -> some_property;
The official SystemRDL spec refers to these as "Ref targets" in Table G1, but
unfortunately does not describe their semantics in much detail.
@@ -18,63 +18,65 @@ The text below describes the interpretations used for this exporter.
Field
-----
swacc
^^^^^
field -> swacc
^^^^^^^^^^^^^^
|EX|
Single-cycle strobe that indicates the field is being sampled during a software
read operation.
swmod
^^^^^
field -> swmod
^^^^^^^^^^^^^^^
|EX|
Single-cycle strobe that indicates the field is being modified during a software
access operation.
swwe/swwel
^^^^^^^^^^
field -> swwe/swwel
^^^^^^^^^^^^^^^^^^^
|OK|
Represents the signal that controls the owning field's swwe/swwel behavior.
Represents the signal that controls the field's swwe/swwel behavior.
anded/ored/xored
^^^^^^^^^^^^^^^^
field -> anded/ored/xored
^^^^^^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the current and/or/xor reduction of the owning field's value.
Represents the current and/or/xor reduction of the field's value.
hwclr/hwset
^^^^^^^^^^^
field -> hwclr/hwset
^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the signal that controls the owning field's hwclr/hwset behavior.
Represents the signal that controls the field's hwclr/hwset behavior.
hwenable/hwmask
field -> hwenable/hwmask
^^^^^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the signal that controls the field's hwenable/hwmask behavior.
field -> we/wel
^^^^^^^^^^^^^^^
|EX|
Represents the signal that controls the owning field's hwenable/hwmask behavior.
Represents the signal that controls the field's we/wel behavior.
we/wel
^^^^^^
field -> next
^^^^^^^^^^^^^
|EX|
next
^^^^
field -> reset
^^^^^^^^^^^^^^
|EX|
reset
^^^^^
|EX|
resetsignal
^^^^^^^^^^^
field -> resetsignal
^^^^^^^^^^^^^^^^^^^^
|EX|
--------------------------------------------------------------------------------
@@ -82,67 +84,118 @@ resetsignal
Field Counter Properties
------------------------
Represents the signal that controls the owning field's we/wel behavior.
decr
^^^^
|NO|
decrthreshold
field -> incr
^^^^^^^^^^^^^
|NO|
decrsaturate
^^^^^^^^^^^^
|NO|
decrvalue
^^^^^^^^^
|EX|
incr
^^^^
|NO|
Represents the signal that controls the field's counter increment control.
incrsaturate/saturate
field -> incrsaturate/saturate
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the internal 1-bit event signal that indicates whether the counter is saturated
at its saturation value.
.. wavedrom::
{
signal: [
{name: 'clk', wave: 'p......'},
{name: 'hwif_in..decr', wave: '0101010'},
{name: '<counter>', wave: '=.=....', data: [1,0]},
{name: '<decrsaturate>', wave: '0.1....'}
],
foot: {
text: "A 4-bit counter saturating"
}
}
field -> incrthreshold/threshold
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the 1-bit event signal that indicates whether the counter has met or
exceeded its incrthreshold.
field -> incrvalue
^^^^^^^^^^^^^^^^^^
|EX|
Represents the value that was assigned to this property.
field -> overflow
^^^^^^^^^^^^^^^^^
|OK|
Represents the event signal that is asserted when the counter is about to wrap.
field -> decr
^^^^^^^^^^^^^
|EX|
Represents the signal that controls the field's counter decrement control.
field -> decrsaturate
^^^^^^^^^^^^^^^^^^^^^
|NO|
incrthreshold/threshold
^^^^^^^^^^^^^^^^^^^^^^^
|NO|
incrvalue
^^^^^^^^^
|EX|
overflow
^^^^^^^^
|NO|
Represents the internal 1-bit event signal that indicates whether the counter is saturated
at its saturation value.
underflow
^^^^^^^^^
|NO|
.. wavedrom::
{
signal: [
{name: 'clk', wave: 'p......'},
{name: 'hwif_in..incr', wave: '0101010'},
{name: '<counter>', wave: '=.=....', data: [14,15]},
{name: '<incrsaturate>', wave: '0.1....'}
],
foot: {
text: "A 4-bit counter saturating"
}
}
field -> decrthreshold
^^^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the 1-bit event signal that indicates whether the counter has met or
exceeded its incrthreshold.
field -> decrvalue
^^^^^^^^^^^^^^^^^^
|EX|
Represents the value that was assigned to this property.
field -> underflow
^^^^^^^^^^^^^^^^^^
|OK|
Represents the event signal that is asserted when the counter is about to wrap.
--------------------------------------------------------------------------------
Field Interrupt Properties
--------------------------
enable
^^^^^^
field -> enable
^^^^^^^^^^^^^^^
|EX|
haltenable
^^^^^^^^^^
field -> haltenable
^^^^^^^^^^^^^^^^^^^
|EX|
haltmask
^^^^^^^^
field -> haltmask
^^^^^^^^^^^^^^^^^
|EX|
mask
^^^^
field -> mask
^^^^^^^^^^^^^
|EX|
@@ -151,10 +204,10 @@ mask
Register
--------
intr
^^^^
reg -> intr
^^^^^^^^^^^
|NO|
halt
^^^^
reg -> halt
^^^^^^^^^^^
|NO|