diff --git a/artiq/gateware/wrpll/__init__.py b/artiq/gateware/wrpll/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/wrpll/filters.py b/artiq/gateware/wrpll/filters.py new file mode 100644 index 000000000..58b664754 --- /dev/null +++ b/artiq/gateware/wrpll/filters.py @@ -0,0 +1,62 @@ +helper_xn1 = 0 +helper_xn2 = 0 +helper_yn0 = 0 +helper_yn1 = 0 +helper_yn2 = 0 + +previous_helper_tag = 0 + +main_xn1 = 0 +main_xn2 = 0 +main_yn0 = 0 +main_yn1 = 0 +main_yn2 = 0 + + +def helper(helper_tag): + global helper_xn1, helper_xn2, helper_yn0, \ + helper_yn1, helper_yn2, previous_helper_tag + + helper_xn0 = helper_tag - previous_helper_tag - 32768 + + helper_yr = 4294967296 + + helper_yn2 = helper_yn1 + helper_yn1 = helper_yn0 + helper_yn0 = ( + ((284885689*((217319150*helper_xn0 >> 44) + + (-17591968725107*helper_xn1 >> 44))) >> 44) + + (-35184372088832*helper_yn1 >> 44) - + (17592186044416*helper_yn2 >> 44)) + + helper_xn2 = helper_xn1 + helper_xn1 = helper_xn0 + + previous_helper_tag = helper_tag + + helper_yn0 = min(helper_yn0, helper_yr) + helper_yn0 = max(helper_yn0, 0 - helper_yr) + + return helper_yn0 + + +def main(main_xn0): + global main_xn1, main_xn2, main_yn0, main_yn1, main_yn2 + + main_yr = 4294967296 + + main_yn2 = main_yn1 + main_yn1 = main_yn0 + main_yn0 = ( + ((133450380908*(((35184372088832*main_xn0) >> 44) + + ((17592186044417*main_xn1) >> 44))) >> 44) + + ((29455872930889*main_yn1) >> 44) - + ((12673794781453*main_yn2) >> 44)) + + main_xn2 = main_xn1 + main_xn1 = main_xn0 + + main_yn0 = min(main_yn0, main_yr) + main_yn0 = max(main_yn0, 0 - main_yr) + + return main_yn0 diff --git a/artiq/gateware/wrpll/si549.py b/artiq/gateware/wrpll/si549.py new file mode 100644 index 000000000..652e3f0b5 --- /dev/null +++ b/artiq/gateware/wrpll/si549.py @@ -0,0 +1,265 @@ +from migen import * +from migen.genlib.fsm import * +from migen.genlib.cdc import MultiReg, PulseSynchronizer, BlindTransfer + +from misoc.interconnect.csr import * + + +class I2CClockGen(Module): + def __init__(self, width): + self.load = Signal(width) + self.clk2x = Signal() + + cnt = Signal.like(self.load) + self.comb += [ + self.clk2x.eq(cnt == 0), + ] + self.sync += [ + If(self.clk2x, + cnt.eq(self.load), + ).Else( + cnt.eq(cnt - 1), + ) + ] + + +class I2CMasterMachine(Module): + def __init__(self, clock_width): + self.scl = Signal(reset=1) + self.sda_o = Signal(reset=1) + self.sda_i = Signal() + + self.submodules.cg = CEInserter()(I2CClockGen(clock_width)) + self.idle = Signal() + self.start = Signal() + self.stop = Signal() + self.write = Signal() + self.read = Signal() + self.ack = Signal() + self.data = Signal(8) + + ### + + busy = Signal() + bits = Signal(4) + + fsm = CEInserter()(FSM("IDLE")) + self.submodules += fsm + + fsm.act("IDLE", + If(self.start, + NextState("START0"), + ).Elif(self.stop & self.start, + NextState("RESTART0"), + ).Elif(self.stop, + NextState("STOP0"), + ).Elif(self.write, + NextValue(bits, 8), + NextState("WRITE0"), + ).Elif(self.read, + NextValue(bits, 8), + NextState("READ0"), + ) + ) + + fsm.act("START0", + NextValue(self.scl, 1), + NextState("START1")) + fsm.act("START1", + NextValue(self.sda_o, 0), + NextState("IDLE")) + + fsm.act("RESTART0", + NextValue(self.scl, 0), + NextState("RESTART1")) + fsm.act("RESTART1", + NextValue(self.sda_o, 1), + NextState("START0")) + + fsm.act("STOP0", + NextValue(self.scl, 0), + NextState("STOP1")) + fsm.act("STOP1", + NextValue(self.scl, 1), + NextValue(self.sda_o, 0), + NextState("STOP2")) + fsm.act("STOP2", + NextValue(self.sda_o, 1), + NextState("IDLE")) + + fsm.act("WRITE0", + NextValue(self.scl, 0), + If(bits == 0, + NextValue(self.sda_o, 1), + NextState("READACK0"), + ).Else( + NextValue(self.sda_o, self.data[7]), + NextState("WRITE1"), + ) + ) + fsm.act("WRITE1", + NextValue(self.scl, 1), + NextValue(self.data[1:], self.data[:-1]), + NextValue(bits, bits - 1), + NextState("WRITE0"), + ) + fsm.act("READACK0", + NextValue(self.scl, 1), + NextState("READACK1"), + ) + fsm.act("READACK1", + NextValue(self.ack, ~self.sda_i), + NextState("IDLE") + ) + + fsm.act("READ0", + NextValue(self.scl, 0), + NextState("READ1"), + ) + fsm.act("READ1", + NextValue(self.data[0], self.sda_i), + NextValue(self.scl, 0), + If(bits == 0, + NextValue(self.sda_o, ~self.ack), + NextState("WRITEACK0"), + ).Else( + NextValue(self.sda_o, 1), + NextState("READ2"), + ) + ) + fsm.act("READ2", + NextValue(self.scl, 1), + NextValue(self.data[:-1], self.data[1:]), + NextValue(bits, bits - 1), + NextState("READ1"), + ) + fsm.act("WRITEACK0", + NextValue(self.scl, 1), + NextState("IDLE"), + ) + + run = Signal() + self.comb += [ + run.eq(self.start | self.stop | self.write | self.read), + self.idle.eq(~run & fsm.ongoing("IDLE")), + self.cg.ce.eq(~self.idle), + fsm.ce.eq(run | self.cg.clk2x), + ] + + +class ADPLLProgrammer(Module): + def __init__(self): + self.i2c_divider = Signal(16) + self.i2c_address = Signal(7) + + self.adpll = Signal(24) + self.stb = Signal() + self.busy = Signal() + self.nack = Signal() + + self.scl = Signal() + self.sda_i = Signal() + self.sda_o = Signal() + + self.scl.attr.add("no_retiming") + self.sda_o.attr.add("no_retiming") + + # # # + + master = I2CMasterMachine(16) + self.submodules += master + + self.comb += [ + master.cg.load.eq(self.i2c_divider.storage), + self.scl.eq(master.scl), + master.sda_i.eq(self.sda_i), + self.sda_o.eq(master.sda_o) + ] + + +class Si549(Module, AutoCSR): + def __init__(self, pads): + self.gpio_enable = CSRStorage(reset=1) + self.gpio_in = CSRStatus(2) + self.gpio_out = CSRStorage(2) + self.gpio_oe = CSRStorage(2) + + self.i2c_divider = CSRStorage(16) + self.i2c_address = CSRStorage(7) + self.errors = CSR(2) + + # in helper clock domain + self.adpll = Signal(24) + self.adpll_stb = Signal() + + # # # + + programmer = ClockDomainsRenamer("helper")(ADPLLProgrammer()) + self.submodules += programmer + + self.i2c_divider.storage.attr.add("no_retiming") + self.i2c_address.storage.attr.add("no_retiming") + self.specials += [ + MultiReg(self.i2c_divider.storage, programmer.i2c_divider, "helper"), + MultiReg(self.i2c_address.storage, programmer.i2c_address, "helper") + ] + self.comb += [ + programmer.adpll.eq(self.adpll), + programmer.adpll_stb.eq(self.adpll_stb) + ] + + self.gpio_enable.storage.attr.add("no_retiming") + self.gpio_out.storage.attr.add("no_retiming") + self.gpio_oe.storage.attr.add("no_retiming") + + # SCL GPIO and mux + ts_scl = TSTriple(1) + self.specials += ts_scl.get_tristate(pads.scl) + + status = Signal() + self.comb += self.gpio_in.status[0].eq(status) + + self.specials += MultiReg(ts_scl.i, status) + self.comb += [ + If(self.gpio_enable.storage, + ts_scl.o.eq(self.gpio_out.storage[0]), + ts_scl.oe.eq(self.gpio_oe.storage[0]) + ).Else( + ts_scl.o.eq(programmer.scl), + ts_scl.oe.eq(1) + ) + ] + + # SDA GPIO and mux + ts_sda = TSTriple(1) + self.specials += ts_sda.get_tristate(pads.sda) + + status = Signal() + self.comb += self.gpio_in.status[1].eq(status) + + self.specials += MultiReg(ts_sda.i, status) + self.comb += [ + If(self.gpio_enable.storage, + ts_sda.o.eq(self.gpio_out.storage[1]), + ts_sda.oe.eq(self.gpio_oe.storage[1]) + ).Else( + ts_sda.o.eq(0), + ts_sda.oe.eq(~programmer.sda_o) + ) + ] + self.specials += MultiReg(ts_sda.i, programmer.sda_i, "helper") + + # Error reporting + collision_cdc = BlindTransfer("helper", "sys") + self.submodules += collision_cdc + self.comb += collision_cdc.i.eq(programmer.stb & programmer.busy) + + nack_cdc = PulseSynchronizer("helper", "sys") + self.submodules += nack_cdc + self.comb += nack_cdc.i.eq(programmer.nack) + + for n, trig in enumerate([collision_cdc.o, nack_cdc.o]): + self.sync += [ + If(self.errors.re & self.errors.r[n], self.errors.w[n].eq(0)), + If(trig, self.errors.w[n].eq(1)) + ] diff --git a/artiq/gateware/wrpll/thls.py b/artiq/gateware/wrpll/thls.py new file mode 100644 index 000000000..3f5aa6425 --- /dev/null +++ b/artiq/gateware/wrpll/thls.py @@ -0,0 +1,636 @@ +import inspect +import ast +from copy import copy +import operator +from functools import reduce +from collections import OrderedDict + +from migen import * +from migen.genlib.fsm import * + + +class Isn: + def __init__(self, immediate=None, inputs=None, outputs=None): + if inputs is None: + inputs = [] + if outputs is None: + outputs = [] + self.immediate = immediate + self.inputs = inputs + self.outputs = outputs + + def __repr__(self): + r = "<" + r += self.__class__.__name__ + if self.immediate is not None: + r += " (" + str(self.immediate) + ")" + for inp in self.inputs: + r += " r" + str(inp) + if self.outputs: + r += " ->" + for outp in self.outputs: + r += " r" + str(outp) + r += ">" + return r + + +class NopIsn(Isn): + opcode = 0 + +class AddIsn(Isn): + opcode = 1 + +class SubIsn(Isn): + opcode = 2 + +class MulShiftIsn(Isn): + opcode = 3 + +# opcode = 4: MulShift with alternate shift + +class MinIsn(Isn): + opcode = 5 + +class MaxIsn(Isn): + opcode = 6 + +class CopyIsn(Isn): + opcode = 7 + +class InputIsn(Isn): + opcode = 8 + +class OutputIsn(Isn): + opcode = 9 + +class EndIsn(Isn): + opcode = 10 + + +class ASTCompiler: + def __init__(self): + self.program = [] + self.data = [] + self.next_ssa_reg = -1 + self.constants = dict() + self.names = dict() + self.globals = OrderedDict() + + def get_ssa_reg(self): + r = self.next_ssa_reg + self.next_ssa_reg -= 1 + return r + + def add_global(self, name): + if name not in self.globals: + r = len(self.data) + self.data.append(0) + self.names[name] = r + self.globals[name] = r + + def input(self, name): + target = self.get_ssa_reg() + self.program.append(InputIsn(outputs=[target])) + self.names[name] = target + + def emit(self, node): + if isinstance(node, ast.BinOp): + if isinstance(node.op, ast.RShift): + if not isinstance(node.left, ast.BinOp) or not isinstance(node.left.op, ast.Mult): + raise NotImplementedError + if not isinstance(node.right, ast.Num): + raise NotImplementedError + left = self.emit(node.left.left) + right = self.emit(node.left.right) + cons = lambda **kwargs: MulShiftIsn(immediate=node.right.n, **kwargs) + else: + left = self.emit(node.left) + right = self.emit(node.right) + if isinstance(node.op, ast.Add): + cons = AddIsn + elif isinstance(node.op, ast.Sub): + cons = SubIsn + elif isinstance(node.op, ast.Mult): + cons = lambda **kwargs: MulShiftIsn(immediate=0, **kwargs) + else: + raise NotImplementedError + output = self.get_ssa_reg() + self.program.append(cons(inputs=[left, right], outputs=[output])) + return output + elif isinstance(node, ast.Call): + if not isinstance(node.func, ast.Name): + raise NotImplementedError + funcname = node.func.id + if node.keywords: + raise NotImplementedError + inputs = [self.emit(x) for x in node.args] + if funcname == "min": + cons = MinIsn + elif funcname == "max": + cons = MaxIsn + else: + raise NotImplementedError + output = self.get_ssa_reg() + self.program.append(cons(inputs=inputs, outputs=[output])) + return output + elif isinstance(node, (ast.Num, ast.UnaryOp)): + if isinstance(node, ast.UnaryOp): + if not isinstance(node.operand, ast.Num): + raise NotImplementedError + if isinstance(node.op, ast.UAdd): + transform = lambda x: x + elif isinstance(node.op, ast.USub): + transform = operator.neg + elif isinstance(node.op, ast.Invert): + transform = operator.invert + else: + raise NotImplementedError + node = node.operand + else: + transform = lambda x: x + n = transform(node.n) + if n in self.constants: + return self.constants[n] + else: + r = len(self.data) + self.data.append(n) + self.constants[n] = r + return r + elif isinstance(node, ast.Name): + return self.names[node.id] + elif isinstance(node, ast.Assign): + output = self.emit(node.value) + for target in node.targets: + assert isinstance(target, ast.Name) + self.names[target.id] = output + elif isinstance(node, ast.Return): + value = self.emit(node.value) + self.program.append(OutputIsn(inputs=[value])) + elif isinstance(node, ast.Global): + pass + else: + raise NotImplementedError + + +class Processor: + def __init__(self, data_width=32, multiplier_stages=2): + self.data_width = data_width + self.multiplier_stages = multiplier_stages + self.multiplier_shifts = [] + self.program_rom_size = None + self.data_ram_size = None + self.opcode_bits = 4 + self.reg_bits = None + + def get_instruction_latency(self, isn): + return { + AddIsn: 2, + SubIsn: 2, + MulShiftIsn: 1 + self.multiplier_stages, + MinIsn: 2, + MaxIsn: 2, + CopyIsn: 1, + InputIsn: 1 + }[isn.__class__] + + def encode_instruction(self, isn, exit): + opcode = isn.opcode + if isn.immediate is not None and not isinstance(isn, MulShiftIsn): + r0 = isn.immediate + if len(isn.inputs) >= 1: + r1 = isn.inputs[0] + else: + r1 = 0 + else: + if len(isn.inputs) >= 1: + r0 = isn.inputs[0] + else: + r0 = 0 + if len(isn.inputs) >= 2: + r1 = isn.inputs[1] + else: + r1 = 0 + r = 0 + for value, bits in ((exit, self.reg_bits), (r1, self.reg_bits), (r0, self.reg_bits), (opcode, self.opcode_bits)): + r <<= bits + r |= value + return r + + def instruction_bits(self): + return 3*self.reg_bits + self.opcode_bits + + def implement(self, program, data): + return ProcessorImpl(self, program, data) + + +class Scheduler: + def __init__(self, processor, reserved_data, program): + self.processor = processor + self.reserved_data = reserved_data + self.used_registers = set(range(self.reserved_data)) + self.exits = dict() + self.program = program + self.remaining = copy(program) + self.output = [] + + def allocate_register(self): + r = min(set(range(max(self.used_registers) + 2)) - self.used_registers) + self.used_registers.add(r) + return r + + def free_register(self, r): + assert r >= self.reserved_data + self.used_registers.discard(r) + + def find_inputs(self, cycle, isn): + mapped_inputs = [] + for inp in isn.inputs: + if inp >= 0: + mapped_inputs.append(inp) + else: + found = False + for i in range(cycle): + if i in self.exits: + r, rm = self.exits[i] + if r == inp: + mapped_inputs.append(rm) + found = True + break + if not found: + return None + return mapped_inputs + + def schedule_one(self, isn): + cycle = len(self.output) + mapped_inputs = self.find_inputs(cycle, isn) + if mapped_inputs is None: + return False + + if isn.outputs: + # check that exit slot is free + latency = self.processor.get_instruction_latency(isn) + exit = cycle + latency + if exit in self.exits: + return False + + # avoid RAW hazard with global writeback + for output in isn.outputs: + if output >= 0: + for risn in self.remaining: + for inp in risn.inputs: + if inp == output: + return False + + # Instruction can be scheduled + + self.remaining.remove(isn) + + for inp, minp in zip(isn.inputs, mapped_inputs): + can_free = inp < 0 and all(inp != rinp for risn in self.remaining for rinp in risn.inputs) + if can_free: + self.free_register(minp) + + if isn.outputs: + assert len(isn.outputs) == 1 + if isn.outputs[0] < 0: + output = self.allocate_register() + else: + output = isn.outputs[0] + self.exits[exit] = (isn.outputs[0], output) + self.output.append(isn.__class__(immediate=isn.immediate, inputs=mapped_inputs)) + + return True + + def schedule(self): + while self.remaining: + success = False + for isn in self.remaining: + if self.schedule_one(isn): + success = True + break + if not success: + self.output.append(NopIsn()) + self.output += [NopIsn()]*(max(self.exits.keys()) - len(self.output) + 1) + return self.output + + +class CompiledProgram: + def __init__(self, processor, program, exits, data, glbs): + self.processor = processor + self.program = program + self.exits = exits + self.data = data + self.globals = glbs + + def pretty_print(self): + for cycle, isn in enumerate(self.program): + l = "{:4d} {:15}".format(cycle, str(isn)) + if cycle in self.exits: + l += " -> r{}".format(self.exits[cycle]) + print(l) + + def dimension_processor(self): + self.processor.program_rom_size = len(self.program) + self.processor.data_ram_size = len(self.data) + self.processor.reg_bits = (self.processor.data_ram_size - 1).bit_length() + for isn in self.program: + if isinstance(isn, MulShiftIsn) and isn.immediate not in self.processor.multiplier_shifts: + self.processor.multiplier_shifts.append(isn.immediate) + + def encode(self): + r = [] + for i, isn in enumerate(self.program): + exit = self.exits.get(i, 0) + r.append(self.processor.encode_instruction(isn, exit)) + return r + + +def compile(processor, function): + node = ast.parse(inspect.getsource(function)) + assert isinstance(node, ast.Module) + assert len(node.body) == 1 + node = node.body[0] + assert isinstance(node, ast.FunctionDef) + assert len(node.args.args) == 1 + arg = node.args.args[0].arg + body = node.body + + astcompiler = ASTCompiler() + for node in body: + if isinstance(node, ast.Global): + for name in node.names: + astcompiler.add_global(name) + arg_r = astcompiler.input(arg) + for node in body: + astcompiler.emit(node) + if isinstance(node, ast.Return): + break + for glbl, location in astcompiler.globals.items(): + new_location = astcompiler.names[glbl] + if new_location != location: + astcompiler.program.append(CopyIsn(inputs=[new_location], outputs=[location])) + + scheduler = Scheduler(processor, len(astcompiler.data), astcompiler.program) + scheduler.schedule() + + program = copy(scheduler.output) + program.append(EndIsn()) + + max_reg = max(max(max(isn.inputs + [0]) for isn in program), max(v[1] for k, v in scheduler.exits.items())) + + return CompiledProgram( + processor=processor, + program=program, + exits={k: v[1] for k, v in scheduler.exits.items()}, + data=astcompiler.data + [0]*(max_reg - len(astcompiler.data) + 1), + glbs=astcompiler.globals) + + +class BaseUnit(Module): + def __init__(self, data_width): + self.stb_i = Signal() + self.i0 = Signal((data_width, True)) + self.i1 = Signal((data_width, True)) + self.stb_o = Signal() + self.o = Signal((data_width, True)) + + +class NopUnit(BaseUnit): + pass + + +class OpUnit(BaseUnit): + def __init__(self, op, data_width, stages): + BaseUnit.__init__(self, data_width) + + o = op(self.i0, self.i1) + stb_o = self.stb_i + for i in range(stages): + n_o = Signal(data_width) + n_stb_o = Signal() + self.sync += [ + n_o.eq(o), + n_stb_o.eq(stb_o) + ] + o = n_o + stb_o = n_stb_o + self.comb += [ + self.o.eq(o), + self.stb_o.eq(stb_o) + ] + + +class SelectUnit(BaseUnit): + def __init__(self, op, data_width): + BaseUnit.__init__(self, data_width) + + self.sync += [ + self.stb_o.eq(self.stb_i), + If(op(self.i0, self.i1), + self.o.eq(self.i0) + ).Else( + self.o.eq(self.i1) + ) + ] + + +class CopyUnit(BaseUnit): + def __init__(self, data_width): + BaseUnit.__init__(self, data_width) + + self.comb += [ + self.stb_o.eq(self.stb_i), + self.o.eq(self.i0) + ] + + +class InputUnit(BaseUnit): + def __init__(self, data_width, input_stb, input): + BaseUnit.__init__(self, data_width) + self.buffer = Signal(data_width) + + self.comb += [ + self.stb_o.eq(self.stb_i), + self.o.eq(self.buffer) + ] + + +class OutputUnit(BaseUnit): + def __init__(self, data_width, output_stb, output): + BaseUnit.__init__(self, data_width) + + self.sync += [ + output_stb.eq(self.stb_i), + output.eq(self.i0) + ] + + +class ProcessorImpl(Module): + def __init__(self, pd, program, data): + self.input_stb = Signal() + self.input = Signal((pd.data_width, True)) + + self.output_stb = Signal() + self.output = Signal((pd.data_width, True)) + + self.busy = Signal() + + # # # + + program_mem = Memory(pd.instruction_bits(), pd.program_rom_size, init=program) + data_mem0 = Memory(pd.data_width, pd.data_ram_size, init=data) + data_mem1 = Memory(pd.data_width, pd.data_ram_size, init=data) + self.specials += program_mem, data_mem0, data_mem1 + + pc = Signal(pd.instruction_bits()) + pc_next = Signal.like(pc) + pc_en = Signal() + self.sync += pc.eq(pc_next) + self.comb += [ + If(pc_en, + pc_next.eq(pc + 1) + ).Else( + pc_next.eq(0) + ) + ] + program_mem_port = program_mem.get_port() + self.specials += program_mem_port + self.comb += program_mem_port.adr.eq(pc_next) + + s = 0 + opcode = Signal(pd.opcode_bits) + self.comb += opcode.eq(program_mem_port.dat_r[s:s+pd.opcode_bits]) + s += pd.opcode_bits + r0 = Signal(pd.reg_bits) + self.comb += r0.eq(program_mem_port.dat_r[s:s+pd.reg_bits]) + s += pd.reg_bits + r1 = Signal(pd.reg_bits) + self.comb += r1.eq(program_mem_port.dat_r[s:s+pd.reg_bits]) + s += pd.reg_bits + exit = Signal(pd.reg_bits) + self.comb += exit.eq(program_mem_port.dat_r[s:s+pd.reg_bits]) + + data_read_port0 = data_mem0.get_port() + data_read_port1 = data_mem1.get_port() + self.specials += data_read_port0, data_read_port1 + self.comb += [ + data_read_port0.adr.eq(r0), + data_read_port1.adr.eq(r1) + ] + + data_write_port = data_mem0.get_port(write_capable=True) + data_write_port_dup = data_mem1.get_port(write_capable=True) + self.specials += data_write_port, data_write_port_dup + self.comb += [ + data_write_port_dup.we.eq(data_write_port.we), + data_write_port_dup.adr.eq(data_write_port.adr), + data_write_port_dup.dat_w.eq(data_write_port.dat_w), + data_write_port.adr.eq(exit) + ] + + nop = NopUnit(pd.data_width) + adder = OpUnit(operator.add, pd.data_width, 1) + subtractor = OpUnit(operator.sub, pd.data_width, 1) + if pd.multiplier_shifts: + if len(pd.multiplier_shifts) != 1: + raise NotImplementedError + multiplier = OpUnit(lambda a, b: a * b >> pd.multiplier_shifts[0], + pd.data_width, pd.multiplier_stages) + else: + multiplier = NopUnit(pd.data_width) + minu = SelectUnit(operator.lt, pd.data_width) + maxu = SelectUnit(operator.gt, pd.data_width) + copier = CopyUnit(pd.data_width) + inu = InputUnit(pd.data_width, self.input_stb, self.input) + outu = OutputUnit(pd.data_width, self.output_stb, self.output) + units = [nop, adder, subtractor, multiplier, minu, maxu, copier, inu, outu] + self.submodules += units + + for unit in units: + self.sync += unit.stb_i.eq(0) + self.comb += [ + unit.i0.eq(data_read_port0.dat_r), + unit.i1.eq(data_read_port1.dat_r), + If(unit.stb_o, + data_write_port.we.eq(1), + data_write_port.dat_w.eq(unit.o) + ) + ] + + decode_table = [ + (NopIsn.opcode, nop), + (AddIsn.opcode, adder), + (SubIsn.opcode, subtractor), + (MulShiftIsn.opcode, multiplier), + (MulShiftIsn.opcode + 1, multiplier), + (MinIsn.opcode, minu), + (MaxIsn.opcode, maxu), + (CopyIsn.opcode, copier), + (InputIsn.opcode, inu), + (OutputIsn.opcode, outu) + ] + for allocated_opcode, unit in decode_table: + self.sync += If(pc_en & (opcode == allocated_opcode), unit.stb_i.eq(1)) + + fsm = FSM() + self.submodules += fsm + fsm.act("IDLE", + pc_en.eq(0), + NextValue(inu.buffer, self.input), + If(self.input_stb, NextState("PROCESSING")) + ) + fsm.act("PROCESSING", + self.busy.eq(1), + pc_en.eq(1), + If(opcode == EndIsn.opcode, + pc_en.eq(0), + NextState("IDLE") + ) + ) + + +a = 0 +b = 0 +c = 0 + +def foo(x): + global a, b, c + c = b + b = a + a = x + return 4748*a + 259*b - 155*c + + +def simple_test(x): + global a + a = a + (x*4 >> 1) + return a + + +if __name__ == "__main__": + proc = Processor() + cp = compile(proc, simple_test) + cp.pretty_print() + cp.dimension_processor() + print(cp.encode()) + proc_impl = proc.implement(cp.encode(), cp.data) + + def send_values(values): + for value in values: + yield proc_impl.input.eq(value) + yield proc_impl.input_stb.eq(1) + yield + yield proc_impl.input.eq(0) + yield proc_impl.input_stb.eq(0) + yield + while (yield proc_impl.busy): + yield + @passive + def receive_values(callback): + while True: + while not (yield proc_impl.output_stb): + yield + callback((yield proc_impl.output)) + yield + + run_simulation(proc_impl, [send_values([42, 40, 10, 10]), receive_values(print)])