From 4a4dee334dde434f56a47fe6fc57a6b37a65f624 Mon Sep 17 00:00:00 2001 From: Graham Edgecombe Date: Thu, 30 Nov 2017 22:30:49 +0000 Subject: [PATCH] Add initial fetch/decode stages --- .gitignore | 7 ++ Makefile | 37 ++++++++ ice40hx8k-b-evn.pcf | 1 + rv32.sv | 25 +++++ rv32_decode.sv | 227 ++++++++++++++++++++++++++++++++++++++++++++ rv32_fetch.sv | 16 ++++ rv32_opcodes.sv | 46 +++++++++ rv32_regs.sv | 26 +++++ top.sv | 9 ++ top.ys | 6 ++ 10 files changed, 400 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 ice40hx8k-b-evn.pcf create mode 100644 rv32.sv create mode 100644 rv32_decode.sv create mode 100644 rv32_fetch.sv create mode 100644 rv32_opcodes.sv create mode 100644 rv32_regs.sv create mode 100644 top.sv create mode 100644 top.ys diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21350b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.* +*~ +*.asc +*.bin +*.blif +!.git* +!.mailmap diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8e1c59b --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +QUIET = -q +SRC = $(wildcard *.sv) +TOP = top +YS = $(TOP).ys +BLIF = $(TOP).blif +ASC = $(TOP).asc +BIN = $(TOP).bin +SPEED = hx +DEVICE = 8k +PACKAGE = ct256 +PCF = ice40hx8k-b-evn.pcf +FREQ_OSC = 12 + +.PHONY: all clean time stat flash + +all: $(TOP).bin + +clean: + $(RM) $(BLIF) $(ASC) $(BIN) + +$(BLIF): $(YS) $(SRC) + yosys $(QUIET) -s $< + +$(ASC): $(BLIF) $(PCF) + arachne-pnr $(QUIET) -d $(DEVICE) -P $(PACKAGE) -o $@ -p $(PCF) $< + +$(BIN): $(ASC) + icepack $< $@ + +time: $(ASC) $(PCF) + icetime -t -m -d $(SPEED)$(DEVICE) -P $(PACKAGE) -p $(PCF) -c $(FREQ_OSC) $< + +stat: $(ASC) + icebox_stat $< + +flash: $(BIN) + iceprog -S $< diff --git a/ice40hx8k-b-evn.pcf b/ice40hx8k-b-evn.pcf new file mode 100644 index 0000000..53bf5cc --- /dev/null +++ b/ice40hx8k-b-evn.pcf @@ -0,0 +1 @@ +set_io clk J3 diff --git a/rv32.sv b/rv32.sv new file mode 100644 index 0000000..17bfc8b --- /dev/null +++ b/rv32.sv @@ -0,0 +1,25 @@ +`include "rv32_decode.sv" +`include "rv32_fetch.sv" + +module rv32 ( + input logic clk +); + rv32_fetch fetch ( + .clk(clk), + + /* data out */ + .pc_out(fetch_pc), + .instr_out(fetch_instr) + ); + + logic [31:0] fetch_pc; + logic [31:0] fetch_instr; + + rv32_decode decode ( + .clk(clk), + + /* data in */ + .pc_in(fetch_pc), + .instr_in(fetch_instr) + ); +endmodule diff --git a/rv32_decode.sv b/rv32_decode.sv new file mode 100644 index 0000000..1295d6a --- /dev/null +++ b/rv32_decode.sv @@ -0,0 +1,227 @@ +`include "rv32_opcodes.sv" +`include "rv32_regs.sv" + +module rv32_decode ( + input logic clk, + + /* data in */ + input logic [31:0] pc_in, + input logic [31:0] instr_in, + + /* control out */ + output logic valid, + + /* data out */ + output logic [31:0] pc_out, + output logic [31:0] rs1_value_out, + output logic [31:0] rs2_value_out, + output logic [31:0] imm_out +); + logic [6:0] funct7 = instr_in[31:25]; + logic [4:0] rs2 = instr_in[24:20]; + logic [4:0] rs1 = instr_in[19:15]; + logic [2:0] funct3 = instr_in[14:12]; + logic [4:0] rd = instr_in[11:7]; + logic [6:0] opcode = instr_in[6:0]; + + logic sign = instr_in[31]; + + logic [31:0] imm_i = {{21{sign}}, instr_in[30:25], instr_in[24:21], instr_in[20]}; + logic [31:0] imm_s = {{21{sign}}, instr_in[30:25], instr_in[11:8], instr_in[7]}; + logic [31:0] imm_b = {{20{sign}}, instr_in[7], instr_in[30:25], instr_in[11:8], 1'b0}; + logic [31:0] imm_u = {sign, instr_in[30:20], instr_in[19:12], 12'b0}; + logic [31:0] imm_j = {{12{sign}}, instr_in[19:12], instr_in[20], instr_in[30:25], instr_in[24:1], 1'b0}; + + rv32_regs regs ( + .clk(clk), + .rs1_in(rs1), + .rs2_in(rs2), + .rs1_value_out(rs1_value_out), + .rs2_value_out(rs2_value_out) + ); + + always_ff @(posedge clk) begin + pc_out <= pc_in; + + valid <= 0; + imm_out <= 32'bx; + + casez ({opcode, funct3, funct7}) + {RV32_OPCODE_LUI, RV32_FUNCT3_ANY, RV32_FUNCT7_ANY}: begin + /* LUI */ + valid <= 1; + imm_out <= imm_u; + end + {RV32_OPCODE_AUIPC, RV32_FUNCT3_ANY, RV32_FUNCT7_ANY}: begin + /* AUIPC */ + valid <= 1; + imm_out <= imm_u; + end + {RV32_OPCODE_JAL, RV32_FUNCT3_ANY, RV32_FUNCT7_ANY}: begin + /* JAL */ + valid <= 1; + imm_out <= imm_j; + end + {RV32_OPCODE_JALR, RV32_FUNCT3_ZERO, RV32_FUNCT7_ANY}: begin + /* JALR */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_BRANCH, RV32_FUNCT3_BRANCH_BEQ, RV32_FUNCT7_ANY}: begin + /* BEQ */ + valid <= 1; + imm_out <= imm_b; + end + {RV32_OPCODE_BRANCH, RV32_FUNCT3_BRANCH_BNE, RV32_FUNCT7_ANY}: begin + /* BNE */ + valid <= 1; + imm_out <= imm_b; + end + {RV32_OPCODE_BRANCH, RV32_FUNCT3_BRANCH_BLT, RV32_FUNCT7_ANY}: begin + /* BLT */ + valid <= 1; + imm_out <= imm_b; + end + {RV32_OPCODE_BRANCH, RV32_FUNCT3_BRANCH_BGE, RV32_FUNCT7_ANY}: begin + /* BGE */ + valid <= 1; + imm_out <= imm_b; + end + {RV32_OPCODE_BRANCH, RV32_FUNCT3_BRANCH_BLTU, RV32_FUNCT7_ANY}: begin + /* BLTU */ + valid <= 1; + imm_out <= imm_b; + end + {RV32_OPCODE_BRANCH, RV32_FUNCT3_BRANCH_BGEU, RV32_FUNCT7_ANY}: begin + /* BGEU */ + valid <= 1; + imm_out <= imm_b; + end + {RV32_OPCODE_LOAD, RV32_FUNCT3_LOAD_LB, RV32_FUNCT7_ANY}: begin + /* LB */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_LOAD, RV32_FUNCT3_LOAD_LH, RV32_FUNCT7_ANY}: begin + /* LH */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_LOAD, RV32_FUNCT3_LOAD_LW, RV32_FUNCT7_ANY}: begin + /* LW */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_LOAD, RV32_FUNCT3_LOAD_LBU, RV32_FUNCT7_ANY}: begin + /* LBU */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_LOAD, RV32_FUNCT3_LOAD_LHU, RV32_FUNCT7_ANY}: begin + /* LHU */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_STORE, RV32_FUNCT3_STORE_SB, RV32_FUNCT7_ANY}: begin + /* SB */ + valid <= 1; + imm_out <= imm_s; + end + {RV32_OPCODE_STORE, RV32_FUNCT3_STORE_SH, RV32_FUNCT7_ANY}: begin + /* SH */ + valid <= 1; + imm_out <= imm_s; + end + {RV32_OPCODE_STORE, RV32_FUNCT3_STORE_SW, RV32_FUNCT7_ANY}: begin + /* SW */ + valid <= 1; + imm_out <= imm_s; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_ADD_SUB, RV32_FUNCT7_ANY}: begin + /* ADDI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_SLT, RV32_FUNCT7_ANY}: begin + /* SLTI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_SLTU, RV32_FUNCT7_ANY}: begin + /* SLTIU */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_XOR, RV32_FUNCT7_ANY}: begin + /* XORI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_OR, RV32_FUNCT7_ANY}: begin + /* ORI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_AND, RV32_FUNCT7_ANY}: begin + /* ANDI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_SLL, RV32_FUNCT7_ZERO}: begin + /* SLLI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_SRL_SRA, RV32_FUNCT7_ZERO}: begin + /* SRLI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP_IMM, RV32_FUNCT3_OP_SRL_SRA, RV32_FUNCT7_OP_SRA}: begin + /* SRAI */ + valid <= 1; + imm_out <= imm_i; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_ADD_SUB, RV32_FUNCT7_ZERO}: begin + /* ADD */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_ADD_SUB, RV32_FUNCT7_OP_SUB}: begin + /* SUB */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_SLL, RV32_FUNCT7_ZERO}: begin + /* SLL */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_SLT, RV32_FUNCT7_ZERO}: begin + /* SLT */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_SLTU, RV32_FUNCT7_ZERO}: begin + /* SLTU */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_XOR, RV32_FUNCT7_ZERO}: begin + /* XOR */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_SRL_SRA, RV32_FUNCT7_ZERO}: begin + /* SRL */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_SRL_SRA, RV32_FUNCT7_OP_SRA}: begin + /* SRA */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_OR, RV32_FUNCT7_ZERO}: begin + /* OR */ + valid <= 1; + end + {RV32_OPCODE_OP, RV32_FUNCT3_OP_AND, RV32_FUNCT7_ZERO}: begin + /* AND */ + valid <= 1; + end + endcase + end +endmodule diff --git a/rv32_fetch.sv b/rv32_fetch.sv new file mode 100644 index 0000000..936ff0c --- /dev/null +++ b/rv32_fetch.sv @@ -0,0 +1,16 @@ +module rv32_fetch ( + input logic clk, + + /* data out */ + output logic [31:0] pc_out, + output logic [31:0] instr_out +); + logic [31:0] instr_mem [255:0]; + logic [31:0] pc; + + always_ff @(posedge clk) begin + instr_out <= instr_mem[pc[31:2]]; + pc <= pc + 4; + pc_out <= pc; + end +endmodule diff --git a/rv32_opcodes.sv b/rv32_opcodes.sv new file mode 100644 index 0000000..5dd1ebb --- /dev/null +++ b/rv32_opcodes.sv @@ -0,0 +1,46 @@ +localparam RV32_OPCODE_LOAD = 7'b0000011; +localparam RV32_OPCODE_MISC_MEM = 7'b0001111; +localparam RV32_OPCODE_OP_IMM = 7'b0010011; +localparam RV32_OPCODE_AUIPC = 7'b0010111; +localparam RV32_OPCODE_STORE = 7'b0100011; +localparam RV32_OPCODE_OP = 7'b0110011; +localparam RV32_OPCODE_LUI = 7'b0110111; +localparam RV32_OPCODE_BRANCH = 7'b1100011; +localparam RV32_OPCODE_JALR = 7'b1100111; +localparam RV32_OPCODE_JAL = 7'b1101111; +localparam RV32_OPCODE_SYSTEM = 7'b1110011; + +localparam RV32_FUNCT3_ANY = 3'b???; +localparam RV32_FUNCT3_ZERO = 3'b000; + +localparam RV32_FUNCT3_BRANCH_BEQ = 3'b000; +localparam RV32_FUNCT3_BRANCH_BNE = 3'b001; +localparam RV32_FUNCT3_BRANCH_BLT = 3'b100; +localparam RV32_FUNCT3_BRANCH_BGE = 3'b101; +localparam RV32_FUNCT3_BRANCH_BLTU = 3'b110; +localparam RV32_FUNCT3_BRANCH_BGEU = 3'b111; + +localparam RV32_FUNCT3_LOAD_LB = 3'b000; +localparam RV32_FUNCT3_LOAD_LH = 3'b001; +localparam RV32_FUNCT3_LOAD_LW = 3'b010; +localparam RV32_FUNCT3_LOAD_LBU = 3'b100; +localparam RV32_FUNCT3_LOAD_LHU = 3'b101; + +localparam RV32_FUNCT3_STORE_SB = 3'b000; +localparam RV32_FUNCT3_STORE_SH = 3'b001; +localparam RV32_FUNCT3_STORE_SW = 3'b010; + +localparam RV32_FUNCT3_OP_ADD_SUB = 3'b000; +localparam RV32_FUNCT3_OP_SLL = 3'b001; +localparam RV32_FUNCT3_OP_SLT = 3'b010; +localparam RV32_FUNCT3_OP_SLTU = 3'b011; +localparam RV32_FUNCT3_OP_XOR = 3'b100; +localparam RV32_FUNCT3_OP_SRL_SRA = 3'b101; +localparam RV32_FUNCT3_OP_OR = 3'b110; +localparam RV32_FUNCT3_OP_AND = 3'b111; + +localparam RV32_FUNCT7_ANY = 7'b???????; +localparam RV32_FUNCT7_ZERO = 7'b0000000; + +localparam RV32_FUNCT7_OP_SRA = 7'b0100000; +localparam RV32_FUNCT7_OP_SUB = 7'b0100000; diff --git a/rv32_regs.sv b/rv32_regs.sv new file mode 100644 index 0000000..a0dff9d --- /dev/null +++ b/rv32_regs.sv @@ -0,0 +1,26 @@ +module rv32_regs ( + input logic clk, + + /* control in */ + input logic [4:0] rs1_in, + input logic [4:0] rs2_in, + input logic [4:0] rd_in, + input logic rd_writeback_in, + + /* data in */ + input logic [31:0] rd_value_in, + + /* data out */ + output logic [31:0] rs1_value_out, + output logic [31:0] rs2_value_out +); + logic [31:0] regs [31:0]; + + always_ff @(posedge clk) begin + rs1_value_out <= regs[rs1_in]; + rs2_value_out <= regs[rs2_in]; + + if (rd_writeback_in && |rd_in) + regs[rd_in] <= rd_value_in; + end +endmodule diff --git a/top.sv b/top.sv new file mode 100644 index 0000000..3ae0341 --- /dev/null +++ b/top.sv @@ -0,0 +1,9 @@ +`include "rv32.sv" + +module top ( + input logic clk +); + rv32 rv32 ( + .clk(clk) + ); +endmodule diff --git a/top.ys b/top.ys new file mode 100644 index 0000000..6be7ab8 --- /dev/null +++ b/top.ys @@ -0,0 +1,6 @@ +read_verilog -sv top.sv +proc +opt +alumacc +share -aggressive +synth_ice40 -top top -blif top.blif