2020from jinja2 import Environment , PackageLoader , select_autoescape
2121from pydantic import BaseModel
2222
23- from .. import ChipFlowError
23+ from .. import ChipFlowError , _ensure_chipflow_root
2424from ._signatures import (
2525 I2CSignature , GPIOSignature , UARTSignature , SPISignature , QSPIFlashSignature ,
26- SimulatableSignature , SIM_ANNOTATION_SCHEMA , SimInterface
26+ SIM_ANNOTATION_SCHEMA , SimInterface
2727 )
2828from ._utils import load_pinlock , Interface
2929
@@ -46,12 +46,15 @@ class SimModel:
4646 capabilities: List of capabilities of the model.
4747 """
4848 name : str
49- signature : Type [SimulatableSignature ]
49+ signature : Type [wiring . Signature ]
5050 capabilities : Optional [List [SimModelCapability ]] = None
5151
52+ def __post_init__ (self ):
53+ if not hasattr (self .signature , '__chipflow_uid__' ):
54+ raise ChipFlowError (f"Signature { self .signature } must be decorated with `sim_annotate()` to use as a simulation model identifier" )
5255
5356
54- def cxxmangle (name , ispublic = True ):
57+ def cxxrtlmangle (name , ispublic = True ):
5558 # RTLIL allows any characters in names other than whitespace. This presents an issue for generating C++ code
5659 # because C++ identifiers may be only alphanumeric, cannot clash with C++ keywords, and cannot clash with cxxrtl
5760 # identifiers. This issue can be solved with a name mangling scheme. We choose a name mangling scheme that results
@@ -92,47 +95,58 @@ class BasicCxxBuilder(BaseModel):
9295 cpp_files: C++ files used to define the model
9396 hpp_files: C++ header files to define the model interfaces
9497 """
95- models : Dict [ str , SimModel ]
98+ models : List [ SimModel ]
9699 cpp_files : List [Path ]
97100 hpp_files : Optional [List [Path ]] = None
98101 hpp_dirs : Optional [List [Path ]] = None
99102
100- def instantiate_model (self , interface_name : str , sim_interface : SimInterface , interface_desc : Interface , ports : Dict [str , io .SimulationPort ]) -> str :
101- name = sim_interface ['name' ]
103+ def model_post_init (self , * args , ** kwargs ):
104+ self ._table = { getattr (m .signature ,'__chipflow_uid__' ): m for m in self .models }
105+
106+ def uid_to_c (self , uid : str ) -> str :
107+ return uid .replace ('.' ,'__' )
108+
109+ def instantiate_model (self , interface : str , sim_interface : SimInterface , interface_desc : Interface , ports : Dict [str , io .SimulationPort ]) -> str :
110+ #TODO cache if this gets slow
111+
112+ uid = sim_interface ['uid' ]
102113 parameters = sim_interface ['parameters' ]
103- if name not in self .models :
114+ if uid not in self ._table :
104115 logger .warn (f"Unable to find simulation model for '{ sim_interface } '" )
105116
106- model = self .models [name ]
117+ model = self ._table [uid ]
118+ print (getattr (model .signature , '__chipflow_uid__' ))
107119 sig = model .signature (** parameters )
108120 members = list (sig .flatten (sig .create ()))
109121
110122 sig_names = [ path for path , _ , _ in members ]
111123 port_names = { n : interface_desc [n ].port_name for n in interface_desc .keys ()}
112124
125+ identifier_uid = self .uid_to_c (uid )
113126 names = [f"\\ io${ port_names [str (n )]} ${ d } " for n ,d in sig_names ]
114- params = [f"top.{ cxxmangle (n )} " for n in names ]
127+ params = [f"top.{ cxxrtlmangle (n )} " for n in names ]
115128
116- out = f"{ model .name } { interface_name } (\" { interface_name } \" , "
129+ out = f"{ model .name } { interface } (\" { interface } \" , "
117130 out += ', ' .join (list (params ))
118131 out += ')\n '
119132 return out
120133
121134def find_builder (builders : List [BasicCxxBuilder ], sim_interface : SimInterface ):
122- name = sim_interface ['name ' ]
135+ uid = sim_interface ['uid ' ]
123136 for b in builders :
124- if name in b .models :
137+ if uid in b ._table :
125138 return b
126- logger .warn (f"Unable to find builder for '{ name } '" )
139+ logger .warn (f"Unable to find builder for '{ uid } '" )
127140 return None
141+
128142_COMMON_BUILDER = BasicCxxBuilder (
129- models = {
130- SPISignature . __name__ : SimModel ('spi_model' , SPISignature ),
131- QSPIFlashSignature . __name__ : SimModel ('spiflash_model' , QSPIFlashSignature , [SimModelCapability .LOAD_DATA ]),
132- UARTSignature . __name__ : SimModel ('uart_model' , UARTSignature ),
133- I2CSignature . __name__ : SimModel ('i2c_model' , I2CSignature ),
134- GPIOSignature . __name__ : SimModel ('gpio_model' , GPIOSignature ),
135- } ,
143+ models = [
144+ SimModel ('spi_model' , SPISignature ),
145+ SimModel ('spiflash_model' , QSPIFlashSignature , [SimModelCapability .LOAD_DATA ]),
146+ SimModel ('uart_model' , UARTSignature ),
147+ SimModel ('i2c_model' , I2CSignature ),
148+ SimModel ('gpio_model' , GPIOSignature ),
149+ ] ,
136150 cpp_files = [ Path ('{COMMON_DIR}' , 'models.cc' ) ],
137151 hpp_files = [ Path ('models.h' ) ],
138152 hpp_dirs = [Path ("{COMMON_DIR}" )],
@@ -203,8 +217,10 @@ def build(self, e):
203217 includes = [hpp for b in self ._builders if b .hpp_files for hpp in b .hpp_files ],
204218 initialisers = [exp for exp in self ._top_sim .values ()],
205219 interfaces = [exp for exp in self ._top_sim .keys ()],
206- clocks = [cxxmangle (f"io${ clk } $i" ) for clk in self ._clocks .keys ()],
207- resets = [cxxmangle (f"io${ rst } $i" ) for rst in self ._resets .keys ()]),
220+ clocks = [cxxrtlmangle (f"io${ clk } $i" ) for clk in self ._clocks .keys ()],
221+ resets = [cxxrtlmangle (f"io${ rst } $i" ) for rst in self ._resets .keys ()],
222+ data_load = [{'model_name' : 'flash' , 'file_name' :_ensure_chipflow_root () / 'build' / 'software' / 'software.bin' , 'args' :[ '0x00100000U' ]}]
223+ ),
208224 file = main_file )
209225
210226
0 commit comments