import cpu_types::*;
module cpu(
input clk,
input rst_n,
// program memory
input [31:0] instruction,
output [31:0] pc,
// ram
output [31:0] memory_address,
input [31:0] memory_out,
output [31:0] memory_write,
output [3:0] memory_byte_enable,
output memory_we,
output ebreak
);
parameter WIDTH = 32;
reg [31:0] pc_next;
wire [4:0] reg_a_1, reg_a_2, reg_a_w;
wire [31:0] reg_rd1, reg_rd2;
reg [31:0] reg_write;
wire reg_we;
reg all_stages_ready;
wire jump;
wire [31:0] jumping_pc_next;
stage_status_t fetch_out;
stage_status_t decode_out;
stage_status_t execute_out;
stage_status_t memory_access_out;
stage_status_t decode_in;
stage_status_t execute_in;
stage_status_t memory_access_in;
stage_status_t writeback_in;
assign ebreak = memory_access_out.instruction.ebreak;
// stage registers
always_ff @(posedge clk) begin
if (rst_n == 0) begin
decode_in.data.address = 0;
execute_in.data.address = 0;
memory_access_in.data.address = 0;
writeback_in.data.address = 0;
end
else begin
if (decode_out.ready && execute_out.ready && memory_access_out.ready)
decode_in = fetch_out;
if (execute_out.ready && memory_access_out.ready)
execute_in = decode_out;
if (memory_access_out.ready)
memory_access_in = execute_out;
writeback_in = memory_access_out;
end
end
assign all_stages_ready = fetch_out.ready && decode_out.ready && execute_out.ready && memory_access_out.ready;
always_comb begin
if (!all_stages_ready)
pc_next = pc;
else if (jump)
pc_next = jumping_pc_next;
else // assume no jump. If jump, if result will be thrown out
pc_next = pc + 4;
end
// data for forwarding from the stages
// Note: this is a record instead of an array
// just because verilator didn't like it as an array
// consider switching back to array.
forwarding_data_status_t data_in_pipeline;
assign data_in_pipeline.execute_out = execute_out.data;
assign data_in_pipeline.access_out = memory_access_out.data;
assign data_in_pipeline.writeback_in = writeback_in.data;
fetch fetch_inst(
.clk(clk),
.pc(pc),
.flush(jump),
.mem_instruction(instruction),
.stage_out(fetch_out)
);
decode decode_inst(
.clk(clk),
.flush(jump),
.data_in_pipeline(data_in_pipeline),
.reg_a_1(reg_a_1),
.reg_a_2(reg_a_2),
.reg_rd1(reg_rd1),
.reg_rd2(reg_rd2),
.stage_in(decode_in),
.stage_out(decode_out)
);
execute execute_inst(
.clk(clk),
.jump(jump),
.jump_pc(jumping_pc_next),
.stage_in(execute_in),
.stage_out(execute_out)
);
memory_access memory_access_inst(
.clk(clk),
.memory_out(memory_out),
.memory_byte_enable(memory_byte_enable),
.memory_write(memory_write),
.memory_we(memory_we),
.memory_address(memory_address),
.stage_in(memory_access_in),
.stage_out(memory_access_out)
);
writeback writeback_inst(
.clk(clk),
.reg_a_write(reg_a_w),
.reg_we(reg_we),
.reg_write(reg_write),
.stage_in(writeback_in)
);
register_file #(.WIDTH(WIDTH), .ADDRESS_LENGTH(5)) register_file_inst(
.clk(clk),
.a1(reg_a_1),
.a2(reg_a_2),
.a3(reg_a_w),
.we3(reg_we),
.wd3(reg_write),
.rd1(reg_rd1),
.rd2(reg_rd2)
);
program_counter program_counter_inst(
.clk(clk),
.rst_n(rst_n),
.pc(pc[11:0]),
.pc_next(pc_next[11:0])
);
endmodule