mirror of
https://github.com/nickmqb/wyre.git
synced 2025-12-05 18:20:36 -08:00
929 lines
21 KiB
Text
929 lines
21 KiB
Text
GeneratorState struct #RefType {
|
|
comp Compilation
|
|
symbols Map<string, Node>
|
|
typeMap Map<Node, Tag>
|
|
constMap Map<Node, Value>
|
|
entities List<Node>
|
|
errors List<Error>
|
|
es EmulatorState
|
|
inst ModuleInstance
|
|
evalCtxOutput int
|
|
evalCtxField int
|
|
isNonIndexable bool
|
|
out CodeBuilder
|
|
first CodeBuilder
|
|
assignments CodeBuilder
|
|
regUpdates CodeBuilder
|
|
globals Set<string>
|
|
}
|
|
|
|
CodeBuilder struct #RefType {
|
|
sb StringBuilder
|
|
indent int
|
|
lineSep string
|
|
skipSep bool
|
|
|
|
create() {
|
|
return CodeBuilder { sb: new StringBuilder{} }
|
|
}
|
|
}
|
|
|
|
NodeWithCtx struct {
|
|
node Node
|
|
ctxOutput int
|
|
ctxField int
|
|
|
|
hash(self NodeWithCtx) {
|
|
return xor(xor(transmute(pointer_cast(self.node, pointer), uint), cast(self.ctxOutput, uint) << 25), cast(self.ctxField, uint))
|
|
}
|
|
|
|
equals(a NodeWithCtx, b NodeWithCtx) {
|
|
return a.node == b.node && a.ctxOutput == b.ctxOutput && a.ctxField == b.ctxField
|
|
}
|
|
}
|
|
|
|
VerilogGenerator {
|
|
comp(comp Compilation, es EmulatorState) {
|
|
s := new GeneratorState {
|
|
comp: comp,
|
|
symbols: comp.symbols,
|
|
typeMap: comp.typeMap,
|
|
constMap: comp.constMap,
|
|
entities: comp.entities,
|
|
errors: comp.errors,
|
|
es: es,
|
|
evalCtxOutput: -1,
|
|
evalCtxField: -1,
|
|
out: new CodeBuilder.create(),
|
|
globals: new Set.create<string>(),
|
|
}
|
|
|
|
s.globals.add("module")
|
|
s.globals.add("endmodule")
|
|
s.globals.add("begin")
|
|
s.globals.add("end")
|
|
s.globals.add("if")
|
|
s.globals.add("else")
|
|
s.globals.add("posedge")
|
|
s.globals.add("negedge")
|
|
s.globals.add("wire")
|
|
s.globals.add("reg")
|
|
s.globals.add("input")
|
|
s.globals.add("output")
|
|
s.globals.add("inout")
|
|
s.globals.add("case")
|
|
s.globals.add("signed")
|
|
s.globals.add("cell")
|
|
|
|
for u in s.comp.units {
|
|
for node in u.contents {
|
|
if node.is(ModuleDef) {
|
|
def := node.as(ModuleDef)
|
|
if def.blackboxKeyword != null {
|
|
s.globals.tryAdd(def.name.value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for mi in es.moduleInstances {
|
|
if mi.def.blackboxKeyword == null {
|
|
mi.genLocals = new Map.create<NodeWithCtx, string>()
|
|
mi.genLocalsSet = new Set.create<string>()
|
|
name := mi.fullName != "" ? mi.fullName.replace(".", "_") : mi.def.name.value
|
|
mi.genGlobalName = uniqueName(s, mi, s.globals, name)
|
|
} else {
|
|
mi.genGlobalName = mi.def.name.value
|
|
}
|
|
}
|
|
|
|
for mi in es.moduleInstances {
|
|
s.globals.tryRemove(mi.genGlobalName)
|
|
}
|
|
|
|
write(s, format("// Generated by Wyre compiler {}\n", compilerVersion))
|
|
|
|
for mi in es.moduleInstances {
|
|
if mi.def.blackboxKeyword == null {
|
|
module(s, mi)
|
|
}
|
|
}
|
|
|
|
return s.out
|
|
}
|
|
|
|
module(s GeneratorState, inst ModuleInstance) {
|
|
s.inst = inst
|
|
def := inst.def
|
|
|
|
for i := 1; i < inst.calls.count {
|
|
mi := s.es.moduleInstances[inst.calls[i]]
|
|
mi.genLocalName = uniqueName(s, s.inst, s.inst.genLocalsSet, mi.localName)
|
|
}
|
|
|
|
write(s, "\nmodule ")
|
|
write(s, inst.genGlobalName)
|
|
write(s, "(")
|
|
|
|
indent(s, ",")
|
|
for inp in def.inputs {
|
|
if inp.flags & ModuleInputFlags.static == 0 {
|
|
tag := s.typeMap.get(inp)
|
|
if tag.kind == TagKind.number {
|
|
input(s, inp, nameOf(s, s.inst, inp, -1, -1), tag)
|
|
} else if tag.kind == TagKind.struct_ {
|
|
sdef := s.entities[tag.q].as(StructDef)
|
|
for f, fi in sdef.fields {
|
|
input(s, inp, nameOf(s, s.inst, inp, -1, fi), s.typeMap.get(f))
|
|
}
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
}
|
|
|
|
for o in def.outputs {
|
|
tag := s.typeMap.get(o)
|
|
if tag.kind == TagKind.number {
|
|
output(s, o, nameOf(s, s.inst, o, -1, -1), tag)
|
|
} else if tag.kind == TagKind.struct_ {
|
|
sdef := s.entities[tag.q].as(StructDef)
|
|
for f, fi in sdef.fields {
|
|
s.evalCtxField = fi
|
|
output(s, o, nameOf(s, s.inst, o, -1, fi), s.typeMap.get(f))
|
|
}
|
|
s.evalCtxField = -1
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
|
|
unindent(s)
|
|
beginLine(s)
|
|
write(s, ");\n")
|
|
|
|
s.assignments = new CodeBuilder.create()
|
|
s.regUpdates = new CodeBuilder.create()
|
|
|
|
s.first = push(s, s.regUpdates)
|
|
firstPos := s.first.sb.count
|
|
block(s, def.body)
|
|
if s.regUpdates.sb.count > 0 {
|
|
beginLine(s)
|
|
}
|
|
for i := 1; i < inst.calls.count {
|
|
callInst(s, s.es.moduleInstances[inst.calls[i]])
|
|
}
|
|
restore(s, s.first)
|
|
|
|
if s.first.sb.count != firstPos {
|
|
beginLine(s)
|
|
}
|
|
|
|
str := s.assignments.sb.compactToString()
|
|
if str != "" {
|
|
write(s, str)
|
|
beginLine(s)
|
|
}
|
|
|
|
str = s.regUpdates.sb.compactToString()
|
|
if str != "" {
|
|
write(s, str)
|
|
}
|
|
|
|
if inst.calls.count == 0 {
|
|
beginLine(s)
|
|
}
|
|
|
|
write(s, "\nendmodule\n")
|
|
}
|
|
|
|
input(s GeneratorState, inp ModuleInputDef, genName string, tag Tag) {
|
|
beginLine(s)
|
|
write(s, "input ")
|
|
numberTag(s, tag)
|
|
write(s, genName)
|
|
}
|
|
|
|
output(s GeneratorState, o AssignStatement, genName string, tag Tag) {
|
|
isReg := o.regKeyword != null
|
|
beginLine(s)
|
|
write(s, "output ")
|
|
if isReg {
|
|
write(s, "reg ")
|
|
}
|
|
numberTag(s, tag)
|
|
write(s, genName)
|
|
if isReg {
|
|
if o.expr != null && o.flags & AssignFlags.regUpdate == 0 {
|
|
write(s, " = ")
|
|
staticValue(s, s.inst, o.localId, tag)
|
|
} else {
|
|
write(s, " = 0")
|
|
}
|
|
}
|
|
}
|
|
|
|
callInst(s GeneratorState, target ModuleInstance) {
|
|
def := target.def
|
|
callExpr := target.callExpr
|
|
|
|
beginLine(s)
|
|
write(s, "(* keep *) ")
|
|
write(s, target.genGlobalName)
|
|
write(s, " ")
|
|
if def.blackboxKeyword != null {
|
|
if hasStaticInputs(s, def) {
|
|
write(s, "#(")
|
|
indent(s, ",")
|
|
for inp in def.inputs {
|
|
if inp.flags & ModuleInputFlags.static != 0 {
|
|
tag := s.typeMap.get(inp)
|
|
beginLine(s)
|
|
write(s, ".")
|
|
write(s, trimHash(inp.name.value))
|
|
write(s, "(")
|
|
staticValue(s, target, inp.localId, tag)
|
|
write(s, ")")
|
|
}
|
|
}
|
|
unindent(s)
|
|
beginLine(s)
|
|
write(s, ") ")
|
|
}
|
|
}
|
|
|
|
write(s, target.genLocalName)
|
|
write(s, "(")
|
|
indent(s, ",")
|
|
for inp in def.inputs {
|
|
if inp.flags & ModuleInputFlags.static == 0 {
|
|
tag := s.typeMap.get(inp)
|
|
if tag.kind == TagKind.number {
|
|
beginLine(s)
|
|
write(s, ".")
|
|
write(s, def.blackboxKeyword == null ? nameOf(s, target, inp, -1, -1) : inp.name.value)
|
|
write(s, "(")
|
|
expression(s, callExpr.args[callExpr.calleeLocalIdToArgIndex[inp.localId]].expr)
|
|
write(s, ")")
|
|
} else if tag.kind == TagKind.struct_ {
|
|
sdef := unpackStruct(s, tag)
|
|
for f, i in sdef.fields {
|
|
beginLine(s)
|
|
write(s, ".")
|
|
write(s, def.blackboxKeyword == null ? nameOf(s, target, inp, -1, i) : inp.name.value)
|
|
write(s, "(")
|
|
s.evalCtxField = i
|
|
expression(s, callExpr.args[callExpr.calleeLocalIdToArgIndex[inp.localId]].expr)
|
|
write(s, ")")
|
|
}
|
|
s.evalCtxField = -1
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
}
|
|
|
|
for o, oi in def.outputs {
|
|
tag := s.typeMap.get(o)
|
|
if tag.kind == TagKind.number {
|
|
beginLine(s)
|
|
write(s, ".")
|
|
write(s, def.blackboxKeyword == null ? nameOf(s, target, o, -1, -1) : o.nameExpr.as(Token).value)
|
|
write(s, "(")
|
|
write(s, nameOf(s, s.inst, callExpr, oi, -1))
|
|
write(s, ")")
|
|
} else if tag.kind == TagKind.struct_ {
|
|
sdef := unpackStruct(s, tag)
|
|
for f, fi in sdef.fields {
|
|
beginLine(s)
|
|
write(s, ".")
|
|
write(s, def.blackboxKeyword == null ? nameOf(s, target, o, -1, fi) : o.nameExpr.as(Token).value)
|
|
write(s, "(")
|
|
write(s, nameOf(s, s.inst, callExpr, oi, fi))
|
|
write(s, ")")
|
|
}
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
|
|
unindent(s)
|
|
beginLine(s)
|
|
write(s, ");")
|
|
|
|
prev := push(s, s.first)
|
|
for o, oi in def.outputs {
|
|
tag := s.typeMap.get(o)
|
|
if tag.kind == TagKind.number {
|
|
beginLine(s)
|
|
write(s, "wire ")
|
|
numberTag(s, tag)
|
|
write(s, nameOf(s, s.inst, callExpr, oi, -1))
|
|
write(s, ";")
|
|
} else if tag.kind == TagKind.struct_ {
|
|
sdef := unpackStruct(s, tag)
|
|
for f, fi in sdef.fields {
|
|
beginLine(s)
|
|
write(s, "wire ")
|
|
numberTag(s, s.typeMap.get(f))
|
|
write(s, nameOf(s, s.inst, callExpr, oi, fi))
|
|
write(s, ";")
|
|
}
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
restore(s, prev)
|
|
|
|
beginLine(s)
|
|
}
|
|
|
|
block(s GeneratorState, block Block) {
|
|
for n in block.contents {
|
|
match n {
|
|
ClockStatement: clock(s, n)
|
|
IfStatement: if_(s, n)
|
|
AssignStatement: assign(s, n)
|
|
}
|
|
}
|
|
}
|
|
|
|
clock(s GeneratorState, st ClockStatement) {
|
|
beginLine(s)
|
|
write(s, "always @(")
|
|
write(s, st.keyword.value)
|
|
write(s, " ")
|
|
write(s, st.name.value)
|
|
write(s, ") begin")
|
|
indent(s, "")
|
|
block(s, st.body)
|
|
unindent(s)
|
|
beginLine(s)
|
|
write(s, "end")
|
|
}
|
|
|
|
if_(s GeneratorState, st IfStatement) {
|
|
beginLine(s)
|
|
write(s, "if (")
|
|
expression(s, st.expr)
|
|
write(s, ") begin")
|
|
indent(s, "")
|
|
block(s, st.ifBody)
|
|
unindent(s)
|
|
if st.elseBranch != null {
|
|
beginLine(s)
|
|
write(s, "end else begin")
|
|
indent(s, "")
|
|
if st.elseBranch.is(IfStatement) {
|
|
if_(s, st.elseBranch.as(IfStatement))
|
|
} else if st.elseBranch.is(Block) {
|
|
block(s, st.elseBranch.as(Block))
|
|
}
|
|
unindent(s)
|
|
}
|
|
beginLine(s)
|
|
write(s, "end")
|
|
}
|
|
|
|
assign(s GeneratorState, st AssignStatement) {
|
|
if (st.flags & AssignFlags.reg) != 0 && st.outKeyword == null {
|
|
prev := push(s, s.first)
|
|
name := st.nameExpr.as(Token).value
|
|
tag := s.typeMap.get(st)
|
|
if tag.kind == TagKind.number {
|
|
reg(s, st, nameOf(s, s.inst, st, -1, -1), tag)
|
|
} else if tag.kind == TagKind.struct_ {
|
|
def := s.entities[tag.q].as(StructDef)
|
|
for f, fi in def.fields {
|
|
s.evalCtxField = fi
|
|
reg(s, st, nameOf(s, s.inst, st, -1, fi), s.typeMap.get(f))
|
|
}
|
|
s.evalCtxField = -1
|
|
} else {
|
|
abandon()
|
|
}
|
|
restore(s, prev)
|
|
}
|
|
if (st.flags & AssignFlags.wire) != 0 && (st.flags & AssignFlags.static) == 0 {
|
|
prev := push(s, s.first)
|
|
tag := s.typeMap.get(st)
|
|
if tag.kind == TagKind.number {
|
|
wire(s, st, nameOf(s, s.inst, st, -1, -1), tag)
|
|
} else if tag.kind == TagKind.struct_ {
|
|
def := s.entities[tag.q].as(StructDef)
|
|
for f, fi in def.fields {
|
|
s.evalCtxField = fi
|
|
wire(s, st, nameOf(s, s.inst, st, -1, fi), s.typeMap.get(f))
|
|
}
|
|
s.evalCtxField = -1
|
|
} else if tag.kind == TagKind.moduleOut {
|
|
// OK
|
|
} else {
|
|
abandon()
|
|
}
|
|
restore(s, prev)
|
|
}
|
|
if st.flags & AssignFlags.regUpdate != 0 {
|
|
nameExpr := st.nameExpr
|
|
match nameExpr {
|
|
Token: {
|
|
sym := s.inst.def.symbols.get(nameExpr.value)
|
|
tag := s.typeMap.get(sym)
|
|
if tag.kind == TagKind.number {
|
|
regUpdate(s, nameOf(s, s.inst, sym, -1, -1), st.expr)
|
|
} else if tag.kind == TagKind.struct_ {
|
|
def := s.entities[tag.q].as(StructDef)
|
|
for f, fi in def.fields {
|
|
s.evalCtxField = fi
|
|
regUpdate(s, nameOf(s, s.inst, sym, -1, fi), st.expr)
|
|
}
|
|
s.evalCtxField = -1
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
DotExpression: {
|
|
dot := nameExpr
|
|
nameToken := dot.lhs.as(Token)
|
|
sym := s.inst.def.symbols.getOrDefault(nameToken.value)
|
|
tag := s.typeMap.get(sym)
|
|
sdef := unpackStruct(s, tag)
|
|
fieldIndex := sdef.symbols.get(dot.rhs.value).fieldIndex
|
|
regUpdate(s, nameOf(s, s.inst, sym, -1, fieldIndex), st.expr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
reg(s GeneratorState, st AssignStatement, genName string, tag Tag) {
|
|
beginLine(s)
|
|
write(s, "(* keep *) reg ")
|
|
numberTag(s, tag)
|
|
write(s, genName)
|
|
if st.expr != null && st.flags & AssignFlags.regUpdate == 0 {
|
|
write(s, " = ")
|
|
staticValue(s, s.inst, st.localId, tag)
|
|
} else {
|
|
write(s, " = 0")
|
|
}
|
|
write(s, ";")
|
|
}
|
|
|
|
wire(s GeneratorState, st AssignStatement, genName string, tag Tag) {
|
|
if st.outKeyword == null {
|
|
beginLine(s)
|
|
write(s, "wire ")
|
|
numberTag(s, tag)
|
|
write(s, genName)
|
|
write(s, ";")
|
|
}
|
|
|
|
cb := new CodeBuilder.create()
|
|
prev := push(s, cb)
|
|
beginLine(s)
|
|
write(s, "assign ")
|
|
write(s, genName)
|
|
write(s, " = ")
|
|
expression(s, st.expr)
|
|
write(s, ";")
|
|
s.out = s.assignments
|
|
write(s, cb.sb.compactToString())
|
|
restore(s, prev)
|
|
}
|
|
|
|
regUpdate(s GeneratorState, genName string, expr Node) {
|
|
beginLine(s)
|
|
write(s, genName)
|
|
write(s, " <= ")
|
|
expression(s, expr)
|
|
write(s, ";")
|
|
}
|
|
|
|
expression(s GeneratorState, e Node) {
|
|
val := s.constMap.getOrDefault(e)
|
|
if val.kind != ValueKind.none {
|
|
assert(s.evalCtxField == -1 && s.evalCtxOutput == -1)
|
|
tag := s.typeMap.get(e)
|
|
value(s, tag, val)
|
|
} else {
|
|
expressionInner(s, e)
|
|
}
|
|
}
|
|
|
|
expressionInner(s GeneratorState, e Node) {
|
|
match e {
|
|
Token: token(s, e)
|
|
NumberExpression: number(s, e)
|
|
UnaryOperatorExpression: unaryOperator(s, e)
|
|
BinaryOperatorExpression: binaryOperator(s, e)
|
|
DotExpression: dot(s, e)
|
|
TernaryOperatorExpression: ternaryOperator(s, e)
|
|
MatchExpression: match_(s, e)
|
|
ParenExpression: paren(s, e)
|
|
IndexExpression: index(s, e)
|
|
CallExpression: call(s, e)
|
|
StructInitializerExpression: structInit(s, e)
|
|
BraceExpression: brace(s, e)
|
|
}
|
|
}
|
|
|
|
token(s GeneratorState, e Token) {
|
|
name := e.value
|
|
sym := s.inst.def.symbols.getOrDefault(name)
|
|
if s.evalCtxOutput == -1 {
|
|
match sym {
|
|
ModuleInputDef: {
|
|
if sym.flags & ModuleInputFlags.static == 0 {
|
|
write(s, nameOf(s, s.inst, sym, -1, s.evalCtxField))
|
|
} else {
|
|
staticValue(s, s.inst, sym.localId, s.typeMap.get(sym))
|
|
}
|
|
}
|
|
AssignStatement: {
|
|
if sym.flags & AssignFlags.static == 0 {
|
|
write(s, nameOf(s, s.inst, sym, -1, s.evalCtxField))
|
|
} else {
|
|
staticValue(s, s.inst, sym.localId, s.typeMap.get(sym))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
assign := sym.as(AssignStatement)
|
|
assert(assign.expr.is(CallExpression))
|
|
expression(s, assign.expr)
|
|
}
|
|
}
|
|
|
|
number(s GeneratorState, e NumberExpression) {
|
|
s.isNonIndexable = true
|
|
sb := s.out.sb
|
|
assert(s.evalCtxField == -1 && s.evalCtxOutput == -1)
|
|
assert(e.dontCare != 0)
|
|
tag := s.typeMap.get(e)
|
|
assert(tag.kind == TagKind.number)
|
|
assert(tag.q > 0)
|
|
mask := 1_uL << (tag.q - 1)
|
|
tag.q.writeTo(sb)
|
|
sb.write("'b")
|
|
while mask != 0 {
|
|
if mask & e.dontCare != 0 {
|
|
sb.write("x")
|
|
} else if mask & e.value != 0 {
|
|
sb.write("1")
|
|
} else {
|
|
sb.write("0")
|
|
}
|
|
mask >>= 1
|
|
}
|
|
}
|
|
|
|
unaryOperator(s GeneratorState, e UnaryOperatorExpression) {
|
|
if e.op.value == "zx" {
|
|
expression(s, e.expr)
|
|
return
|
|
}
|
|
s.isNonIndexable = true
|
|
write(s, e.op.value)
|
|
write(s, "(")
|
|
expression(s, e.expr)
|
|
write(s, ")")
|
|
}
|
|
|
|
binaryOperator(s GeneratorState, e BinaryOperatorExpression) {
|
|
s.isNonIndexable = true
|
|
write(s, "(")
|
|
expression(s, e.lhs)
|
|
write(s, ") ")
|
|
write(s, e.op.value)
|
|
write(s, " (")
|
|
expression(s, e.rhs)
|
|
write(s, ")")
|
|
}
|
|
|
|
dot(s GeneratorState, e DotExpression) {
|
|
tag := s.typeMap.get(e.lhs)
|
|
if tag.kind == TagKind.struct_ {
|
|
assert(s.evalCtxField == -1)
|
|
def := s.entities[tag.q].as(StructDef)
|
|
s.evalCtxField = def.symbols.get(e.rhs.value).fieldIndex
|
|
expression(s, e.lhs)
|
|
s.evalCtxField = -1
|
|
} else if tag.kind == TagKind.moduleOut {
|
|
assert(s.evalCtxOutput == -1)
|
|
def := s.entities[tag.q].as(ModuleDef)
|
|
s.evalCtxOutput = def.symbols.get(e.rhs.value).as(AssignStatement).outputIndex
|
|
expression(s, e.lhs)
|
|
s.evalCtxOutput = -1
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
|
|
ternaryOperator(s GeneratorState, e TernaryOperatorExpression) {
|
|
s.isNonIndexable = true
|
|
write(s, "(")
|
|
expression(s, e.conditionExpr)
|
|
write(s, ") ? (")
|
|
expression(s, e.trueExpr)
|
|
write(s, ") : (")
|
|
expression(s, e.falseExpr)
|
|
write(s, ")")
|
|
}
|
|
|
|
match_(s GeneratorState, e MatchExpression) {
|
|
eb := new CodeBuilder.create()
|
|
prev := push(s, eb)
|
|
s.isNonIndexable = false
|
|
expression(s, e.target)
|
|
restore(s, prev)
|
|
|
|
target := ""
|
|
if !s.isNonIndexable {
|
|
target = eb.sb.compactToString()
|
|
} else {
|
|
target = newLocal(s, s.typeMap.get(e.target), eb.sb.compactToString())
|
|
}
|
|
|
|
indent(s, "")
|
|
for cs in e.cases {
|
|
beginLine(s)
|
|
write(s, "(((")
|
|
write(s, target)
|
|
write(s, ") == ")
|
|
expression(s, cs.valueExpr)
|
|
write(s, ") ? (")
|
|
expression(s, cs.resultExpr)
|
|
write(s, ") :")
|
|
}
|
|
|
|
write(s, " ")
|
|
resultTag := s.typeMap.get(e)
|
|
write(s, format("{}'b{}", resultTag.q, string.repeatChar('x', resultTag.q)))
|
|
write(s, string.repeatChar(')', e.cases.count))
|
|
unindent(s)
|
|
|
|
s.isNonIndexable = true
|
|
}
|
|
|
|
paren(s GeneratorState, e ParenExpression) {
|
|
s.isNonIndexable = true
|
|
write(s, "(")
|
|
expression(s, e.expr)
|
|
write(s, ")")
|
|
}
|
|
|
|
index(s GeneratorState, e IndexExpression) {
|
|
eb := new CodeBuilder.create()
|
|
prev := push(s, eb)
|
|
s.isNonIndexable = false
|
|
expression(s, e.target)
|
|
restore(s, prev)
|
|
|
|
if !s.isNonIndexable {
|
|
write(s, eb.sb.compactToString())
|
|
} else {
|
|
write(s, newLocal(s, s.typeMap.get(e.target), eb.sb.compactToString()))
|
|
}
|
|
|
|
sb := s.out.sb
|
|
sb.write("[")
|
|
upper := s.constMap.get(e.upperExpr).z
|
|
upper.writeTo(sb)
|
|
if e.lowerExpr != null {
|
|
sb.write(":")
|
|
lower := s.constMap.get(e.lowerExpr).z
|
|
lower.writeTo(sb)
|
|
}
|
|
sb.write("]")
|
|
|
|
s.isNonIndexable = true
|
|
}
|
|
|
|
call(s GeneratorState, e CallExpression) {
|
|
if e.builtin == BuiltinCall.rep {
|
|
rep(s, e)
|
|
return
|
|
}
|
|
assert(e.builtin == BuiltinCall.none)
|
|
assert(s.evalCtxOutput >= 0)
|
|
write(s, nameOf(s, s.inst, e, s.evalCtxOutput, s.evalCtxField))
|
|
}
|
|
|
|
rep(s GeneratorState, e CallExpression) {
|
|
s.isNonIndexable = true
|
|
n := TypeChecker.unpackInt(s.constMap.get(e.args[1].expr))
|
|
write(s, "{ ")
|
|
sep := false
|
|
for i := 0; i < n {
|
|
if sep {
|
|
write(s, ", ")
|
|
} else {
|
|
sep = true
|
|
}
|
|
expression(s, e.args[0].expr)
|
|
}
|
|
write(s, " }")
|
|
}
|
|
|
|
structInit(s GeneratorState, e StructInitializerExpression) {
|
|
assert(s.evalCtxField >= 0)
|
|
def := unpackStruct(s, s.typeMap.get(e))
|
|
argIndex := e.fieldIndexToArgIndex[s.evalCtxField]
|
|
if argIndex >= 0 {
|
|
arg := e.args[argIndex].expr
|
|
prevCtxField := s.evalCtxField
|
|
s.evalCtxField = -1
|
|
expression(s, arg)
|
|
s.evalCtxField = prevCtxField
|
|
} else {
|
|
s.isNonIndexable = true
|
|
write(s, "0")
|
|
}
|
|
}
|
|
|
|
brace(s GeneratorState, e BraceExpression) {
|
|
s.isNonIndexable = true
|
|
write(s, "{ ")
|
|
sep := false
|
|
for arg in e.args {
|
|
if sep {
|
|
write(s, ", ")
|
|
} else {
|
|
sep = true
|
|
}
|
|
expression(s, arg)
|
|
}
|
|
write(s, " }")
|
|
}
|
|
|
|
newLocal(s GeneratorState, tag Tag, valStr string) {
|
|
prev := push(s, s.first)
|
|
beginLine(s)
|
|
write(s, "wire ")
|
|
numberTag(s, tag)
|
|
name := uniqueName(s, s.inst, s.inst.genLocalsSet, "local")
|
|
write(s, name)
|
|
write(s, ";")
|
|
restore(s, prev)
|
|
|
|
prev = push(s, s.assignments)
|
|
beginLine(s)
|
|
write(s, "assign ")
|
|
write(s, name)
|
|
write(s, " = ")
|
|
write(s, valStr)
|
|
write(s, ";")
|
|
restore(s, prev)
|
|
|
|
return name
|
|
}
|
|
|
|
staticValue(s GeneratorState, instance ModuleInstance, localId int, tag Tag) {
|
|
si := instance.localState[localId] + max(0, s.evalCtxField)
|
|
value(s, tag, s.es.rs[si])
|
|
}
|
|
|
|
value(s GeneratorState, tag Tag, value Value) {
|
|
s.isNonIndexable = true
|
|
assert(tag.kind == TagKind.number)
|
|
if tag.q == 0 {
|
|
write(s, "(((compiler_bug:invalid_num")
|
|
}
|
|
if value.kind == ValueKind.ulong_ {
|
|
write(s, format("{}'d{}", tag.q, value.z))
|
|
} else if value.kind == ValueKind.byteArray {
|
|
data := EmulatorRunner.unpackArray(value)
|
|
write(s, format("{}'h", tag.q))
|
|
from := min((tag.q + 7) / 8, data.count)
|
|
if from > 0 {
|
|
for i := from - 1; i >= 0; i -= 1 {
|
|
Util.writeByteHexTo(data[i], s.out.sb)
|
|
}
|
|
} else {
|
|
write(s, "0")
|
|
}
|
|
} else {
|
|
abandon()
|
|
}
|
|
}
|
|
|
|
numberTag(s GeneratorState, tag Tag) {
|
|
assert(tag.kind == TagKind.number)
|
|
assert(tag.q > 0)
|
|
if tag.q > 1 {
|
|
write(s, format("[{}:0] ", tag.q - 1))
|
|
}
|
|
}
|
|
|
|
nameOf(s GeneratorState, inst ModuleInstance, node Node, ctxOutput int, ctxField int) string {
|
|
nc := NodeWithCtx { node: node, ctxOutput: ctxOutput, ctxField: ctxField }
|
|
existingName := inst.genLocals.maybeGet(nc)
|
|
if existingName.hasValue {
|
|
return existingName.value
|
|
}
|
|
sb := StringBuilder{}
|
|
match node {
|
|
ModuleInputDef: {
|
|
sb.write(trimHash(node.name.value))
|
|
if ctxField != -1 {
|
|
sb.write("_")
|
|
sb.write(unpackStruct(s, s.typeMap.get(node)).fields[ctxField].name.value)
|
|
}
|
|
}
|
|
AssignStatement: {
|
|
assert(s.typeMap.get(node).kind != TagKind.moduleOut)
|
|
sb.write(trimHash(node.nameExpr.as(Token).value))
|
|
if ctxField != -1 {
|
|
sb.write("_")
|
|
sb.write(unpackStruct(s, s.typeMap.get(node)).fields[ctxField].name.value)
|
|
}
|
|
}
|
|
CallExpression: {
|
|
target := s.es.moduleInstances[inst.calls[node.callId]]
|
|
output := target.def.outputs[ctxOutput]
|
|
sb.write(target.genLocalName)
|
|
sb.write("_")
|
|
sb.write(target.def.blackboxKeyword == null ? nameOf(s, target, output, -1, ctxField) : output.nameExpr.as(Token).value)
|
|
}
|
|
}
|
|
name := uniqueName(s, inst, inst.genLocalsSet, sb.compactToString())
|
|
inst.genLocals.add(nc, name)
|
|
return name
|
|
}
|
|
|
|
uniqueName(s GeneratorState, inst ModuleInstance, set Set<string>, origName string) {
|
|
name := origName
|
|
i := 1
|
|
while true {
|
|
if !s.globals.contains(name) && !inst.genLocalsSet.contains(name) {
|
|
set.add(name)
|
|
return name
|
|
}
|
|
name = format("{}_{}", origName, i)
|
|
i += 1
|
|
}
|
|
}
|
|
|
|
hasStaticInputs(s GeneratorState, def ModuleDef) {
|
|
result := false
|
|
for inp in def.inputs {
|
|
result ||= (inp.flags & ModuleInputFlags.static) != 0
|
|
}
|
|
return result
|
|
}
|
|
|
|
trimHash(s string) {
|
|
if s[0] == '#' {
|
|
return s.slice(1, s.length)
|
|
}
|
|
return s
|
|
}
|
|
|
|
beginLine(s GeneratorState) {
|
|
if !s.out.skipSep {
|
|
write(s, s.out.lineSep)
|
|
} else {
|
|
s.out.skipSep = false
|
|
}
|
|
write(s, "\n")
|
|
for i := 0; i < s.out.indent {
|
|
s.out.sb.writeChar('\t')
|
|
}
|
|
}
|
|
|
|
write(s GeneratorState, str string) {
|
|
s.out.sb.write(str)
|
|
}
|
|
|
|
indent(s GeneratorState, lineSep string) {
|
|
s.out.lineSep = lineSep
|
|
s.out.skipSep = true
|
|
s.out.indent += 1
|
|
}
|
|
|
|
unindent(s GeneratorState) {
|
|
s.out.lineSep = ""
|
|
s.out.indent -= 1
|
|
}
|
|
|
|
push(s GeneratorState, cb CodeBuilder) {
|
|
prev := s.out
|
|
s.out = cb
|
|
return prev
|
|
}
|
|
|
|
restore(s GeneratorState, cb CodeBuilder) {
|
|
s.out = cb
|
|
}
|
|
|
|
unpackStruct(s GeneratorState, tag Tag) {
|
|
assert(tag.kind == TagKind.struct_)
|
|
return s.entities[tag.q].as(StructDef)
|
|
}
|
|
|
|
unpackModule(s GeneratorState, tag Tag) {
|
|
assert(tag.kind == TagKind.moduleOut)
|
|
return s.entities[tag.q].as(ModuleDef)
|
|
}
|
|
}
|