Implement read buffering. (#22)

This commit is contained in:
Alex Mykyta
2022-11-06 23:28:07 -08:00
parent 279a3c5788
commit 9e76a712a7
19 changed files with 813 additions and 77 deletions

View File

@@ -0,0 +1,58 @@
from typing import TYPE_CHECKING
from systemrdl.node import AddrmapNode, RegNode, FieldNode, SignalNode
from .storage_generator import RBufStorageStructGenerator
from .implementation_generator import RBufLogicGenerator
from ..utils import get_indexed_path
if TYPE_CHECKING:
from ..exporter import RegblockExporter
class ReadBuffering:
def __init__(self, exp:'RegblockExporter'):
self.exp = exp
@property
def top_node(self) -> 'AddrmapNode':
return self.exp.top_node
def get_storage_struct(self) -> str:
struct_gen = RBufStorageStructGenerator()
s = struct_gen.get_struct(self.top_node, "rbuf_storage_t")
assert s is not None
return s + "\nrbuf_storage_t rbuf_storage;"
def get_implementation(self) -> str:
gen = RBufLogicGenerator(self)
s = gen.get_content(self.top_node)
assert s is not None
return s
def get_trigger(self, node: RegNode) -> str:
trigger = node.get_property('rbuffer_trigger')
if isinstance(trigger, RegNode):
# Trigger is a register.
# trigger when lowermost address of the register is written
regwidth = node.get_property('regwidth')
accesswidth = node.get_property('accesswidth')
strb_prefix = self.exp.dereferencer.get_access_strobe(trigger, reduce_substrobes=False)
if accesswidth < regwidth:
return f"{strb_prefix}[0] && !decoded_req_is_wr"
else:
return f"{strb_prefix} && !decoded_req_is_wr"
elif isinstance(trigger, SignalNode):
s = self.exp.dereferencer.get_value(trigger)
if trigger.get_property('activehigh'):
return s
else:
return f"~{s}"
else:
# Trigger is a field or propref bit
return self.exp.dereferencer.get_value(trigger)
def get_rbuf_data(self, node: RegNode) -> str:
return "rbuf_storage." + get_indexed_path(self.top_node, node) + ".data"

View File

@@ -0,0 +1,59 @@
from typing import TYPE_CHECKING
from systemrdl.component import Reg
from systemrdl.node import RegNode
from ..forloop_generator import RDLForLoopGenerator
if TYPE_CHECKING:
from . import ReadBuffering
class RBufLogicGenerator(RDLForLoopGenerator):
i_type = "genvar"
def __init__(self, rbuf: 'ReadBuffering') -> None:
super().__init__()
self.rbuf = rbuf
self.exp = rbuf.exp
self.template = self.exp.jj_env.get_template(
"read_buffering/template.sv"
)
def enter_Reg(self, node: RegNode) -> None:
super().enter_Reg(node)
assert isinstance(node.inst, Reg)
if not node.get_property('buffer_reads'):
return
context = {
'node': node,
'rbuf': self.rbuf,
'get_assignments': self.get_assignments,
}
self.add_content(self.template.render(context))
def get_assignments(self, node: RegNode) -> str:
data = self.rbuf.get_rbuf_data(node)
bidx = 0
s = []
for field in node.fields():
if bidx < field.low:
# zero padding before field
s.append(f"{data}[{field.low-1}:{bidx}] = '0;")
value = self.exp.dereferencer.get_value(field)
if field.msb < field.lsb:
# Field gets bitswapped since it is in [low:high] orientation
value = f"{{<<{{{value}}}}}"
s.append(f"{data}[{field.high}:{field.low}] = {value};")
bidx = field.high + 1
regwidth = node.get_property('regwidth')
if bidx < regwidth:
# zero padding after last field
s.append(f"{data}[{regwidth-1}:{bidx}] = '0;")
return "\n".join(s)

View File

@@ -0,0 +1,18 @@
from systemrdl.node import FieldNode, RegNode
from ..struct_generator import RDLStructGenerator
class RBufStorageStructGenerator(RDLStructGenerator):
def enter_Field(self, node: FieldNode) -> None:
# suppress parent class's field behavior
pass
def enter_Reg(self, node: RegNode) -> None:
super().enter_Reg(node)
if not node.get_property('buffer_reads'):
return
regwidth = node.get_property('regwidth')
self.add_member("data", regwidth)

View File

@@ -0,0 +1,5 @@
always_ff @(posedge clk) begin
if({{rbuf.get_trigger(node)}}) begin
{{get_assignments(node)|indent(8)}}
end
end