From 1e0fb7c26638f5e42fa094f69ba8b7a35100e5b5 Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Sun, 5 Jan 2020 04:46:35 -0500 Subject: [PATCH] Add basic multi-cycle core prototype This multi-cycle core is inspired by the "6800 in nMigen" YouTube series. It's currently not optimized for frequencies or really anything, except convenience of implementation. There are no tests because it's late at night and I'm sleepy. :( --- core.py | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 core.py diff --git a/core.py b/core.py new file mode 100644 index 0000000..5d870fc --- /dev/null +++ b/core.py @@ -0,0 +1,142 @@ +from enum import Enum +from nmigen import * +from nmigen.build import Platform +from nmigen.cli import main + +class Op(Enum): + ADD = 0b000 + NOR = 0b001 + LW = 0b010 + SW = 0b011 + BEQ = 0b100 + JALR = 0b101 + HALT = 0b110 + NOOP = 0b111 + +class Rw(Enum): + READ = 0 + WRITE = 1 + +class JadeRabbitCore(Elaboratable): + def __init__(self): + self.pc = Signal(16) + self.halted = Signal() + self.addr = Signal(16) + self.d_in = Signal(32) + self.d_out = Signal(32) + self.en = Signal() + self.rw = Signal(Rw) + self.op = Signal(Op) + self.reg_a = Signal(range(8)) + self.reg_b = Signal(range(8)) + self.reg_d = Signal(range(8)) + self.offset = Signal(16) + + self.a = Signal(32) + self.b = Signal(32) + self.tmp = Signal(32) + # Cycles: + # Fetch - fetch data from memory + # Decode - read from registers + # Execute - do ALU work + # Memory (optional) - read/write memory if needed + # Halt + self.cycle = Signal(range(5)) + self.regs = Array(Signal(32) for _ in range(8)) + + def decode(self, m: Module, inst: Value) -> None: + reg_a, reg_b = inst[19:22], inst[16:19] + m.d.sync += [ + self.op.eq(inst[22:25]), + self.reg_a.eq(reg_a), + self.reg_b.eq(reg_b), + self.reg_d.eq(inst[0:3]), + self.offset.eq(inst[0:16]), + ] + m.d.sync += [ + self.a.eq(self.regs[reg_a]), + self.b.eq(self.regs[reg_b]), + ] + + def elaborate(self, platform: Platform) -> Module: + m = Module() + with m.If(~self.halted): + m.d.sync += self.cycle.eq(self.cycle + 1) + with m.If(self.cycle == 0): + m.d.sync += self.addr.eq(self.pc) + m.d.sync += self.rw.eq(Rw.READ) + m.d.sync += self.en.eq(True) + with m.Elif(self.cycle == 1): + m.d.sync += self.en.eq(False) + self.decode(m, self.d_in) + with m.Else(): + with m.Switch(self.op): + with m.Case(Op.ADD): + with m.If(self.cycle == 2): + tmp = self.a + self.b + m.d.sync += self.regs[self.reg_d].eq(tmp) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(self.pc + 1) + with m.Case(Op.NOR): + with m.If(self.cycle == 2): + tmp = ~(self.a | self.b) + m.d.sync += self.regs[self.reg_d].eq(tmp) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(self.pc + 1) + with m.Case(Op.LW): + with m.If(self.cycle == 2): + m.d.sync += self.addr.eq(self.a + self.offset) + m.d.sync += self.en.eq(True) + m.d.sync += self.rw.eq(Rw.READ) + with m.If(self.cycle == 3): + m.d.sync += self.regs[self.reg_b].eq(self.d_in) + m.d.sync += self.en.eq(False) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(self.pc + 1) + with m.Case(Op.SW): + with m.If(self.cycle == 2): + m.d.sync += self.addr.eq(self.a + self.offset) + m.d.sync += self.d_out.eq(self.b) + m.d.sync += self.en.eq(True) + m.d.sync += self.rw.eq(Rw.WRITE) + with m.If(self.cycle == 3): + m.d.sync += self.en.eq(False) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(self.pc + 1) + with m.Case(Op.BEQ): + with m.If(self.cycle == 2): + dest = self.pc + 1 + self.offset + dest = Mux(self.a == self.b, dest, self.pc + 1) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(dest) + with m.Case(Op.JALR): + with m.If(self.cycle == 2): + same_reg = self.reg_a == self.reg_b + dest = Mux(same_reg, self.pc + 1, self.a) + m.d.sync += self.regs[self.reg_b].eq(self.pc + 1) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(dest) + with m.Case(Op.HALT): + with m.If(self.cycle == 2): + m.d.sync += self.halted.eq(True) + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(self.pc + 1) + with m.Case(Op.NOOP): + with m.If(self.cycle == 2): + m.d.sync += self.cycle.eq(0) + m.d.sync += self.pc.eq(self.pc + 1) + return m + + def inputs(self): + return [self.d_in] + + def outputs(self): + return [self.addr, self.d_out, self.rw, self.en] + + def ports(self): + return self.inputs() + self.outputs() + + +if __name__ == '__main__': + core = JadeRabbitCore() + main(core, ports=core.ports()) -- 2.43.2