2020-09-27 16:04:16 -06:00
|
|
|
module core(
|
|
|
|
input clk,
|
|
|
|
input reset,
|
|
|
|
output dummy_out,
|
|
|
|
|
|
|
|
output reg [31:0] mem_inst_addr,
|
|
|
|
input [31:0] mem_inst_data,
|
|
|
|
|
|
|
|
output reg [31:0] mem_data_addr,
|
|
|
|
output reg [31:0] mem_data_wdata,
|
|
|
|
input [31:0] mem_data_rdata,
|
|
|
|
output reg mem_data_en,
|
|
|
|
output reg mem_data_we,
|
|
|
|
input mem_data_valid,
|
|
|
|
input mem_data_done
|
|
|
|
);
|
|
|
|
|
|
|
|
// Register File
|
|
|
|
reg [31:0] regfile [0:31];
|
|
|
|
initial regfile[0] = 32'h00000000;
|
|
|
|
|
|
|
|
// Registers
|
|
|
|
reg [31:0] r_if_pc = 0, r_id_pc, r_ex_pc, r_mem_pc, r_wb_pc;
|
|
|
|
reg r_id_stall, r_ex_stall, r_mem_stall, r_wb_stall;
|
|
|
|
reg [31:0] r_id_inst, r_ex_inst, r_mem_inst, r_wb_inst;
|
|
|
|
reg [4:0] r_ex_rd, r_mem_rd, r_wb_rd;
|
|
|
|
reg r_ex_alu_seed;
|
|
|
|
reg [2:0] r_ex_aluop;
|
|
|
|
reg [31:0] r_ex_s1, r_ex_s2, r_mem_s1, r_mem_s2;
|
|
|
|
reg [31:0] r_mem_alu_out, r_wb_alu_out;
|
|
|
|
reg r_mem_alu_zero;
|
|
|
|
reg r_ex_jump;
|
2020-09-27 18:04:08 -06:00
|
|
|
reg r_ex_store, r_mem_store;
|
|
|
|
reg r_ex_load, r_mem_load;
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
// IF
|
|
|
|
reg s_if_halt;
|
|
|
|
reg [31:0] s_if_next_pc;
|
|
|
|
reg [31:0] s_if_inst;
|
|
|
|
reg s_if_stall;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_if_halt = 0;
|
|
|
|
|
|
|
|
if (r_ex_jump) begin
|
|
|
|
s_if_next_pc = s_ex_alu_out;
|
|
|
|
s_if_stall = 1'b1;
|
|
|
|
end else begin
|
|
|
|
s_if_next_pc = r_if_pc + 4;
|
|
|
|
s_if_stall = 1'b0;
|
|
|
|
end
|
|
|
|
|
|
|
|
mem_inst_addr = r_if_pc;
|
|
|
|
s_if_inst = mem_inst_data;
|
|
|
|
end
|
|
|
|
|
|
|
|
// ID
|
|
|
|
reg s_id_halt;
|
|
|
|
reg [6:0] s_id_opcode;
|
|
|
|
reg [2:0] s_id_funct3;
|
|
|
|
reg [6:0] s_id_funct7;
|
|
|
|
reg [4:0] s_id_rd, s_id_rs1, s_id_rs2;
|
|
|
|
reg [31:0] s_id_immed_itype, s_id_immed_stype, s_id_immed_utype, s_id_immed_btype, s_id_immed_jtype;
|
|
|
|
reg [31:0] s_id_s1, s_id_s2;
|
|
|
|
reg [2:0] s_id_aluop;
|
|
|
|
reg s_id_alu_seed;
|
|
|
|
reg s_id_invalid;
|
|
|
|
reg s_id_jump, s_id_branch;
|
2020-09-27 18:04:08 -06:00
|
|
|
reg s_id_store, s_id_load;
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
// RV32I / RV64I / RV32M
|
|
|
|
localparam OP_LUI = 7'b0110111,
|
|
|
|
OP_AUIPC = 7'b0010111,
|
|
|
|
OP_JAL = 7'b1101111,
|
|
|
|
OP_JALR = 7'b1100111,
|
|
|
|
OP_BRANCH = 7'b1100011,
|
|
|
|
OP_LOAD = 7'b0000011,
|
|
|
|
OP_STORE = 7'b0100011,
|
|
|
|
OP_IMM = 7'b0010011,
|
|
|
|
OP_ALU = 7'b0110011,
|
|
|
|
OP_FENCE = 7'b0001111,
|
|
|
|
OP_SYSTEM = 7'b1110011;
|
|
|
|
// RV64M
|
|
|
|
// localparam OP_???????? = 7'b0111011;
|
|
|
|
// RV32A / RV64A
|
|
|
|
// localparam OP_ATOMIC = 7'b0101111;
|
|
|
|
// TODO: add opcodes for other extensions
|
|
|
|
|
|
|
|
// ALU OPCODES
|
|
|
|
localparam ALUOP_ADD = 0,
|
|
|
|
ALUOP_XOR = 1,
|
|
|
|
ALUOP_OR = 2,
|
|
|
|
ALUOP_AND = 3,
|
|
|
|
ALUOP_SL = 4,
|
|
|
|
ALUOP_SR = 5,
|
|
|
|
ALUOP_SLT = 6,
|
|
|
|
ALUOP_SLTU = 7;
|
|
|
|
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_id_halt = 0;
|
|
|
|
s_id_invalid = 0;
|
2020-09-27 18:04:08 -06:00
|
|
|
s_id_store = 0;
|
|
|
|
s_id_load = 0;
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
s_id_opcode = r_id_inst[6:0];
|
|
|
|
s_id_rd = r_id_inst[11:7];
|
|
|
|
s_id_rs1 = r_id_inst[19:15];
|
|
|
|
s_id_rs2 = r_id_inst[24:20];
|
|
|
|
s_id_funct3 = r_id_inst[14:12];
|
|
|
|
s_id_funct7 = r_id_inst[31:25];
|
|
|
|
|
|
|
|
s_id_immed_itype = {{20{r_id_inst[31]}}, r_id_inst[31:20]};
|
|
|
|
s_id_immed_stype = {{20{r_id_inst[31]}}, r_id_inst[31:25], r_id_inst[11:7]};
|
|
|
|
s_id_immed_utype = {r_id_inst[31:12], 12'b0};
|
|
|
|
s_id_immed_btype = {{19{r_id_inst[31]}}, r_id_inst[31], r_id_inst[7], r_id_inst[30:25], r_id_inst[11:8], 1'b0};
|
|
|
|
s_id_immed_jtype = {{11{r_id_inst[31]}}, r_id_inst[31], r_id_inst[19:12], r_id_inst[20], r_id_inst[30:21], 1'b0};
|
|
|
|
|
|
|
|
case (s_id_opcode)
|
|
|
|
OP_LUI: begin
|
|
|
|
s_id_s1 = 32'h00000000;
|
|
|
|
s_id_s2 = s_id_immed_utype;
|
|
|
|
s_id_aluop = ALUOP_ADD;
|
|
|
|
s_id_alu_seed = 0;
|
|
|
|
s_id_jump = 0;
|
|
|
|
s_id_branch = 0;
|
|
|
|
end
|
|
|
|
OP_AUIPC: begin
|
|
|
|
s_id_s1 = r_id_pc;
|
|
|
|
s_id_s2 = s_id_immed_utype;
|
|
|
|
s_id_aluop = ALUOP_ADD;
|
|
|
|
s_id_alu_seed = 0;
|
|
|
|
s_id_jump = 0;
|
|
|
|
s_id_branch = 0;
|
|
|
|
end
|
|
|
|
OP_JAL: begin
|
|
|
|
s_id_s1 = r_id_pc;
|
|
|
|
s_id_s2 = s_id_immed_jtype;
|
|
|
|
s_id_aluop = ALUOP_ADD;
|
|
|
|
s_id_alu_seed = 0;
|
|
|
|
s_id_jump = 1;
|
|
|
|
s_id_branch = 0;
|
|
|
|
end
|
|
|
|
OP_JALR: begin
|
|
|
|
s_id_s1 = regfile[s_id_rs1];
|
|
|
|
s_id_s2 = s_id_immed_itype;
|
|
|
|
s_id_aluop = ALUOP_ADD;
|
|
|
|
s_id_alu_seed = 0;
|
|
|
|
s_id_jump = 1;
|
|
|
|
s_id_branch = 0;
|
|
|
|
end
|
|
|
|
// OP_BRANCH: begin
|
|
|
|
|
|
|
|
// end
|
|
|
|
// OP_LOAD: begin
|
|
|
|
|
|
|
|
// end
|
|
|
|
// OP_STORE: begin
|
|
|
|
|
|
|
|
// end
|
|
|
|
OP_IMM: begin
|
|
|
|
s_id_s1 = regfile[s_id_rs1];
|
|
|
|
s_id_s2 = s_id_immed_itype;
|
|
|
|
s_id_jump = 0;
|
|
|
|
s_id_branch = 0;
|
|
|
|
casex ({s_id_funct3, s_id_funct7})
|
|
|
|
10'b000xxxxxxx: begin s_id_aluop = ALUOP_ADD; s_id_alu_seed = 1'b0; end // ADDI
|
|
|
|
10'b010xxxxxxx: begin s_id_aluop = ALUOP_SLT; s_id_alu_seed = 1'bx; end // SLTI
|
|
|
|
10'b011xxxxxxx: begin s_id_aluop = ALUOP_SLTU; s_id_alu_seed = 1'bx; end // SLTUI
|
|
|
|
10'b100xxxxxxx: begin s_id_aluop = ALUOP_XOR; s_id_alu_seed = 1'bx; end // XORI
|
|
|
|
10'b110xxxxxxx: begin s_id_aluop = ALUOP_OR; s_id_alu_seed = 1'bx; end // ORI
|
|
|
|
10'b111xxxxxxx: begin s_id_aluop = ALUOP_AND; s_id_alu_seed = 1'bx; end // ANDI
|
|
|
|
10'b0010000000: begin s_id_aluop = ALUOP_SL; s_id_alu_seed = 1'bx; end // SLLI
|
|
|
|
10'b1010000000: begin s_id_aluop = ALUOP_SR; s_id_alu_seed = 1'b0; end // SRLI
|
|
|
|
10'b1010100000: begin s_id_aluop = ALUOP_SR; s_id_alu_seed = 1'b1; end // SRAI
|
|
|
|
default: begin
|
|
|
|
s_id_s1 = 32'hxxxxxxxx;
|
|
|
|
s_id_s2 = 32'hxxxxxxxx;
|
|
|
|
s_id_invalid = 1;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
OP_ALU: begin
|
|
|
|
s_id_s1 = regfile[s_id_rs1];
|
|
|
|
s_id_s2 = regfile[s_id_rs2];
|
|
|
|
s_id_jump = 0;
|
|
|
|
s_id_branch = 0;
|
|
|
|
case ({s_id_funct3, s_id_funct7})
|
|
|
|
10'b0000000000: begin s_id_aluop = ALUOP_ADD; s_id_alu_seed = 1'b0; end // ADD
|
|
|
|
10'b0000100000: begin s_id_aluop = ALUOP_ADD; s_id_alu_seed = 1'b1; end // SUB
|
|
|
|
10'b0010000000: begin s_id_aluop = ALUOP_SL; s_id_alu_seed = 1'bx; end // SLL
|
|
|
|
10'b0100000000: begin s_id_aluop = ALUOP_SLT; s_id_alu_seed = 1'bx; end // SLT
|
|
|
|
10'b0110000000: begin s_id_aluop = ALUOP_SLTU; s_id_alu_seed = 1'bx; end // SLTU
|
|
|
|
10'b1000000000: begin s_id_aluop = ALUOP_XOR; s_id_alu_seed = 1'bx; end // XOR
|
|
|
|
10'b1100000000: begin s_id_aluop = ALUOP_OR; s_id_alu_seed = 1'bx; end // OR
|
|
|
|
10'b1110000000: begin s_id_aluop = ALUOP_AND; s_id_alu_seed = 1'bx; end // AND
|
|
|
|
10'b1010000000: begin s_id_aluop = ALUOP_SR; s_id_alu_seed = 1'b0; end // SRL
|
|
|
|
10'b1010100000: begin s_id_aluop = ALUOP_SR; s_id_alu_seed = 1'b1; end // SRA
|
|
|
|
default: begin
|
|
|
|
s_id_s1 = 32'hxxxxxxxx;
|
|
|
|
s_id_s2 = 32'hxxxxxxxx;
|
|
|
|
s_id_invalid = 1;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
// OP_FENCE: begin
|
|
|
|
|
|
|
|
// end
|
|
|
|
// OP_SYSTEM: begin
|
|
|
|
|
|
|
|
// end
|
|
|
|
default: begin
|
|
|
|
s_id_jump = 0;
|
|
|
|
s_id_branch = 0;
|
|
|
|
s_id_s1 = 32'hxxxxxxxx;
|
|
|
|
s_id_s2 = 32'hxxxxxxxx;
|
|
|
|
s_id_invalid = 1;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
|
|
|
|
if (s_id_invalid) begin
|
|
|
|
$display("Invalid instruction at PC=0x%h", r_id_pc);
|
|
|
|
s_id_halt = 1'b1;
|
|
|
|
s_id_aluop = 3'hx;
|
|
|
|
s_id_alu_seed = 1'bx;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// EX
|
|
|
|
reg s_ex_halt;
|
|
|
|
reg [31:0] s_ex_data1, s_ex_data2;
|
|
|
|
reg [31:0] s_ex_alu_out;
|
|
|
|
reg s_ex_alu_zero;
|
|
|
|
reg [31:0] s_ex_ra;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_ex_halt = 0;
|
|
|
|
|
|
|
|
s_ex_data1 = r_ex_s1;
|
|
|
|
s_ex_data2 = r_ex_s2;
|
|
|
|
|
|
|
|
case (r_ex_aluop)
|
|
|
|
ALUOP_ADD: begin // seed=1: subtract
|
|
|
|
s_ex_alu_out = s_ex_data1 + (s_ex_data2 ^ {32{r_ex_alu_seed}}) + r_ex_alu_seed;
|
|
|
|
end
|
|
|
|
ALUOP_XOR: begin
|
|
|
|
s_ex_alu_out = (|s_ex_data1) ^ (|s_ex_data2);
|
|
|
|
end
|
|
|
|
ALUOP_OR: begin
|
|
|
|
s_ex_alu_out = (|s_ex_data1) | (|s_ex_data2);
|
|
|
|
end
|
|
|
|
ALUOP_AND: begin
|
|
|
|
s_ex_alu_out = (|s_ex_data1) & (|s_ex_data2);
|
|
|
|
end
|
|
|
|
ALUOP_SL: begin
|
|
|
|
s_ex_alu_out = s_ex_data1 << s_ex_data2;
|
|
|
|
end
|
|
|
|
ALUOP_SR: begin // seed=1: arithmetic
|
|
|
|
s_ex_alu_out = s_ex_data1 >> s_ex_data2;
|
|
|
|
if (r_ex_alu_seed) begin
|
|
|
|
s_ex_alu_out = s_ex_data1 >>> s_ex_data2;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
ALUOP_SLT: begin
|
|
|
|
s_ex_alu_out = $signed(s_ex_data1) < $signed(s_ex_data2);
|
|
|
|
end
|
|
|
|
ALUOP_SLTU: begin
|
|
|
|
s_ex_alu_out = s_ex_data1 < s_ex_data2;
|
|
|
|
end
|
|
|
|
default: begin
|
|
|
|
s_ex_halt = 1;
|
|
|
|
s_ex_alu_out = 32'hxxxxxxxx;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
s_ex_alu_zero = (s_ex_alu_out == 0);
|
|
|
|
|
|
|
|
s_ex_ra = r_ex_pc + 4;
|
|
|
|
end
|
|
|
|
|
|
|
|
// MEM
|
|
|
|
reg s_mem_halt;
|
|
|
|
reg s_mem_bp;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_mem_halt = 0;
|
|
|
|
s_mem_bp = 0;
|
|
|
|
|
|
|
|
if (r_mem_store) begin
|
|
|
|
mem_data_en = 1;
|
|
|
|
mem_data_we = 1;
|
|
|
|
s_mem_bp = !mem_data_done;
|
|
|
|
end else if (r_mem_load) begin
|
|
|
|
mem_data_en = 1;
|
|
|
|
mem_data_we = 0;
|
|
|
|
s_mem_bp = !mem_data_valid;
|
|
|
|
end else begin
|
|
|
|
mem_data_en = 0;
|
|
|
|
mem_data_we = 0;
|
|
|
|
s_mem_bp = 0;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// WB
|
|
|
|
reg s_wb_halt;
|
|
|
|
reg [31:0] s_wb_data;
|
|
|
|
reg s_wb_write;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_wb_halt = 0;
|
|
|
|
|
|
|
|
// load instructions do not use output of alu in wb
|
|
|
|
s_wb_data = r_wb_alu_out;
|
|
|
|
|
|
|
|
// FIXME: always writes!!!
|
|
|
|
s_wb_write = !r_wb_stall;
|
|
|
|
end
|
|
|
|
|
|
|
|
// SYS
|
|
|
|
reg s_sys_halt;
|
|
|
|
|
|
|
|
always @(*) begin
|
|
|
|
s_sys_halt = s_if_halt || s_id_halt || s_ex_halt || s_mem_halt || s_wb_halt;
|
|
|
|
end
|
|
|
|
|
|
|
|
// Register update
|
|
|
|
always @(posedge clk) begin
|
|
|
|
if (reset) begin
|
|
|
|
r_if_pc <= 32'h00000000;
|
|
|
|
// rather than resetting all flip-flops just stall the pipeline so values are ignored.
|
|
|
|
r_id_stall <= 1;
|
|
|
|
r_ex_stall <= 1;
|
|
|
|
r_mem_stall <= 1;
|
|
|
|
r_wb_stall <= 1;
|
|
|
|
|
|
|
|
end else begin
|
|
|
|
// NOTE: halt disabled because startup causes hault
|
|
|
|
// if (s_sys_halt && 0) begin
|
|
|
|
// // stay halted forever
|
|
|
|
// end else begin
|
|
|
|
// IF
|
2020-09-27 18:04:08 -06:00
|
|
|
// if (!s_mem_bp) begin
|
2020-09-27 16:04:16 -06:00
|
|
|
r_if_pc <= s_if_next_pc;
|
2020-09-27 18:04:08 -06:00
|
|
|
// end
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
// ID
|
2020-09-27 18:04:08 -06:00
|
|
|
// if (!s_mem_bp) begin
|
2020-09-27 16:04:16 -06:00
|
|
|
r_id_stall <= s_if_stall;
|
|
|
|
r_id_pc <= r_if_pc;
|
|
|
|
r_id_inst <= s_if_inst;
|
2020-09-27 18:04:08 -06:00
|
|
|
// end
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
// EX
|
2020-09-27 18:04:08 -06:00
|
|
|
// if (!s_mem_bp) begin
|
2020-09-27 16:04:16 -06:00
|
|
|
// TODO: also stall EX if taking branch
|
|
|
|
r_ex_stall <= r_id_stall;
|
|
|
|
r_ex_pc <= r_id_pc;
|
|
|
|
r_ex_inst <= r_id_inst;
|
|
|
|
r_ex_rd <= s_id_rd;
|
|
|
|
r_ex_s1 <= s_id_s1;
|
|
|
|
r_ex_s2 <= s_id_s2;
|
|
|
|
r_ex_aluop <= s_id_aluop;
|
|
|
|
r_ex_alu_seed <= s_id_alu_seed;
|
|
|
|
r_ex_jump <= s_id_jump;
|
2020-09-27 18:04:08 -06:00
|
|
|
r_ex_store <= s_id_store;
|
|
|
|
r_ex_load <= s_id_load;
|
|
|
|
// end
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
|
|
|
|
// MEM
|
2020-09-27 18:04:08 -06:00
|
|
|
// if (!s_mem_bp) begin
|
2020-09-27 16:04:16 -06:00
|
|
|
r_mem_stall <= r_ex_stall;
|
|
|
|
r_mem_pc <= r_ex_pc;
|
|
|
|
r_mem_inst <= r_ex_inst;
|
|
|
|
r_mem_rd <= r_ex_rd;
|
|
|
|
r_mem_s1 <= r_ex_s1;
|
|
|
|
r_mem_s2 <= r_ex_s2;
|
|
|
|
r_mem_alu_out <= s_ex_alu_out;
|
|
|
|
r_mem_alu_zero <= s_ex_alu_zero;
|
2020-09-27 18:04:08 -06:00
|
|
|
r_mem_store <= r_ex_store;
|
|
|
|
r_mem_load <= r_ex_load;
|
|
|
|
// end
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
// WB
|
2020-09-27 18:04:08 -06:00
|
|
|
// if (!s_mem_bp) begin
|
2020-09-27 16:04:16 -06:00
|
|
|
r_wb_stall <= r_mem_stall;
|
|
|
|
r_wb_pc <= r_mem_pc;
|
|
|
|
r_wb_rd <= r_mem_rd;
|
|
|
|
r_wb_alu_out <= r_mem_alu_out;
|
2020-09-27 18:04:08 -06:00
|
|
|
// end
|
2020-09-27 16:04:16 -06:00
|
|
|
|
|
|
|
// Register File
|
|
|
|
if (r_wb_rd != 0 && s_wb_write) begin
|
|
|
|
regfile[r_wb_rd] <= s_wb_data;
|
|
|
|
end
|
|
|
|
// end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assign dummy_out = s_wb_data[0];
|
|
|
|
|
|
|
|
endmodule
|