mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-19 07:09:05 +00:00
184 lines
6.6 KiB
Python
184 lines
6.6 KiB
Python
from pathlib import Path
|
|
|
|
with open("kernel/constids.inc") as f:
|
|
X = set([line[2:-2] for line in f.readlines() if len(line) > 2])
|
|
|
|
# f.write(X)
|
|
# ValidConstID = NewType('ValidConstID', str)
|
|
|
|
|
|
class ValidConstID(str):
|
|
# https://stackoverflow.com/questions/69844072/why-isnt-python-newtype-compatible-with-isinstance-and-type
|
|
def __new__(cls, *args, **kwargs):
|
|
return str.__new__(cls, *args, **kwargs)
|
|
|
|
|
|
def id(str):
|
|
assert str in X
|
|
return ValidConstID(str)
|
|
|
|
|
|
class CellType():
|
|
name: str
|
|
inputs: list[ValidConstID, ValidConstID | int]
|
|
outputs = list[ValidConstID, ValidConstID | int]
|
|
other_params = list[ValidConstID, type]
|
|
|
|
def __init__(self, name, inputs, outputs, other_params, add_wire_width_expr):
|
|
self.name = name
|
|
self.inputs = inputs
|
|
self.outputs = outputs
|
|
self.other_params = other_params
|
|
self.add_wire_width_expr = add_wire_width_expr
|
|
self.inputs.sort()
|
|
self.outputs.sort()
|
|
self.other_params.sort()
|
|
|
|
def arg_inputs(self, call=False):
|
|
s = ""
|
|
if call:
|
|
s += "".join(map(
|
|
lambda inp: f"sig_{inp[0].lower()}, ", self.inputs))
|
|
else:
|
|
s += "".join(map(
|
|
lambda inp: f"const RTLIL::SigSpec &sig_{inp[0].lower()}, ", self.inputs))
|
|
return s
|
|
|
|
def arg_outputs(self, call=False):
|
|
s = ""
|
|
if call:
|
|
s += "".join(map(
|
|
lambda outp: f"sig_{outp[0].lower()}, ", self.outputs))
|
|
else:
|
|
s += "".join(map(
|
|
lambda outp: f"const RTLIL::SigSpec &sig_{outp[0].lower()}, ", self.outputs))
|
|
return s
|
|
|
|
def emit_add_h(self, filename):
|
|
|
|
def _argumentize_param(param):
|
|
is_only_one_param_signed = len(
|
|
list(filter(lambda x: "_SIGNED" in x[0], self.other_params))) == 1
|
|
if "_SIGNED" in param and is_only_one_param_signed:
|
|
return "is_signed = false"
|
|
else:
|
|
return param.lower()
|
|
|
|
with open(filename, 'a') as f:
|
|
f.write(
|
|
f"RTLIL::Cell* add{self.name.title()}(RTLIL::IdString name, ")
|
|
f.write(self.arg_inputs() + self.arg_outputs())
|
|
f.write("".join(
|
|
map(lambda par: f"{par[1].__name__} {_argumentize_param(par[0])}, ", self.other_params)))
|
|
f.write("const std::string &src = \"\");\n")
|
|
|
|
def emit_add_cc(self, filename):
|
|
|
|
def _argumentize_param(param):
|
|
is_only_one_param_signed = len(
|
|
list(filter(lambda x: "_SIGNED" in x[0], self.other_params))) == 1
|
|
if "_SIGNED" in param and is_only_one_param_signed:
|
|
return "is_signed"
|
|
else:
|
|
return param.lower()
|
|
|
|
with open(filename, 'a') as f:
|
|
f.write(
|
|
f"RTLIL::Cell* RTLIL::Module::add{self.name.title()}(RTLIL::IdString name, ")
|
|
f.write(self.arg_inputs() + self.arg_outputs())
|
|
f.write("".join(
|
|
map(lambda par: f"{par[1].__name__} {_argumentize_param(par[0])}, ", self.other_params)))
|
|
f.write("const std::string &src)\n")
|
|
|
|
f.write("{\n")
|
|
f.write(
|
|
f"\tRTLIL::Cell *cell = addCell(name, ID(${self.name}));\n")
|
|
|
|
for param in self.other_params:
|
|
f.write(
|
|
f"\tcell->parameters[ID::{param[0]}] = {_argumentize_param(param[0])};\n")
|
|
|
|
for input, width in self.inputs:
|
|
if isinstance(width, ValidConstID):
|
|
f.write(
|
|
f"\tcell->parameters[ID::{width}] = sig_{input.lower()}.size();\n")
|
|
|
|
for output, width in self.outputs:
|
|
if isinstance(width, ValidConstID):
|
|
f.write(
|
|
f"\tcell->parameters[ID::{width}] = sig_{output.lower()}.size();\n")
|
|
|
|
for input, _ in self.inputs:
|
|
f.write(
|
|
f"\tcell->setPort(ID::{input}, sig_{input.lower()});\n")
|
|
for output, _ in self.outputs:
|
|
f.write(
|
|
f"\tcell->setPort(ID::{output}, sig_{output.lower()});\n")
|
|
f.write("\tcell->set_src_attribute(src);\n")
|
|
f.write("\treturn cell;\n")
|
|
f.write("}\n\n")
|
|
|
|
if self.add_wire_width_expr:
|
|
f.write(
|
|
f"RTLIL::SigSpec RTLIL::Module::{self.name.title()}(RTLIL::IdString name, {self.arg_inputs()}")
|
|
f.write("".join(
|
|
map(lambda par: f"{par[1].__name__} {_argumentize_param(par[0])}, ", self.other_params)))
|
|
f.write("const std::string &src) {\n")
|
|
f.write(
|
|
f"\tRTLIL::SigSpec sig_y = addWire(NEW_ID, {self.add_wire_width_expr});\n")
|
|
f.write(
|
|
f"\tadd{self.name.title()}(name, {self.arg_inputs(call=True)}{self.arg_outputs(call=True)}")
|
|
f.write("".join(
|
|
map(lambda par: f"{_argumentize_param(par[0])}", self.other_params)))
|
|
f.write(f", src);\n")
|
|
f.write("\treturn sig_y;\n")
|
|
f.write("}\n\n")
|
|
# _func(const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed, const std::string &src) { \
|
|
# RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \
|
|
# add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \
|
|
# return sig_y; \
|
|
# }
|
|
|
|
|
|
def unary(name):
|
|
inputs = [(id("A"), id("A_WIDTH"))]
|
|
outputs = [(id("Y"), id("Y_WIDTH"))]
|
|
other_params = [(id("A_SIGNED"), bool)]
|
|
add_wire_width_expr = "sig_a.size()"
|
|
return CellType(name, inputs, outputs, other_params, add_wire_width_expr)
|
|
|
|
|
|
celltypes = []
|
|
celltypes += [unary("pos")]
|
|
celltypes += [unary("neg")]
|
|
celltypes += [unary("not")]
|
|
|
|
shim_headers = Path("kernel/adds.shim.h")
|
|
shim_headers.unlink(missing_ok=True)
|
|
shim_src = Path("kernel/adds.shim.cc")
|
|
shim_src.unlink(missing_ok=True)
|
|
|
|
|
|
def emit_boilerplate():
|
|
warning = "/* Generated by shim.py, do not modify */\n"
|
|
with open(shim_headers, 'a') as f:
|
|
f.write(warning)
|
|
f.write('#ifndef SHIM_H\n')
|
|
f.write('#define SHIM_H\n')
|
|
f.write('#include "kernel/yosys.h"\n')
|
|
f.write('#endif /* SHIM_H */\n')
|
|
|
|
with open(shim_src, 'a') as f:
|
|
f.write(warning)
|
|
f.write('#include "kernel/yosys.h"\n')
|
|
f.write("USING_YOSYS_NAMESPACE\n")
|
|
|
|
|
|
emit_boilerplate()
|
|
|
|
for celltype in celltypes:
|
|
celltype.emit_add_h(shim_headers)
|
|
|
|
for celltype in celltypes:
|
|
celltype.emit_add_cc(shim_src)
|