77from amaranth import *
88from amaranth .lib import wiring , io
99from amaranth .back import rtlil
10+ from amaranth .hdl ._ir import PortDirection
1011
1112from .. import ChipFlowError
1213from .silicon import SiliconPlatformPort , FFSynchronizer
1617
1718
1819class SimPlatform :
19- def __init__ (self ):
20+
21+ def __init__ (self , config ):
2022 self .build_dir = os .path .join (os .environ ['CHIPFLOW_ROOT' ], 'build' , 'sim' )
2123 self .extra_files = dict ()
22- self .clk = Signal ()
23- self .rst = Signal ()
24- self .buttons = Signal (2 )
25- self .sim_boxes = dict ()
24+ self ._ports = {}
25+ self ._config = config
2626
2727 def add_file (self , filename , content ):
2828 if not isinstance (content , (str , bytes )):
2929 content = content .read ()
3030 self .extra_files [filename ] = content
3131
32- def add_model (self , inst_type , iface , edge_det = []):
33- conns = dict (i_clk = ClockSignal (), a_keep = True )
34-
35- def is_model_out (field_name ):
36- assert field_name .endswith ("_o" ) or field_name .endswith ("_oe" ) or field_name .endswith ("_i" ), field_name
37- return field_name .endswith ("_i" )
38- for field_name in iface .signature .members :
39- if is_model_out (field_name ):
40- conns [f"o_{ field_name } " ] = getattr (iface , field_name )
41- else :
42- conns [f"i_{ field_name } " ] = getattr (iface , field_name )
43- if inst_type not in self .sim_boxes :
44- box = 'attribute \\ blackbox 1\n '
45- box += 'attribute \\ cxxrtl_blackbox 1\n '
46- box += 'attribute \\ keep 1\n '
47- box += f'module \\ { inst_type } \n '
48- box += ' attribute \\ cxxrtl_edge "a"\n '
49- box += ' wire width 1 input 0 \\ clk\n '
50- for i , ((field_name ,), _ , field ) in enumerate (iface .signature .flatten (iface )):
51- field_width = Shape .cast (field .shape ()).width
52- if field_name in edge_det :
53- box += ' attribute \\ cxxrtl_edge "a"\n '
54- box += f' wire width { field_width } { "output" if is_model_out (field_name ) else "input" } { i } \\ { field_name } \n ' # noqa: E501
55- box += 'end\n \n '
56- self .sim_boxes [inst_type ] = box
57- return Instance (inst_type , ** conns )
58-
59- def add_monitor (self , inst_type , iface ):
60- conns = dict (i_clk = ClockSignal (), a_keep = True )
61- for field_name in iface .signature .members :
62- conns [f'i_{ field_name } ' ] = getattr (iface , field_name )
63- if inst_type not in self .sim_boxes :
64- box = 'attribute \\ blackbox 1\n '
65- box += 'attribute \\ cxxrtl_blackbox 1\n '
66- box += 'attribute \\ keep 1\n '
67- box += f'module \\ { inst_type } \n '
68- box += ' attribute \\ cxxrtl_edge "a"\n '
69- box += ' wire width 1 input 0 \\ clk\n '
70- for i , ((field_name ,), _ , field ) in enumerate (iface .signature .flatten (iface )):
71- field_width = Shape .cast (field .shape ()).width
72- box += f' wire width { field_width } input { i + 1 } \\ { field_name } \n '
73- box += 'end\n \n '
74- self .sim_boxes [inst_type ] = box
75- return Instance (inst_type , ** conns )
76-
7732 def build (self , e ):
7833 Path (self .build_dir ).mkdir (parents = True , exist_ok = True )
7934
80- output = rtlil .convert (e , name = "sim_top" , ports = [self .clk , self .rst , self .buttons ], platform = self )
35+ ports = []
36+ for port_name , port in self ._ports .items ():
37+ if port .direction in (io .Direction .Input , io .Direction .Bidir ):
38+ ports .append ((f"io${ port_name } $i" , port .i , PortDirection .Input ))
39+ if port .direction in (io .Direction .Output , io .Direction .Bidir ):
40+ ports .append ((f"io${ port_name } $o" , port .o , PortDirection .Output ))
41+ if port .direction is io .Direction .Bidir :
42+ ports .append ((f"io${ port_name } $oe" , port .oe , PortDirection .Output ))
43+
44+ output = rtlil .convert (e , name = "sim_top" , ports = ports , platform = self )
8145
8246 top_rtlil = Path (self .build_dir ) / "sim_soc.il"
8347 with open (top_rtlil , "w" ) as rtlil_file :
84- for box_content in self .sim_boxes .values ():
85- rtlil_file .write (box_content )
8648 rtlil_file .write (output )
8749 top_ys = Path (self .build_dir ) / "sim_soc.ys"
8850 with open (top_ys , "w" ) as yosys_file :
@@ -91,14 +53,13 @@ def build(self, e):
9153 with open (extra_path , "w" ) as extra_file :
9254 extra_file .write (extra_content )
9355 if extra_filename .endswith (".il" ):
94- print (f"read_rtlil { extra_filename } " , file = yosys_file )
56+ print (f"read_rtlil { extra_path } " , file = yosys_file )
9557 else :
9658 # FIXME: use -defer (workaround for YosysHQ/yosys#4059)
97- print (f"read_verilog { extra_filename } " , file = yosys_file )
59+ print (f"read_verilog { extra_path } " , file = yosys_file )
9860 print ("read_rtlil sim_soc.il" , file = yosys_file )
9961 print ("hierarchy -top sim_top" , file = yosys_file )
100- # FIXME: use the default -O6 (workaround for YosysHQ/yosys#4227)
101- print ("write_cxxrtl -O4 -header sim_soc.cc" , file = yosys_file )
62+ print ("write_cxxrtl -header sim_soc.cc" , file = yosys_file )
10263
10364 def instantiate_ports (self , m : Module ):
10465 if hasattr (self , "_pinlock" ):
@@ -108,26 +69,26 @@ def instantiate_ports(self, m: Module):
10869 for component , iface in pinlock .port_map .items ():
10970 for k , v in iface .items ():
11071 for name , port in v .items ():
111- self ._ports [port .port_name ] = SiliconPlatformPort ( component , name , port )
72+ self ._ports [port .port_name ] = io . SimulationPort ( port . direction , port . width , invert = port . invert , name = f" { component } - { name } " )
11273
113- # for clock, name in self._config["chipflow"]["clocks"].items():
114- # if name not in pinlock.package.clocks:
115- # raise ChipFlowError("Unable to find clock {name} in pinlock")
74+ for clock , name in self ._config ["chipflow" ]["clocks" ].items ():
75+ if name not in pinlock .package .clocks :
76+ raise ChipFlowError ("Unable to find clock {name} in pinlock" )
11677
117- # port_data = pinlock.package.clocks[name]
118- # port = io.SimulationPort(component, name, port_data, invert=True)
119- # self._ports[name] = port
78+ port_data = pinlock .package .clocks [name ]
79+ port = io .SimulationPort (io . Direction . Input , port_data . width , invert = True , name = f"clock- { name } " )
80+ self ._ports [name ] = port
12081
121- # if clock == 'default':
122- # clock = 'sync'
123- # setattr(m.domains, clock, ClockDomain(name=clock))
124- # clk_buffer = io.Buffer("i", port)
125- # setattr(m.submodules, "clk_buffer_" + clock, clk_buffer)
126- # m.d.comb += ClockSignal().eq(clk_buffer.i)
82+ if clock == 'default' :
83+ clock = 'sync'
84+ setattr (m .domains , clock , ClockDomain (name = clock ))
85+ clk_buffer = io .Buffer ("i" , port )
86+ setattr (m .submodules , "clk_buffer_" + clock , clk_buffer )
87+ m .d .comb += ClockSignal ().eq (clk_buffer .i )
12788
12889 for reset , name in self ._config ["chipflow" ]["resets" ].items ():
12990 port_data = pinlock .package .resets [name ]
130- port = SiliconPlatformPort ( component , name , port_data )
91+ port = io . SimulationPort ( io . Direction . Input , port_data . width , invert = port . invert , name = f"clock- { name } " , )
13192 self ._ports [name ] = port
13293 rst_buffer = io .Buffer ("i" , port )
13394 setattr (m .submodules , reset , rst_buffer )
0 commit comments