Implement new register file

This commit is contained in:
Markus Wegmann 2016-12-20 04:43:15 +01:00
parent b9bdeea057
commit 1673231b23

View file

@ -49,93 +49,284 @@ module riscv_prefetch_buffer
// Prefetch Buffer Status
output logic busy_o
);
assign addr_o = addr_i; // Fix assignment, as no other adress is expected.
/// Regs
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED } CS, NS;
logic [15:0] last_instr_rdata_q; // A 16 bit register to store one compressed instruction for next fetch
logic [31:2] last_instr_addr_q; // A 16 bit register to store one compressed instruction for next fetch
logic [15:0] last_instr_rdata;
logic [31:2] last_instr_addr;
logic instr_is_compressed; // Shows if current instruction fetch is compressed
logic instr_is_misaligned;
logic instr_part_in_fifo; // Indicates if address (mod 4) is already fetched.
logic instr_part_in_fifo_is_compressed;
logic [15:0] last_instr_rdata_Q, last_instr_rdata_n; // A 16 bit register to store one compressed instruction or half full instruction for next fetch
logic [31:0] last_instr_addr_Q, last_instr_addr_n; // The adress from the last fetch
logic last_addr_valid_Q, last_addr_valid_n; // Content of registers is valid
logic last_addr_misaligned_Q, last_addr_misaligned_n // Indicates whether we need to fetch the second part of an misaligned full instruction
assign last_instr_rdata = instr_rdata_i[31:16]; // Throw away lower part to keep instruction register at 16 bit
assign last_instr_addr = addr_i[31:2];
/// Combinational signals
logic [31:0] addr_next; // Calculate the next adress. This is THE actual process counter (PC)
logic [31:0] addr_selected; // The next address selected to be used
logic instr_is_compressed; // Shows if current instruction fetch is compressed
logic instr_is_misaligned;
logic instr_part_in_fifo; // Indicates if address (mod 4) is already fetched.
logic instr_part_in_fifo_is_compressed;
assign busy_o = (CS != IDLE) || instr_req_o;
assign instr_is_compressed = (instr_rdata_i[1:0] != 2'b11); // Check if instruction is not a 32 bit instruction and therefore compressed
assign instr_addr_is_misaligned = (instr_addr_o[1] == 1'b1); // Check if address is (addr/2 mod 2) == 1
assign addr_is_misaligned = (addr_selected[1] == 1'b1); // Check if address is (addr/2 mod 2) == 1
assign instr_part_in_fifo = ( (addr_i[31:2] == last_instr_addr_q) && instr_addr_is_misaligned ); // Check if (address / 4) is the same and
assign instr_part_in_fifo_is_compressed = (last_instr_rdata_q[1:0] != 2'b11);
assign instr_part_in_fifo = ( last_addr_valid_Q && (addr_selected[31:2] == last_instr_addr_Q[31:2]) && addr_is_misaligned); // Check if addresses are the same word
assign instr_part_in_fifo_is_compressed = (last_instr_rdata_Q[1:0] != 2'b11);
enum logic []
enum logic [2:0] {UNKNOWN_ALIGNED, FULL_INSTR_ALIGNED, C_INSTR_ALIGNED, C_INSTR_IN_REG, PART_INSTR_IN_REG} instruction_format;
enum logic [1:0] {INSTR_ALIGNED, C_INSTR_MISALIGNED, C_INSTR_IN_REG, PART_INSTR_IN_REG} instruction_format;
// Calculate next address
always_comb
begin
unique case (instruction_format)
UNKNOWN_ALIGNED: addr_next = last_instr_addr_n;
FULL_INSTR_ALIGNED: addr_next = last_instr_addr_n + 32'h4;
C_INSTR_ALIGNED: addr_next = last_instr_addr_n + 32'h2;
C_INSTR_IN_REG: addr_next = last_instr_addr_n + 32'h2;
PART_INSTR_IN_REG: addr_next = last_instr_addr_n + 32'h4;
default: addr_next = last_instr_addr_n;
endcase
end
// Construct the outgoing instruction
always_comb
begin
unique case (instruction_format)
INSTR_ALIGNED: rdata_o = instr_rdata_i;
C_INSTR_MISALIGNED: rdata_o = {16'h0000, instr_rdata_i[15:0]};
UNKNOWN_ALIGNED: rdata_o = 32'h0000;
FULL_INSTR_ALIGNED: rdata_o = instr_rdata_i;
C_INSTR_ALIGNED: rdata_o = {16'h0000, instr_rdata_i[15:0]}
C_INSTR_IN_REG: rdata_o = {16'h0000, last_instr_rdata};
PART_INSTR_IN_REG: rdata_o = {instr_rdata_i[15:0], last_instr_rdata};
default: rdata_o = instr_rdata_i;
default: rdata_o = 32'h0000;
endcase
end
always_comb
begin
NS = CS;
valid_o = 1'b1;
instr_req_o = 1'b0;
instr_addr_o = 1'b0;
last_instr_rdata_n = last_instr_rdata_Q; // Throw away lower part to keep instruction register at 16 bit
last_instr_addr_n = last_instr_addr_Q;
last_addr_valid_n = last_addr_valid_Q;
last_addr_full_misaligned_n = last_addr_full_misaligned_Q;
busy_o = 1'b0;
valid_o = 0'b0;
instr_req_o = 1'b0;
instr_addr_o = 32'b0;
addr_selected = addr_next;
addr_o = last_instr_addr_Q;
instruction_format = UNKNOWN_ALIGNED;
unique case (CS)
case IDLE:
if (req_i == 1'b1)
begin
IDLE: begin
last_addr_full_misaligned_n = 1'b0;
if (req_i) begin
if (branch_i)
addr_selected = addr_i;
// Check if already buffered
if (instr_part_in_fifo && instr_part_in_fifo_is_compressed) begin
instruction_format = C_INSTR_IN_REG;
addr_o = addr_selected;
valid_o = 1'b1;
NS = IDLE;
end else if (instr_part_in_fifo && ~instr_part_in_fifo_is_compressed) begin
last_addr_full_misaligned_n = 1'b1;
last_instr_addr_n = addr_selected;
instr_req_o = 1'b1;
instr_addr_o = {addr_selected[31:2] + 30'h1, 2'b00};
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else
NS = WAIT_GNT;
end
end
end else begin
last_instr_addr_n = addr_selected;
instr_req_o = 1'b1;
instr_addr_o = {addr_selected[31:0], 2'b00};
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else
NS = WAIT_GNT;
end
end
end
case
end
WAIT_GNT: begin
if (last_addr_full_misaligned_Q) begin
instr_req_o = 1'b1;
instr_addr_o = {last_instr_addr_Q[31:2] + 30'h1, 2'b00};
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else
NS = WAIT_GNT;
end
end
else begin
instr_req_o = 1'b1;
instr_addr_o = {last_instr_addr_Q[31:2], 2'b00};
if (instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end
end
WAIT_RVALID: begin
if (~branch_i) begin
NS = WAIT_RVALID;
if (instr_rvalid_i) begin
// Regs
last_instr_rdata_n = instr_rdata_i;
last_addr_valid_n = 1'b1;
last_addr_full_misaligned_n = 1'b0;
// Output
if (last_addr_full_misaligned_Q) begin
instruction_format = PART_INSTR_IN_REG;
addr_o = last_instr_addr_Q - 32'h2;
valid_o = 1'b1;
NS = IDLE; // Can go to IDLE as there is still information to process (and we do not want an unneccessary access if next instruction should be compressed)
end
else if (last_instr_addr_Q[1] == 1'b0) // If last address is aligned
if (instr_rdata_i[1:0] != 2'b11) begin // If compressed
instruction_format = C_INSTR_ALIGNED;
addr_o = last_instr_addr_Q;
valid_o = 1'b1;
NS = IDLE; // Can go to IDLE as there is still information to process (and we do not want an unneccessary access if next instruction should be compressed as well)
end
else begin
instruction_format = FULL_INSTR_ALIGNED;
addr_o = last_instr_addr_Q;
valid_o = 1'b1;
instr_req_o = 1'b1;
last_instr_addr_n = addr_selected;
instr_addr_o = addr_selected;
if (instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end
end
else begin // If last address is misaligned
if (instr_rdata_i[1:0] != 2'b11) begin // If compressed
instruction_format = C_INSTR_IN_REG;
addr_o = last_instr_addr_Q;
valid_o = 1'b1;
instr_req_o = 1'b1;
last_instr_addr_n = addr_selected;
instr_addr_o = addr_selected;
if (instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end
else begin // Instruction is overlapping
last_addr_full_misaligned_n = 1'b1;
last_instr_addr_n = addr_selected;
instr_req_o = 1'b1;
instr_addr_o = {addr_selected[31:2] + 30'h1, 2'b00};
if (instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end
end
end
end
else begin
last_addr_valid_n = 1'b0;
if (instr_rvalid_i)
NS = IDLE;
else
NS = WAIT_ABORTED;
end
end
WAIT_ABORTED: begin
if (instr_rvalid_i)
NS = IDLE;
else
NS = WAIT_ABORTED;
end
default: NS = IDLE;
end
end
//////////////////////////////////////////////////////////////////////////////
// registers
// registers //
//////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
CS <= IDLE;
instr_reg_q <= 32'h0000;
end
else
begin
CS <= NS;
CS <= IDLE;
last_instr_rdata_Q <= 32'h0000;
last_instr_addr_Q <= 32'h0000;
last_addr_valid_Q <= 1'b0;
last_addr_full_misaligned_Q <= 1'b0;
end
else begin
CS <= NS;
last_instr_rdata_Q <= last_instr_rdata_n;
last_instr_addr_Q <= last_instr_addr_n;
last_addr_valid_Q <= last_addr_valid_n;
last_addr_full_misaligned_Q <= last_addr_full_misaligned_n;
end
end