🐛 Fixes in instr realigner

This commit is contained in:
Florian Zaruba 2017-06-28 19:17:07 +02:00
parent 4cd7f99a07
commit cd004b731a
7 changed files with 82 additions and 44 deletions

View file

@ -43,14 +43,14 @@ riscv-tests = rv64ui-p-add rv64ui-p-addi rv64ui-p-slli rv64ui-p-addiw rv64ui-p-
rv64mi-p-csr rv64mi-p-mcsr rv64mi-p-illegal \
rv64mi-p-ma_addr rv64mi-p-ma_fetch rv64mi-p-sbreak rv64mi-p-scall \
rv64si-p-csr rv64si-p-ma_fetch rv64si-p-scall rv64si-p-wfi rv64si-p-sbreak \
rv64si-p-dirty rv64uc-p-rvc
# rv64ui-v-add rv64ui-v-addi rv64ui-p-slli rv64ui-v-addiw rv64ui-v-addw rv64ui-v-and rv64ui-v-auipc \
# rv64ui-v-beq rv64ui-v-bge rv64ui-v-bgeu rv64ui-v-andi rv64ui-v-blt rv64ui-v-bltu rv64ui-v-bne \
# rv64ui-v-simple rv64ui-v-jal rv64ui-v-jalr rv64ui-v-or rv64ui-v-ori rv64ui-v-sub rv64ui-v-subw \
# rv64ui-v-xor rv64ui-v-xori rv64ui-v-slliw rv64ui-v-sll rv64ui-v-slli rv64ui-v-sllw \
# rv64ui-v-slt rv64ui-v-slti rv64ui-v-sltiu rv64ui-v-sltu rv64ui-v-sra rv64ui-v-srai \
# rv64ui-v-sraiw rv64ui-v-sraw rv64ui-v-srl rv64ui-v-srli rv64ui-v-srliw rv64ui-v-srlw \
# rv64ui-v-lb rv64ui-v-lbu rv64ui-v-ld rv64ui-v-lh rv64ui-v-lhu rv64ui-v-lui
rv64si-p-dirty rv64uc-p-rvc \
rv64ui-v-add rv64ui-v-addi rv64ui-p-slli rv64ui-v-addiw rv64ui-v-addw rv64ui-v-and rv64ui-v-auipc \
rv64ui-v-beq rv64ui-v-bge rv64ui-v-bgeu rv64ui-v-andi rv64ui-v-blt rv64ui-v-bltu rv64ui-v-bne \
rv64ui-v-simple rv64ui-v-jal rv64ui-v-jalr rv64ui-v-or rv64ui-v-ori rv64ui-v-sub rv64ui-v-subw \
rv64ui-v-xor rv64ui-v-xori rv64ui-v-slliw rv64ui-v-sll rv64ui-v-slli rv64ui-v-sllw \
rv64ui-v-slt rv64ui-v-slti rv64ui-v-sltiu rv64ui-v-sltu rv64ui-v-sra rv64ui-v-srai \
rv64ui-v-sraiw rv64ui-v-sraw rv64ui-v-srl rv64ui-v-srli rv64ui-v-srliw rv64ui-v-srlw \
rv64ui-v-lb rv64ui-v-lbu rv64ui-v-ld rv64ui-v-lh rv64ui-v-lhu rv64ui-v-lui
riscv-test = rv64ui-p-add

View file

@ -273,9 +273,10 @@ module ariane
.fetch_entry_valid_0_o ( fetch_valid_if_id ),
.fetch_ack_0_i ( decode_ack_id_if ),
.fetch_entry_1_o (),
.fetch_entry_valid_1_o (),
.fetch_ack_1_i (),
// Reserved for future use
.fetch_entry_1_o ( ),
.fetch_entry_valid_1_o ( ),
.fetch_ack_1_i ( ),
.*
);
@ -524,9 +525,9 @@ module ariane
assign tracer_if.flush_unissued = flush_unissued_instr_ctrl_id;
assign tracer_if.flush = flush_ctrl_ex;
// fetch
assign tracer_if.fetch = fetch_entry_if_id;
assign tracer_if.fetch_valid = fetch_valid_if_id;
assign tracer_if.fetch_ack = decode_ack_id_if;
assign tracer_if.instruction = id_stage_i.compressed_decoder_i.instr_o;
assign tracer_if.fetch_valid = id_stage_i.instr_realigner_i.fetch_entry_valid_o;
assign tracer_if.fetch_ack = id_stage_i.instr_realigner_i.fetch_ack_i;
// Issue
assign tracer_if.issue_ack = issue_stage_i.scoreboard_i.issue_ack_i;
assign tracer_if.issue_sbe = issue_stage_i.scoreboard_i.issue_instr_o;

View file

@ -177,7 +177,7 @@ module dcache_arbiter #(
else begin $error("There was a grant without a request."); $stop(); end
// assert that the address does not contain X when request is sent
assert property ( @(posedge clk_i) (data_req_o) |-> (!$isunknown(address_index_o)) )
else begin $info("address contains X when request is set"); end
else begin $error("address contains X when request is set"); $stop(); end
// there should be no rvalid when we are in IDLE
// assert property (

View file

@ -51,12 +51,12 @@ module id_stage (
logic is_control_flow_instr;
scoreboard_entry decoded_instruction;
fetch_entry fetch_entry;
logic is_illegal;
logic [31:0] instruction;
logic is_compressed;
logic fetch_ack_i;
logic fetch_entry_valid;
instr_realigner instr_realigner_i (
.fetch_entry_0_i ( fetch_entry_i ),
@ -64,7 +64,7 @@ module id_stage (
.fetch_ack_0_o ( decoded_instr_ack_o ),
.fetch_entry_o ( fetch_entry ),
.fetch_entry_valid_o ( fetch_entry_valid_o ),
.fetch_entry_valid_o ( fetch_entry_valid ),
.fetch_ack_i ( fetch_ack_i ),
.*
);
@ -106,7 +106,7 @@ module id_stage (
// if we have a space in the register and the fetch is valid, go get it
// or the issue stage is currently acknowledging an instruction, which means that we will have space
// for a new instruction
if ((!issue_q.valid || issue_instr_ack_i) && fetch_entry_valid_i) begin
if ((!issue_q.valid || issue_instr_ack_i) && fetch_entry_valid) begin
fetch_ack_i = 1'b1;
issue_n = { 1'b1, decoded_instruction, is_control_flow_instr};
end

View file

@ -32,13 +32,19 @@ module instr_realigner (
output logic fetch_entry_valid_o,
input logic fetch_ack_i
);
// ----------
// Registers
// ----------
// the last instruction was unaligned
logic unaligned_n, unaligned_q;
logic unaligned_n, unaligned_q;
// save the unaligned part of the instruction to this ff
logic [15:0] unaligned_instr_n, unaligned_instr_q;
logic [15:0] unaligned_instr_n, unaligned_instr_q;
// the previous instruction was compressed
logic compressed_n, compressed_q;
logic compressed_n, compressed_q;
// register to save the unaligned address
logic [63:0] unaligned_address_n, unaligned_address_q;
// get the next instruction, needed on a unaligned access
logic jump_unaligned_half_word;
// check if the lower compressed instruction was no branch otherwise we will need to squash this instruction
// but only if we predicted it to be taken, the predict was on the lower 16 bit compressed instruction
@ -46,17 +52,22 @@ module instr_realigner (
assign kill_upper_16_bit = fetch_entry_0_i.branch_predict.valid &&
fetch_entry_0_i.branch_predict.predict_taken &&
fetch_entry_0_i.branch_predict.is_lower_16;
// ----------
// Registers
// ----------
always_comb begin : realign_instr
unaligned_n = unaligned_q;
unaligned_instr_n = unaligned_instr_q;
compressed_n = compressed_q;
unaligned_n = unaligned_q;
unaligned_instr_n = unaligned_instr_q;
compressed_n = compressed_q;
unaligned_address_n = unaligned_address_q;
// directly output this instruction. adoptions are made throughout the process
fetch_entry_o = fetch_entry_0_i;
fetch_entry_valid_o = fetch_entry_valid_0_i;
fetch_ack_0_o = fetch_ack_i;
fetch_entry_o = fetch_entry_0_i;
fetch_entry_valid_o = fetch_entry_valid_0_i;
fetch_ack_0_o = fetch_ack_i;
// we just jumped to a half word and encountered an unaligned 32-bit instruction
jump_unaligned_half_word = 1'b0;
// ---------------------------------
// Input port & Instruction Aligner
// ---------------------------------
@ -95,6 +106,8 @@ module instr_realigner (
end else begin
// save the lower 16 bit
unaligned_instr_n = fetch_entry_0_i.instruction[31:16];
// save the address
unaligned_address_n = {fetch_entry_0_i.address[63:2], 2'b10};
// and that it was unaligned
unaligned_n = 1'b1;
// this does not consume space in the FIFO
@ -110,9 +123,11 @@ module instr_realigner (
// we have an outstanding unaligned instruction
else if (unaligned_q) begin
fetch_entry_o.address = {fetch_entry_0_i.address, 2'b10};
fetch_entry_o.address = unaligned_address_q;
fetch_entry_o.instruction = {fetch_entry_0_i.instruction[15:0], unaligned_instr_q};
// again should we look at the upper bits?
if (!kill_upper_16_bit) begin
// whats up with the other upper 16 bit of this instruction
// is the second instruction also compressed, like:
@ -135,6 +150,8 @@ module instr_realigner (
end else if (!kill_upper_16_bit) begin
// save the lower 16 bit
unaligned_instr_n = fetch_entry_0_i.instruction[31:16];
// save the address
unaligned_address_n = {fetch_entry_0_i.address[63:2], 2'b10};
// and that it was unaligned
unaligned_n = 1'b1;
end
@ -163,22 +180,40 @@ module instr_realigner (
unaligned_instr_n = fetch_entry_0_i.instruction[31:16];
// and that it was unaligned
unaligned_n = 1'b1;
// save the address
unaligned_address_n = {fetch_entry_0_i.address[63:2], 2'b10};
// we need to wait for the second instruction
fetch_entry_valid_o = 1'b0;
// so get it by acknowledging this instruction
fetch_ack_0_o = 1'b1;
// we got to an unaligned instruction -> get the next entry to full-fill the need
jump_unaligned_half_word = 1'b1;
end
// there can never be a whole 32 bit instruction on a half word access
end
end else
end
// ----------------------------
// Next compressed instruction
// ----------------------------
// we are serving the second part of an instruction which was also compressed
if (fetch_entry_valid_0_i) begin
compressed_n = 1'b0;
if (compressed_q) begin
fetch_ack_0_o = fetch_ack_i;
compressed_n = 1'b0;
fetch_entry_o.instruction = {16'b0, fetch_entry_0_i.instruction[31:16]};
fetch_entry_o.address = {fetch_entry_0_i.address, 2'b10};
fetch_entry_o.address = {fetch_entry_0_i.address[63:2], 2'b10};
fetch_entry_valid_o = 1'b1;
end
// if we didn't get an acknowledge keep the registers stable
if (!fetch_ack_i && !jump_unaligned_half_word) begin
unaligned_n = unaligned_q;
unaligned_instr_n = unaligned_instr_q;
compressed_n = compressed_q;
unaligned_address_n = unaligned_address_q;
end
if (flush_i) begin
// clear the unaligned instruction
// clear the unaligned and compressed instruction
unaligned_n = 1'b0;
compressed_n = 1'b0;
end
@ -191,10 +226,12 @@ module instr_realigner (
if (~rst_ni) begin
unaligned_q <= 1'b0;
unaligned_instr_q <= 16'b0;
unaligned_address_q <= 64'b0;
compressed_q <= 1'b0;
end else begin
unaligned_q <= unaligned_n;
unaligned_instr_q <= unaligned_instr_n;
unaligned_address_q <= unaligned_address_n;
compressed_q <= compressed_n;
end
end

View file

@ -22,9 +22,9 @@ class instruction_tracer;
// interface to the core
virtual instruction_tracer_if tracer_if;
// keep the decoded instructions in a queue
fetch_entry decode_queue [$];
logic [31:0] decode_queue [$];
// keep the issued instructions in a queue
fetch_entry issue_queue [$];
logic [31:0] issue_queue [$];
// issue scoreboard entries
scoreboard_entry issue_sbe_queue [$];
scoreboard_entry issue_sbe;
@ -52,7 +52,7 @@ class instruction_tracer;
endfunction : create_file
task trace();
fetch_entry decode_instruction, issue_instruction, issue_commit_instruction;
logic [31:0] decode_instruction, issue_instruction, issue_commit_instruction;
scoreboard_entry commit_instruction;
// initialize register 0
@ -69,7 +69,7 @@ class instruction_tracer;
// -------------------
// we are decoding an instruction
if (tracer_if.pck.fetch_valid && tracer_if.pck.fetch_ack) begin
decode_instruction = fetch_entry'(tracer_if.pck.fetch);
decode_instruction = tracer_if.pck.instruction;
decode_queue.push_back(decode_instruction);
end
// -------------------
@ -111,9 +111,9 @@ class instruction_tracer;
// check if the write back is valid, if not we need to source the result from the register file
// as the most recent version of this register will be there.
if (tracer_if.pck.we) begin
printInstr(issue_sbe, issue_commit_instruction.instruction, tracer_if.pck.wdata, address_mapping);
printInstr(issue_sbe, issue_commit_instruction, tracer_if.pck.wdata, address_mapping);
end else
printInstr(issue_sbe, issue_commit_instruction.instruction, reg_file[commit_instruction.rd], address_mapping);
printInstr(issue_sbe, issue_commit_instruction, reg_file[commit_instruction.rd], address_mapping);
end
// --------------
@ -162,7 +162,7 @@ class instruction_tracer;
load_mapping = {};
endfunction;
function void printInstr(scoreboard_entry sbe, logic [63:0] instr, logic [63:0] result, logic [63:0] paddr);
function void printInstr(scoreboard_entry sbe, logic [31:0] instr, logic [63:0] result, logic [63:0] paddr);
instruction_trace_item iti = new ($time, clk_ticks, sbe, instr, this.reg_file, result, paddr);
// print instruction to console
string print_instr = iti.printInstr();

View file

@ -26,7 +26,7 @@ interface instruction_tracer_if (
logic flush_unissued;
logic flush;
// Decode
fetch_entry fetch;
logic [31:0] instruction;
logic fetch_valid;
logic fetch_ack;
// Issue stage
@ -53,7 +53,7 @@ interface instruction_tracer_if (
exception exception;
// the tracer just has a passive interface we do not drive anything with it
clocking pck @(posedge clk);
input rstn, flush_unissued, flush, fetch, fetch_valid, fetch_ack, issue_ack, issue_sbe, waddr,
input rstn, flush_unissued, flush, instruction, fetch_valid, fetch_ack, issue_ack, issue_sbe, waddr,
st_valid, st_paddr, ld_valid, ld_kill, ld_paddr,
wdata, we, commit_instr, commit_ack, exception;
endclocking