execution and writeback changes for new ID system

This commit is contained in:
Eric Matthews 2020-05-31 20:01:02 -07:00
parent faede7fe7e
commit a0f4368f85
22 changed files with 443 additions and 587 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2017 Eric Matthews, Lesley Shannon
* Copyright © 2017-2020 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,9 +27,10 @@ import taiga_types::*;
module alu_unit(
input logic clk,
input logic rst,
input logic single_cycle_issue_possible,
unit_issue_interface.unit issue,
input alu_inputs_t alu_inputs,
output unit_writeback_t wb
unit_writeback_interface.unit wb
);
logic[XLEN:0] add_sub_result;
@ -77,10 +78,10 @@ module alu_unit(
////////////////////////////////////////////////////
//Output
assign issue.ready = 1;
assign issue.ready = single_cycle_issue_possible;//single_cycle_issue_possible;
assign wb.rd = result;
assign wb.done = issue.new_request;
assign wb.id = issue.instruction_id;
assign wb.id = issue.id;
////////////////////////////////////////////////////
//Assertions

View file

@ -65,6 +65,7 @@ module branch_unit(
logic [31:0] pc_ex;
logic instruction_is_completing;
logic jal_jalr_ex;
////////////////////////////////////////////////////
//Implementation
//Only stall condition is if the following instruction is not valid for pc comparisons.
@ -108,17 +109,18 @@ module branch_unit(
new_pc_ex[31:1] <= new_pc[31:1];
new_pc_ex[0] <= new_pc[0] & ~branch_inputs.jalr;
id_ex <= issue.id;
jal_jalr_ex <= branch_inputs.jal | branch_inputs.jalr;
end
end
////////////////////////////////////////////////////
//Exception support
instruction_id_t jmp_instruction_id;
id_t jmp_id;
generate if (ENABLE_M_MODE) begin
always_ff @(posedge clk) begin
if (instruction_is_completing | ~branch_issued_r)
jmp_instruction_id <= issue.instruction_id;
jmp_id <= issue.id;
end
assign potential_branch_exception = new_pc[1] & issue.new_request;
@ -126,16 +128,15 @@ module branch_unit(
assign br_exception.valid = new_pc_ex[1] & branch_taken_ex & branch_issued_r;
assign br_exception.code = INST_ADDR_MISSALIGNED;
assign br_exception.pc = pc_ex;
assign br_exception.tval = new_pc_ex;
assign br_exception.id = jmp_instruction_id;
assign br_exception.id = jmp_id;
end
endgenerate
////////////////////////////////////////////////////
//ID Management
assign branch_complete = instruction_is_completing | br_exception.valid;
assign branch_complete = (instruction_is_completing & ~jal_jalr_ex);
assign branch_id = id_ex;
////////////////////////////////////////////////////

View file

@ -40,6 +40,7 @@ module csr_regs
output exception_packet_t csr_exception,
output logic [1:0] current_privilege,
input logic gc_supress_writeback,
input logic [31:0] exception_pc,
//Decode
input logic instruction_issued_no_rd,
@ -382,7 +383,7 @@ generate if (ENABLE_M_MODE) begin
always_ff @(posedge clk) begin
mepc[1:0] <= '0;
if (mwrite_decoder[MEPC[7:0]] | gc_exception.valid)
mepc[XLEN-1:2] <= gc_exception.valid ? gc_exception.pc[XLEN-1:2] : updated_csr[XLEN-1:2];
mepc[XLEN-1:2] <= gc_exception.valid ? exception_pc[XLEN-1:2] : updated_csr[XLEN-1:2];
end
assign csr_mepc = mepc;

View file

@ -35,7 +35,6 @@ module decode_and_issue (
input logic [31:0] decode_pc,
input logic [31:0] decode_instruction,
tracking_interface.decode ti,
register_file_issue_interface.issue rf_issue,
output alu_inputs_t alu_inputs,
@ -57,7 +56,6 @@ module decode_and_issue (
output id_t issue_id,
output logic issue_stage_valid,
output logic id_issued,
output logic dummy_id_complete,
output logic instruction_issued_no_rd,
output logic instruction_issued_with_rd,
output logic illegal_instruction,
@ -189,26 +187,7 @@ module decode_and_issue (
end
end
assign rf_issue.instruction_issued = instruction_issued_with_rd & (|rd_addr_issue_stage);
assign rf_issue.id = ti.issue_id;
////////////////////////////////////////////////////
//Tracking Interface
//CSR results are passed through the load/store output
always_comb begin
unit_needed_for_id_gen = unit_needed[NUM_WB_UNITS-1:0];
unit_needed_for_id_gen[LS_UNIT_WB_ID] |= (unit_needed[GC_UNIT_ID] & is_csr);
end
one_hot_to_integer #(NUM_WB_UNITS) unit_id_gen (.*, .one_hot(unit_needed_for_id_gen), .int_out(unit_needed_for_id_gen_int));
always_ff @(posedge clk) begin
if (issue_stage_ready) begin
ti.inflight_packet.is_store <= is_store;
ti.issue_unit_id <= unit_needed_for_id_gen_int;
ti.exception_possible <= opcode_trim inside {LOAD_T, STORE_T, AMO_T};
ti.inflight_packet.rd_addr <= rd_addr;
end
end
assign ti.issued = instruction_issued & (uses_rd_issue_stage | unit_needed_issue_stage[LS_UNIT_WB_ID]);
assign rf_issue.id = issue_id;
////////////////////////////////////////////////////
//Unit Determination
@ -239,14 +218,15 @@ module decode_and_issue (
////////////////////////////////////////////////////
//Issue Determination
assign issue_valid = issue_stage_valid & ti.id_available & ~gc_issue_hold & ~gc_fetch_flush;
assign issue_valid = issue_stage_valid & ~gc_issue_hold & ~gc_fetch_flush;
assign operands_ready = ~rf_issue.rs1_conflict & ~rf_issue.rs2_conflict;
//All units share the same operand ready logic except load-store which has an internal forwarding path
always_comb begin
unit_operands_ready = {NUM_UNITS{operands_ready}};
unit_operands_ready[LS_UNIT_WB_ID] = ~rf_issue.rs1_conflict;
unit_operands_ready[LS_UNIT_WB_ID] = ~rf_issue.rs1_conflict & ~rf_issue.rs2_conflict;
unit_operands_ready[BRANCH_UNIT_ID] &= unit_ready[ALU_UNIT_WB_ID];
end
assign issue_ready = unit_needed_issue_stage & unit_ready;
@ -257,7 +237,6 @@ module decode_and_issue (
assign instruction_issued_with_rd = instruction_issued & uses_rd_issue_stage;
assign id_issued = instruction_issued;
assign dummy_id_complete = instruction_issued & ~unit_needed_issue_stage[BRANCH_UNIT_ID];
////////////////////////////////////////////////////
//ALU unit inputs
logic [XLEN-1:0] alu_rs1_data;
@ -401,10 +380,9 @@ module decode_and_issue (
assign ls_inputs.load = is_load_r;
assign ls_inputs.store = is_store_r;
assign ls_inputs.fn3 = amo_op ? LS_W_fn3 : fn3_issue_stage;
assign ls_inputs.pc = pc_issue_stage;
assign ls_inputs.rs1 = rf_issue.rs1_data;
assign ls_inputs.rs2 = rf_issue.rs2_data;
assign ls_inputs.forwarded_store = rf_issue.rs2_conflict;
assign ls_inputs.forwarded_store = 0;//rf_issue.rs2_conflict;
assign ls_inputs.store_forward_id = rf_issue.rs2_id;
////////////////////////////////////////////////////
@ -558,9 +536,8 @@ module decode_and_issue (
////////////////////////////////////////////////////
//Unit EX signals
generate for (i = 0; i < NUM_UNITS; i++) begin
assign unit_issue[i].possible_issue = unit_needed_issue_stage[i] & unit_operands_ready[i] & issue_stage_valid & ti.id_available & ~gc_issue_hold;
assign unit_issue[i].possible_issue = unit_needed_issue_stage[i] & unit_operands_ready[i] & issue_stage_valid & ~gc_issue_hold;
assign unit_issue[i].new_request = issue[i];
assign unit_issue[i].instruction_id = ti.issue_id;
assign unit_issue[i].id = issue_id;
always_ff @(posedge clk) begin
unit_issue[i].new_request_r <= issue[i];
@ -583,7 +560,7 @@ module decode_and_issue (
//Illegal instruction if the instruction is invalid, but could otherwise be issued
assign illegal_instruction = illegal_instruction_pattern_r & issue_stage_valid & ti.id_available & ~gc_issue_hold & ~gc_fetch_flush;
assign illegal_instruction = illegal_instruction_pattern_r & issue_stage_valid & ~gc_issue_hold & ~gc_fetch_flush;
end endgenerate
////////////////////////////////////////////////////
//End of Implementation
@ -597,7 +574,7 @@ module decode_and_issue (
generate if (ENABLE_TRACE_INTERFACE) begin
assign tr_operand_stall = |(unit_needed_issue_stage & unit_ready) & issue_valid & ~|(unit_operands_ready & issue_ready);
assign tr_unit_stall = ~|(unit_needed_issue_stage & unit_ready) & issue_valid & |(unit_operands_ready & issue_ready);
assign tr_no_id_stall = |(unit_needed_issue_stage & unit_ready) & (issue_stage_valid & ~ti.id_available & ~gc_issue_hold & ~gc_fetch_flush) & |(unit_operands_ready & issue_ready);
assign tr_no_id_stall = 0;
assign tr_no_instruction_stall = ~issue_stage_valid | gc_fetch_flush;
assign tr_other_stall = issue_stage_valid & ~instruction_issued & ~(tr_operand_stall | tr_unit_stall | tr_no_id_stall | tr_no_instruction_stall);
assign tr_branch_operand_stall = tr_operand_stall & unit_needed_issue_stage[BRANCH_UNIT_ID];

View file

@ -33,7 +33,7 @@ module div_unit
input div_inputs_t div_inputs,
unit_issue_interface.unit issue,
output unit_writeback_t wb
unit_writeback_interface.unit wb
);
logic signed_divop;
@ -53,7 +53,7 @@ module div_unit
logic negate_quotient;
logic negate_remainder;
logic reuse_result;
instruction_id_t instruction_id;
id_t id;
} div_fifo_inputs_t;
div_fifo_inputs_t fifo_inputs;
@ -94,18 +94,18 @@ module div_unit
assign fifo_inputs.negate_quotient = negate_quotient;
assign fifo_inputs.negate_remainder = negate_remainder;
assign fifo_inputs.reuse_result = div_inputs.reuse_result;
assign fifo_inputs.instruction_id = issue.instruction_id;
assign fifo_inputs.id = issue.id;
////////////////////////////////////////////////////
//Input FIFO
taiga_fifo #(.DATA_WIDTH($bits(div_fifo_inputs_t)), .FIFO_DEPTH(MAX_INFLIGHT_COUNT))
taiga_fifo #(.DATA_WIDTH($bits(div_fifo_inputs_t)), .FIFO_DEPTH(MAX_IDS))
div_input_fifo (.fifo(input_fifo), .*);
assign input_fifo.data_in = fifo_inputs;
assign input_fifo.push = issue.possible_issue;
assign input_fifo.supress_push = gc_fetch_flush;
assign issue.ready = 1; //As FIFO depth is the same as MAX_INFLIGHT_COUNT
assign input_fifo.pop = div_done;
assign input_fifo.pop = wb.done & wb.ack;
assign div_op = input_fifo.data_out;
////////////////////////////////////////////////////
@ -117,7 +117,7 @@ module div_unit
set_clr_reg_with_rst #(.SET_OVER_CLR(1), .WIDTH(1), .RST_VALUE('0)) in_progress_m (
.clk, .rst,
.set(div_core.start),
.clr(div_core.done),
.clr(wb.ack),
.result(in_progress)
);
@ -129,10 +129,18 @@ module div_unit
////////////////////////////////////////////////////
//Output
logic done_r;
assign negate_result = div_op.remainder_op ? div_op.negate_remainder : (~div_core.divisor_is_zero & div_op.negate_quotient);
assign wb.rd = negate_if (div_op.remainder_op ? div_core.remainder : ({32{div_core.divisor_is_zero}} | div_core.quotient), negate_result);
assign wb.done = div_done;
assign wb.id = div_op.instruction_id;
always_ff @ (posedge clk) begin
if (wb.ack)
done_r <= 0;
else if (div_done)
done_r <= 1;
end
assign wb.done = div_done | done_r;
assign wb.id = div_op.id;
////////////////////////////////////////////////////
//Assertions

View file

@ -46,7 +46,6 @@ module gc_unit(
//Load Store Unit
input exception_packet_t ls_exception,
input logic ls_exception_valid,
//TLBs
output logic tlb_on,
@ -57,13 +56,17 @@ module gc_unit(
mmu_interface.csr dmmu,
//ID Management
output logic system_op_complete,
output id_t system_op_id,
output logic system_op_or_exception_complete,
output id_t system_op_or_exception_id,
//Exception
output id_t exception_id,
input logic [31:0] exception_pc,
//WB
input logic instruction_retired,
input logic instruction_queue_empty,
input instruction_id_t oldest_id,
input logic writeback_is_idle,
//unit_writeback_interface.unit gc_wb,
//External
@ -77,14 +80,13 @@ module gc_unit(
output logic gc_fetch_pc_override,
output logic gc_supress_writeback,
output logic ls_exception_ack,
output logic [31:0] gc_fetch_pc,
//Write-back to Load-Store Unit
output logic[31:0] csr_rd,
output instruction_id_t csr_id,
output logic csr_done
output id_t csr_id,
output logic csr_done,
input logic ls_is_idle
);
//Largest depth for TLBs
@ -139,7 +141,7 @@ module gc_unit(
// *If in-order mode and inflight queue empty, disable zero cycle write-back (eg. ALU)
//*Hold fetch during potential fetch exception, when fetch buffer drained, if no other exceptions trigger exception
typedef enum {RST_STATE, IDLE_STATE, TLB_CLEAR_STATE, IQ_DRAIN, IQ_DISCARD} gc_state;
typedef enum {RST_STATE, IDLE_STATE, TLB_CLEAR_STATE, IQ_DRAIN} gc_state;
gc_state state;
gc_state next_state;
gc_state prev_state;
@ -175,10 +177,7 @@ module gc_unit(
logic processing_csr;
logic csr_ready_to_complete;
logic csr_ready_to_complete_r;
instruction_id_t instruction_id;
instruction_id_t exception_id;
instruction_id_t exception_id_r;
id_t instruction_id;
//implementation
////////////////////////////////////////////////////
@ -190,8 +189,10 @@ module gc_unit(
////////////////////////////////////////////////////
//ID Management
assign system_op_complete = issue.new_request & (gc_inputs.is_fence | gc_inputs.is_i_fence);
assign system_op_id = issue.id;
assign system_op_or_exception_complete =
(issue.new_request & (gc_inputs.is_fence | gc_inputs.is_i_fence)) |
gc_exception.valid;
assign system_op_or_exception_id = issue.new_request ? issue.id : exception_id;
//Instruction decode
assign opcode = stage1.instruction[6:0];
@ -205,15 +206,11 @@ module gc_unit(
assign gc_fetch_flush = branch_flush | gc_fetch_pc_override;
always_ff @ (posedge clk) begin
gc_issue_hold <= issue.new_request || processing_csr || (next_state inside {TLB_CLEAR_STATE, IQ_DRAIN, IQ_DISCARD}) || potential_branch_exception;
gc_issue_hold <= issue.new_request || processing_csr || (next_state inside {TLB_CLEAR_STATE, IQ_DRAIN}) || potential_branch_exception;
end
always_ff @ (posedge clk) begin
gc_issue_flush <= (next_state == IQ_DISCARD);
end
always_ff @ (posedge clk) begin
gc_supress_writeback <= next_state inside {TLB_CLEAR_STATE, IQ_DISCARD} ? 1 : 0;
gc_supress_writeback <= next_state inside {TLB_CLEAR_STATE} ? 1 : 0;
end
////////////////////////////////////////////////////
@ -238,12 +235,11 @@ module gc_unit(
RST_STATE : next_state = IDLE_STATE;
IDLE_STATE : begin
if (ls_exception.valid | (branch_exception_is_jump & potential_branch_exception)) begin
next_state = (exception_id == oldest_id) ? IQ_DISCARD : IQ_DRAIN;
next_state = IQ_DRAIN;
end
end
TLB_CLEAR_STATE : if (tlb_clear_done) next_state = IDLE_STATE;
IQ_DRAIN : if (exception_id_r == oldest_id) next_state = IQ_DISCARD;
IQ_DISCARD : if (instruction_queue_empty) next_state = IDLE_STATE;
IQ_DRAIN : next_state = IDLE_STATE;
default : next_state = RST_STATE;
endcase
end
@ -259,7 +255,6 @@ module gc_unit(
end
////////////////////////////////////////////////////
//Exception handling
logic processing_ls_exception;
//The type of call instruction is depedent on the current privilege level
always_comb begin
@ -271,43 +266,27 @@ module gc_unit(
endcase
end
always_ff @(posedge clk) begin
if (gc_exception.valid)
processing_ls_exception <= ls_exception.valid;
end
assign ls_exception_ack = processing_ls_exception && (prev_state inside {IDLE_STATE, IQ_DRAIN}) && (state == IQ_DISCARD);
assign exception_id =
potential_branch_exception ? br_exception.id :
(ls_exception.valid ? ls_exception.id : issue.instruction_id);
always_ff @(posedge clk) begin
if (gc_exception.valid)
exception_id_r <= exception_id;
end
(ls_exception.valid ? ls_exception.id : issue.id);
//TODO: check if possible to convert to unique if, verify potential for overlap
always_comb begin
//PC sourced from instruction metadata table
if (br_exception.valid) begin
gc_exception.code = br_exception.code;
gc_exception.pc = br_exception.pc;
gc_exception.tval = br_exception.tval;
end else if (illegal_instruction) begin
gc_exception.code = ILLEGAL_INST;
gc_exception.pc = gc_inputs.pc;
gc_exception.tval = gc_inputs.instruction;//optional, can be zero instead
end else if (ls_exception.valid) begin
gc_exception.code = ls_exception.code;
gc_exception.pc = ls_exception.pc;
gc_exception.tval = ls_exception.tval;
end else if (gc_inputs.is_ecall) begin
gc_exception.code = ecall_code;
gc_exception.pc = gc_inputs.pc;
gc_exception.tval = '0;
end else begin
gc_exception.code = BREAK;
gc_exception.pc = gc_inputs.pc;
gc_exception.tval = '0;
end
end
@ -352,12 +331,12 @@ module gc_unit(
.result(processing_csr)
);
assign csr_ready_to_complete = processing_csr && (oldest_id == instruction_id);
assign csr_ready_to_complete = processing_csr & ls_is_idle & writeback_is_idle;
always_ff @(posedge clk) begin
csr_ready_to_complete_r <= csr_ready_to_complete;
csr_id <= instruction_id;
if (issue.new_request) begin
instruction_id <= issue.instruction_id;
instruction_id <= issue.id;
end
end

View file

@ -29,8 +29,8 @@ module id_inuse (
input logic [4:0] rs1_addr,
input logic [4:0] rs2_addr,
input logic [4:0] issued_rd_addr,
input instruction_id_t issue_id,
input instruction_id_t retired_id,
input id_t issue_id,
input id_t retired_id,
input logic issued,
input logic retired,
output logic rs1_inuse,

View file

@ -58,8 +58,8 @@ module id_management
input logic branch_complete,
input id_t branch_id,
input logic system_op_complete,
input id_t system_op_id,
input logic system_op_or_exception_complete,
input id_t system_op_or_exception_id,
input logic instruction_retired,
input id_t retired_id
@ -75,10 +75,9 @@ module id_management
logic decoded_toggle_mem [MAX_IDS];
logic decoded_issued_toggle_mem [MAX_IDS];
logic issued_toggle_mem [MAX_IDS];
logic dummy_toggle_mem [MAX_IDS];
logic branch_complete_toggle_mem [MAX_IDS];
logic store_complete_toggle_mem [MAX_IDS];
logic system_op_complete_toggle_mem [MAX_IDS];
logic system_op_or_exception_complete_toggle_mem [MAX_IDS];
logic retired_toggle_mem [MAX_IDS];
////////////////////////////////////////////////////
@ -146,12 +145,6 @@ module id_management
issued_toggle_mem[issue_id] <= ~issued_toggle_mem[issue_id];
end
initial dummy_toggle_mem = '{default: 0};
always_ff @ (posedge clk) begin
if (dummy_id_complete)
dummy_toggle_mem[issue_id] <= ~dummy_toggle_mem[issue_id];
end
initial branch_complete_toggle_mem = '{default: 0};
always_ff @ (posedge clk) begin
if (branch_complete)
@ -164,10 +157,10 @@ module id_management
store_complete_toggle_mem[store_id] <= ~store_complete_toggle_mem[store_id];
end
initial system_op_complete_toggle_mem = '{default: 0};
initial system_op_or_exception_complete_toggle_mem = '{default: 0};
always_ff @ (posedge clk) begin
if (system_op_complete)
system_op_complete_toggle_mem[system_op_id] <= ~system_op_complete_toggle_mem[system_op_id];
if (system_op_or_exception_complete)
system_op_or_exception_complete_toggle_mem[system_op_or_exception_id] <= ~system_op_or_exception_complete_toggle_mem[system_op_or_exception_id];
end
initial retired_toggle_mem = '{default: 0};
@ -183,11 +176,9 @@ module id_management
assign id_not_inflight =
~(issued_toggle_mem[pc_id_i] ^
branch_complete_toggle_mem[pc_id_i] ^
dummy_toggle_mem[pc_id_i]
);// ^
//store_complete_toggle_mem[pc_id_i] ^
//system_op_complete_toggle_mem[pc_id_i] ^
//retired_toggle_mem[pc_id_i]);
store_complete_toggle_mem[pc_id_i] ^
system_op_or_exception_complete_toggle_mem[pc_id_i] ^
retired_toggle_mem[pc_id_i]);
always_ff @ (posedge clk) begin
if (rst)

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2019 Eric Matthews, Lesley Shannon
* Copyright © 2020 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,49 +20,67 @@
* Eric Matthews <ematthew@sfu.ca>
*/
import taiga_config::*;
import taiga_types::*;
module id_tracking
(
import taiga_config::*;
import taiga_types::*;
(
input logic clk,
input logic rst,
input logic issued,
input logic retired,
input logic gc_fetch_flush,
//ID issuing
output id_t next_id,
output logic id_available,
output instruction_id_t oldest_id,
output instruction_id_t next_id,
output logic empty
);
input id_assigned,
// m
//Decode ID
input id_t decode_id,
input decode_issued,
output decode_id_valid,
//Issue stage
input id_t issue_id,
input instruction_issued,
);
//////////////////////////////////////////
localparam LOG2_MAX_INFLIGHT_COUNT = $clog2(MAX_INFLIGHT_COUNT);
logic [LOG2_MAX_INFLIGHT_COUNT:0] inflight_count;
localparam LOG2_MAX_IDS = $clog2(MAX_IDS);
fifo_interface #(.DATA_WIDTH($bits(id_t))) fetched_ids();
////////////////////////////////////////////////////
//Implementation
always_ff @ (posedge clk) begin
if (rst)
oldest_id <= 0;
else
oldest_id <= oldest_id + LOG2_MAX_INFLIGHT_COUNT'(retired);
end
always_ff @ (posedge clk) begin
if (rst)
next_id <= 0;
else
next_id <= next_id + LOG2_MAX_INFLIGHT_COUNT'(issued);
next_id <= next_id + LOG2_MAX_IDS'(id_assigned);
end
//Upper bit is id_available
assign fetched_ids.push = id_assigned;
assign fetched_ids.pop = decode_issued;
assign fetched_ids.data_in = next_id;
assign decode_id = fetched_ids.data_out;
assign decode_id_valid = fetched_ids.valid;
taiga_fifo #(.DATA_WIDTH($bits(id_t)), .FIFO_DEPTH(MAX_IDS))
fetched_ids_fifo (.fifo(fetched_ids), .rst(rst | gc_fetch_flush), .*);
always_ff @ (posedge clk) begin
if (rst)
inflight_count <= '1;
id_available <= 0;
else
inflight_count <= inflight_count + (LOG2_MAX_INFLIGHT_COUNT+1)'(retired) - (LOG2_MAX_INFLIGHT_COUNT+1)'(issued);
id_available <=
end
assign empty = &inflight_count;//all ones
assign id_available = inflight_count[LOG2_MAX_INFLIGHT_COUNT];
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
@ -70,7 +88,6 @@ module id_tracking
////////////////////////////////////////////////////
//Assertions
always_ff @ (posedge clk) begin
assert (rst | !(~rst & ~id_available & issued)) else $error("Issued without valid ID!");
assert (rst | !(~rst & empty & (retired & ~issued))) else $error("Retired without any instruction inflight!");
assert (rst | !(~rst & ~id_available & id_assigned)) else $error("Issued without valid ID!");
end
endmodule

View file

@ -38,7 +38,6 @@ module instruction_metadata
input logic fetch_complete,
input logic [31:0] fetch_instruction,
//Decode ID
input id_t decode_id,
output logic [31:0] decode_pc,
@ -47,18 +46,22 @@ module instruction_metadata
//Branch Predictor
input branch_metadata_t branch_metadata_if,
input id_t branch_id,
output branch_metadata_t branch_metadata_ex
output branch_metadata_t branch_metadata_ex,
//Writeback/Register File
input id_t retired_id,
output logic [4:0] retired_rd_addr,
//Exception
//input id_t exception_id,
//output logic [31:0] exception_pc,
//output logic [31:0] exception_instruction
input id_t exception_id,
output logic [31:0] exception_pc
);
//////////////////////////////////////////
logic [31:0] pc_table [MAX_IDS];
logic [31:0] instruction_table [MAX_IDS];
logic [$bits(branch_metadata_t)-1:0] branch_metadata_table [MAX_IDS];
logic [31:0] rd_table [MAX_IDS];
////////////////////////////////////////////////////
//Implementation
@ -80,6 +83,12 @@ module instruction_metadata
instruction_table[fetch_id] <= fetch_instruction;
end
//rd table
// always_ff @ (posedge clk) begin
// if (instruction_retired)
// rd_table[id_retired] <= retired_rd;
// end
////////////////////////////////////////////////////
//Outputs
@ -90,11 +99,13 @@ module instruction_metadata
//Branch Predictor
assign branch_metadata_ex = branch_metadata_table[branch_id];
//Register File
assign retired_rd_addr = instruction_table[retired_id][11:7];
//Exception Support
// generate if (ENABLE_M_MODE) begin
// assign exception_pc = pc_table[exception_id];
// assign exception_instruction = instruction_table[exception_id];
// end endgenerate
generate if (ENABLE_M_MODE) begin
assign exception_pc = pc_table[exception_id];
end endgenerate
////////////////////////////////////////////////////
//End of Implementation

View file

@ -53,13 +53,29 @@ interface unit_issue_interface;
logic possible_issue;
logic new_request;
logic new_request_r;
instruction_id_t instruction_id;
id_t id;
logic ready;
modport decode (input ready, output possible_issue, new_request, new_request_r, instruction_id, id);
modport unit (output ready, input possible_issue, new_request, new_request_r, instruction_id, id);
modport decode (input ready, output possible_issue, new_request, new_request_r, id);
modport unit (output ready, input possible_issue, new_request, new_request_r, id);
endinterface
interface unit_writeback_interface;
logic ack;
id_t id;
logic done;
logic [XLEN-1:0] rd;
modport unit (
input ack,
output id, done, rd
);
modport wb (
output ack,
input id, done, rd
);
endinterface
interface ras_interface;
@ -95,7 +111,7 @@ interface exception_interface;
exception_code_t code;
logic [31:0] pc;
logic [31:0] addr;
instruction_id_t id;
id_t id;
modport econtrol (output valid, code, pc, addr, id, input ack);
modport unit (input valid, code, pc, addr, id, output ack);
@ -107,13 +123,13 @@ interface register_file_issue_interface;
logic[XLEN-1:0] rs1_data;
logic[4:0] rs2_addr; //if not used required to be zero
logic[XLEN-1:0] rs2_data;
instruction_id_t id;
id_t id;
logic uses_rs1;
logic uses_rs2;
logic rs1_conflict;
logic rs2_conflict;
instruction_id_t rs2_id;
id_t rs2_id;
logic instruction_issued;
modport issue (output rd_addr, rs1_addr, rs2_addr, instruction_issued, id, uses_rs1, uses_rs2, input rs1_conflict, rs2_conflict, rs1_data, rs2_data, rs2_id);
@ -122,40 +138,24 @@ endinterface
interface register_file_writeback_interface;
logic[4:0] rd_addr;
//Writeback data
logic retiring;
logic rd_nzero;
id_t id;
logic[XLEN-1:0] rd_data;
instruction_id_t id;
instruction_id_t rs1_id;
instruction_id_t rs2_id;
//Forwarding signals
id_t rs1_id;
id_t rs2_id;
logic[XLEN-1:0] rs1_data;
logic[XLEN-1:0] rs2_data;
logic rs1_valid;
logic rs2_valid;
modport writeback (output rd_addr, retiring, rd_nzero, rd_data, id, rs1_data, rs2_data, rs1_valid, rs2_valid, input rs1_id, rs2_id);
modport rf (input rd_addr, retiring, rd_nzero, rd_data, id, rs1_data, rs2_data, rs1_valid, rs2_valid, output rs1_id, rs2_id);
modport writeback (output retiring, rd_data, id, rs1_data, rs2_data, rs1_valid, rs2_valid, input rs1_id, rs2_id);
modport rf (input retiring, rd_data, id, rs1_data, rs2_data, rs1_valid, rs2_valid, output rs1_id, rs2_id);
endinterface
interface tracking_interface;
instruction_id_t issue_id;
logic id_available;
inflight_instruction_packet inflight_packet;
logic issued;
logic [WB_UNITS_WIDTH-1:0] issue_unit_id;
logic exception_possible;
modport decode (input issue_id, id_available, output inflight_packet, issued, issue_unit_id, exception_possible);
modport wb (output issue_id, id_available, input inflight_packet, issued, issue_unit_id, exception_possible);
endinterface
interface fifo_interface #(parameter DATA_WIDTH = 42);//#(parameter type data_type = logic[31:0]);
logic push;
logic pop;
@ -218,30 +218,30 @@ interface load_store_queue_interface;
logic [3:0] be;
logic [2:0] fn3;
logic [31:0] data_in;
instruction_id_t id;
id_t id;
logic forwarded_store;
instruction_id_t data_id;
id_t data_id;
logic possible_issue;
logic new_issue;
logic ready;
instruction_id_t id_needed_by_store;
id_t id_needed_by_store;
data_access_shared_inputs_t transaction_out;
logic transaction_ready;
logic empty;
logic accepted;
modport queue (input addr, load, store, be, fn3, data_in, id, forwarded_store, data_id, possible_issue, new_issue, accepted, output ready, id_needed_by_store, transaction_out, transaction_ready);
modport ls (output addr, load, store, be, fn3, data_in, id, forwarded_store, data_id, possible_issue, new_issue, accepted, input ready, id_needed_by_store, transaction_out, transaction_ready);
modport queue (input addr, load, store, be, fn3, data_in, id, forwarded_store, data_id, possible_issue, new_issue, accepted, output ready, id_needed_by_store, transaction_out, transaction_ready, empty);
modport ls (output addr, load, store, be, fn3, data_in, id, forwarded_store, data_id, possible_issue, new_issue, accepted, input ready, id_needed_by_store, transaction_out, transaction_ready, empty);
endinterface
interface writeback_store_interface;
instruction_id_t id_needed_at_issue;
instruction_id_t id_needed_at_commit;
instruction_id_t commit_id;
id_t id_needed_at_issue;
id_t id_needed_at_commit;
id_t commit_id;
logic commit;
logic [MAX_INFLIGHT_COUNT-1:0] hold_for_store_ids;
logic [MAX_IDS-1:0] hold_for_store_ids;
logic forwarding_data_ready;
logic [31:0] forwarded_data;
@ -293,15 +293,3 @@ interface unsigned_division_interface #(parameter DATA_WIDTH = 32);
modport divider (output remainder, quotient, done, divisor_is_zero, input dividend, divisor, start);
endinterface
//Unit sets the ID of the instruction that will provide the data
//data_valid is high when the data is valid
interface post_issue_forwarding_interface;
instruction_id_t id;
logic [31:0] data;
logic data_valid;
modport unit (input data, data_valid, output id);
modport wb (output data, data_valid, input id);
endinterface

View file

@ -33,16 +33,16 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
input logic gc_issue_flush,
load_store_queue_interface.queue lsq,
output logic [MAX_INFLIGHT_COUNT-1:0] wb_hold_for_store_ids,
output logic [MAX_IDS-1:0] wb_hold_for_store_ids,
//Writeback data
input logic [31:0] writeback_data,
input logic writeback_valid
);
logic [MAX_INFLIGHT_COUNT-1:0] valid;
logic [$clog2(MAX_INFLIGHT_COUNT)-1:0] hold_for_store_ids [MAX_INFLIGHT_COUNT];
logic [$clog2(MAX_INFLIGHT_COUNT)-1:0] hold_for_store_ids_r [MAX_INFLIGHT_COUNT];
instruction_id_t oldest_id;
logic [MAX_IDS-1:0] valid;
logic [$clog2(MAX_IDS)-1:0] hold_for_store_ids [MAX_IDS];
logic [$clog2(MAX_IDS)-1:0] hold_for_store_ids_r [MAX_IDS];
id_t oldest_id;
typedef struct packed {
logic [31:0] addr;
@ -51,24 +51,24 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
logic [3:0] be;
logic [2:0] fn3;
logic [31:0] data_in;
instruction_id_t id;
id_t id;
logic forwarded_store;
instruction_id_t data_id;
id_t data_id;
} lsq_entry_t;
lsq_entry_t new_lsq_entry;
logic [$bits(lsq_entry_t)-1:0] lsq_entries [MAX_INFLIGHT_COUNT];
logic [$bits(lsq_entry_t)-1:0] lsq_entries [MAX_IDS];
lsq_entry_t oldest_lsq_entry;
fifo_interface #(.DATA_WIDTH($bits(instruction_id_t))) oldest_fifo ();
fifo_interface #(.DATA_WIDTH($bits(id_t))) oldest_fifo ();
////////////////////////////////////////////////////
//Implementation
//Can accept an input so long as it is a load or as long as an update from writeback for an exisiting store is not in progress
//Can always buffer new requests
assign lsq.ready = 1;
//FIFO to store ordering of IDs
taiga_fifo #(.DATA_WIDTH($bits(instruction_id_t)), .FIFO_DEPTH(MAX_INFLIGHT_COUNT)) oldest_id_fifo (
taiga_fifo #(.DATA_WIDTH($bits(id_t)), .FIFO_DEPTH(MAX_IDS)) oldest_id_fifo (
.clk, .rst(rst | gc_issue_flush),
.fifo(oldest_fifo)
);
@ -79,6 +79,8 @@ module load_store_queue //ID-based input buffer for Load/Store Unit
assign oldest_fifo.pop = lsq.accepted;
assign oldest_id = oldest_fifo.data_out;
assign lsq.empty = ~oldest_fifo.valid;
////////////////////////////////////////////////////
//Request attributes and input data (LUTRAMs)
always_comb begin

View file

@ -55,20 +55,15 @@ module load_store_unit (
//Writeback-Store Interface
writeback_store_interface.ls wb_store,
input instruction_id_t oldest_id,
output logic load_store_exception_clear,
output instruction_id_t load_store_exception_id,
input logic potential_exception,
//CSR support
input logic[31:0] csr_rd,
input instruction_id_t csr_id,
input id_t csr_id,
input logic csr_done,
output logic ls_is_idle,
output exception_packet_t ls_exception,
output logic ls_exception_valid,
input logic ls_exception_ack,
output unit_writeback_t wb
unit_writeback_interface.unit wb
);
localparam NUM_SUB_UNITS = USE_D_SCRATCH_MEM+USE_BUS+USE_DCACHE;
@ -108,11 +103,12 @@ module load_store_unit (
logic [NUM_SUB_UNITS-1:0] sub_unit_address_match;
logic unit_stall;
logic done_r;
typedef struct packed{
logic [2:0] fn3;
logic [1:0] byte_addr;
instruction_id_t instruction_id;
id_t id;
logic [NUM_SUB_UNITS_W-1:0] subunit_id;
} load_attributes_t;
load_attributes_t load_attributes_in, stage2_attr;
@ -133,12 +129,7 @@ module load_store_unit (
////////////////////////////////////////////////////
//Alignment Exception
instruction_id_t exception_id;
logic exception_is_store;
generate if (ENABLE_M_MODE) begin
assign load_store_exception_clear = issue.new_request;
assign load_store_exception_id = issue.instruction_id;
always_comb begin
case(ls_inputs.fn3)
@ -151,16 +142,9 @@ generate if (ENABLE_M_MODE) begin
assign ls_exception.valid = unaligned_addr & issue.new_request;
assign ls_exception.code = ls_inputs.store ? STORE_AMO_ADDR_MISSALIGNED : LOAD_ADDR_MISSALIGNED;
assign ls_exception.pc = ls_inputs.pc;
assign ls_exception.tval = virtual_address;
assign ls_exception.id = issue.instruction_id;
assign ls_exception.id = issue.id;
always_ff @ (posedge clk) begin
if (ls_exception.valid) begin
exception_is_store <= ls_inputs.store;
exception_id <= issue.instruction_id;
end
end
end
endgenerate
////////////////////////////////////////////////////
@ -199,14 +183,14 @@ endgenerate
assign lsq.data_in = ls_inputs.rs2;
assign lsq.load = ls_inputs.load;
assign lsq.store = ls_inputs.store;
assign lsq.id = issue.instruction_id;
assign lsq.id = issue.id;
assign lsq.forwarded_store = ls_inputs.forwarded_store;
assign lsq.data_id = ls_inputs.store_forward_id;
assign lsq.possible_issue = issue.possible_issue & ~unaligned_addr;
assign lsq.new_issue = issue.new_request & ~unaligned_addr;
logic [MAX_INFLIGHT_COUNT-1:0] wb_hold_for_store_ids;
logic [MAX_IDS-1:0] wb_hold_for_store_ids;
load_store_queue lsq_block (.*, .writeback_valid(wb_store.forwarding_data_ready), .writeback_data(wb_store.forwarded_data));
assign shared_inputs = lsq.transaction_out;
@ -214,16 +198,9 @@ endgenerate
////////////////////////////////////////////////////
//ID Management
assign store_complete = (lsq.accepted & lsq.transaction_out.store) | (ls_exception_ack & exception_is_store);
assign store_id = $clog2(MAX_IDS)'(wb_store.commit_id);
assign store_complete = lsq.accepted & lsq.transaction_out.store;
assign store_id = lsq.transaction_out.id;
////////////////////////////////////////////////////
//Writeback-Store interface
assign wb_store.id_needed_at_issue = ls_inputs.store_forward_id;
assign wb_store.id_needed_at_commit = lsq.id_needed_by_store;
assign wb_store.commit_id = ls_exception_ack ? exception_id : lsq.transaction_out.id;
assign wb_store.commit = (lsq.accepted & lsq.transaction_out.store) | (ls_exception_ack & exception_is_store);
assign wb_store.hold_for_store_ids = wb_hold_for_store_ids;
////////////////////////////////////////////////////
//Unit tracking
assign current_unit = sub_unit_address_match;
@ -245,10 +222,12 @@ endgenerate
////////////////////////////////////////////////////
//Primary Control Signals
assign ls_is_idle = lsq.empty & (~load_attributes.valid);
assign units_ready = &unit_ready;
assign load_complete = |unit_data_valid;
assign ready_for_issue = units_ready & (~unit_switch_stall);
assign ready_for_issue = units_ready & (~unit_switch_stall) & (~done_r | wb.ack);
assign issue.ready = lsq.ready;
assign issue_request = lsq.accepted;
@ -259,11 +238,11 @@ endgenerate
taiga_fifo #(.DATA_WIDTH($bits(load_attributes_t)), .FIFO_DEPTH(ATTRIBUTES_DEPTH)) attributes_fifo (.fifo(load_attributes), .*);
assign load_attributes_in.fn3 = shared_inputs.fn3;
assign load_attributes_in.byte_addr = shared_inputs.addr[1:0];
assign load_attributes_in.instruction_id = shared_inputs.id;
assign load_attributes_in.id = shared_inputs.id;
assign load_attributes.data_in = load_attributes_in;
assign load_attributes.push = issue_request & shared_inputs.load;
assign load_attributes.pop = load_complete;
assign load_attributes.pop = ((done_r | load_complete) & wb.ack);
assign load_attributes.supress_push = 0;
assign stage2_attr = load_attributes.data_out;
@ -338,9 +317,17 @@ endgenerate
////////////////////////////////////////////////////
//Output bank
always_ff @ (posedge clk) begin
if (wb.ack)
done_r <= 0;
else if (load_complete)
done_r <= 1;
end
assign wb.rd = csr_done ? csr_rd : final_load_data;
assign wb.done = csr_done | load_complete | (ls_exception_ack & ~exception_is_store);
assign wb.id = csr_done ? csr_id : (ls_exception_ack ? exception_id : stage2_attr.instruction_id);
assign wb.done = csr_done | load_complete | done_r;
assign wb.id = csr_done ? csr_id : stage2_attr.id;
////////////////////////////////////////////////////
//End of Implementation

View file

@ -30,17 +30,20 @@ module mul_unit(
input mul_inputs_t mul_inputs,
unit_issue_interface.unit issue,
output unit_writeback_t wb
unit_writeback_interface.unit wb
);
logic signed [63:0] result;
logic mulh [2];
logic done [2];
instruction_id_t id [2];
id_t id [2];
logic rs1_signed, rs2_signed;
logic signed [32:0] rs1_ext, rs2_ext;
logic signed [32:0] rs1_r, rs2_r;
logic stage1_advance;
logic stage2_advance;
////////////////////////////////////////////////////
//Implementation
assign rs1_signed = mul_inputs.op[1:0] inside {MULH_fn3[1:0], MULHSU_fn3[1:0]};//MUL doesn't matter
@ -49,26 +52,36 @@ module mul_unit(
assign rs1_ext = signed'({mul_inputs.rs1[31] & rs1_signed, mul_inputs.rs1});
assign rs2_ext = signed'({mul_inputs.rs2[31] & rs2_signed, mul_inputs.rs2});
assign issue.ready = stage1_advance;
assign stage1_advance = ~done[0] | stage2_advance;
assign stage2_advance = ~done[1] | wb.ack;
//Input and output registered Multiply
always_ff @ (posedge clk) begin
rs1_r <= rs1_ext;
rs2_r <= rs2_ext;
result <= 64'(rs1_r * rs2_r);
if (stage1_advance) begin
rs1_r <= rs1_ext;
rs2_r <= rs2_ext;
end
if (stage2_advance) begin
result <= 64'(rs1_r * rs2_r);
end
end
always_ff @ (posedge clk) begin
mulh[0] <= (mul_inputs.op[1:0] != MUL_fn3[1:0]);
id[0] <= issue.instruction_id;
done[0] <= issue.new_request;
mulh[1] <= mulh[0];
id[1] <= id[0];
done[1] <= done[0];
if (stage1_advance) begin
mulh[0] <= (mul_inputs.op[1:0] != MUL_fn3[1:0]);
id[0] <= issue.id;
done[0] <= issue.new_request;
end
if (stage2_advance) begin
mulh[1] <= mulh[0];
id[1] <= id[0];
done[1] <= done[0];
end
end
//Issue/write-back handshaking
////////////////////////////////////////////////////
assign issue.ready = 1;
assign wb.rd = mulh[1] ? result[63:32] : result[31:0];
assign wb.done = done[1];
assign wb.id = id[1];

View file

@ -58,8 +58,8 @@ module one_hot_to_integer
////////////////////////////////////////////////////
//Assertions
always_ff @ (posedge clk) begin
assert (rst || (~rst && $onehot0(one_hot))) else $error("One-hot signal has multiple bits set!");
end
// always_ff @ (posedge clk) begin
// assert (rst || (~rst && $onehot0(one_hot))) else $error("One-hot signal has multiple bits set!");
//end
endmodule

View file

@ -1,87 +0,0 @@
/*
* Copyright © 2017-2019 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Initial code developed under the supervision of Dr. Lesley Shannon,
* Reconfigurable Computing Lab, Simon Fraser University.
*
* Author(s):
* Eric Matthews <ematthew@sfu.ca>
*/
import taiga_config::*;
import riscv_types::*;
import taiga_types::*;
module pre_decode
(
input logic clk,
input logic rst,
//Fetch
input logic [31:0] pre_decode_instruction,
input logic [31:0] pre_decode_pc,
input branch_predictor_metadata_t branch_metadata,
input logic branch_prediction_used,
input logic [BRANCH_PREDICTOR_WAYS-1:0] bp_update_way,
input logic pre_decode_push,
//Global Control
input logic gc_fetch_flush,
//Decode
input logic pre_decode_pop,
output logic fb_valid,
output fetch_buffer_packet_t fb
);
logic buffer_reset;
fetch_buffer_packet_t new_data;
fetch_buffer_packet_t data_in;
fetch_buffer_packet_t data_out;
fifo_interface #(.DATA_WIDTH($bits(fetch_buffer_packet_t))) fb_fifo();
////////////////////////////////////////////////////
//Implementation
//FIFO
assign buffer_reset = rst | gc_fetch_flush;
assign fb_fifo.supress_push = 0;//Covered by reseting on gc_fetch_flush
assign fb_fifo.push = pre_decode_push;
assign fb_fifo.pop = pre_decode_pop;
assign fb_fifo.data_in = data_in;
assign fb = fb_fifo.data_out;
assign fb_valid = fb_fifo.valid;
taiga_fifo #(
.DATA_WIDTH($bits(fetch_buffer_packet_t)),
.FIFO_DEPTH(FETCH_BUFFER_DEPTH)
) fb_fifo_block (.fifo(fb_fifo), .rst(buffer_reset), .*);
////////////////////////////////////////////////////
//Pre-Decode
assign data_in.instruction = pre_decode_instruction;
assign data_in.pc = pre_decode_pc;
////////////////////////////////////////////////////
//Branch Predictor support
assign data_in.branch_metadata = branch_metadata;
assign data_in.branch_prediction_used = branch_prediction_used;
assign data_in.bp_update_way = bp_update_way;
////////////////////////////////////////////////////
//Assertions
endmodule

View file

@ -33,6 +33,9 @@ module register_file(
register_file_writeback_interface.rf wb,
register_file_issue_interface.rf issue,
//ID Metadata
input logic [4:0] retired_rd_addr,
//Trace signals
output logic tr_rs1_forwarding_needed,
output logic tr_rs2_forwarding_needed,
@ -40,7 +43,7 @@ module register_file(
);
(* ramstyle = "MLAB, no_rw_check" *) logic [XLEN-1:0] register [32];
(* ramstyle = "MLAB, no_rw_check" *) instruction_id_t in_use_by [32];
(* ramstyle = "MLAB, no_rw_check" *) id_t in_use_by [32];
logic rs1_inuse;
logic rs2_inuse;
@ -57,16 +60,16 @@ module register_file(
//Writeback unit does not assert wb.commit when the target register is r0
always_ff @ (posedge clk) begin
if (~gc_supress_writeback & valid_write)
register[wb.rd_addr] <= wb.rd_data;
if (~gc_supress_writeback & in_use_match)
register[retired_rd_addr] <= wb.rd_data;
end
assign in_use_match = (wb.id == in_use_by[wb.rd_addr]) && valid_write;
assign in_use_match = (wb.id == in_use_by[retired_rd_addr]) && valid_write;
reg_inuse inuse (.*,
.clr(1'b0),
.rs1_addr(issue.rs1_addr),.rs2_addr(issue.rs2_addr), .issued_rd_addr(issue.rd_addr),
.retired_rd_addr(wb.rd_addr),
.retired_rd_addr(retired_rd_addr),
.issued(issue.instruction_issued),
.retired(in_use_match),
.rs1_inuse(rs1_inuse),
@ -82,7 +85,7 @@ module register_file(
assign wb.rs2_id = in_use_by[issue.rs2_addr];
assign issue.rs2_id = wb.rs2_id;
assign valid_write = wb.rd_nzero & wb.retiring;
assign valid_write = (|retired_rd_addr) & wb.retiring;
assign rs1_feedforward = rs1_inuse;
assign rs2_feedforward = rs2_inuse;

View file

@ -66,13 +66,11 @@ module taiga (
div_inputs_t div_inputs;
gc_inputs_t gc_inputs;
unit_issue_interface unit_issue [NUM_UNITS-1:0]();
unit_issue_interface unit_issue [NUM_UNITS]();
exception_packet_t ls_exception;
logic ls_exception_valid;
tracking_interface ti();
unit_writeback_t unit_wb [NUM_WB_UNITS-1:0];
unit_writeback_interface unit_wb [NUM_WB_UNITS]();
register_file_writeback_interface rf_wb();
mmu_interface immu();
@ -111,10 +109,14 @@ module taiga (
id_t store_id;
logic branch_complete;
id_t branch_id;
logic system_op_complete;
id_t system_op_id;
logic system_op_or_exception_complete;
id_t system_op_or_exception_id;
logic instruction_retired;
id_t retired_id;
logic [4:0] retired_rd_addr;
//Exception
id_t exception_id;
logic [31:0] exception_pc;
//Global Control
logic gc_issue_hold;
@ -122,13 +124,14 @@ module taiga (
logic gc_fetch_flush;
logic gc_fetch_pc_override;
logic gc_supress_writeback;
instruction_id_t oldest_id;
id_t oldest_id;
logic [31:0] gc_fetch_pc;
logic ls_exception_ack;
logic[31:0] csr_rd;
instruction_id_t csr_id;
id_t csr_id;
logic csr_done;
logic ls_is_idle;
//Decode Unit and Fetch Unit
logic illegal_instruction;
@ -143,9 +146,9 @@ module taiga (
//LS
writeback_store_interface wb_store();
logic load_store_exception_clear;
instruction_id_t load_store_exception_id;
logic potential_exception;
//WB
logic single_cycle_issue_possible;
logic writeback_is_idle;
//Trace Interface Signals
logic tr_operand_stall;
@ -180,8 +183,8 @@ module taiga (
logic tr_rs1_and_rs2_forwarding_needed;
unit_id_t tr_num_instructions_completing;
instruction_id_t tr_num_instructions_in_flight;
instruction_id_t tr_num_of_instructions_pending_writeback;
id_t tr_num_instructions_in_flight;
id_t tr_num_of_instructions_pending_writeback;
////////////////////////////////////////////////////
//Implementation

View file

@ -163,11 +163,13 @@ package taiga_config;
////////////////////////////////////////////////////
//FIFO/Buffer Depths
//All parameters restricted to powers of two
parameter MAX_IDS = 16;
parameter MAX_INFLIGHT_COUNT = 4;
parameter FETCH_BUFFER_DEPTH = 4;
//ID limit
//MAX_IDS restricted to a power of 2
parameter MAX_IDS = 32;
////////////////////////////////////////////////////
//Number of Writeback Buffers
parameter WRITEBACK_BUFFERS = 3;
////////////////////////////////////////////////////
//Trace Options
@ -185,15 +187,19 @@ package taiga_config;
////////////////////////////////////////////////////
//Write-Back Unit IDs
parameter NUM_WB_UNITS = 2 + USE_MUL + USE_DIV;
parameter NUM_UNITS = NUM_WB_UNITS + 2;
parameter NUM_MULTI_CYCLE_WB_UNITS = 1 + USE_MUL + USE_DIV;//LS
parameter NUM_SINGLE_CYCLE_WB_UNITS = 1;//ALU
parameter ALU_UNIT_WB_ID = 0;
parameter LS_UNIT_WB_ID = 1;
parameter NUM_WB_UNITS = NUM_MULTI_CYCLE_WB_UNITS + NUM_SINGLE_CYCLE_WB_UNITS;
parameter NUM_UNITS = NUM_WB_UNITS + 2;//Branch and CSRs
parameter LS_UNIT_WB_ID = 0;
parameter DIV_UNIT_WB_ID = LS_UNIT_WB_ID + USE_DIV;
parameter MUL_UNIT_WB_ID = DIV_UNIT_WB_ID + USE_MUL;
parameter MUL_UNIT_WB_ID = DIV_UNIT_WB_ID + 1;
parameter ALU_UNIT_WB_ID = MUL_UNIT_WB_ID + USE_MUL;
//Non-writeback units
parameter BRANCH_UNIT_ID = MUL_UNIT_WB_ID + 1;
parameter BRANCH_UNIT_ID = ALU_UNIT_WB_ID + 1;
parameter GC_UNIT_ID = BRANCH_UNIT_ID + 1;
////////////////////////////////////////////////////

View file

@ -24,12 +24,10 @@ package taiga_types;
import taiga_config::*;
import riscv_types::*;
localparam ID_W = $clog2(MAX_INFLIGHT_COUNT);
localparam WB_UNITS_WIDTH = $clog2(NUM_WB_UNITS);
typedef logic[$clog2(MAX_IDS)-1:0] id_t;
typedef logic[ID_W-1:0] instruction_id_t;
typedef logic[WB_UNITS_WIDTH-1:0] unit_id_t;
typedef logic[1:0] branch_predictor_metadata_t;
@ -63,24 +61,10 @@ package taiga_types;
typedef struct packed{
logic valid;
exception_code_t code;
logic [31:0] pc;
logic [31:0] tval;
instruction_id_t id;
id_t id;
} exception_packet_t;
typedef struct packed{
logic [4:0] rd_addr;
logic is_store;
} inflight_instruction_packet;
typedef struct packed{
logic [31:0] instruction;
logic [31:0] pc;
branch_predictor_metadata_t branch_metadata;
logic branch_prediction_used;
logic [BRANCH_PREDICTOR_WAYS-1:0] bp_update_way;
} fetch_buffer_packet_t;
typedef struct packed{
branch_predictor_metadata_t branch_predictor_metadata;
logic branch_prediction_used;
@ -88,21 +72,6 @@ package taiga_types;
} branch_metadata_t;
typedef struct packed{
logic id_assigned;
id_t pc_id;
logic [31:0] pc;
logic complete;
id_t instruction_id;
logic [31:0] instruction;
} fetch_instruction_metadata_t;
typedef struct packed{
instruction_id_t id;
logic done;
logic [XLEN-1:0] rd;
} unit_writeback_t;
typedef struct packed{
logic [XLEN:0] in1;//contains sign padding bit for slt operation
logic [XLEN:0] in2;//contains sign padding bit for slt operation
@ -159,9 +128,7 @@ package taiga_types;
logic load;
logic store;
logic forwarded_store;
instruction_id_t store_forward_id;
//exception support
logic [31:0] pc;
id_t store_forward_id;
//amo support
amo_details_t amo;
} load_store_inputs_t;
@ -216,7 +183,7 @@ package taiga_types;
logic [3:0] be;
logic [2:0] fn3;
logic [31:0] data_in;
instruction_id_t id;
id_t id;
} data_access_shared_inputs_t;
typedef enum {
@ -260,8 +227,8 @@ package taiga_types;
//Writeback
unit_id_t num_instructions_completing;
instruction_id_t num_instructions_in_flight;
instruction_id_t num_of_instructions_pending_writeback;
id_t num_instructions_in_flight;
id_t num_of_instructions_pending_writeback;
} taiga_trace_events_t;
typedef struct packed {

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 Eric Matthews, Lesley Shannon
* Copyright © 2017-2020 Eric Matthews, Lesley Shannon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -31,199 +31,188 @@ module write_back(
input logic gc_fetch_flush,
input logic instruction_issued_with_rd,
input unit_writeback_t unit_wb[NUM_WB_UNITS-1:0],
unit_writeback_interface.wb unit_wb[NUM_WB_UNITS],
register_file_writeback_interface.writeback rf_wb,
tracking_interface.wb ti,
output logic instruction_retired,
output id_t retired_id,
output logic instruction_queue_empty,
output instruction_id_t oldest_id,
input logic load_store_exception_clear,
input instruction_id_t load_store_exception_id,
output logic potential_exception,
//Writeback-Store Interface
writeback_store_interface.wb wb_store,
output logic single_cycle_issue_possible,
output logic writeback_is_idle,
//Trace signals
output unit_id_t tr_num_instructions_completing,
output instruction_id_t tr_num_instructions_in_flight,
output instruction_id_t tr_num_of_instructions_pending_writeback
output id_t tr_num_instructions_in_flight,
output id_t tr_num_of_instructions_pending_writeback
);
//////////////////////////////////////
//Inflight metadata for IDs
(* ramstyle = "MLAB, no_rw_check" *) logic[$bits(inflight_instruction_packet)-1:0] id_metadata [MAX_INFLIGHT_COUNT-1:0];
logic unit_ack [NUM_WB_UNITS];
//aliases for write-back-interface signals
instruction_id_t unit_instruction_id [NUM_WB_UNITS-1:0];
logic [NUM_WB_UNITS-1:0] unit_done;
logic [XLEN-1:0] unit_rd [NUM_WB_UNITS-1:0];
id_t unit_instruction_id [NUM_WB_UNITS];
logic unit_done [NUM_WB_UNITS];
logic [XLEN-1:0] unit_rd [NUM_WB_UNITS];
//Per-ID muxes for commit buffer
logic [$clog2(NUM_WB_UNITS)-1:0] id_unit_select [MAX_INFLIGHT_COUNT-1:0];
logic [$clog2(NUM_WB_UNITS)-1:0] id_unit_select_r [MAX_INFLIGHT_COUNT-1:0];
logic [$clog2(NUM_WB_UNITS)-1:0] buffer_unit_select [WRITEBACK_BUFFERS];
//Commit buffer
logic [XLEN-1:0] results_by_id [MAX_INFLIGHT_COUNT-1:0];
logic [XLEN-1:0] results_by_id_new [MAX_INFLIGHT_COUNT-1:0];
instruction_id_t id_retiring;
inflight_instruction_packet retiring_instruction_packet;
typedef struct packed{
logic [XLEN-1:0] rd;
id_t id;
} commit_buffer_t;
commit_buffer_t commit_buffer [WRITEBACK_BUFFERS];
logic commit_buffer_valid [WRITEBACK_BUFFERS];
logic [MAX_INFLIGHT_COUNT-1:0] id_inuse;
logic [MAX_INFLIGHT_COUNT-1:0] id_potential_exception;
logic [MAX_INFLIGHT_COUNT-1:0] exception_cleared_one_hot;
id_t id_retiring;
logic [MAX_INFLIGHT_COUNT-1:0] id_writeback_pending;
logic [MAX_INFLIGHT_COUNT-1:0] id_writeback_pending_r;
localparam LOG2_WRITEBACK_BUFFERS = $clog2(WRITEBACK_BUFFERS);
logic [MAX_INFLIGHT_COUNT-1:0] id_writing_to_buffer;
logic retiring;
logic [$clog2(NUM_WB_UNITS):0] num_units_done;
logic [$clog2(WRITEBACK_BUFFERS):0] num_buffers_ready;
logic [MAX_INFLIGHT_COUNT-1:0] id_retiring_one_hot;
logic [MAX_INFLIGHT_COUNT-1:0] id_issued_one_hot;
logic result_ready [WRITEBACK_BUFFERS];
logic retiring_next_cycle, retiring;
logic commit_buffer_ready [WRITEBACK_BUFFERS];
logic [LOG2_WRITEBACK_BUFFERS-1:0] commit_buffer_index_retiring;
genvar i, j;
////////////////////////////////////////////////////
//Implementation
//Re-assigning interface inputs to array types so that they can be dynamically indexed
genvar i;
generate
for (i=0; i< NUM_WB_UNITS; i++) begin : interface_to_array_g
assign unit_instruction_id[i] = unit_wb[i].id;
assign unit_done[i] = unit_wb[i].done;
assign unit_rd[i] = unit_wb[i].rd;
end
endgenerate
generate for (i=0; i< NUM_WB_UNITS; i++) begin : wb_interfaces_to_arrays_g
assign unit_instruction_id[i] = unit_wb[i].id;
assign unit_done[i] = unit_wb[i].done;
assign unit_rd[i] = unit_wb[i].rd;
assign unit_wb[i].ack = unit_ack[i];
end endgenerate
////////////////////////////////////////////////////
//ID done determination
//For each ID, check if a unit is reporting that ID as done and OR the results together
//Additionally, OR the result of any store operation completing
//Unit done determination
always_comb begin
id_writing_to_buffer = '0;
for (int i=0; i< MAX_INFLIGHT_COUNT; i++) begin
for (int j=0; j< NUM_WB_UNITS; j++) begin
id_writing_to_buffer[i] |= (unit_instruction_id[j] == ID_W'(i)) && unit_done[j];
end
id_writing_to_buffer[i] |= (wb_store.commit_id == ID_W'(i)) && wb_store.commit;
num_units_done = 0;
for (int i=0; i < NUM_MULTI_CYCLE_WB_UNITS; i++) begin
num_units_done += ($clog2(NUM_WB_UNITS)+1)'(unit_done[i]);
end
num_buffers_ready = 0;
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
num_buffers_ready += ($clog2(WRITEBACK_BUFFERS)+1)'(commit_buffer_ready[i]);
end
single_cycle_issue_possible = (($clog2(NUM_WB_UNITS)+1)'(num_buffers_ready) > num_units_done);
end
////////////////////////////////////////////////////
//Commit Buffer index retiring
//Priority given to decreasing indices
always_comb begin
commit_buffer_index_retiring = 0;
for (int i=WRITEBACK_BUFFERS-1; i >= 0; i--) begin
if (commit_buffer_valid[i])
commit_buffer_index_retiring = LOG2_WRITEBACK_BUFFERS'(i);
end
end
////////////////////////////////////////////////////
//Commit Buffer ready to accept new data
always_comb begin
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
commit_buffer_ready[i] = ~commit_buffer_valid[i];
end
//Can always retire, so if not retiring, this index will not be valid and thus ready to commit to
commit_buffer_ready[commit_buffer_index_retiring] = 1;
end
////////////////////////////////////////////////////
//Unit select for writeback buffer
//Set unit_ID for each ID as they are issued
//If ID is not in use, use the current issue_unit_id value
//This is used to support single cycle units, such as the ALU
logic commit_buffer_write [WRITEBACK_BUFFERS];
always_comb begin
id_issued_one_hot = 0;
id_issued_one_hot[ti.issue_id] = 1;
id_issued_one_hot &= {MAX_INFLIGHT_COUNT{ti.issued}};
unit_ack = '{default: 0};
buffer_unit_select = '{default: 0};
commit_buffer_write = '{default: 0};
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
for (int j=0; j < NUM_WB_UNITS; j++) begin
if (unit_done[j] & ~unit_ack[j] & ~commit_buffer_write[i]) begin
buffer_unit_select[i] = $clog2(NUM_WB_UNITS)'(j);
unit_ack[j] = commit_buffer_ready[i];
commit_buffer_write[i] = commit_buffer_ready[i];
end
end
end
// single_cycle_issue_possible = 0;
// for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
// if (commit_buffer_ready[i] & ~commit_buffer_write[i]) begin
// single_cycle_issue_possible = 1;
// buffer_unit_select[i] = ALU_UNIT_WB_ID;
// commit_buffer_write[i] = 1;
// break;
// end
// end
end
generate for (i=0; i< MAX_INFLIGHT_COUNT; i++) begin
always_ff @ (posedge clk) begin
if (id_issued_one_hot[i])
id_unit_select_r[i] <= ti.issue_unit_id;
end
assign id_unit_select[i] = id_inuse[i] ? id_unit_select_r[i] : ti.issue_unit_id;
end endgenerate
////////////////////////////////////////////////////
//Writeback Buffer
//Mux outputs of units based on IDs
//If ID is done write result to buffer
generate for (i=0; i< MAX_INFLIGHT_COUNT; i++) begin
always_ff @ (posedge clk) begin
if (id_writing_to_buffer[i])
results_by_id[i] <= unit_rd[id_unit_select[i]];
end
end endgenerate
////////////////////////////////////////////////////
//Unit Forwarding Support
//Track whether an ID has written to the commit buffer
set_clr_reg_with_rst #(.SET_OVER_CLR(0), .WIDTH($bits(id_inuse)), .RST_VALUE('0)) id_inuse_m (
.clk, .rst,
.set(id_issued_one_hot),
.clr(id_writing_to_buffer),
.result(id_inuse)
);
assign wb_store.forwarding_data_ready = ~id_inuse[wb_store.id_needed_at_commit];
assign wb_store.forwarded_data = results_by_id[wb_store.id_needed_at_commit];
////////////////////////////////////////////////////
//ID Tracking
//Provides ordering of IDs, ID for issue and oldest ID for committing to register file
writeback_id_tracking id_counters (.*, .issued(ti.issued), .retired(retiring_next_cycle), .id_available(ti.id_available),
.oldest_id(oldest_id), .next_id(ti.issue_id), .empty(instruction_queue_empty));
////////////////////////////////////////////////////
//Metadata storage for IDs
//stores destination register for each ID and whether it is a store instruction
initial id_metadata = '{default: 0};
//Inflight Instruction ID table
//Stores rd_addr and whether instruction is a store
//Writeback Commit Buffer
always_ff @ (posedge clk) begin
if (ti.id_available)
id_metadata[ti.issue_id] <= ti.inflight_packet;
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
if (rst)
commit_buffer_valid[i] <= 0;
else
commit_buffer_valid[i] <= commit_buffer_write[i] | (commit_buffer_valid[i] & ~commit_buffer_ready[i]);
end
end
assign retiring_instruction_packet = id_metadata[id_retiring];
////////////////////////////////////////////////////
//Potential Exception Tracking
// always_comb begin
// exception_cleared_one_hot = 0;
// exception_cleared_one_hot[load_store_exception_id] = load_store_exception_clear;
// end
// always_ff @ (posedge clk) begin
// if (rst)
// id_potential_exception <= 0;
// else
// id_potential_exception <= (id_potential_exception | {MAX_INFLIGHT_COUNT{ti.exception_possible}} & id_issued_one_hot) & ~exception_cleared_one_hot;
// end
// assign potential_exception = |id_potential_exception;
always_ff @ (posedge clk) begin
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
if (commit_buffer_ready[i]) begin
commit_buffer[i].rd <= unit_rd[buffer_unit_select[i]];
commit_buffer[i].id <= unit_instruction_id[buffer_unit_select[i]];
end
end
end
////////////////////////////////////////////////////
//Register File Interface
//Track whether the ID has a pending write to the register file
always_ff @ (posedge clk) begin
if (rst)
id_writeback_pending_r <= 0;
else
id_writeback_pending_r <= id_writeback_pending;
end
assign id_writeback_pending = id_writing_to_buffer | (id_writeback_pending_r & ~id_retiring_one_hot);
//Is the oldest instruction ready to commit?
assign retiring_next_cycle = id_writeback_pending[oldest_id] & ~wb_store.hold_for_store_ids[oldest_id];
always_ff @(posedge clk) begin
retiring <= retiring_next_cycle;
id_retiring <= oldest_id;
end
always_comb begin
id_retiring_one_hot = 0;
id_retiring_one_hot[id_retiring] = retiring;
retiring = 0;
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
retiring |= commit_buffer_valid[i];
end
end
assign id_retiring = commit_buffer[commit_buffer_index_retiring].id;
//Instruction completion tracking for retired instruction count
assign instruction_retired = retiring & ~retiring_instruction_packet.is_store;
assign retired_id = $clog2(MAX_IDS)'(id_retiring);
assign instruction_retired = retiring;
assign retired_id = id_retiring;
assign rf_wb.rd_addr = retiring_instruction_packet.rd_addr;
assign rf_wb.id = id_retiring;
assign rf_wb.retiring = instruction_retired;
assign rf_wb.rd_nzero = |retiring_instruction_packet.rd_addr;
assign rf_wb.rd_data = results_by_id[id_retiring];
assign rf_wb.rd_data = commit_buffer[commit_buffer_index_retiring].rd;
//Register bypass for issue operands
assign rf_wb.rs1_valid = id_writeback_pending_r[rf_wb.rs1_id];//includes the instruction writing to the register file
assign rf_wb.rs2_valid = id_writeback_pending_r[rf_wb.rs2_id];
assign rf_wb.rs1_data = results_by_id[rf_wb.rs1_id];
assign rf_wb.rs2_data = results_by_id[rf_wb.rs2_id];
logic [WRITEBACK_BUFFERS-1:0] rs1_addr_match;
logic [WRITEBACK_BUFFERS-1:0] rs2_addr_match;
logic [LOG2_WRITEBACK_BUFFERS-1:0] rs1_sel;
logic [LOG2_WRITEBACK_BUFFERS-1:0] rs2_sel;
always_comb begin
writeback_is_idle = 0;
rs1_sel = {LOG2_WRITEBACK_BUFFERS{1'b?}};
rs2_sel = {LOG2_WRITEBACK_BUFFERS{1'b?}};
for (int i=0; i < WRITEBACK_BUFFERS; i++) begin
writeback_is_idle |= commit_buffer_valid[i];
rs1_addr_match[i] = commit_buffer_valid[i] && (commit_buffer[i].id == rf_wb.rs1_id);
rs2_addr_match[i] = commit_buffer_valid[i] && (commit_buffer[i].id == rf_wb.rs2_id);
if (rs1_addr_match[i])
rs1_sel = LOG2_WRITEBACK_BUFFERS'(i);
if (rs2_addr_match[i])
rs2_sel = LOG2_WRITEBACK_BUFFERS'(i);
end
writeback_is_idle = ~writeback_is_idle;
end
assign rf_wb.rs1_valid = |rs1_addr_match;
assign rf_wb.rs2_valid = |rs2_addr_match;
assign rf_wb.rs1_data = commit_buffer[rs1_sel].rd;
assign rf_wb.rs2_data = commit_buffer[rs2_sel].rd;
////////////////////////////////////////////////////
//End of Implementation
////////////////////////////////////////////////////
@ -233,22 +222,23 @@ module write_back(
////////////////////////////////////////////////////
//Trace Interface
generate if (ENABLE_TRACE_INTERFACE) begin
//Checks if any two pairs are set indicating mux contention
always_comb begin
tr_num_instructions_completing = 0;
for (int i=0; i<NUM_WB_UNITS; i++) begin
tr_num_instructions_completing += unit_done[i];
end
// instruction_id_t num_of_instructions_pending_writeback;
// generate if (ENABLE_TRACE_INTERFACE) begin
//Checks if any two pairs are set indicating mux contention
// always_comb begin
// tr_num_instructions_completing = 0;
// for (int i=0; i<NUM_WB_UNITS; i++) begin
// tr_num_instructions_completing += unit_done[i];
// end
tr_num_instructions_in_flight = 0;
tr_num_of_instructions_pending_writeback = 0;
for (int i=0; i<MAX_INFLIGHT_COUNT-1; i++) begin
tr_num_instructions_in_flight += ID_W'(id_inuse[i]);
tr_num_of_instructions_pending_writeback += ID_W'(id_writeback_pending[i]);
end
end
end
endgenerate
// num_of_instructions_pending_writeback = 0;
// for (int i=0; i<MAX_INFLIGHT_COUNT-1; i++) begin
// num_of_instructions_pending_writeback += ID_W'(id_writeback_pending_r[i]);
// end
// tr_num_instructions_in_flight = tr_num_of_instructions_pending_writeback > 2 ? 2'b1 : 0;
// end
// end
// endgenerate
endmodule

View file

@ -98,11 +98,9 @@
../core/illegal_instruction_checker.sv
../core/decode_and_issue.sv
../core/id_inuse.sv
../core/reg_inuse.sv
../core/register_file.sv
../core/writeback_id_tracking.sv
../core/write_back.sv
../core/placer_randomizer.sv