From c4af443ef04baeac7c2d4e13540db92156f0e488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20L=C3=B6her?= Date: Mon, 5 Dec 2022 12:25:33 +0100 Subject: [PATCH] Add 08_jumps. --- 08_jumps/bench.py | 54 ++++++++++++++ 08_jumps/blink.py | 38 ++++++++++ 08_jumps/soc.py | 176 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 08_jumps/bench.py create mode 100644 08_jumps/blink.py create mode 100644 08_jumps/soc.py diff --git a/08_jumps/bench.py b/08_jumps/bench.py new file mode 100644 index 0000000..e7214e6 --- /dev/null +++ b/08_jumps/bench.py @@ -0,0 +1,54 @@ +from amaranth import * +from amaranth.sim import * + +from soc import SOC + +soc = SOC() + +sim = Simulator(soc) + +prev_clk = 0 + +def proc(): + while True: + global prev_clk + clk = yield soc.slow_clk + if prev_clk == 0 and prev_clk != clk: + state = (yield soc.state) + if state == 2: + print("-- NEW CYCLE -----------------------") + print(" F: LEDS = {:05b}".format((yield soc.leds))) + print(" F: pc={}".format((yield soc.pc))) + print(" F: instr={:#032b}".format((yield soc.instr))) + if (yield soc.isALUreg): + print(" ALUreg rd={} rs1={} rs2={} funct3={}".format( + (yield soc.rdId), (yield soc.rs1Id), (yield soc.rs2Id), + (yield soc.funct3))) + if (yield soc.isALUimm): + print(" ALUimm rd={} rs1={} imm={} funct3={}".format( + (yield soc.rdId), (yield soc.rs1Id), (yield soc.Iimm), + (yield soc.funct3))) + if (yield soc.isLoad): + print(" LOAD") + if (yield soc.isStore): + print(" STORE") + if (yield soc.isSystem): + print(" SYSTEM") + break + if state == 4: + print(" R: LEDS = {:05b}".format((yield soc.leds))) + print(" R: rs1={}".format((yield soc.rs1))) + print(" R: rs2={}".format((yield soc.rs2))) + if state == 1: + print(" E: LEDS = {:05b}".format((yield soc.leds))) + print(" E: Writeback x{} = {:032b}".format((yield soc.rdId), + (yield soc.writeBackData))) + yield + prev_clk = clk + +sim.add_clock(1e-6) +sim.add_sync_process(proc) + +with sim.write_vcd('bench.vcd', 'bench.gtkw', traces=soc.ports): + # Let's run for a quite long time + sim.run_until(2, ) diff --git a/08_jumps/blink.py b/08_jumps/blink.py new file mode 100644 index 0000000..518fef0 --- /dev/null +++ b/08_jumps/blink.py @@ -0,0 +1,38 @@ +from amaranth import * +from amaranth_boards.arty_a7 import * + +from soc import SOC + +# A platform contains board specific information about FPGA pin assignments, +# toolchain and specific information for uploading the bitfile. +platform = ArtyA7_35Platform(toolchain="Symbiflow") + +# We need a top level module +m = Module() + +# This is the instance of our SOC +soc = SOC() + +# The SOC is turned into a submodule (fragment) of our top level module. +m.submodules.soc = soc + +# The platform allows access to the various resources defined by the board +# definition from amaranth-boards. +led0 = platform.request('led', 0) +led1 = platform.request('led', 1) +led2 = platform.request('led', 2) +led3 = platform.request('led', 3) +rgb = platform.request('rgb_led') + +# We connect the SOC leds signal to the various LEDs on the board. +m.d.comb += [ + led0.o.eq(soc.leds[0]), + led1.o.eq(soc.leds[1]), + led1.o.eq(soc.leds[2]), + led1.o.eq(soc.leds[3]), + rgb.r.o.eq(soc.leds[4]), +] + +# To generate the bitstream, we build() the platform using our top level +# module m. +platform.build(m, do_program=False) diff --git a/08_jumps/soc.py b/08_jumps/soc.py new file mode 100644 index 0000000..c674317 --- /dev/null +++ b/08_jumps/soc.py @@ -0,0 +1,176 @@ +import sys +from amaranth import * + +from clockworks import Clockworks +from riscv_assembler import RiscvAssembler + +class SOC(Elaboratable): + + def __init__(self): + + self.leds = Signal(5) + + # Signals in this list can easily be plotted as vcd traces + self.ports = [] + + a = RiscvAssembler() + a.read("""begin: + ADD x1, x0, x0 + l0: + ADDI x1, x1, 1 + JAL x0, l0 + EBREAK + """) + + a.assemble() + self.sequence = a.mem + print("memory = {}".format(self.sequence)) + + def elaborate(self, platform): + + m = Module() + + cw = Clockworks(slow=21, sim_slow=10) + m.submodules.cw = cw + + # Program counter + pc = Signal(32) + + # Current instruction + instr = Signal(32, reset=0b0110011) + + # Instruction memory initialised with above 'sequence' + mem = Array([Signal(32, reset=x, name="mem") for x in self.sequence]) + + # Register bank + regs = Array([Signal(32, name="x"+str(x)) for x in range(32)]) + rs1 = Signal(32) + rs2 = Signal(32) + + # ALU registers + aluOut = Signal(32) + + # Opcode decoder + isALUreg = (instr[0:7] == 0b0110011) + isALUimm = (instr[0:7] == 0b0010011) + isBranch = (instr[0:7] == 0b1100011) + isJALR = (instr[0:7] == 0b1100111) + isJAL = (instr[0:7] == 0b1101111) + isAUIPC = (instr[0:7] == 0b0010111) + isLUI = (instr[0:7] == 0b0110111) + isLoad = (instr[0:7] == 0b0000011) + isStore = (instr[0:7] == 0b0100011) + isSystem = (instr[0:7] == 0b1110011) + + # Immediate format decoder + Uimm = (Cat(Repl(0, 12), instr[12:32])) + Iimm = (Cat(instr[20:31], Repl(instr[31], 21))) + Simm = (Cat(instr[7:12], Cat(instr[25:31], Repl(instr[31], 21)))), + Bimm = (Cat(0, Cat(instr[8:12], Cat(instr[25:31], Cat( + instr[7], Repl(instr[31], 20)))))) + Jimm = (Cat(0, Cat(instr[21:31], Cat(instr[20], Cat( + instr[12:20], Repl(instr[31], 12)))))) + + # Register addresses decoder + rs1Id = (instr[15:20]) + rs2Id = (instr[20:25]) + rdId = ( instr[7:12]) + + # Function code decdore + funct3 = (instr[12:15]) + funct7 = (instr[25:32]) + + # ALU + aluIn1 = rs1 + aluIn2 = Mux(isALUreg, rs2, Iimm) + shamt = Mux(isALUreg, rs2[0:5], instr[20:25]) + + with m.Switch(funct3) as alu: + with m.Case(0b000): + m.d.comb += aluOut.eq(Mux(funct7[5] & instr[5], + (aluIn1 - aluIn2), (aluIn1 + aluIn2))) + with m.Case(0b001): + m.d.comb += aluOut.eq(aluIn1 << shamt) + with m.Case(0b010): + m.d.comb += aluOut.eq(aluIn1.as_signed() < aluIn2.as_signed()) + with m.Case(0b011): + m.d.comb += aluOut.eq(aluIn1 < aluIn2) + with m.Case(0b100): + m.d.comb += aluOut.eq(aluIn1 ^ aluIn2) + with m.Case(0b101): + m.d.comb += aluOut.eq(Mux( + funct7[5], + (aluIn1.as_signed() >> shamt), # arithmetic right shift + (aluIn1.as_unsigned() >> shamt))) # logical right shift + with m.Case(0b110): + m.d.comb += aluOut.eq(aluIn1 | aluIn2) + with m.Case(0b111): + m.d.comb += aluOut.eq(aluIn1 & aluIn2) + + # Next program counter is either next intstruction or depends on + # jump target + nextPc = Mux(isJAL, pc + Jimm, Mux(isJALR, rs1 + Iimm, pc + 4)) + + # Main state machine + with m.FSM(reset="FETCH_INSTR", domain="slow") as fsm: + with m.State("FETCH_INSTR"): + m.d.slow += instr.eq(mem[pc[2:32]]) + m.next = "FETCH_REGS" + with m.State("FETCH_REGS"): + m.d.slow += [ + rs1.eq(regs[rs1Id]), + rs2.eq(regs[rs2Id]) + ] + m.next = "EXECUTE" + with m.State("EXECUTE"): + m.d.slow += pc.eq(nextPc) + m.next = "FETCH_INSTR" + + # Register write back + writeBackData = Mux((isJAL | isJALR), (pc + 4), aluOut) + writeBackEn = fsm.ongoing("EXECUTE") & ( + isALUreg | + isALUimm | + isJAL | + isJALR) + + with m.If(writeBackEn & (rdId != 0)): + m.d.slow += regs[rdId].eq(writeBackData) + # Assign writeBackData to leds to see what is happening + m.d.slow += self.leds.eq(writeBackData) + + # Export signals for simulation + def export(signal, name): + if type(signal) is not Signal: + newsig = Signal(signal.shape(), name = name) + m.d.comb += newsig.eq(signal) + else: + newsig = signal + self.ports.append(newsig) + setattr(self, name, newsig) + + if platform is None: + export(ClockSignal("slow"), "slow_clk") + export(pc, "pc") + export(instr, "instr") + export(isALUreg, "isALUreg") + export(isALUimm, "isALUimm") + export(isJAL, "isJAL") + export(isJALR, "isJALR") + export(isLoad, "isLoad") + export(isStore, "isStore") + export(isSystem, "isSystem") + export(rdId, "rdId") + export(rs1Id, "rs1Id") + export(rs2Id, "rs2Id") + export(Iimm, "Iimm") + export(funct3, "funct3") + export(rdId, "rdId") + export(rs1, "rs1") + export(rs2, "rs2") + export(writeBackData, "writeBackData") + export(writeBackEn, "writeBackEn") + export(aluOut, "aluOut") + export((1 << fsm.state), "state") + + return m