Producer/Consumer Model: Defining Registers
Each module defines its own register-file, which is a set of memory-space addressable registers, starting at a unique base-address.
Each register within a register-file is addressed using an offset above base-address. The memory space dedicated to a register-file is defined by the width of the offset. A register is defined using the Register_Base template class. The template variable is the address offset width, which can vary from module to module, based on register file memory allocation. |
|
Each register can have one or more fields, defined using the Field_Base template class. The template variable is the field width.
Each register and each of its fields is described via a set of constants, that are then used in defining a corresponding register or field class. The constant variable names follow the following syntax:
u unit name, that contains the register
r register name
f field name
p property. For a register: name, (address) offset and desc(ription). For a field: name, desc(ription), width, lsbit, reset (value) and access (type).
e.g. u_producer_r_control_f_en_p_width
refers to the width property of the en field in the control register of the producer unit.
Register and field classes follow a well defined pattern, making it easy to auto-generate them from a specification document.
Register
Each register is described with the following set of constants:
- Name
- Address offset (above the module's register-file base address)
- Description
During register construction, the sum of its fields' width is tested to be equal to register's width.
Field
Each field is described with the following set of constants:
- Name
- Description
- Width in bits
- LSbit position within its register
- Reset value
- Access type (R, W, RW)
Field access type
Access type is enforced when an entire register is accessed, via the data() function, either for reading or writing, to guard against illegal operations. A module must use this function when responding to a read or write access to its register.
Access type is NOT enforced when an individual field is accessed, via the val() function, to allow a module to manipulate its fields as it sees fit.
Using val() to assign a new value to a field, tests and warns when the assigned value can't fit in field's width.
Undefined bits
Undefined bits are also grouped into fields, so that their width and LSbit values can be used in calculating the next field's LSbit value, eliminating a hard coded constant and a potential bug.
Each register and each of its fields is described via a set of constants, that are then used in defining a corresponding register or field class. The constant variable names follow the following syntax:
u unit name, that contains the register
r register name
f field name
p property. For a register: name, (address) offset and desc(ription). For a field: name, desc(ription), width, lsbit, reset (value) and access (type).
e.g. u_producer_r_control_f_en_p_width
refers to the width property of the en field in the control register of the producer unit.
Register and field classes follow a well defined pattern, making it easy to auto-generate them from a specification document.
Register
Each register is described with the following set of constants:
- Name
- Address offset (above the module's register-file base address)
- Description
During register construction, the sum of its fields' width is tested to be equal to register's width.
Field
Each field is described with the following set of constants:
- Name
- Description
- Width in bits
- LSbit position within its register
- Reset value
- Access type (R, W, RW)
Field access type
Access type is enforced when an entire register is accessed, via the data() function, either for reading or writing, to guard against illegal operations. A module must use this function when responding to a read or write access to its register.
Access type is NOT enforced when an individual field is accessed, via the val() function, to allow a module to manipulate its fields as it sees fit.
Using val() to assign a new value to a field, tests and warns when the assigned value can't fit in field's width.
Undefined bits
Undefined bits are also grouped into fields, so that their width and LSbit values can be used in calculating the next field's LSbit value, eliminating a hard coded constant and a potential bug.