@@ -20,8 +20,19 @@ if TYPE_CHECKING:
|
||||
from ..exporter import RegblockExporter
|
||||
|
||||
class FieldLogic:
|
||||
def __init__(self, exp:'RegblockExporter'):
|
||||
def __init__(
|
||||
self,
|
||||
exp:'RegblockExporter',
|
||||
retime_external_reg: bool,
|
||||
retime_external_regfile: bool,
|
||||
retime_external_mem: bool,
|
||||
retime_external_addrmap: bool,
|
||||
):
|
||||
self.exp = exp
|
||||
self.retime_external_reg = retime_external_reg
|
||||
self.retime_external_regfile = retime_external_regfile
|
||||
self.retime_external_mem = retime_external_mem
|
||||
self.retime_external_addrmap = retime_external_addrmap
|
||||
|
||||
self._hw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
|
||||
self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]]
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from systemrdl.walker import WalkerAction
|
||||
from systemrdl.node import RegNode, RegfileNode, MemNode, AddrmapNode
|
||||
|
||||
from ..struct_generator import RDLStructGenerator
|
||||
from ..forloop_generator import RDLForLoopGenerator
|
||||
from ..utils import get_always_ff_event
|
||||
from ..utils import get_always_ff_event, get_indexed_path
|
||||
from ..identifier_filter import kw_filter as kwf
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import FieldLogic
|
||||
from systemrdl.node import FieldNode, RegNode
|
||||
from systemrdl.node import FieldNode, AddressableNode
|
||||
from .bases import SVLogic
|
||||
|
||||
class CombinationalStructGenerator(RDLStructGenerator):
|
||||
@@ -18,6 +21,12 @@ class CombinationalStructGenerator(RDLStructGenerator):
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
|
||||
def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]:
|
||||
super().enter_AddressableComponent(node)
|
||||
|
||||
if node.external:
|
||||
return WalkerAction.SkipDescendants
|
||||
return WalkerAction.Continue
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
# If a field doesn't implement storage, it is not relevant here
|
||||
@@ -67,6 +76,13 @@ class FieldStorageStructGenerator(RDLStructGenerator):
|
||||
super().__init__()
|
||||
self.field_logic = field_logic
|
||||
|
||||
def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]:
|
||||
super().enter_AddressableComponent(node)
|
||||
|
||||
if node.external:
|
||||
return WalkerAction.SkipDescendants
|
||||
return WalkerAction.Continue
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
self.push_struct(kwf(node.inst_name))
|
||||
|
||||
@@ -88,14 +104,39 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
self.field_storage_template = self.exp.jj_env.get_template(
|
||||
"field_logic/templates/field_storage.sv"
|
||||
)
|
||||
self.external_reg_template = self.exp.jj_env.get_template(
|
||||
"field_logic/templates/external_reg.sv"
|
||||
)
|
||||
self.external_block_template = self.exp.jj_env.get_template(
|
||||
"field_logic/templates/external_block.sv"
|
||||
)
|
||||
self.intr_fields = [] # type: List[FieldNode]
|
||||
self.halt_fields = [] # type: List[FieldNode]
|
||||
|
||||
|
||||
def enter_Reg(self, node: 'RegNode') -> None:
|
||||
def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]:
|
||||
super().enter_AddressableComponent(node)
|
||||
|
||||
if node.external and not isinstance(node, RegNode):
|
||||
# Is an external block
|
||||
self.assign_external_block_outputs(node)
|
||||
|
||||
# Do not recurse
|
||||
return WalkerAction.SkipDescendants
|
||||
|
||||
return WalkerAction.Continue
|
||||
|
||||
def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
|
||||
self.intr_fields = []
|
||||
self.halt_fields = []
|
||||
|
||||
if node.external:
|
||||
self.assign_external_reg_outputs(node)
|
||||
# Do not recurse to fields
|
||||
return WalkerAction.SkipDescendants
|
||||
|
||||
return WalkerAction.Continue
|
||||
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
if node.implements_storage:
|
||||
@@ -277,3 +318,49 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
|
||||
def assign_external_reg_outputs(self, node: 'RegNode') -> None:
|
||||
prefix = "hwif_out." + get_indexed_path(self.exp.top_node, node)
|
||||
strb = self.exp.dereferencer.get_access_strobe(node)
|
||||
|
||||
width = min(self.exp.cpuif.data_width, node.get_property('regwidth'))
|
||||
if width != self.exp.cpuif.data_width:
|
||||
bslice = f"[{width - 1}:0]"
|
||||
else:
|
||||
bslice = ""
|
||||
|
||||
context = {
|
||||
"prefix": prefix,
|
||||
"strb": strb,
|
||||
"bslice": bslice,
|
||||
"retime": self.field_logic.retime_external_reg,
|
||||
"get_always_ff_event": lambda resetsignal : get_always_ff_event(self.exp.dereferencer, resetsignal),
|
||||
"get_resetsignal": self.exp.dereferencer.get_resetsignal,
|
||||
"resetsignal": self.exp.top_node.cpuif_reset,
|
||||
}
|
||||
self.add_content(self.external_reg_template.render(context))
|
||||
|
||||
def assign_external_block_outputs(self, node: 'AddressableNode') -> None:
|
||||
prefix = "hwif_out." + get_indexed_path(self.exp.top_node, node)
|
||||
strb = self.exp.dereferencer.get_external_block_access_strobe(node)
|
||||
addr_width = node.size.bit_length()
|
||||
|
||||
retime = False
|
||||
if isinstance(node, RegfileNode):
|
||||
retime = self.field_logic.retime_external_regfile
|
||||
elif isinstance(node, MemNode):
|
||||
retime = self.field_logic.retime_external_mem
|
||||
elif isinstance(node, AddrmapNode):
|
||||
retime = self.field_logic.retime_external_addrmap
|
||||
|
||||
context = {
|
||||
"prefix": prefix,
|
||||
"strb": strb,
|
||||
"addr_width": addr_width,
|
||||
"retime": retime,
|
||||
"get_always_ff_event": lambda resetsignal : get_always_ff_event(self.exp.dereferencer, resetsignal),
|
||||
"get_resetsignal": self.exp.dereferencer.get_resetsignal,
|
||||
"resetsignal": self.exp.top_node.cpuif_reset,
|
||||
}
|
||||
self.add_content(self.external_block_template.render(context))
|
||||
|
||||
31
src/peakrdl_regblock/field_logic/templates/external_block.sv
Normal file
31
src/peakrdl_regblock/field_logic/templates/external_block.sv
Normal file
@@ -0,0 +1,31 @@
|
||||
{% if retime -%}
|
||||
|
||||
|
||||
always_ff {{get_always_ff_event(resetsignal)}} begin
|
||||
if({{get_resetsignal(resetsignal)}}) begin
|
||||
{{prefix}}.req <= '0;
|
||||
{{prefix}}.addr <= '0;
|
||||
{{prefix}}.req_is_wr <= '0;
|
||||
{{prefix}}.wr_data <= '0;
|
||||
{{prefix}}.wr_biten <= '0;
|
||||
end else begin
|
||||
{{prefix}}.req <= {{strb}};
|
||||
{{prefix}}.addr <= decoded_addr[{{addr_width-1}}:0];
|
||||
{{prefix}}.req_is_wr <= decoded_req_is_wr;
|
||||
{{prefix}}.wr_data <= decoded_wr_data;
|
||||
{{prefix}}.wr_biten <= decoded_wr_biten;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
{%- else -%}
|
||||
|
||||
|
||||
assign {{prefix}}.req = {{strb}};
|
||||
assign {{prefix}}.addr = decoded_addr[{{addr_width-1}}:0];
|
||||
assign {{prefix}}.req_is_wr = decoded_req_is_wr;
|
||||
assign {{prefix}}.wr_data = decoded_wr_data;
|
||||
assign {{prefix}}.wr_biten = decoded_wr_biten;
|
||||
|
||||
|
||||
{%- endif %}
|
||||
28
src/peakrdl_regblock/field_logic/templates/external_reg.sv
Normal file
28
src/peakrdl_regblock/field_logic/templates/external_reg.sv
Normal file
@@ -0,0 +1,28 @@
|
||||
{% if retime -%}
|
||||
|
||||
|
||||
always_ff {{get_always_ff_event(resetsignal)}} begin
|
||||
if({{get_resetsignal(resetsignal)}}) begin
|
||||
{{prefix}}.req <= '0;
|
||||
{{prefix}}.req_is_wr <= '0;
|
||||
{{prefix}}.wr_data <= '0;
|
||||
{{prefix}}.wr_biten <= '0;
|
||||
end else begin
|
||||
{{prefix}}.req <= {{strb}};
|
||||
{{prefix}}.req_is_wr <= decoded_req_is_wr;
|
||||
{{prefix}}.wr_data <= decoded_wr_data{{bslice}};
|
||||
{{prefix}}.wr_biten <= decoded_wr_biten{{bslice}};
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
{%- else -%}
|
||||
|
||||
|
||||
assign {{prefix}}.req = {{strb}};
|
||||
assign {{prefix}}.req_is_wr = decoded_req_is_wr;
|
||||
assign {{prefix}}.wr_data = decoded_wr_data{{bslice}};
|
||||
assign {{prefix}}.wr_biten = decoded_wr_biten{{bslice}};
|
||||
|
||||
|
||||
{%- endif %}
|
||||
Reference in New Issue
Block a user