Model
Models define how values are encoded to bytes and decoded back to Python types.
In practice, a Model is selected per Variable (usually with base=... on
RemoteVariable), and Block transactions apply that Model during read/write.
Most users interact with Models indirectly through Variable base and related
type configuration. Advanced users can use Model classes directly for custom
encoding/decoding workflows.
Why Models Exist
Models separate three closely related concerns:
Hardware representation such as bit width, endianness, and signedness.
Python-facing type behavior such as
int,bool,float, orstr.Conversion logic used by
Blockstaging and transaction code.
This keeps Variable definitions clear and lets the same conversion behavior be reused across many registers.
How Variables Select A Model
Most users select a Model when defining each RemoteVariable.
import pyrogue as pr
class MyRegs(pr.Device):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add(pr.RemoteVariable(
name='Status',
offset=0x00,
bitSize=32,
mode='RO',
base=pr.UInt, # Model selection
))
In the current implementation, RemoteVariable usually receives a Model
class such as pr.UInt or pr.Float rather than a pre-built instance.
The Variable constructor then instantiates the Model using the Variable’s
effective bit width.
That is why base=pr.UInt is the normal form. For custom or parameterized
Models such as fixed-point encodings, the base you pass must still line up
with the Variable’s bit layout.
What A Model Defines
A Model is more than a byte-conversion helper. It also defines metadata that shapes how the Variable behaves in Python and in the generated tree metadata.
Common Model responsibilities include:
pytypefor the native Python-facing type.defaultdispfor the default display format when the Variable does not overridedisp.minValue()andmaxValue()for default limit behavior.toBytes()andfromBytes()for raw conversion.fromString()for display-string parsing.modelIdfor the lower-level Rogue memory-processing path.
This is why Models belong conceptually between Variable and Blocks: Variables present the value-oriented API, Models define the encoding, and Blocks move the bytes.
Built-In Model Families
Common built-in Models include:
Integer:
UInt,UIntBE,UIntReversed,Int,IntBEBoolean:
BoolText:
StringFloating point:
Float,FloatBE,Double,DoubleBEFixed point:
Fixed,UFixedCustom Python conversion path: Models that use
modelId = rim.PyFunc
Built-In Model Types
Model |
Hardware Type |
Python Type |
Bit Size |
Notes |
|---|---|---|---|---|
unsigned integer |
int |
unconstrained |
Little endian |
|
unsigned integer |
int |
unconstrained |
Big endian |
|
unsigned integer |
int |
unconstrained |
Reversed bit order |
|
signed integer |
int |
unconstrained |
Little endian |
|
signed integer |
int |
unconstrained |
Big endian |
|
bit |
bool |
1-bit |
||
bytes |
string |
unconstrained |
||
32-bit float |
float |
32-bits |
||
32-bit float |
float |
32-bits |
Big endian |
|
64-bit float |
float |
64-bits |
||
64-bit float |
float |
64-bits |
Big endian |
|
fixed point |
float |
unconstrained |
Fixed-point conversion |
|
fixed point |
float |
unconstrained |
Unsigned fixed-point conversion |
For low-level Model class reference and constants, see Model.
Fixed-Point Models
Fixed and UFixed are important enough, and nuanced enough in
practice, that they now have their own focused page:
That page explains the fixed-point mental model, bitSize and binPoint,
the conversion formulas, numeric range, and a worked example.
Model Utility Helpers
The Python Model module also includes a few small helpers that are useful when you need to reason about raw layouts or write a custom Model:
wordCount()computes how many words are needed for a bit width.byteCount()computes how many bytes are needed for a bit width.reverseBits()reverses bit significance across a fixed width.twosComplement()interprets a value with two’s-complement sign semantics.
These are especially useful in custom conversion code and in documentation examples where raw register layout matters.
Model Instances And Caching
One implementation detail is worth knowing when you use Model classes directly:
the Model metaclass caches instances by constructor arguments.
In practice, repeated requests for the same Model and parameters, such as
pr.UInt(16), return the same shared Model instance. Most users do not need
to think about this because Variables create Models for them, but it explains
why Models are treated more like reusable type descriptors than like
per-Variable mutable state.
Model Conversion Flow In Block Access
When a Variable is read or written:
Variable logic resolves its Model and layout metadata.
Block conversion methods pack or unpack values for that Model.
Block transaction methods move bytes to or from hardware.
Model selection answers “how bytes map to values”; Block transactions answer “when bytes move.”
For transaction flow details, see Blocks.
Custom Model Example
Use a custom Model when built-ins do not match an encoding format.
import pyrogue as pr
import rogue.interfaces.memory as rim
class BitReversedUInt(pr.Model):
pytype = int
defaultdisp = '{:#x}'
modelId = rim.PyFunc
def __init__(self, bitsize):
super().__init__(bitsize)
def toBytes(self, value):
# Reverse bit order so MSB appears at bit position 0 in memory.
raw_normal = int(value)
raw_reversed = pr.reverseBits(raw_normal, self.bitSize)
return raw_reversed.to_bytes(pr.byteCount(self.bitSize), 'little', signed=False)
def fromBytes(self, ba):
raw_reversed = int.from_bytes(ba, 'little', signed=False)
return pr.reverseBits(raw_reversed, self.bitSize)
def fromString(self, string):
return int(string, 0)
def minValue(self):
return 0
def maxValue(self):
return (2 ** self.bitSize) - 1
class MyDevice(pr.Device):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add(pr.RemoteVariable(
name='AsicStatus',
offset=0x1000,
bitSize=16,
bitOffset=0,
mode='RW',
base=BitReversedUInt,
))
This is the same overall pattern used by built-in Models: define the Python type behavior and the byte conversion behavior in one reusable object, then attach that Model to one or more Variables.
How BitReversedUInt Differs From Built-In UInt
This example shows a register layout where hardware bit order differs from normal integer interpretation:
Built-in
UIntassumes standard bit significance ordering.BitReversedUIntreverses bits on write and read so software uses normal integer semantics while memory uses reversed bit positions.This is useful for custom register layouts where the hardware view is not a normal integer bit ordering.
What To Explore Next
Variable type and access behavior: Variable
Block packing and transaction flow: Blocks
Fixed-point usage details: Fixed-Point Models
API Reference
Python Model base/reference: Model
C++ memory Model reference: Model
Model helpers: wordCount, byteCount, reverseBits, twosComplement