]> Witch of Git - jade-rabbit/blob - core.py
Add basic multi-cycle core prototype
[jade-rabbit] / core.py
1 from enum import Enum
2 from nmigen import *
3 from nmigen.build import Platform
4 from nmigen.cli import main
5
6 class Op(Enum):
7 ADD = 0b000
8 NOR = 0b001
9 LW = 0b010
10 SW = 0b011
11 BEQ = 0b100
12 JALR = 0b101
13 HALT = 0b110
14 NOOP = 0b111
15
16 class Rw(Enum):
17 READ = 0
18 WRITE = 1
19
20 class JadeRabbitCore(Elaboratable):
21 def __init__(self):
22 self.pc = Signal(16)
23 self.halted = Signal()
24 self.addr = Signal(16)
25 self.d_in = Signal(32)
26 self.d_out = Signal(32)
27 self.en = Signal()
28 self.rw = Signal(Rw)
29 self.op = Signal(Op)
30 self.reg_a = Signal(range(8))
31 self.reg_b = Signal(range(8))
32 self.reg_d = Signal(range(8))
33 self.offset = Signal(16)
34
35 self.a = Signal(32)
36 self.b = Signal(32)
37 self.tmp = Signal(32)
38 # Cycles:
39 # Fetch - fetch data from memory
40 # Decode - read from registers
41 # Execute - do ALU work
42 # Memory (optional) - read/write memory if needed
43 # Halt
44 self.cycle = Signal(range(5))
45 self.regs = Array(Signal(32) for _ in range(8))
46
47 def decode(self, m: Module, inst: Value) -> None:
48 reg_a, reg_b = inst[19:22], inst[16:19]
49 m.d.sync += [
50 self.op.eq(inst[22:25]),
51 self.reg_a.eq(reg_a),
52 self.reg_b.eq(reg_b),
53 self.reg_d.eq(inst[0:3]),
54 self.offset.eq(inst[0:16]),
55 ]
56 m.d.sync += [
57 self.a.eq(self.regs[reg_a]),
58 self.b.eq(self.regs[reg_b]),
59 ]
60
61 def elaborate(self, platform: Platform) -> Module:
62 m = Module()
63 with m.If(~self.halted):
64 m.d.sync += self.cycle.eq(self.cycle + 1)
65 with m.If(self.cycle == 0):
66 m.d.sync += self.addr.eq(self.pc)
67 m.d.sync += self.rw.eq(Rw.READ)
68 m.d.sync += self.en.eq(True)
69 with m.Elif(self.cycle == 1):
70 m.d.sync += self.en.eq(False)
71 self.decode(m, self.d_in)
72 with m.Else():
73 with m.Switch(self.op):
74 with m.Case(Op.ADD):
75 with m.If(self.cycle == 2):
76 tmp = self.a + self.b
77 m.d.sync += self.regs[self.reg_d].eq(tmp)
78 m.d.sync += self.cycle.eq(0)
79 m.d.sync += self.pc.eq(self.pc + 1)
80 with m.Case(Op.NOR):
81 with m.If(self.cycle == 2):
82 tmp = ~(self.a | self.b)
83 m.d.sync += self.regs[self.reg_d].eq(tmp)
84 m.d.sync += self.cycle.eq(0)
85 m.d.sync += self.pc.eq(self.pc + 1)
86 with m.Case(Op.LW):
87 with m.If(self.cycle == 2):
88 m.d.sync += self.addr.eq(self.a + self.offset)
89 m.d.sync += self.en.eq(True)
90 m.d.sync += self.rw.eq(Rw.READ)
91 with m.If(self.cycle == 3):
92 m.d.sync += self.regs[self.reg_b].eq(self.d_in)
93 m.d.sync += self.en.eq(False)
94 m.d.sync += self.cycle.eq(0)
95 m.d.sync += self.pc.eq(self.pc + 1)
96 with m.Case(Op.SW):
97 with m.If(self.cycle == 2):
98 m.d.sync += self.addr.eq(self.a + self.offset)
99 m.d.sync += self.d_out.eq(self.b)
100 m.d.sync += self.en.eq(True)
101 m.d.sync += self.rw.eq(Rw.WRITE)
102 with m.If(self.cycle == 3):
103 m.d.sync += self.en.eq(False)
104 m.d.sync += self.cycle.eq(0)
105 m.d.sync += self.pc.eq(self.pc + 1)
106 with m.Case(Op.BEQ):
107 with m.If(self.cycle == 2):
108 dest = self.pc + 1 + self.offset
109 dest = Mux(self.a == self.b, dest, self.pc + 1)
110 m.d.sync += self.cycle.eq(0)
111 m.d.sync += self.pc.eq(dest)
112 with m.Case(Op.JALR):
113 with m.If(self.cycle == 2):
114 same_reg = self.reg_a == self.reg_b
115 dest = Mux(same_reg, self.pc + 1, self.a)
116 m.d.sync += self.regs[self.reg_b].eq(self.pc + 1)
117 m.d.sync += self.cycle.eq(0)
118 m.d.sync += self.pc.eq(dest)
119 with m.Case(Op.HALT):
120 with m.If(self.cycle == 2):
121 m.d.sync += self.halted.eq(True)
122 m.d.sync += self.cycle.eq(0)
123 m.d.sync += self.pc.eq(self.pc + 1)
124 with m.Case(Op.NOOP):
125 with m.If(self.cycle == 2):
126 m.d.sync += self.cycle.eq(0)
127 m.d.sync += self.pc.eq(self.pc + 1)
128 return m
129
130 def inputs(self):
131 return [self.d_in]
132
133 def outputs(self):
134 return [self.addr, self.d_out, self.rw, self.en]
135
136 def ports(self):
137 return self.inputs() + self.outputs()
138
139
140 if __name__ == '__main__':
141 core = JadeRabbitCore()
142 main(core, ports=core.ports())