Skip to content

Commit bcb1bfc

Browse files
committed
wip: now somehat generating flash load
1 parent c35a3b3 commit bcb1bfc

File tree

5 files changed

+90
-66
lines changed

5 files changed

+90
-66
lines changed

chipflow_lib/common/sim/main.cc.jinja

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ int main(int argc, char **argv) {
5252
// agent.breakpoint(CXXRTL_LOCATION);
5353
};
5454

55-
flash.load_data(BUILD_DIR "/software/software.bin", 0x00100000U);
55+
{% for data in data_load %}
56+
{{data.model_name}}.load_data("{{data.file_name}}", {{data.args | join(', ')}});
57+
{% endfor %}
58+
5659
agent.step();
5760
agent.advance(1_us);
5861

chipflow_lib/common/sim/models.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ struct gpio_model {
103103

104104
struct spi_model {
105105
std::string name;
106-
spi_model(const std::string &name, const value<1> &clk, const value<1> &csn, const value<1> &copi, value<1> &cipo) :
106+
spi_model(const std::string &name, const value<1> &clk, const value<1> &copi, value<1> &cipo, const value<1> &csn) :
107107
name(name), clk(clk), csn(csn), copi(copi), cipo(cipo) {
108108
};
109109

@@ -127,7 +127,7 @@ struct spi_model {
127127

128128
struct i2c_model {
129129
std::string name;
130-
i2c_model(const std::string &name, const value<1> &sda_o, const value<1> &sda_oe, value<1> &sda_i, const value<1> &scl_o, const value<1> &scl_oe, value<1> &scl_i) : name(name), sda_oe(sda_oe), sda_i(sda_i), scl_oe(scl_oe), scl_i(scl_i) {};
130+
i2c_model(const std::string &name, const value<1> &scl_o, const value<1> &scl_oe, value<1> &scl_i, const value<1> &sda_o, const value<1> &sda_oe, value<1> &sda_i) : name(name), sda_oe(sda_oe), sda_i(sda_i), scl_oe(scl_oe), scl_i(scl_i) {};
131131

132132
void step(unsigned timestamp);
133133
private:

chipflow_lib/platforms/_signatures.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# SPDX-License-Identifier: BSD-2-Clause
22

3+
import re
34
from typing_extensions import Unpack, TypedDict
45

56
from amaranth.lib import wiring
@@ -10,38 +11,34 @@
1011
SIM_ANNOTATION_SCHEMA = str(_chipflow_schema_uri("sim-interface", 0))
1112

1213
class SimInterface(TypedDict):
13-
name: str
14+
uid: str
1415
parameters: dict
1516

17+
_VALID_UID = re.compile('[a-zA-Z_.]').search
1618

17-
def sim_annotate(klass):
18-
original_init_subclass = klass.__init_subclass__
19+
def sim_annotate(base="com.chipflow.chipflow_lib"):
20+
def decorate(klass):
21+
assert _VALID_UID(base)
22+
dec = amaranth_annotate(SimInterface, SIM_ANNOTATION_SCHEMA)
23+
klass = dec(klass)
1924

20-
def new_init_subclass(cls, /, **kwargs):
21-
original_init = cls.__init__
25+
original_init = klass.__init__
2226
def new_init(self,*args, **kwargs):
2327
original_init(self, *args, **kwargs)
24-
self._model = {
25-
"name": cls.__name__,
26-
"parameters": self._get_sim_parameters(),
27-
}
28+
self.__chipflow_annotation__ = {
29+
"uid": klass.__chipflow_uid__,
30+
"parameters": self.__chipflow_parameters__(),
31+
}
2832

29-
if original_init_subclass:
30-
original_init_subclass(**kwargs)
31-
cls.__init__ = new_init
33+
klass.__init__ = new_init
34+
klass.__chipflow_uid__ = f"{base}.{klass.__name__}"
35+
klass.__chipflow_parameters__ = lambda self: {}
36+
return klass
37+
return decorate
3238

33-
dec = amaranth_annotate(SimInterface, SIM_ANNOTATION_SCHEMA)
34-
klass = dec(klass)
35-
klass.__init_subclass__ = classmethod(new_init_subclass)
36-
klass._get_sim_parameters = lambda self: {}
37-
return klass
3839

39-
40-
@sim_annotate
41-
class SimulatableSignature(wiring.Signature):
42-
...
43-
44-
class JTAGSignature(SimulatableSignature):
40+
@sim_annotate()
41+
class JTAGSignature(wiring.Signature):
4542
def __init__(self, **kwargs: Unpack[IOModelOptions]):
4643
super().__init__({
4744
"trst": Out(InputIOSignature(1)),
@@ -52,7 +49,8 @@ def __init__(self, **kwargs: Unpack[IOModelOptions]):
5249
})
5350

5451

55-
class SPISignature(SimulatableSignature):
52+
@sim_annotate()
53+
class SPISignature(wiring.Signature):
5654
def __init__(self, **kwargs: Unpack[IOModelOptions]):
5755
super().__init__({
5856
"sck": Out(OutputIOSignature(1)),
@@ -61,29 +59,34 @@ def __init__(self, **kwargs: Unpack[IOModelOptions]):
6159
"csn": Out(OutputIOSignature(1)),
6260
})
6361

64-
class QSPIFlashSignature(SimulatableSignature):
62+
@sim_annotate()
63+
class QSPIFlashSignature(wiring.Signature):
6564
def __init__(self, **kwargs: Unpack[IOModelOptions]):
6665
super().__init__({
6766
"clk": Out(OutputIOSignature(1)),
6867
"csn": Out(OutputIOSignature(1)),
6968
"d": Out(BidirIOSignature(4, individual_oe=True)),
7069
})
7170

72-
class UARTSignature(SimulatableSignature):
71+
@sim_annotate()
72+
class UARTSignature(wiring.Signature):
7373
def __init__(self, **kwargs: Unpack[IOModelOptions]):
7474
super().__init__({
7575
"tx": Out(OutputIOSignature(1)),
7676
"rx": Out(InputIOSignature(1)),
7777
})
7878

79-
class I2CSignature(SimulatableSignature):
79+
@sim_annotate()
80+
class I2CSignature(wiring.Signature):
8081
def __init__(self, **kwargs: Unpack[IOModelOptions]):
8182
super().__init__({
8283
"scl": Out(BidirIOSignature(1)),
8384
"sda": Out(BidirIOSignature(1))
8485
})
8586

86-
class GPIOSignature(SimulatableSignature):
87+
@sim_annotate()
88+
class GPIOSignature(wiring.Signature):
89+
8790
def __init__(self, pin_count=1, **kwargs: Unpack[IOModelOptions]):
8891
if pin_count > 32:
8992
raise ValueError(f"Pin pin_count must be lesser than or equal to 32, not {pin_count}")
@@ -92,7 +95,8 @@ def __init__(self, pin_count=1, **kwargs: Unpack[IOModelOptions]):
9295
super().__init__({
9396
"gpio": Out(BidirIOSignature(pin_count, **kwargs))
9497
})
95-
def _get_sim_parameters(self):
98+
99+
def __chipflow_parameters__(self):
96100
return {'pin_count': self._pin_count}
97101

98102
def __repr__(self) -> str:

chipflow_lib/platforms/_utils.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,18 @@ class Annotation(meta.Annotation):
147147
schema = annotation_schema()
148148

149149
def __init__(self, model: modeltype):
150-
self._model = model
150+
self.__chipflow_annotation__ = model
151151

152152
@property
153153
def origin(self): # type: ignore
154-
return self._model
154+
return self.__chipflow_annotation__
155155

156156
def as_json(self): # type: ignore
157-
return PydanticModel.dump_python(self._model)
157+
return PydanticModel.dump_python(self.__chipflow_annotation__)
158158

159159
def annotations(self, *args): # type: ignore
160160
annotations = wiring.Signature.annotations(self, *args) # type: ignore
161-
annotation = Annotation(self._model)
161+
annotation = Annotation(self.__chipflow_annotation__)
162162
return annotations + (annotation,) # type: ignore
163163

164164
def decorator(klass):
@@ -211,34 +211,35 @@ def __init__(self, **kwargs: Unpack[IOModel]):
211211
if 'clock_domain' not in model:
212212
model['clock_domain'] = 'sync'
213213

214-
self._model = model
214+
self.__chipflow_annotation__ = model
215215
super().__init__(sig)
216216

217217
@property
218218
def direction(self) -> io.Direction:
219219
"The direction of the IO port"
220-
return self._model['direction']
220+
return self.__chipflow_annotation__['direction']
221221

222222
@property
223223
def width(self) -> int:
224224
"The width of the IO port, in wires"
225-
return self._model['width']
225+
return self.__chipflow_annotation__['width']
226226

227227
@property
228228
def invert(self) -> Iterable[bool]:
229229
"A tuple as wide as the IO port, with a bool for the polarity inversion for each wire"
230-
assert type(self._model['invert']) is tuple
231-
return self._model['invert']
230+
assert type(self.__chipflow_annotation__['invert']) is tuple
231+
return self.__chipflow_annotation__['invert']
232232

233233
@property
234234
def options(self) -> IOModelOptions:
235235
"""
236236
Options set on the io port at construction
237237
"""
238-
return self._model
238+
return self.__chipflow_annotation__
239239

240240
def __repr__(self):
241-
return f"IOSignature({','.join('{0}={1!r}'.format(k,v) for k,v in self._model.items())})"
241+
return f"IOSignature({','.join('{0}={1!r}'.format(k,v) for k,v in self.__chipflow_annotation__.items())})"
242+
242243

243244
def OutputIOSignature(width: int, **kwargs: Unpack[IOModelOptions]):
244245
"""This creates an :py:obj:`Amaranth Signature <amaranth.lib.wiring.Signature>` which is then used to decorate package output signals

chipflow_lib/platforms/sim.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
from jinja2 import Environment, PackageLoader, select_autoescape
2121
from pydantic import BaseModel
2222

23-
from .. import ChipFlowError
23+
from .. import ChipFlowError, _ensure_chipflow_root
2424
from ._signatures import (
2525
I2CSignature, GPIOSignature, UARTSignature, SPISignature, QSPIFlashSignature,
26-
SimulatableSignature, SIM_ANNOTATION_SCHEMA, SimInterface
26+
SIM_ANNOTATION_SCHEMA, SimInterface
2727
)
2828
from ._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

121134
def 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

Comments
 (0)