Initial Commit - Forked from PeakRDL-regblock @ a440cc19769069be831d267505da4f3789a26695
This commit is contained in:
163
docs/dev_notes/template-layers/4-fields
Normal file
163
docs/dev_notes/template-layers/4-fields
Normal file
@@ -0,0 +1,163 @@
|
||||
--------------------------------------------------------------------------------
|
||||
Field storage / next value layer
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Where all the magic happens!!
|
||||
|
||||
Any field that implements storage is defined here.
|
||||
Bigass struct that only contains storage elements
|
||||
|
||||
Each field consists of:
|
||||
- Entries in the storage element struct
|
||||
- if implements storage - field value
|
||||
- user extensible values?
|
||||
- Entries in the combo struct
|
||||
- if implements storage:
|
||||
- Field's "next" value
|
||||
- load-enable strobe
|
||||
- If counter
|
||||
various event strobes (overflow/overflow).
|
||||
These are convenient to generate alongside the field next state logic
|
||||
- user extensible values?
|
||||
- an always_comb block:
|
||||
- generates the "next value" combinational signal
|
||||
- May generate other intermediate strobes?
|
||||
incr/decr?
|
||||
- series of if/else statements that assign the next value in the storage element
|
||||
Think of this as a flat list of "next state" conditons, ranked by their precedence as follows:
|
||||
- reset
|
||||
Actually, handle this in the always_ff
|
||||
- sw access (if sw precedence)
|
||||
- onread/onwrite
|
||||
- hw access
|
||||
- Counter
|
||||
beware of clear events and incr/decr events happening simultaneously
|
||||
- next
|
||||
- etc
|
||||
- sw access (if hw precedence)
|
||||
- onread/onwrite
|
||||
- always_comb block to also generate write-enable strobes for the actual
|
||||
storage element
|
||||
This is better for low-power design
|
||||
- an always_ff block
|
||||
Implements the actual storage element
|
||||
Also a tidy place to abstract the specifics of activehigh/activelow field reset
|
||||
selection.
|
||||
|
||||
TODO:
|
||||
Scour the RDL spec.
|
||||
Does this "next state" precedence model hold true in all situations?
|
||||
|
||||
TODO:
|
||||
Think about user-extensibility
|
||||
Provide a mechanism for users to extend/override field behavior
|
||||
|
||||
TODO:
|
||||
Does the endianness the user sets matter anywhere?
|
||||
|
||||
Implementation
|
||||
Makes sense to use a listener class
|
||||
|
||||
Be sure to skip alias registers
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
NextStateConditional Class
|
||||
Describes a single conditional action that determines the next state of a field
|
||||
Provides information to generate the following content:
|
||||
if(<conditional>) begin
|
||||
<assignments>
|
||||
end
|
||||
|
||||
- is_match(self, field: FieldNode) -> bool:
|
||||
Returns True if this conditional is relevant to the field. If so,
|
||||
it instructs the FieldBuider that code for this conditional shall be emitted
|
||||
TODO: better name than "is_match"? More like "is this relevant"
|
||||
|
||||
- get_predicate(self, field: FieldNode) -> str:
|
||||
Returns the rendered conditional text
|
||||
|
||||
- get_assignments(self, field: FieldNode) -> List[str]:
|
||||
Returns a list of rendered assignment strings
|
||||
This will basically always be two:
|
||||
<field>.next = <next value>
|
||||
<field>.load_next = '1;
|
||||
|
||||
- get_extra_combo_signals(self, field: FieldNode) -> List[TBD]:
|
||||
Some conditionals will need to set some extra signals (eg. counter underflow/overflow strobes)
|
||||
Compiler needs to know to:
|
||||
- declare these inthe combo struct
|
||||
- initialize them in the beginning of always_comb
|
||||
|
||||
Return something that denotes the following information: (namedtuple?)
|
||||
- signal name: str
|
||||
- width: int
|
||||
- default value assignment: str
|
||||
|
||||
Multiple NextStateConditional can declare the same extra combo signal
|
||||
as long as their definitions agree
|
||||
--> Assert this
|
||||
|
||||
|
||||
FieldBuilder Class
|
||||
Describes how to build fields
|
||||
|
||||
Contains NextStateConditional definitions
|
||||
Nested inside the class namespace, define all the NextStateConditional classes
|
||||
that apply
|
||||
User can override definitions or add own to extend behavior
|
||||
|
||||
NextStateConditional objects are stored in a dictionary as follows:
|
||||
_conditionals {
|
||||
assignment_precedence: [
|
||||
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 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 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!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Misc
|
||||
--------------------------------------------------------------------------------
|
||||
What about complex behaviors like a read-clear counter?
|
||||
if({{software read}})
|
||||
next = 0
|
||||
elif({{increment}})
|
||||
next = prev + 1
|
||||
|
||||
--> Implement this by stacking multiple NextStateConditional in the same assignment precedence.
|
||||
In this case, there would be a special action on software read that would be specific to read-clear counters
|
||||
this would get inserted ahead of the search order.
|
||||
|
||||
|
||||
Precedence & Search order
|
||||
There are two layers of priority I need to keep track of:
|
||||
- Assignment Precedence
|
||||
RTL precedence of the assignment conditional
|
||||
- Search order (sp?)
|
||||
Within an assignment precedence, order in which the NextStateConditional classes are
|
||||
searched for a match
|
||||
|
||||
For assignment precedence, it makes sense to use an integer enumeration for this
|
||||
since there really aren't too many precedence levels that apply here.
|
||||
Space out the integer enumerations so that user can reliably insert their own actions, ie:
|
||||
my_precedence = AssignmentPrecedence.SW_ACCESS + 1
|
||||
|
||||
For search order, provide a user API to load a NextStateConditional into
|
||||
a precedence 'bin'. Pushing into a bin always inserts into the front of the search order
|
||||
This makes sense since user overrides will always want to be highest priority - and
|
||||
rule themselves out before falling back to builtin behavior
|
||||
Reference in New Issue
Block a user