Add step 12 in top.
This commit is contained in:
		
							
								
								
									
										61
									
								
								12_size_optimisation/bench.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								12_size_optimisation/bench.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | from amaranth import * | ||||||
|  | from amaranth.sim import * | ||||||
|  |  | ||||||
|  | from soc import SOC | ||||||
|  |  | ||||||
|  | soc = SOC() | ||||||
|  |  | ||||||
|  | sim = Simulator(soc) | ||||||
|  |  | ||||||
|  | prev_clk = 0 | ||||||
|  |  | ||||||
|  | def proc(): | ||||||
|  |     cpu = soc.cpu | ||||||
|  |     mem = soc.memory | ||||||
|  |     while True: | ||||||
|  |         global prev_clk | ||||||
|  |         clk = yield soc.slow_clk | ||||||
|  |         if prev_clk == 0 and prev_clk != clk: | ||||||
|  |             state = (yield soc.cpu.fsm.state) | ||||||
|  |             if state == 2: | ||||||
|  |                 print("-- NEW CYCLE -----------------------") | ||||||
|  |                 print("  F: LEDS = {:05b}".format((yield soc.leds))) | ||||||
|  |                 print("  F: pc={}".format((yield cpu.pc))) | ||||||
|  |                 print("  F: instr={:#032b}".format((yield cpu.instr))) | ||||||
|  |                 if (yield cpu.isALUreg): | ||||||
|  |                     print("     ALUreg rd={} rs1={} rs2={} funct3={}".format( | ||||||
|  |                         (yield cpu.rdId), (yield cpu.rs1Id), (yield cpu.rs2Id), | ||||||
|  |                         (yield cpu.funct3))) | ||||||
|  |                 if (yield cpu.isALUimm): | ||||||
|  |                     print("     ALUimm rd={} rs1={} imm={} funct3={}".format( | ||||||
|  |                         (yield cpu.rdId), (yield cpu.rs1Id), (yield cpu.Iimm), | ||||||
|  |                         (yield cpu.funct3))) | ||||||
|  |                 if (yield cpu.isBranch): | ||||||
|  |                     print("    BRANCH rs1={} rs2={}".format( | ||||||
|  |                         (yield cpu.rs1Id), (yield cpu.rs2Id))) | ||||||
|  |                 if (yield cpu.isLoad): | ||||||
|  |                     print("    LOAD") | ||||||
|  |                 if (yield cpu.isStore): | ||||||
|  |                     print("    STORE") | ||||||
|  |                 if (yield cpu.isSystem): | ||||||
|  |                     print("    SYSTEM") | ||||||
|  |                     break | ||||||
|  |             if state == 4: | ||||||
|  |                 print("  R: LEDS = {:05b}".format((yield soc.leds))) | ||||||
|  |                 print("  R: rs1={}".format((yield cpu.rs1))) | ||||||
|  |                 print("  R: rs2={}".format((yield cpu.rs2))) | ||||||
|  |             if state == 1: | ||||||
|  |                 print("  E: LEDS = {:05b}".format((yield soc.leds))) | ||||||
|  |                 print("  E: Writeback x{} = {:032b}".format((yield cpu.rdId), | ||||||
|  |                                              (yield cpu.writeBackData))) | ||||||
|  |             if state == 8: | ||||||
|  |                 print("  NEW") | ||||||
|  |         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, ) | ||||||
							
								
								
									
										38
									
								
								12_size_optimisation/blink.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								12_size_optimisation/blink.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
							
								
								
									
										180
									
								
								12_size_optimisation/cpu.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								12_size_optimisation/cpu.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | |||||||
|  | from amaranth import * | ||||||
|  |  | ||||||
|  | class CPU(Elaboratable): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         self.mem_addr = Signal(32) | ||||||
|  |         self.mem_rstrb = Signal() | ||||||
|  |         self.mem_rdata = Signal(32) | ||||||
|  |         self.x1 = Signal(32) | ||||||
|  |         self.fsm = None | ||||||
|  |  | ||||||
|  |     def elaborate(self, platform): | ||||||
|  |         m = Module() | ||||||
|  |  | ||||||
|  |         # Program counter | ||||||
|  |         pc = Signal(32) | ||||||
|  |         self.pc = pc | ||||||
|  |  | ||||||
|  |         # Current instruction | ||||||
|  |         instr = Signal(32, reset=0b0110011) | ||||||
|  |         self.instr = instr | ||||||
|  |  | ||||||
|  |         # 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) | ||||||
|  |         takeBranch = 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) | ||||||
|  |         self.isALUreg = isALUreg | ||||||
|  |         self.isALUimm = isALUimm | ||||||
|  |         self.isBranch = isBranch | ||||||
|  |         self.isLoad = isLoad | ||||||
|  |         self.isStore = isStore | ||||||
|  |         self.isSystem = isSystem | ||||||
|  |  | ||||||
|  |         def Extend(x, n): | ||||||
|  |             return [x for i in range(n + 1)] | ||||||
|  |  | ||||||
|  |         # Immediate format decoder | ||||||
|  |         Uimm = Cat(Const(0, 12), instr[12:32]) | ||||||
|  |         Iimm = Cat(instr[20:31], *Extend(instr[31], 21)) | ||||||
|  |         Simm = Cat(instr[7:12], instr[25:31], *Extend(instr[31], 21)) | ||||||
|  |         Bimm = Cat(0, instr[8:12], instr[25:31], instr[7], | ||||||
|  |             *Extend(instr[31], 20)) | ||||||
|  |         Jimm = Cat(0, instr[21:31], instr[20], instr[12:20], | ||||||
|  |             *Extend(instr[31], 12)) | ||||||
|  |         self.Iimm = Iimm | ||||||
|  |  | ||||||
|  |         # Register addresses decoder | ||||||
|  |         rs1Id = instr[15:20] | ||||||
|  |         rs2Id = instr[20:25] | ||||||
|  |         rdId = instr[7:12] | ||||||
|  |  | ||||||
|  |         self.rdId = rdId | ||||||
|  |         self.rs1Id = rs1Id | ||||||
|  |         self.rs2Id = rs2Id | ||||||
|  |  | ||||||
|  |         # Function code decdore | ||||||
|  |         funct3 = instr[12:15] | ||||||
|  |         funct7 = instr[25:32] | ||||||
|  |         self.funct3 = funct3 | ||||||
|  |  | ||||||
|  |         # ALU | ||||||
|  |         aluIn1 = rs1 | ||||||
|  |         aluIn2 = Mux((isALUreg | isBranch), rs2, Iimm) | ||||||
|  |         shamt = Mux(isALUreg, rs2[0:5], instr[20:25]) | ||||||
|  |  | ||||||
|  |         # Wire memory address to pc | ||||||
|  |         m.d.comb += self.mem_addr.eq(pc) | ||||||
|  |  | ||||||
|  |         aluMinus = Cat(~aluIn1, C(0,1)) + Cat(aluIn2, C(0,1)) + 1 | ||||||
|  |         aluPlus = aluIn1 + aluIn2 | ||||||
|  |  | ||||||
|  |         EQ = aluMinus[0:32] == 0 | ||||||
|  |         LTU = aluMinus[32] | ||||||
|  |         LT = Mux((aluIn1[31] ^ aluIn2[31]), aluIn1[31], aluMinus[32]) | ||||||
|  |  | ||||||
|  |         def flip32(x): | ||||||
|  |             a = [x[i] for i in range(0, 32)] | ||||||
|  |             return Cat(*reversed(a)) | ||||||
|  |  | ||||||
|  |         # TODO: check these again! | ||||||
|  |         shifter_in = Mux(funct3 == 0b001, flip32(aluIn1), aluIn1) | ||||||
|  |         shifter = Cat(shifter_in, (instr[30] & aluIn1[31])) >> aluIn2[0:5] | ||||||
|  |         leftshift = flip32(shifter) | ||||||
|  |  | ||||||
|  |         with m.Switch(funct3) as alu: | ||||||
|  |             with m.Case(0b000): | ||||||
|  |                 m.d.comb += aluOut.eq(Mux(funct7[5] & instr[5], | ||||||
|  |                                           aluMinus[0:32], aluPlus)) | ||||||
|  |             with m.Case(0b001): | ||||||
|  |                 m.d.comb += aluOut.eq(leftshift) | ||||||
|  |             with m.Case(0b010): | ||||||
|  |                 m.d.comb += aluOut.eq(LT) | ||||||
|  |             with m.Case(0b011): | ||||||
|  |                 m.d.comb += aluOut.eq(LTU) | ||||||
|  |             with m.Case(0b100): | ||||||
|  |                 m.d.comb += aluOut.eq(aluIn1 ^ aluIn2) | ||||||
|  |             with m.Case(0b101): | ||||||
|  |                 m.d.comb += aluOut.eq(shifter) | ||||||
|  |             with m.Case(0b110): | ||||||
|  |                 m.d.comb += aluOut.eq(aluIn1 | aluIn2) | ||||||
|  |             with m.Case(0b111): | ||||||
|  |                 m.d.comb += aluOut.eq(aluIn1 & aluIn2) | ||||||
|  |  | ||||||
|  |         with m.Switch(funct3) as alu_branch: | ||||||
|  |             with m.Case(0b000): | ||||||
|  |                 m.d.comb += takeBranch.eq(EQ) | ||||||
|  |             with m.Case(0b001): | ||||||
|  |                 m.d.comb += takeBranch.eq(~EQ) | ||||||
|  |             with m.Case(0b100): | ||||||
|  |                 m.d.comb += takeBranch.eq(LT) | ||||||
|  |             with m.Case(0b101): | ||||||
|  |                 m.d.comb += takeBranch.eq(~LT) | ||||||
|  |             with m.Case(0b110): | ||||||
|  |                 m.d.comb += takeBranch.eq(LTU) | ||||||
|  |             with m.Case(0b111): | ||||||
|  |                 m.d.comb += takeBranch.eq(~LTU) | ||||||
|  |             with m.Case("---"): | ||||||
|  |                 m.d.comb += takeBranch.eq(0) | ||||||
|  |  | ||||||
|  |         # Next program counter is either next intstruction or depends on | ||||||
|  |         # jump target | ||||||
|  |         pcPlusImm = pc + Mux(instr[3], Jimm[0:32], | ||||||
|  |                              Mux(instr[4], Uimm[0:32], | ||||||
|  |                                  Bimm[0:32])) | ||||||
|  |         pcPlus4 = pc + 4 | ||||||
|  |  | ||||||
|  |         nextPc = Mux(((isBranch & takeBranch) | isJAL), pcPlusImm, | ||||||
|  |                      Mux(isJALR, Cat(C(0, 1), aluPlus[1:32]), | ||||||
|  |                          pcPlus4)) | ||||||
|  |  | ||||||
|  |         # Main state machine | ||||||
|  |         with m.FSM(reset="FETCH_INSTR") as fsm: | ||||||
|  |             self.fsm = fsm | ||||||
|  |             m.d.comb += self.mem_rstrb.eq(fsm.ongoing("FETCH_INSTR")) | ||||||
|  |             with m.State("FETCH_INSTR"): | ||||||
|  |                 m.next = "WAIT_INSTR" | ||||||
|  |             with m.State("WAIT_INSTR"): | ||||||
|  |                 m.d.sync += instr.eq(self.mem_rdata) | ||||||
|  |                 m.next = ("FETCH_REGS") | ||||||
|  |             with m.State("FETCH_REGS"): | ||||||
|  |                 m.d.sync += [ | ||||||
|  |                     rs1.eq(regs[rs1Id]), | ||||||
|  |                     rs2.eq(regs[rs2Id]) | ||||||
|  |                 ] | ||||||
|  |                 m.next = "EXECUTE" | ||||||
|  |             with m.State("EXECUTE"): | ||||||
|  |                 m.d.sync += pc.eq(nextPc) | ||||||
|  |                 m.next = "FETCH_INSTR" | ||||||
|  |  | ||||||
|  |         # Register write back | ||||||
|  |         writeBackData = Mux((isJAL | isJALR), pcPlus4, | ||||||
|  |                             Mux(isLUI, Uimm, | ||||||
|  |                                 Mux(isAUIPC, pcPlusImm, aluOut))) | ||||||
|  |  | ||||||
|  |         writeBackEn = fsm.ongoing("EXECUTE") & ~isBranch & ~isStore | ||||||
|  |  | ||||||
|  |         self.writeBackData = writeBackData | ||||||
|  |  | ||||||
|  |         with m.If(writeBackEn & (rdId != 0)): | ||||||
|  |             m.d.sync += regs[rdId].eq(writeBackData) | ||||||
|  |             # Also assign to debug output to see what is happening | ||||||
|  |             m.d.sync += self.x1.eq(writeBackData) | ||||||
|  |  | ||||||
|  |         return m | ||||||
							
								
								
									
										36
									
								
								12_size_optimisation/memory.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								12_size_optimisation/memory.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | from amaranth import * | ||||||
|  | from riscv_assembler import RiscvAssembler | ||||||
|  |  | ||||||
|  | class Memory(Elaboratable): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         a = RiscvAssembler() | ||||||
|  |  | ||||||
|  |         a.read("""begin: | ||||||
|  |         ADD x1, x0, x0 | ||||||
|  |         ADDI x2, x0, 31 | ||||||
|  |         l0: | ||||||
|  |         ADDI x1, x1, 1 | ||||||
|  |         BNE x1, x2, l0 | ||||||
|  |         EBREAK | ||||||
|  |         """) | ||||||
|  |  | ||||||
|  |         a.assemble() | ||||||
|  |         self.instructions = a.mem | ||||||
|  |         print("memory = {}".format(self.instructions)) | ||||||
|  |  | ||||||
|  |         # Instruction memory initialised with above instructions | ||||||
|  |         self.mem = Array([Signal(32, reset=x, name="mem") | ||||||
|  |                           for x in self.instructions]) | ||||||
|  |  | ||||||
|  |         self.mem_addr = Signal(32) | ||||||
|  |         self.mem_rdata = Signal(32) | ||||||
|  |         self.mem_rstrb = Signal() | ||||||
|  |  | ||||||
|  |     def elaborate(self, platform): | ||||||
|  |         m = Module() | ||||||
|  |  | ||||||
|  |         with m.If(self.mem_rstrb): | ||||||
|  |             m.d.sync += self.mem_rdata.eq(self.mem[self.mem_addr[2:32]]) | ||||||
|  |  | ||||||
|  |         return m | ||||||
							
								
								
									
										82
									
								
								12_size_optimisation/soc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								12_size_optimisation/soc.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | import sys | ||||||
|  | from amaranth import * | ||||||
|  |  | ||||||
|  | from clockworks import Clockworks | ||||||
|  | from memory import Memory | ||||||
|  | from cpu import CPU | ||||||
|  |  | ||||||
|  | class SOC(Elaboratable): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |  | ||||||
|  |         self.leds = Signal(5) | ||||||
|  |  | ||||||
|  |         # Signals in this list can easily be plotted as vcd traces | ||||||
|  |         self.ports = [] | ||||||
|  |  | ||||||
|  |     def elaborate(self, platform): | ||||||
|  |  | ||||||
|  |         m = Module() | ||||||
|  |         cw = Clockworks(slow=19, sim_slow=10) | ||||||
|  |         memory = DomainRenamer("slow")(Memory()) | ||||||
|  |         cpu = DomainRenamer("slow")(CPU()) | ||||||
|  |         m.submodules.cw = cw | ||||||
|  |         m.submodules.cpu = cpu | ||||||
|  |         m.submodules.memory = memory | ||||||
|  |  | ||||||
|  |         self.cpu = cpu | ||||||
|  |         self.memory = memory | ||||||
|  |  | ||||||
|  |         x1 = Signal(32) | ||||||
|  |  | ||||||
|  |         # Connect memory to CPU | ||||||
|  |         m.d.comb += [ | ||||||
|  |             memory.mem_addr.eq(cpu.mem_addr), | ||||||
|  |             memory.mem_rstrb.eq(cpu.mem_rstrb), | ||||||
|  |             cpu.mem_rdata.eq(memory.mem_rdata) | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |         # CPU debug output | ||||||
|  |         m.d.comb += [ | ||||||
|  |             x1.eq(cpu.x1), | ||||||
|  |             self.leds.eq(x1[0:5]) | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |         # 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(isBranch, "isBranch") | ||||||
|  |             #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(Bimm, "Bimm") | ||||||
|  |             #export(Jimm, "Jimm") | ||||||
|  |             #export(funct3, "funct3") | ||||||
|  |             #export(rdId, "rdId") | ||||||
|  |             #export(rs1, "rs1") | ||||||
|  |             #export(rs2, "rs2") | ||||||
|  |             #export(writeBackData, "writeBackData") | ||||||
|  |             #export(writeBackEn, "writeBackEn") | ||||||
|  |             #export(aluOut, "aluOut") | ||||||
|  |             #export((1 << cpu.fsm.state), "state") | ||||||
|  |  | ||||||
|  |         return m | ||||||
| @@ -33,6 +33,8 @@ class Top(Elaboratable): | |||||||
|             path = "10_lui_auipc" |             path = "10_lui_auipc" | ||||||
|         elif step == 11: |         elif step == 11: | ||||||
|             path = "11_modules" |             path = "11_modules" | ||||||
|  |         elif step == 12: | ||||||
|  |             path = "12_size_optimisation" | ||||||
|         else: |         else: | ||||||
|             print("Invalid step_number {}.".format(step)) |             print("Invalid step_number {}.".format(step)) | ||||||
|             exit(1) |             exit(1) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user