0% found this document useful (0 votes)
8 views16 pages

Pipelined Core

The document describes a Verilog module for a core processor, detailing its architecture including instruction fetching, decoding, execution, and memory stages. It defines various data structures, control signals, and operations for handling instructions, including ALU operations and hazard detection. The module interfaces with memory through requests and responses, managing the flow of data and control signals across different stages of instruction processing.

Uploaded by

John
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views16 pages

Pipelined Core

The document describes a Verilog module for a core processor, detailing its architecture including instruction fetching, decoding, execution, and memory stages. It defines various data structures, control signals, and operations for handling instructions, including ALU operations and hazard detection. The module interfaces with memory through requests and responses, managing the flow of data and control signals across different stages of instruction processing.

Uploaded by

John
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

`ifndef _core_v

`define _core_v
`include "system.sv"
`include "base.sv"
`include "memory_io.sv"
`include "memory.sv"

module core(
input logic clk
,input logic reset
,input logic [`word_address_size-1:0] reset_pc
,output memory_io_req inst_mem_req
,input memory_io_rsp inst_mem_rsp
,output memory_io_req data_mem_req
,input memory_io_rsp data_mem_rsp
);

word pc;

// fetch decode data transition


typedef struct packed {
logic [31:0] pc;
} fetch_reg;

fetch_reg fetch_n, fetch_r;


logic fetch_en;
logic stall_fetch;
logic fetch_valid;
logic [31:0] next_pc_fetch;

assign fetch_en = !stall_fetch; // for stalling


assign fetch_valid = 1'b1; // for flushing
always_comb begin
fetch_n.pc = next_pc_fetch;
end

// fetch register
always_ff @(posedge clk) begin
if(reset) begin
fetch_r <= reset_pc;
end else if (fetch_en) begin
fetch_r <= fetch_n;
end else if (!fetch_valid) begin
fetch_r <= '0;
end
end

// instruction fetch request


always_comb begin
inst_mem_req.addr = fetch_r.pc;
inst_mem_req.do_read = 4'b1111;
inst_mem_req.valid = fetch_en;
end

typedef enum logic [3:0] {


ALU_NO_OP = 4'b0000, // Default value for no operation
ALU_ADD = 4'b0001, // Addition
ALU_SUB = 4'b0010, // Subtraction
ALU_SLL = 4'b0011, // Shift Left Logical
ALU_SRA = 4'b0100, // Shift Right Arithmetic
ALU_AUIPC = 4'b0101, // add upper immediate to pc
ALU_AND = 4'b0110, // Bitwise AND
ALU_OR = 4'b0111, // Bitwise OR
ALU_XOR = 4'b1000, // Bitwise XOR
ALU_LOAD = 4'b1001, // Load instruction
ALU_STORE = 4'b1010, // Store instruction
ALU_LUI = 4'b1011, // Lui instruction
ALU_BRCH = 4'b1100, // branch instructions
ALU_JAL = 4'b1101, // jump and link
ALU_JALR = 4'b1110 // indirect jump
} alu_op_t;

alu_op_t alu_op;

// decode-exe data tranisition


typedef struct packed {
logic [6:0] opcode;
logic [4:0] rd, rs1, rs2;
logic [2:0] funct3;
logic [6:0] funct7;
logic [31:0] pc;
logic [31:0] rs1_data;
logic [31:0] rs2_data;
logic [31:0] imm;
alu_op_t alu_op;
} decode_reg;

decode_reg decode_n, decode_r;


logic decode_en;
logic stall_decode;
// assign it to instr valid for now, later add stall logic
logic decode_valid; // for flushing
assign decode_en = !stall_decode;

// register file
logic [31:0] rs1_data;
logic [31:0] rs2_data;
logic [31:0] rd_data;

// Writeback stage intermediate values


// Also used for access register file
logic [31:0] wb_write_data;
logic [4:0] wb_rd;
logic wb_write_enable;

register_file get_reg_value (
.clk(clk),
.reset(reset),
.rs1(inst_mem_rsp.data[19:15]), // rs1
.rs2(inst_mem_rsp.data[24:20]), // rs2
.rd(wb_rd), // rd, destination register
.write_enable(wb_write_enable),
.write_data(wb_write_data),
.rs1_data(rs1_data),
.rs2_data(rs2_data),
.rd_data(rd_data)
);

logic decode_flush;

// mux to determine whether to flush based on branch resolution


always_comb begin
decode_valid = !decode_flush && fetch_valid;
end

always_ff @(posedge clk) begin


if(reset) begin
decode_r <= '0;
end else if(decode_en) begin
decode_r <= decode_n;
end else if (!decode_valid) begin
decode_r <= '0;
end

end

// decode stage logic


always_comb begin
// Extract instruction fields
decode_n.opcode = inst_mem_rsp.data[6:0];
decode_n.rd = inst_mem_rsp.data[11:7];
decode_n.funct3 = inst_mem_rsp.data[14:12];
decode_n.rs1 = inst_mem_rsp.data[19:15];
decode_n.rs2 = inst_mem_rsp.data[24:20];
decode_n.funct7 = inst_mem_rsp.data[31:25];

// Read register values


decode_n.rs1_data = rs1_data;
decode_n.rs2_data = rs2_data;

// Pass PC to next stage


decode_n.pc = fetch_r.pc;

// Compute Immediate
case (decode_n.opcode)
7'b0010011, 7'b0000011, 7'b1100111: // I-Type, and jalr
decode_n.imm = {{20{inst_mem_rsp.data[31]}},
inst_mem_rsp.data[31:20]};

7'b0100011: // S-Type (Stores: SB, SH, SW)


decode_n.imm = {{20{inst_mem_rsp.data[31]}},
inst_mem_rsp.data[31:25], inst_mem_rsp.data[11:7]};

7'b1100011: // B-Type
decode_n.imm = {{19{inst_mem_rsp.data[31]}}, inst_mem_rsp.data[7],
inst_mem_rsp.data[30:25], inst_mem_rsp.data[11:8], 1'b0};

7'b1101111: // J-Type (JAL)


decode_n.imm = {{11{inst_mem_rsp.data[31]}},
inst_mem_rsp.data[19:12], inst_mem_rsp.data[20], inst_mem_rsp.data[30:21], 1'b0};

7'b0110111, 7'b0010111: // U-Type (LUI, AUIPC)


decode_n.imm = {inst_mem_rsp.data[31:12], 12'b0};

default:
decode_n.imm = 32'b0;
endcase

// Compute ALU Operation


decode_n.alu_op = ALU_NO_OP; // Default
case (decode_n.opcode)
7'b0110011: begin // R-Type
case ({decode_n.funct7, decode_n.funct3})
10'b0000000000: decode_n.alu_op = ALU_ADD;
10'b0100000000: decode_n.alu_op = ALU_SUB;
10'b0000000001: decode_n.alu_op = ALU_SLL;
10'b0100000101: decode_n.alu_op = ALU_SRA;
10'b0000000111: decode_n.alu_op = ALU_AND;
10'b0000000110: decode_n.alu_op = ALU_OR;
10'b0000000100: decode_n.alu_op = ALU_XOR;
default: decode_n.alu_op = ALU_NO_OP;
endcase
end

7'b0010011: begin // I-Type


case (decode_n.funct3)
3'b000: decode_n.alu_op = ALU_ADD;
3'b001: decode_n.alu_op = ALU_SLL;
3'b101: if (decode_n.funct7 == 7'b0100000) decode_n.alu_op =
ALU_SRA;
3'b111: decode_n.alu_op = ALU_AND;
3'b110: decode_n.alu_op = ALU_OR;
3'b100: decode_n.alu_op = ALU_XOR;
default: decode_n.alu_op = ALU_NO_OP;
endcase
end

7'b0010111: decode_n.alu_op = ALU_AUIPC;


7'b0110111: decode_n.alu_op = ALU_LUI;
7'b0000011: decode_n.alu_op = ALU_LOAD;
7'b0100011: decode_n.alu_op = ALU_STORE;
7'b1100011: decode_n.alu_op = ALU_BRCH;
7'b1101111: decode_n.alu_op = ALU_JAL;
7'b1100111: decode_n.alu_op = ALU_JALR;

default: decode_n.alu_op = ALU_NO_OP;


endcase

end
// hazard detection
// dependencies rs1 or rs2 equals the rd in ex, mem, or wb.
// structural hazard: instr_mem_rsp.valid or data_mem_rsp.valid does not go high
logic hazard_appear;
logic exe_r_rd;
logic mem_r_rd;
always_comb begin

hazard_appear = 1'b0;

if (!inst_mem_rsp.valid)
hazard_appear = 1'b1;

if (exe_r_rd != 5'b0) begin


if (decode_n.rs1 == exe_r_rd)
hazard_appear = 1'b1;
if (decode_n.rs2 == exe_r_rd)
hazard_appear = 1'b1;
end

if (mem_r_rd != 5'b0) begin


if (decode_n.rs1 == mem_r_rd)
hazard_appear = 1'b1;
if (decode_n.rs2 == mem_r_rd)
hazard_appear = 1'b1;
end

if (wb_rd != 5'b0 && wb_write_enable) begin


if (decode_n.rs1 == wb_rd)
hazard_appear = 1'b1;
if (decode_n.rs2 == wb_rd)
hazard_appear = 1'b1;
end
end
assign stall_decode = hazard_appear;
assign stall_fetch = hazard_appear;

// exe-memory data tranisition


typedef struct packed {
logic [31:0] alu_result;
logic [2:0] funct3;
logic [31:0] rs2_data;
logic [4:0] rd;
logic [6:0] opcode;
logic branch_taken;
logic [31:0] jump_target;
logic [31:0] mem_address;
} exe_reg;

exe_reg exe_n, exe_r;


logic exe_en;
logic exe_valid;
logic [31:0] executed_operand1, executed_operand2;
// flush intermidiate signal assignements
assign decode_flush = exe_r.branch_taken;
assign exe_flush = exe_r.branch_taken;
logic mem_flush;
assign mem_flush = exe_r.branch_taken;

assign exe_en = !hazard_appear; // Also, 1 for now, later add hazard detection
always_comb begin
exe_valid = !exe_flush && decode_valid;
end

always_ff @(posedge clk)begin


if(reset)begin
exe_r <= '0;
end else if (exe_en) begin
exe_r <= exe_n;
end else if (!exe_valid) begin
exe_r <= '0;
end
end

assign exe_r_rd = exe_r.rd;


assign exe_r_opcode = exe_r.opcode;

// execute process logic


always_comb begin
// Select ALU operands
executed_operand1 = decode_r.rs1_data;

if(decode_r.opcode == 7'b0110011) begin


executed_operand2 = decode_r.rs2_data;
end else begin
executed_operand2 = decode_r.imm;
end

// Initialize default values


exe_n.alu_result = 32'b0;
exe_n.branch_taken = 1'b0;
exe_n.jump_target = 32'b0;
exe_n.mem_address = 32'b0;

exe_n.funct3 = decode_r.funct3;
exe_n.rs2_data = decode_r.rs2_data;
exe_n.rd = decode_r.rd;
exe_n.opcode = decode_r.opcode;

// ALU operations
case (decode_r.alu_op)
// Arithmetic and Logic Operations
ALU_ADD: exe_n.alu_result = executed_operand1 + executed_operand2;
ALU_SUB: exe_n.alu_result = executed_operand1 - executed_operand2;
ALU_SLL: exe_n.alu_result = executed_operand1 <<
executed_operand2[4:0];
ALU_SRA: exe_n.alu_result = executed_operand1 >>>
executed_operand2[4:0];
ALU_AND: exe_n.alu_result = executed_operand1 & executed_operand2;
ALU_OR: exe_n.alu_result = executed_operand1 | executed_operand2;
ALU_XOR: exe_n.alu_result = executed_operand1 ^ executed_operand2;
ALU_AUIPC: exe_n.alu_result = decode_r.pc + executed_operand2;
ALU_LUI: exe_n.alu_result = executed_operand2;
// Load and Store Address Calculation
ALU_LOAD, ALU_STORE: exe_n.mem_address = decode_r.rs1_data +
decode_r.imm;

// Branch Operations
ALU_BRCH: begin
case (decode_r.funct3)
3'b000: exe_n.branch_taken = (decode_r.rs1_data == decode_r.rs2_data);
// BEQ
3'b001: exe_n.branch_taken = (decode_r.rs1_data !=
decode_r.rs2_data); // BNE
3'b100: exe_n.branch_taken = ($signed(decode_r.rs1_data) <
$signed(decode_r.rs2_data)); // BLT
3'b101: exe_n.branch_taken = ($signed(decode_r.rs1_data) >=
$signed(decode_r.rs2_data)); // BGE
3'b110: exe_n.branch_taken = (decode_r.rs1_data < decode_r.rs2_data); //
BLTU
3'b111: exe_n.branch_taken = (decode_r.rs1_data >=
decode_r.rs2_data); // BGEU
default: exe_n.branch_taken = 1'b0;
endcase
exe_n.jump_target = decode_r.pc + decode_r.imm;
end

// Jumps
ALU_JAL: begin
exe_n.jump_target = decode_r.pc + decode_r.imm;
exe_n.alu_result = decode_r.pc + 4;
end

ALU_JALR: begin
exe_n.jump_target = (decode_r.rs1_data + decode_r.imm) & ~1;
exe_n.alu_result = decode_r.pc + 4;
end

default: exe_n.alu_result = 32'b0; // Default


endcase

// pc combinational control
// next_pc_fetch and fetch.n available
// as soom as decode_r is available
case (decode_r.opcode)
7'b1101111, 7'b1100111: begin // jal, jalr
next_pc_fetch = exe_n.jump_target;
end

7'b1100011: begin // branch


if (exe_n.branch_taken) begin
next_pc_fetch = exe_n.jump_target;
end else begin
next_pc_fetch = decode_r.pc + 4;
end
end

default : next_pc_fetch = decode_r.pc + 4;


endcase

end
// memory-writeback data tranisition
typedef struct packed {
logic [2:0] funct3;
logic [31:0] alu_result;
logic [4:0] rd;
logic [6:0] opcode;
} mem_reg;

mem_reg mem_n, mem_r;


logic mem_en;
logic mem_valid;
assign mem_en = !hazard_appear; // just for now
always_comb begin
mem_valid = !mem_flush && exe_valid;
end

always_ff @(posedge clk) begin


if(reset) begin
mem_r <= '0;
end else if (mem_en) begin
mem_r <= mem_n;
end else if (!mem_valid) begin
mem_r <= '0;
end
end

assign mem_r_rd = mem_r.rd;

// memory stage logic


always_comb begin
// Simply pass data forward
mem_n.funct3 = exe_r.funct3;
mem_n.alu_result = exe_r.alu_result;
mem_n.rd = exe_r.rd;
mem_n.opcode = exe_r.opcode;

// Default assignments
data_mem_req.valid = 1'b0;
data_mem_req.do_read = 4'b0000;
data_mem_req.do_write = 4'b0000;
data_mem_req.addr = exe_r.mem_address;
data_mem_req.data = exe_r.rs2_data;// data to store
// Load
if (exe_r.opcode == 7'b0000011) begin
data_mem_req.valid = 1'b1;
data_mem_req.do_read = 4'b1111; // Read full word
end

// Store Instructions
if (exe_r.opcode == 7'b0100011) begin
data_mem_req.valid = 1'b1;
case (exe_r.funct3)
3'b000: data_mem_req.do_write = 4'b0001; // SB
3'b001: data_mem_req.do_write = 4'b0011; // SH
3'b010: data_mem_req.do_write = 4'b1111; // SW
default: data_mem_req.do_write = 4'b0000;
endcase
end
end

// writeback process logic


logic wb_en;
logic wb_valid;
assign wb_en = 1'b1;
assign wb_valid = 1'b1;

always_ff @(posedge clk) begin


if(reset) begin
wb_write_enable = 1'b0;
wb_write_data = 32'b0;
wb_rd = '0;
end else if (wb_en) begin
wb_rd = mem_r.rd;

case (mem_r.opcode)
7'b0000011: begin // loads
if (data_mem_rsp.valid) begin
case (mem_r.funct3)
3'b000: wb_write_data = {{24{data_mem_rsp.data[7]}},
data_mem_rsp.data[7:0]}; // LB
3'b001: wb_write_data = {{16{data_mem_rsp.data[15]}},
data_mem_rsp.data[15:0]}; // LH
3'b010: wb_write_data = data_mem_rsp.data; // LW
3'b100: wb_write_data = {24'b0, data_mem_rsp.data[7:0]}; // LBU
3'b101: wb_write_data = {16'b0, data_mem_rsp.data[15:0]}; //
LHU
default: wb_write_data = 32'b0;
endcase
wb_write_enable = 1'b1;
end
else begin
wb_write_enable = 1'b0;
end
end

7'b0110011, // R-type
7'b0010011, // I-type
7'b1101111, // JAL
7'b1100111, // JALR
7'b0110111, // LUI
7'b0010111: // AUIPC
begin
wb_write_data = mem_r.alu_result;
wb_write_enable = 1'b1;
end

default: begin
wb_write_enable = 1'b0;
wb_write_data = 32'b0;
end
endcase
end else if (!wb_valid) begin
wb_write_enable = 1'b0;
wb_write_data = 32'b0;
wb_rd = '0;
end
end

integer cnt = 0;
always_ff @(negedge clk) begin
$display("---------------next cycle----------------------------------");
$display("Cycle: %d ", cnt);
$display("");
$display("fetch part info: ---------");
$display("n pc: %x, r pc: %x", fetch_n.pc, fetch_r.pc);
$display("branch taken: %b", exe_n.branch_taken);
$display("");
$display("decode part info: --------");
$display("instr back : %b", inst_mem_rsp.data);
$display("decode_n reg: ");
$display("pc: %x", decode_n.pc);
$display("opcode: %b, rd: %d, rs1: %d, rs2: %d,", decode_n.opcode,
decode_n.rd, decode_n.rs1, decode_n.rs2);
$display("f3: %b, f7: %b", decode_n.funct3, decode_n.funct7);
$display("rs1 data: %d, rs2 data: %d", decode_n.rs1_data, decode_n.rs2_data);
$display("imm: %d", decode_n.imm);
$display("alu_op: %s", alu_op_to_string(decode_n.alu_op));
$display("decode_r reg: ");
$display("pc: %x", decode_r.pc);
$display("opcode: %b, rd: %d, rs1: %d, rs2: %d,", decode_r.opcode, decode_r.rd,
decode_r.rs1, decode_r.rs2);
$display("f3: %b, f7: %b", decode_r.funct3, decode_r.funct7);
$display("rs1 data: %d, rs2 data: %d", decode_r.rs1_data, decode_r.rs2_data);
$display("imm: %d", decode_r.imm);
$display("alu_op: %s", alu_op_to_string(decode_r.alu_op));
$display("");
$display("exe part info: -----------");
$display("next pc fetch: %x", next_pc_fetch);
$display("oprand1: %d, operand2: %d", executed_operand1,
executed_operand2);
$display("exe_n reg: ");
$display("opcode: %b", exe_n.opcode);
$display("alu_result: %d, rd: %d", exe_n.alu_result, exe_n.rd);
$display("branch taken: %b, jump target: %x", exe_n.branch_taken,
exe_n.jump_target);
$display("data to store: %d, addr to access: %x", exe_n.rs2_data,
exe_n.mem_address);
$display("exe_r reg: ");
$display("opcode: %b", exe_r.opcode);
$display("alu_result: %d, rd: %d", exe_r.alu_result, exe_r.rd);
$display("branch taken: %b, jump target: %x", exe_r.branch_taken,
exe_r.jump_target);
$display("data to store: %d, addr to access: %x", exe_r.rs2_data,
exe_r.mem_address);
$display("");
$display("mem part info: -----------");
$display("just move data forward and operating mem req");
$display("");
$display("wb part info: ------------");
$display("write enable: %b, rd: %d", wb_write_enable, wb_rd);
$display("wb_write_data: %d", wb_write_data);
$display("opcode: %b, alu_result: %d", mem_r.opcode, mem_r.alu_result);
if (cnt == 20) begin
$finish;
end

cnt <= cnt + 1'b1;


end

endmodule

module register_file (
input logic clk,
input logic reset,
input logic [4:0] rs1,
input logic [4:0] rs2,
input logic [4:0] rd,
input logic write_enable,
input logic [31:0] write_data,
output logic [31:0] rs1_data,
output logic [31:0] rs2_data,
output logic [31:0] rd_data
);
// register 2d array, where each register has width [31:0]
// and the 2d array has 32 registers [31:0]
logic [31:0][31:0] registers;

// read operations
always_comb begin

if(rs1 == 5'b0) begin


rs1_data = 32'b0;
end else begin
rs1_data = registers[rs1];
end

if(rs2 == 5'b0) begin


rs2_data = 32'b0;
end else begin
rs2_data = registers[rs2];
end

if(rd == 5'b0) begin


rd_data = 32'b0;
end else begin
rd_data = registers[rd];
end

end

// write operation
always_ff @(posedge clk)begin
if (reset) begin
for(int i = 0; i < 32; i++) begin
registers[i] <= 32'b0;
end
end else if (write_enable && rd != 0) begin
registers[rd] <= write_data;
end
end
endmodule

function automatic logic [8*16-1:0] alu_op_to_string(input [3:0] alu_op);


// We’ll return up to 16 ASCII characters in a 128-bit bus
// so that we can safely store short strings like "ALU_ADD", etc.
begin
case (alu_op)
4'b0000: alu_op_to_string = "ALU_NO_OP";
4'b0001: alu_op_to_string = "ALU_ADD";
4'b0010: alu_op_to_string = "ALU_SUB";
4'b0011: alu_op_to_string = "ALU_SLL";
4'b0100: alu_op_to_string = "ALU_SRA";
4'b0101: alu_op_to_string = "ALU_AUIPC";
4'b0110: alu_op_to_string = "ALU_AND";
4'b0111: alu_op_to_string = "ALU_OR";
4'b1000: alu_op_to_string = "ALU_XOR";
4'b1001: alu_op_to_string = "ALU_LOAD";
4'b1010: alu_op_to_string = "ALU_STORE";
4'b1011: alu_op_to_string = "ALU_LUI";
4'b1100: alu_op_to_string = "ALU_BRCH";
4'b1101: alu_op_to_string = "ALU_JAL";
4'b1110: alu_op_to_string = "ALU_JALR";
default: alu_op_to_string = "UNKNOWN";
endcase
end
endfunction

`endif

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy