/// LSU EE 4720 -- Spring 2002 -- Computer Architecture
//
/// Pipelined Hardwired Control MIPS, Dynamically Scheduled
//
// Implements a small subset of MIPS32 instructions and features.
//
// Time-stamp: <21 April 2002, 14:16:27 CDT, koppel@sol>
//
/// Dependencies
/// To compile run this the following is also needed:
//
// mipspipetb.v The testbench. It is included in here for convenience.
//
// mips_memory.v Memory system interface. Also included for convenience.
//
// An "assembled" program, for example dstest.v. The name of the
// file is specified in the MIPS_PROG macro, the testbench uses the
// macro to include the file.
//
// ped A Perlscript used to format pipeline execution diagrams.
// It is invoked by the testbench.
/// Under Construction
/// Limitations
//
// This code will probably never implement all of MIPS32, but the
// limitations below will be addressed at some time.
//
// No bypassing, so there is large latency between instructions.
// No load or store instructions.
// No floating-point operations.
/// Specify Program to Load
//
// A quick-and-dirty method of loading a program is used. (For now.)
// Therefore the description must be re-compiled each time the program
// is changed. (The program is assembled by SPIM and some perl code.)
//
`define MIPS_PROG "dstest.v"
/// Testbench Settings
//
// Maximum number of cycles to simulate.
//
`define CYCLE_LIMIT 50000
// Maximum number of cycles to print register and instruction data.
//
`define WATCH_LIMIT 100
// Maximum number of instruction states to trace. (Roughly product of
// number of cycles times average number of in-flight instructions.)
`define PTRACE_LIMIT 100000
/// Unexpected Macro
//
// Used in the default case item of case statements when the default
// item should not be executed. Used in case statements that assign
// the same register in each item. If the default item is executed
// (indicating a programming bug) simulation is stopped and hopefully
// the bug is fixed. For synthesis, the unexpected macro would assign
// the variable, avoiding the synthesis of a latch. Alas, Leonardo
// Spectrum does not recognize macros with parameters so a task is
// used to assign the variable. That task must be included in each
// module. (If Leonardo understood hierarchical references, the task
// could be put in a special utility module, but it can't.)
`ifdef exemplar
`define UNEXPECTED unexpected
`else
`define UNEXPECTED(var,ctrl) begin var = 0; if( ctrl[0] !== 1'bx ) $stop; end 0:
`endif
///
/// MIPS Processor
///
module cpu_p1(exc,data_out_2, addr_1,addr_2,size_2,we_2,
data_in_1,data_in_2, mem_error_in_1,mem_error_in_2,reset,clk);
input [31:0] data_in_1, data_in_2;
input [2:0] mem_error_in_1, mem_error_in_2;
input reset,clk;
output [7:0] exc;
output [31:0] data_out_2, addr_1, addr_2;
output [1:0] size_2;
output we_2;
///
/// MODULE CONFIGURATION CONSTANTS
///
/// Debugging
//
// Skip ready instruction if $random & SCHED_RDELAY_MASK != 0.
//
parameter SCHED_RDELAY_MASK = 7;
/// Reorder Buffer
//
parameter ROB_lg = 3;
parameter ROB_sze = (1<<ROB_lg);
`define ROB_idxr ROB_lg-1:0
`define ROB_szer 0:ROB_sze-1
/// Physical Register File
//
parameter PRF_sze = ROB_sze + 32;
parameter PRF_lg = ROB_sze >= 32 ? ROB_lg + 1 : 6;
`define PRF_idxr PRF_lg-1:0
// Register Map Vector (Used to store 32-element register map in one vector.)
`define RMV_r (32*PRF_lg-1):0
/// Integer (so far) Instruction Queue
//
parameter IQI_sze = 8; // KEEP idxr UPDATED!! Yes, YOU, it's NOT automatic!
`define IQI_idxr 3:0
`define IQI_1r IQI_sze-1:0
`define IQI_2r IQI_sze*2-1:0
/// Branch Queue
//
parameter BQ_lg = 2; // >0 for now
parameter BQ_sze = 1 << BQ_lg;
`define BQ_idxr BQ_lg-1:0
// Prediction Mask
`define BQ_pmr BQ_sze-1:0
///
/// MIPS CONSTANTS
///
//
// Defined by the ISA
/// "opcode" Field Values
//
parameter O_rfmt = 6'h0;
parameter O_j = 6'h2;
parameter O_beq = 6'h4;
parameter O_bne = 6'h5;
parameter O_addi = 6'h8;
parameter O_slti = 6'ha;
parameter O_andi = 6'hc;
parameter O_ori = 6'hd;
parameter O_lui = 6'hf;
parameter O_lw = 6'h23;
parameter O_lbu = 6'h24;
parameter O_sw = 6'h2b;
parameter O_sb = 6'h28;
/// "function" Field Values
//
parameter F_sll = 6'h0;
parameter F_srl = 6'h2;
parameter F_sys = 6'hc;
parameter F_add = 6'h20;
parameter F_sub = 6'h22;
parameter F_and = 6'h24;
parameter F_or = 6'h25;
parameter F_xor = 6'h26;
///
/// IMPLEMENTATION CONSTANTS
///
//
// Defined for this implementation, not standardized. These codes
// are used by other modules in this implementation, so they should
// be changed consistently.
/// Processor Exception Codes
//
parameter EXC_none = 8'd0;
parameter EXC_if_bus = 8'd1; // Bus Error (Mis-aligned address.)
parameter EXC_if_seg = 8'd2; // Bad Address
parameter EXC_id_ins = 8'd3; // Illegal (Reserved) Instruction
parameter EXC_id_sys = 8'd5; // Syscall Instruction
parameter EXC_me_bus = 8'd6; // Bus Error (Mis-aligned address.)
parameter EXC_me_seg = 8'd7; // Bad Address
//
// The exception codes above are not MIPS codes, though they are
// similar. (For one thing, MIPS does not use the bus exception
// for a misaligned address.) For the real codes see Table 6-17 in
//http://www.ece.lsu.edu/ee4720/mips32v3.pdf
/// ALU Operations + Extra Bit
//
// The lower 5 bits of the codes below are used by the ALU, the
// sixth bit is used for special cases and is removed in the ID
// stage.
//
parameter OP_xxx = 6'h0; // Don't care.
parameter OP_add = 6'h0;
parameter OP_sll = 6'h1;
parameter OP_srl = 6'h2;
parameter OP_xor = 6'h3;
parameter OP_sub = 6'h4;
parameter OP_or = 6'h5;
parameter OP_and = 6'h6;
parameter OP_slt = 6'h7;
parameter OP_seq = 6'h8;
parameter OP_b = 6'h9;
parameter OP_sne = 6'ha;
parameter OP_ill = 6'h20; // Illegal Instruction
parameter OP_sys = 6'h21; // Syscall
/// Memory Exception Codes
//
parameter MEM_ERR_none = 0;
parameter MEM_ERR_bus = 1; // Bad alignment.
parameter MEM_ERR_seg = 2; // Bad address.
///
/// MODULE CONSTANTS
///
//
// Defined for this module, intended to improve readability of code.
/// PC Mux
//
parameter PC_npc = 2'd0;
// parameter PC_dsp = 2'd1; // Displacement (Branches)
parameter PC_alt = 2'd1; // Alternate Path (for misprediction recovery)
parameter PC_rgn = 2'd2; // Region (Jumps)
parameter PC_rs = 2'd3;
parameter PC_bp = 2'd3; // Branch Predictor
/// ALU Muxen
//
parameter SRC_xx = 3'd6; // Won't be used, avoids stalls on alu_a and alu_b.
parameter SRC_00 = 3'd6; // Use zero, or doesn't use ALU.
parameter SRC_me = 3'd1;
parameter SRC_wb = 3'd2;
parameter SRC_rs = 3'd3;
parameter SRC_sa = 3'd4;
parameter SRC_rt = 3'd3;
parameter SRC_im = 3'd4;
parameter SRC_np = 3'd5;
/// Register Number to Write Back
//
parameter WB_00 = 3'd0;
parameter WB_rd = 3'd1;
parameter WB_rt = 3'd2;
/// Immediate Formatting
//
parameter IMM_x = 3'd0; // Don't care.
parameter IMM_s = 3'd0;
parameter IMM_u = 3'd1;
parameter IMM_l = 3'd2;
/// Memory Access Size
//
parameter ME_SIZE_0 = 2'd0;
parameter ME_SIZE_1 = 2'd1;
parameter ME_SIZE_2 = 2'd2;
parameter ME_SIZE_4 = 2'd3;
parameter ME_CONTROL_nop = { ME_SIZE_0, 1'd0 };
///
/// DECLARATIONS
///
/// Instruction Fields
//
wire [4:0] rs, rt, rd, sa;
wire [5:0] opcode, func;
wire [25:0] ii;
wire [15:0] immed;
/// Some ALU Connections
//
wire [31:0] alu_out;
reg [31:0] alu_a, alu_b;
/// Register Files and Maps
//
// Physical Register File
reg [31:0] prf_value[0:PRF_sze-1];
reg prf_avail[0:PRF_sze-1]; // If 1, value available.
reg [`PRF_idxr] reg_id_map[0:31]; // ID: architected reg -> physical reg
reg [`PRF_idxr] reg_co_map[0:31]; // Commit: architected reg -> physical reg
// Backups of id map. Entire id map stored in a single element.
reg [`RMV_r] reg_id_map_backup [0:BQ_sze-1];
///
/// INSTRUCTION HANDLING UNITS
///
///
/// Reorder Buffer Declarations
///
// ROB Main Element Size
parameter ROB_melt_sze = 32 + 32 + 1 + 1 + 5 + PRF_lg;
// ROB Divided into three sections, each section written at a
// different time. All sections are indexed by the same head and
// tail pointers.
reg [ROB_melt_sze-1:0] rob_main [0:ROB_sze-1]; // Main, write at ID
reg [8:0] rob_dexc [0:ROB_sze-1]; // Done/Exception, write at WB
reg [`PRF_idxr] rob_dstp [0:ROB_sze-1]; // Dest, write at commit.
reg [`ROB_idxr] rob_head; // Next element to commit.
reg [`ROB_idxr] rob_tail; // First empty element.
// Note: ROB element at tail should never be used.
wire rob_empty = rob_head == rob_tail;
wire rob_full;
// ROB Tail Symbols
//
// Main, written at ID.
//
wire [31:0] rob_t_pc;
wire [31:0] tb_rob_t_din; // Dynamic instruction number (for testbench).
wire tb_rob_t_idest; // If 1, instruction writes a register (for tb).
wire rob_t_done_1; // Done when rob_t_done_1 == rob_t_done_2.
reg [4:0] rob_t_dest_a; // Architected destination register.
// Incumbent: Physical register previously mapped to destination
// register. Will be added to free list (put in dest_p field) if
// instruction commits.
reg [`PRF_idxr] rob_t_incumb;
//
// Done/Exception, written at writeback (complete).
//
reg [7:0] rob_t_exc; // Exception code raised by instruction.
wire rob_t_done_2; // Set to done_1 when instruction completes.
//
// Physical Destination (now part of free list), written at commit.
//
// For a ROB element in use holds physical register for destination
// of instruction, for a ROB elt not in use, holds a free physical
// register.
wire [`PRF_idxr] rob_t_dest_p;
// ROB Head Symbols
//
wire [31:0] rob_h_pc;
wire [31:0] tb_rob_h_din;
wire tb_rob_h_idest;
wire rob_h_done_1; // Done when rob_h_done_1 == rob_h_done_2.
wire [4:0] rob_h_dest_a;
wire [`PRF_idxr] rob_h_dest_p;
wire [`PRF_idxr] rob_h_incumb;
wire [7:0] rob_h_exc;
wire rob_h_done_2;
assign rob_t_done_2 = rob_dexc[rob_tail];
assign {rob_h_pc,
tb_rob_h_din,
tb_rob_h_idest,
rob_h_done_1,
rob_h_dest_a,
rob_h_incumb } = rob_main[rob_head];
assign {rob_h_exc, rob_h_done_2} = rob_dexc[rob_head];
///
/// Instruction Queues, Scheduler
///
parameter IQ_elt_sze = 2*PRF_lg + 5 + 32 + 2*3 + 5 + 8 + 1
+ PRF_lg + ROB_lg + BQ_lg + 1 + 1 + 1 + 2*32;
`define IQI_eltr IQ_elt_sze-1:0
// Instruction queue divided into four sections.
//
// iqi: Main storage.
// iqi_occ: Occupied bit, used to find empty and ready entries.
// iqi_await: Waiting bits, when both zero instruction ready.
// iqi_bmask: B-mask, used to find instructions that need to be squashed.
//
reg [IQ_elt_sze-1:0] iqi [0:IQI_sze-1];
reg [`IQI_1r] iqi_occ;
reg [`IQI_2r] iqi_await;
reg [`BQ_pmr] iqi_bmask[0:IQI_sze-1];
// For each physical register, mask indicating waiting iqi elements.
reg [`IQI_2r] pr_to_iqi_await [0:PRF_sze-1];
///
/// Branch Queue
///
parameter BQE_sze = 32 + 32;
// Branch queue has one element per in-flight branch. Element
// holds the path not taken, to be used for recovery. Element
// also holds PC of branch, for debugging.
//
reg [BQE_sze-1:0] bq [0:BQ_sze-1];
wire [31:0] bqe_res_alt_path;
wire [31:0] tb_bqe_res_pc;
reg [`BQ_idxr] bq_tail;
wire [`BQ_idxr] bq_tail_soon;
// Used to determine when bmask_ins should be updated and
// when to backup the id map.
//
reg [1:0] backup_id_map_sr; // Shift Register
// Branch masks have one bit per branch queue entry, when 1 that
// entry is active. A copy of bmask_ins is carried by in-flight
// instructions to determine whether the instruction should be
// squashed when a branch is mispredicted. Mask bmask_reg is used
// to determine whether the id register map was backed up before a
// misprediction. (If not, the current id map is valid.)
//
reg [`BQ_pmr] bmask_ins; // Assigned to instructions.
reg [`BQ_pmr] bmask_reg; // Assigned to reg_id_map.
// Matched against bmask, used to detect instructions to squash
// and whether id map backed up.
wire [`BQ_pmr] wb_bp_mask_bad, wb_bp_mask_good;
wire [31:0] id_alt_path;
wire [31:0] id_pred_path, id_taken_path;
wire wb_bp_good, wb_bp_bad;
reg [31:0] id_bq_alt_path;
reg [31:0] id_bq_pc;
///
/// PIPELINE LATCHES
///
/// IF: Instruction Fetch
//
reg [31:0] if_pc, next_if_pc;
/// ID: Instruction Decode
//
reg [31:0] if_id_ir;
reg [31:0] if_id_npc, if_id_pc;
reg [7:0] if_id_exc, next_if_id_exc;
reg if_id_occ;
reg [31:0] tb_if_din, tb_if_id_din;
/// QU: Instruction Queue
//
// All of the group below are put in an (so far, the) issue queue.
reg [`PRF_idxr] id_qu_rs;
reg [`PRF_idxr] id_qu_rt;
reg [4:0] id_qu_sa;
reg [31:0] id_qu_imm, next_id_qu_imm;
reg [2:0] id_qu_alu_a_src, next_id_qu_alu_a_src;
reg [2:0] id_qu_alu_b_src, next_id_qu_alu_b_src;
reg [4:0] id_qu_alu_op, next_id_qu_alu_op;
reg [7:0] id_qu_exc;
reg id_qu_idest;
reg [`PRF_idxr] id_qu_dest_p;
reg [`ROB_idxr] id_qu_rob_idx;
reg [`BQ_idxr] id_qu_bq_idx;
reg id_qu_bp;
reg id_qu_bp_taken;
reg id_qu_done_1;
reg [31:0] tb_id_qu_pc;
reg [31:0] tb_id_qu_din;
// The items below are put in the issue queue but in separate memories
// for coding ease and assumed efficient synthesis.
reg [`BQ_pmr] id_qu_bmask;
reg id_qu_occ;
/// RR: Register Read
//
parameter IQ_rr_pac_sze = IQ_elt_sze - 2*PRF_lg - 2*32;
reg [`PRF_idxr] qu_rr_rs;
reg [`PRF_idxr] qu_rr_rt;
reg [`BQ_pmr] qu_rr_bmask;
reg [31:0] tb_qu_rr_pc;
reg [31:0] tb_qu_rr_din;
reg [IQ_rr_pac_sze-1:0] qu_rr_elt;
reg qu_rr_occ;
/// EX: Execute
//
parameter IQ_ex_pac_sze = IQ_rr_pac_sze - 5 - 32 - 2*3 - 5 - 8;
reg [4:0] rr_ex_sa;
reg [31:0] rr_ex_imm;
reg [2:0] rr_ex_alu_a_src;
reg [2:0] rr_ex_alu_b_src;
reg [4:0] rr_ex_alu_op;
reg [7:0] rr_ex_exc;
reg [31:0] tb_rr_ex_pc;
reg [31:0] tb_rr_ex_din;
reg [IQ_ex_pac_sze-1:0] rr_ex_elt;
reg [31:0] rr_ex_rs_val;
reg [31:0] rr_ex_rt_val;
reg [`BQ_pmr] rr_ex_bmask;
reg rr_ex_occ;
/// WB: Writeback
//
reg [31:0] ex_wb_result;
reg [7:0] ex_wb_exc;
reg ex_wb_occ;
reg [`ROB_idxr] ex_wb_rob_idx;
reg ex_wb_done_1;
reg ex_wb_idest;
reg [`PRF_idxr] ex_wb_dest_p;
reg [`BQ_idxr] ex_wb_bq_idx;
reg ex_wb_bp;
reg ex_wb_bp_taken;
reg [31:0] tb_ex_wb_pc;
reg [31:0] tb_ex_wb_din;
///
/// INTERSTAGE SIGNALS
///
// Others are declared elsewhere.
reg branch_in_id;
reg freeze_id;
reg [1:0] pc_src;
wire iqi_full;
///
/// INSTANTIATION
///
alu our_alu(alu_out, alu_a, alu_b, rr_ex_alu_op);
///
/// FUNCTIONS
///
task unexpected;
inout [31:0] var;
input [10:0] control;
var = 0;
endtask
function [`IQI_2r] iqi_mask_2;
input [1:0] bits;
input [`IQI_idxr] pos;
iqi_mask_2 = bits << {pos,1'b0};
endfunction
/// Some Memory Connections
//
assign addr_1 = if_pc;
`ifdef XXX
assign addr_2 = ex_me_alu;
assign we_2 = ex_me_we;
assign size_2 = ex_me_size;
assign data_out_2 = ex_me_rt_val;
`endif
///
/// Pipeline Flow Control
///
wire squash_if = wb_bp_bad;
wire squash_id = ex_wb_occ && | ( wb_bp_mask_bad & bmask_ins );
wire squash_qu = ex_wb_occ && | ( wb_bp_mask_bad & id_qu_bmask );
wire stall_bq_full = if_id_occ && branch_in_id && bmask_ins[bq_tail_soon];
wire stall_rob_full = if_id_occ && rob_full;
wire stall = stall_rob_full || stall_bq_full || freeze_id || iqi_full;
wire stall_if = stall;
wire stall_id = stall;
wire stall_qu = iqi_full;
wire id_live = if_id_occ && ~squash_id && ~stall_id;
wire qu_live = id_qu_occ && ~squash_qu && ~stall_qu;
///
/// PIPELINE STARTS HERE
///
///
/// IF: Instruction Fetch
///
wire [31:0] if_npc = if_pc + 4;
always @( pc_src or if_id_npc or id_pred_path
or ii or bqe_res_alt_path or if_npc )
case( pc_src )
PC_npc : next_if_pc = if_npc;
PC_rgn : next_if_pc = { if_id_npc[31:28], ii, 2'b0 };
PC_alt : next_if_pc = bqe_res_alt_path;
PC_bp : next_if_pc = id_pred_path;
// PC_rs : next_if_pc = 32'd0; // Update!
default : `UNEXPECTED(next_if_pc,pc_src);
endcase
always @( mem_error_in_1 )
case( mem_error_in_1 )
MEM_ERR_none : next_if_id_exc = 0;
MEM_ERR_seg : next_if_id_exc = EXC_if_seg;
MEM_ERR_bus : next_if_id_exc = EXC_if_bus;
default : `UNEXPECTED(next_if_id_exc, mem_error_in_1);
endcase
/// Registers Below
always @( posedge clk )
if( reset ) begin
// The value below is the usual entry point for SPIM-compiled
// code. Real MIPS processors reset PC to 'hbfc00000.
if_pc <= 'h400000;
tb_if_din <= 1;
end else if( squash_if || ~stall_if ) begin
if_pc <= next_if_pc;
tb_if_din <= tb_if_din + 1;
end
always @( posedge clk )
if( reset ) begin
if_id_occ <= 0;
if_id_exc <= 0;
end else if ( stall_id && squash_id ) begin
if_id_occ <= 0;
end else if( ~stall_id ) begin
if_id_pc <= if_pc;
if_id_ir <= data_in_1;
if_id_npc <= next_if_pc;
if_id_exc <= next_if_id_exc;
if_id_occ <= ~squash_if;
tb_if_id_din <= tb_if_din;
end
///
/// ID: Instruction Decode
///
// Stage-Local Declarations
//
reg [17:0] d_a_op_b; // Dest <- operand_a op operand_b, immed_fmt
reg [2:0] size_we; // Memory control bits.
reg [2:0] immed_fmt; // Formating to apply to immediate.
reg [2:0] dest_field;
reg extra_op_bit;
reg [2:0] alu_a_src_maybe, alu_b_src_maybe;
reg [7:0] id_exc;
assign {opcode,rs,rt,rd,sa,func} = if_id_ir;
assign ii = if_id_ir[25:0];
assign immed = if_id_ir[15:0];
wire [31:0] rs_p = reg_id_map[rs];
wire [31:0] rt_p = reg_id_map[rt];
wire [31:0] rd_p = reg_id_map[rd];
always @( if_id_ir or if_id_occ or if_id_npc
or opcode or func or rs or rt or rd or immed )
begin
// Note: Case statements below could be synthesized as a memory
// which is why only constants appear on the RHS of the assignments.
case( opcode )
O_rfmt:
// R-Format Instructions
case( func )
F_sll : d_a_op_b = {WB_rd, SRC_sa, OP_sll, SRC_rt, IMM_x};
F_srl : d_a_op_b = {WB_rd, SRC_sa, OP_srl, SRC_rt, IMM_x};
F_sys : d_a_op_b = {WB_00, SRC_00, OP_sys, SRC_00, IMM_x};
F_add : d_a_op_b = {WB_rd, SRC_rs, OP_add, SRC_rt, IMM_x};
F_sub : d_a_op_b = {WB_rd, SRC_rs, OP_sub, SRC_rt, IMM_x};
F_and : d_a_op_b = {WB_rd, SRC_rs, OP_and, SRC_rt, IMM_x};
F_or : d_a_op_b = {WB_rd, SRC_rs, OP_or, SRC_rt, IMM_x};
F_xor : d_a_op_b = {WB_rd, SRC_rs, OP_xor, SRC_rt, IMM_x};
default : d_a_op_b = {WB_00, SRC_00, OP_ill, SRC_00, IMM_x};
endcase
// I- and J-Format Instructions
O_lw, O_lbu
: d_a_op_b = {WB_rt, SRC_rs, OP_add, SRC_im, IMM_s};
O_sb : d_a_op_b = {WB_00, SRC_rs, OP_add, SRC_im, IMM_s};
O_lui : d_a_op_b = {WB_rt, SRC_rs, OP_or, SRC_im, IMM_l};
O_addi : d_a_op_b = {WB_rt, SRC_rs, OP_add, SRC_im, IMM_s};
O_andi : d_a_op_b = {WB_rt, SRC_rs, OP_and, SRC_im, IMM_u};
O_ori : d_a_op_b = {WB_rt, SRC_rs, OP_or, SRC_im, IMM_u};
O_slti : d_a_op_b = {WB_rt, SRC_rs, OP_slt, SRC_im, IMM_s};
O_j : d_a_op_b = {WB_00, SRC_00, OP_xxx, SRC_00, IMM_x};
O_bne : d_a_op_b = {WB_00, SRC_rs, OP_sne, SRC_rt, IMM_x};
O_beq : d_a_op_b = {WB_00, SRC_rs, OP_seq, SRC_rt, IMM_x};
default : d_a_op_b = {WB_00, SRC_00, OP_ill, SRC_00, IMM_s};
endcase
{ dest_field,
alu_a_src_maybe,
extra_op_bit,
next_id_qu_alu_op,
alu_b_src_maybe,
immed_fmt
} = d_a_op_b;
next_id_qu_alu_a_src = alu_a_src_maybe == SRC_rs && !rs
? SRC_00 : alu_a_src_maybe;
next_id_qu_alu_b_src = alu_b_src_maybe == SRC_rt && !rt
? SRC_00 : alu_b_src_maybe;
case( opcode )
O_lbu : size_we = {ME_SIZE_1, 1'b0};
O_lw : size_we = {ME_SIZE_4, 1'b0};
O_sb : size_we = {ME_SIZE_1, 1'b1};
default : size_we = {ME_SIZE_0, 1'b0};
endcase
case( {extra_op_bit,next_id_qu_alu_op} )
OP_sys : id_exc = EXC_id_sys;
OP_ill : id_exc = EXC_id_ins;
default : id_exc = EXC_none;
endcase
case( opcode )
O_bne, O_beq: branch_in_id = 1;
default: branch_in_id = 0;
endcase
case( immed_fmt )
IMM_s: next_id_qu_imm = { immed[15] ? 16'hffff : 16'h0, immed };
IMM_l: next_id_qu_imm = { immed, 16'h0 };
IMM_u: next_id_qu_imm = { 16'h0, immed };
default: `UNEXPECTED(next_id_qu_imm,immed_fmt);
endcase
end
wire [7:0] next_id_qu_exc = if_id_exc ? if_id_exc : id_exc;
// exemplar full_case
always @( dest_field or rd or rt or rd_p or rt_p or rob_t_dest_p )
case ( dest_field )
WB_00: begin rob_t_dest_a = 0; rob_t_incumb = rob_t_dest_p; end
WB_rd: begin rob_t_dest_a = rd; rob_t_incumb = rd_p; end
WB_rt: begin rob_t_dest_a = rt; rob_t_incumb = rt_p; end
default: `UNEXPECTED(rob_t_incumb,dest_field);
endcase
assign rob_t_dest_p = rob_dstp[rob_tail];
wire next_id_qu_idest = rob_t_dest_a !== 0;
assign rob_t_pc = if_id_pc;
assign tb_rob_t_din = tb_if_id_din;
assign tb_rob_t_idest = next_id_qu_idest;
assign rob_t_done_1 = ~rob_t_done_2;
// next_id_qu_me = size_we;
reg id_pred_taken;
always @( posedge clk ) id_pred_taken <= $random;
// always @( posedge clk ) id_pred_taken <= 0;
always @( opcode or if_id_occ or wb_bp_bad ) begin
case( 1 )
wb_bp_bad : pc_src = PC_alt;
!if_id_occ : pc_src = PC_npc;
default :
case( opcode )
O_bne,
O_beq : pc_src = PC_bp;
O_j : pc_src = PC_rgn;
default : pc_src = PC_npc;
endcase
endcase
end
assign id_taken_path = if_id_npc + {immed[15]?14'h3fff:14'h0,immed,2'b0};
assign { id_pred_path, id_alt_path } = id_pred_taken ?
{ id_taken_path, if_npc } :
{ if_npc, id_taken_path };
/// Branch Misprediction Recovery
//
reg [`BQ_pmr] next_bmask_ins, next_bmask_reg;
wire cdb_mispredict_maybe = ex_wb_bp_taken ^ ex_wb_result[0];
assign wb_bp_good = ex_wb_occ && ex_wb_bp && !cdb_mispredict_maybe;
assign wb_bp_bad = ex_wb_occ && ex_wb_bp && cdb_mispredict_maybe;
assign bq_tail_soon = bq_tail + backup_id_map_sr[0];
wire cdb_before_bq = ~bmask_reg[ex_wb_bq_idx];
assign {bqe_res_alt_path,tb_bqe_res_pc} =
cdb_before_bq ? {id_bq_alt_path,id_bq_pc} : bq[ex_wb_bq_idx];
always @( bmask_ins or bmask_reg or ex_wb_occ or ex_wb_bp or ex_wb_bq_idx
or wb_bp_bad or id_live or backup_id_map_sr[0] or bq_tail_soon
or bq_tail or qu_live or id_qu_bp or backup_id_map_sr[1] ) begin
next_bmask_ins = bmask_ins;
next_bmask_reg = bmask_reg;
if( id_live && backup_id_map_sr[1] ) next_bmask_ins[bq_tail] = 1;
if( id_live && backup_id_map_sr[0] ) next_bmask_reg[bq_tail] = 1;
// Probably won't synthesize well, if at all.
if( ex_wb_occ & ex_wb_bp )
begin
next_bmask_ins[ex_wb_bq_idx] = 0;
next_bmask_reg[ex_wb_bq_idx] = 0;
end
if( wb_bp_bad ) begin:NB
integer i;
reg set_to_zero;
set_to_zero = ex_wb_bq_idx > bq_tail_soon;
for(i=0; i<BQ_sze; i=i+1) begin
if( i == ex_wb_bq_idx + 1 ) set_to_zero = ~ set_to_zero;
if( i == bq_tail_soon ) set_to_zero = ~ set_to_zero;
if( set_to_zero ) begin
next_bmask_ins[i] = 0;
next_bmask_reg[i] = 0;
end
end
end
end
always @( posedge clk )
if( reset ) begin
bq_tail <= 0;
bmask_ins <= 0;
bmask_reg <= 0;
end else begin
if( wb_bp_bad ) begin
bq_tail <= ex_wb_bq_idx;
end else if( id_live && backup_id_map_sr[1] ) begin
bq[bq_tail_soon] <= { id_bq_alt_path, id_bq_pc };
end else if( id_live && backup_id_map_sr[0] ) begin
bq_tail <= bq_tail + 1;
end
if( id_live && branch_in_id ) begin
id_bq_alt_path <= id_alt_path;
id_bq_pc <= if_id_pc;
end
bmask_ins <= next_bmask_ins;
bmask_reg <= next_bmask_reg;
end
// ID Register Map
always @( posedge clk ) begin:IDM
integer i;
if( reset ) begin
for(i=0; i<32; i=i+1) reg_id_map[i] <= i;
backup_id_map_sr <= 0;
end else begin:IDME
reg [`RMV_r] id_map_vec;
reg id_map_update, bit_1, good_and_fast;
good_and_fast = wb_bp_good && cdb_before_bq;
bit_1 = good_and_fast ? 0 : backup_id_map_sr[1];
if ( wb_bp_bad ) begin
backup_id_map_sr <= 0;
end else if( id_live ) begin
backup_id_map_sr <= {branch_in_id,bit_1};
end else if( good_and_fast ) begin
backup_id_map_sr <= 0;
end
if ( backup_id_map_sr[0]
&& id_live
&& !wb_bp_bad && !good_and_fast
) begin
// Not checked for synthesis efficiency.
for(i=0; i<32; i=i+1) id_map_vec = { id_map_vec, reg_id_map[i] };
reg_id_map_backup[bq_tail] = id_map_vec;
end
id_map_update = id_live && next_id_qu_idest;
if( wb_bp_bad && !cdb_before_bq ) begin
id_map_vec = reg_id_map_backup[ex_wb_bq_idx];
// Not checked for synthesis efficiency.
for(i=0; i<32; i=i+1) begin
reg_id_map[31-i] <= id_map_vec;
id_map_vec = id_map_vec >> PRF_lg;
end
end else if( id_map_update )
reg_id_map[rob_t_dest_a] <= rob_t_dest_p;
end
end
// ROB ID
//
wire [`ROB_idxr] next_rob_tail = rob_tail + 1;
assign rob_full = next_rob_tail == rob_head;
always @( posedge clk )
if( reset ) begin:RID
integer i;
rob_tail <= 0;
// Replace with something that doesn't require a complete sweep?
for(i=0; i<ROB_sze; i=i+1) rob_main[i] <= 32 + i;
end else begin
if( wb_bp_bad ) begin:RT
reg [`ROB_idxr] next_idx;
next_idx = ex_wb_rob_idx + 1;
if( rob_tail == next_idx ) begin
if( id_live ) rob_tail <= next_rob_tail;
end else begin
rob_tail <= ex_wb_rob_idx + 2;
end
end else begin
if( id_live ) rob_tail <= next_rob_tail;
end
if( id_live ) begin
rob_main[rob_tail] <= {rob_t_pc, tb_rob_t_din, tb_rob_t_idest,
rob_t_done_1,
rob_t_dest_a,rob_t_incumb};
end
end
always @( posedge clk )
if( reset || squash_qu ) begin
id_qu_occ <= 0;
tb_id_qu_pc <= 0;
freeze_id <= 0;
end else if( ~stall_qu ) begin
freeze_id <= id_qu_occ && id_qu_exc !== 0;
id_qu_rs <= rs_p;
id_qu_rt <= rt_p;
id_qu_sa <= sa;
id_qu_imm <= next_id_qu_imm;
id_qu_alu_a_src <= next_id_qu_alu_a_src;
id_qu_alu_b_src <= next_id_qu_alu_b_src;
id_qu_alu_op <= next_id_qu_alu_op;
id_qu_exc <= next_id_qu_exc;
id_qu_idest <= next_id_qu_idest;
id_qu_dest_p <= rob_t_dest_p;
id_qu_rob_idx <= rob_tail;
id_qu_bq_idx <= bq_tail_soon;
id_qu_bp <= branch_in_id;
id_qu_bp_taken <= id_pred_taken;
id_qu_done_1 <= rob_t_done_1;
tb_id_qu_pc <= if_id_pc;
tb_id_qu_din <= tb_if_id_din;
id_qu_bmask <= bmask_ins & ~wb_bp_mask_good;
id_qu_occ <= id_live;
end else begin
id_qu_bmask <= id_qu_bmask & ~wb_bp_mask_good;
end
///
/// Q: Issue / Instruction Queue, Schedule,
/// DS: Dispatch
///
assign iqi_full = &iqi_occ;
reg iqi_free_idx_assigned;
reg [`IQI_idxr] iqi_free_idx;
always @( iqi_occ ) begin:IQIO
integer i;
iqi_free_idx_assigned = 0;
iqi_free_idx = 0; // Avoid latch.
for(i=0; i<IQI_sze; i=i+1)
if( !iqi_free_idx_assigned && !iqi_occ[i] ) begin
iqi_free_idx_assigned = 1;
iqi_free_idx = i;
end
end
wire qu_need_rs = id_qu_alu_a_src === SRC_rs;
wire qu_need_rt = id_qu_alu_b_src === SRC_rt;
wire [`IQI_2r] iqi_await_update_maybe = pr_to_iqi_await[ex_wb_dest_p];
wire [`IQI_2r] iqi_await_update
= ex_wb_occ && ex_wb_idest ? iqi_await_update_maybe : 0;
wire [`IQI_2r] iqi_await_rs = pr_to_iqi_await[id_qu_rs];
wire [`IQI_2r] iqi_await_rt = pr_to_iqi_await[id_qu_rt];
wire qu_rs_avail = prf_avail[id_qu_rs]
|| ex_wb_occ && ex_wb_idest && ex_wb_dest_p == id_qu_rs;
wire qu_rt_avail = prf_avail[id_qu_rt]
|| ex_wb_occ && ex_wb_idest && ex_wb_dest_p == id_qu_rt;
wire [`IQI_2r] await_new_rs
= iqi_mask_2( {qu_need_rs & ~qu_rs_avail,1'b0}, iqi_free_idx);
wire [`IQI_2r] await_new_rt
= iqi_mask_2( qu_need_rt & ~qu_rt_avail, iqi_free_idx);
wire [`IQI_2r] await_new = await_new_rs | await_new_rt;
reg [`IQI_2r] pr_to_iqi_flush_mask;
always @( posedge clk ) begin:IQIF
integer i;
if( qu_live ) begin
if( id_qu_idest ) pr_to_iqi_await[id_qu_dest_p] <= 0;
pr_to_iqi_await[id_qu_rs] <= iqi_await_rs | await_new_rs;
if( id_qu_rs != id_qu_rt )
pr_to_iqi_await[id_qu_rt] <= iqi_await_rt | await_new_rt;
end
// exemplar translate_off
if( wb_bp_bad ) // For faster simulation.
// exemplar translate_on
for(i=0; i<PRF_sze; i=i+1)
pr_to_iqi_await[i] = pr_to_iqi_await[i] & ~ pr_to_iqi_flush_mask;
end
wire [`IQI_2r] iqi_await_clr_mask
= ~iqi_mask_2({qu_live,qu_live},iqi_free_idx);
wire [`IQI_2r] iqi_await_next = reset
? 0
: iqi_await & ~iqi_await_update & iqi_await_clr_mask
| ( qu_live ? await_new : 0 );
always @( posedge clk ) iqi_await <= iqi_await_next;
reg iqi_something_ready;
reg [`IQI_idxr] iqi_ready_idx;
// exemplar translate_off
initial begin iqi_ready_idx = 0; iqi_free_idx = 0; end
// exemplar translate_on
reg another_cycle_kludge;
initial another_cycle_kludge = 0;
always @( posedge clk ) another_cycle_kludge <= !another_cycle_kludge;
always @( another_cycle_kludge or iqi_occ or iqi_await ) begin:IQIR
integer i;
iqi_something_ready = 0;
iqi_ready_idx = 0; // Avoid latch.
for(i=IQI_sze-1; i >= 0; i=i-1) begin
if( !( $random & SCHED_RDELAY_MASK ) // Randomly skip to shake out bugs.
&& iqi_occ[i]
&& ! ( iqi_await & iqi_mask_2(3,i) ) )
begin
iqi_ready_idx = i;
iqi_something_ready = 1;
end
end
end
assign wb_bp_mask_bad = wb_bp_bad << ( ex_wb_occ ? ex_wb_bq_idx : 0 );
assign wb_bp_mask_good = wb_bp_good << ( ex_wb_occ ? ex_wb_bq_idx : 0 );
wire [`IQI_1r] iqi_remove_mask = iqi_something_ready << iqi_ready_idx;
wire [`IQI_1r] iqi_insert_mask = qu_live << iqi_free_idx;
reg [`IQI_1r] iqi_flush_mask;
reg iqi_bmask_update; // A kludge.
always @( wb_bp_mask_bad or iqi_bmask_update ) begin:FM
integer i;
reg f;
for(i=0; i<IQI_sze; i=i+1) begin
f = |( iqi_bmask[i] & wb_bp_mask_bad );
iqi_flush_mask[i] = f;
pr_to_iqi_flush_mask[i<<1] = f;
pr_to_iqi_flush_mask[(i<<1)+1] = f;
end
end
always @( posedge clk )
if( reset )
iqi_occ <= 0;
else
iqi_occ <= iqi_occ & ~iqi_remove_mask & ~iqi_flush_mask
| iqi_insert_mask;
wire [`IQI_eltr] iqi_ready_elt = iqi[iqi_ready_idx];
wire [31:0] tb_ds_pc, tb_ds_din;
assign {tb_ds_pc, tb_ds_din } = iqi_ready_elt;
always @( posedge clk ) begin:IQIPM
integer i;
if( qu_live )
iqi[iqi_free_idx] <= { id_qu_rs, id_qu_rt, id_qu_sa, id_qu_imm,
id_qu_alu_a_src, id_qu_alu_b_src,
id_qu_alu_op, id_qu_exc,
id_qu_idest, id_qu_dest_p,
id_qu_rob_idx,
id_qu_bq_idx, id_qu_bp, id_qu_bp_taken,
id_qu_done_1, tb_id_qu_pc, tb_id_qu_din };
iqi_bmask_update <= iqi_bmask_update === 0;
for(i=0; i<IQI_sze; i=i+1) begin
if( qu_live && i == iqi_free_idx )
iqi_bmask[i] <= id_qu_bmask & ~wb_bp_mask_good;
else
iqi_bmask[i] <= iqi_bmask[i] & ~wb_bp_mask_good;
end
end
always @( posedge clk )
if( reset ) begin
qu_rr_occ <= 0;
tb_qu_rr_pc <= 0;
end else begin
{ qu_rr_rs, qu_rr_rt,
qu_rr_elt,
tb_qu_rr_pc, tb_qu_rr_din } <= iqi_ready_elt;
qu_rr_bmask <= iqi_bmask[iqi_ready_idx] & ~wb_bp_mask_good;
qu_rr_occ <= iqi_something_ready
&& ! ( iqi_bmask[iqi_ready_idx] & wb_bp_mask_bad );
end
///
/// Register Read
///
wire [31:0] pr_rs_val = prf_value[qu_rr_rs];
wire [31:0] pr_rt_val = prf_value[qu_rr_rt];
always @( posedge clk )
if( reset ) begin
rr_ex_occ <= 0;
tb_rr_ex_pc <= 0;
end else begin
{rr_ex_sa, rr_ex_imm,
rr_ex_alu_a_src, rr_ex_alu_b_src, rr_ex_alu_op, rr_ex_exc,
rr_ex_elt} <= qu_rr_elt;
rr_ex_rs_val <= pr_rs_val;
rr_ex_rt_val <= pr_rt_val;
rr_ex_bmask <= qu_rr_bmask & ~wb_bp_mask_good;
rr_ex_occ <= qu_rr_occ && ! ( qu_rr_bmask & wb_bp_mask_bad );
tb_rr_ex_pc <= tb_qu_rr_pc;
tb_rr_ex_din <= tb_qu_rr_din;
end
///
/// Execute
///
always @( rr_ex_alu_a_src or rr_ex_rs_val or rr_ex_sa )
case( rr_ex_alu_a_src )
SRC_rs: alu_a = rr_ex_rs_val;
SRC_sa: alu_a = rr_ex_sa;
SRC_00: alu_a = 0;
default: `UNEXPECTED(alu_a,rr_ex_alu_a_src);
endcase
always @( rr_ex_alu_b_src or rr_ex_rt_val or rr_ex_imm )
case( rr_ex_alu_b_src )
SRC_rt: alu_b = rr_ex_rt_val;
SRC_im: alu_b = rr_ex_imm;
SRC_00: alu_b = 0;
default: `UNEXPECTED(alu_b,rr_ex_alu_b_src);
endcase
always @( posedge clk )
if( reset ) begin
ex_wb_occ <= 0;
tb_ex_wb_pc <= 0;
end else begin
ex_wb_result <= alu_out;
ex_wb_exc <= rr_ex_exc;
tb_ex_wb_pc <= tb_rr_ex_pc;
tb_ex_wb_din <= tb_rr_ex_din;
{ ex_wb_idest, ex_wb_dest_p,
ex_wb_rob_idx,
ex_wb_bq_idx, ex_wb_bp, ex_wb_bp_taken,
ex_wb_done_1
} <= rr_ex_elt;
ex_wb_occ <= rr_ex_occ && ! ( rr_ex_bmask & wb_bp_mask_bad );
end
///
/// Writeback
///
// ROB Complete
//
// exemplar translate_off
integer i;
initial for(i=0;i<ROB_sze;i=i+1) rob_dexc[i] = 0;
// exemplar translate_on
always @( posedge clk )
if( ex_wb_occ ) rob_dexc[ex_wb_rob_idx] <= {ex_wb_exc,ex_wb_done_1};
always @( posedge clk )
if( reset ) begin:PRF
integer i;
for(i=0; i<32; i=i+1) prf_avail[i] <= 1;
end else begin
if( ex_wb_occ && ex_wb_idest ) begin
prf_value[ex_wb_dest_p] <= ex_wb_result;
prf_avail[ex_wb_dest_p] <= 1;
end
if( id_qu_occ && id_qu_idest ) prf_avail[id_qu_dest_p] <= 0;
end
///
/// Commit
///
wire rob_h_complete = !rob_empty && rob_h_done_1 == rob_h_done_2;
assign rob_h_dest_p = rob_dstp[rob_head];
always @( posedge clk )
if( reset ) begin:CM
integer i;
for(i=0; i<32; i=i+1) reg_co_map[i] <= i;
rob_head <= 0;
end else if( rob_h_complete ) begin
rob_head <= rob_head + 1;
if( rob_h_dest_a ) reg_co_map[rob_h_dest_a] <= rob_h_dest_p;
end
// ROB Commit
//
always @( posedge clk )
if( reset ) begin:ROBD
integer i;
for(i=0; i<ROB_sze; i=i+1) rob_dstp[i] <= 32 + i;
end else if( rob_h_complete ) begin
rob_dstp[rob_head] <= rob_h_incumb;
end
assign exc = {1'b0,rob_h_complete ? rob_h_exc : EXC_none};
///
/// END OF HARDWARE DESCRIPTION
///
// exemplar translate_off
///
/// CONFIGURATION VALIDITY CHECK
///
initial begin:I1
reg [`IQI_idxr] test;
test = IQI_sze - 1;
if( test !== IQI_sze - 1 ) begin
$display("Macro IQI_idxr does not match IQI_sze.");
$stop;
end
end
///
/// TESTBENCH INTERFACE CODE
///
reg [31:0] tbi_done_pc;
reg tbi_inst_done;
always @( posedge clk ) tbi_inst_done <= rob_h_complete;
always @( posedge clk ) tbi_done_pc <= rob_h_pc;
task tbi_poke_gpr;
input [5:0] r;
input [31:0] val;
if( ^reg_id_map[r] === 1'bx )
prf_value[r] = val;
else
prf_value[reg_id_map[r]] = val;
endtask
function [31:0] tbi_peek_gpr;
input [5:0] r;
tbi_peek_gpr = prf_value[reg_co_map[r]];
endfunction
task tbi_iterate_pipeline_segments;
output valid;
output [15:0] name;
output [31:0] pc;
output [31:0] din;
output [7:0] exc;
output occ;
reg [88:0] info;
integer stage;
reg [`ROB_idxr] rob_idx;
begin
if( stage === 32'bx ) begin stage = 0; rob_idx = rob_head; end
for(valid = 0; stage < 8 && !valid; valid = occ == 1 ) begin
case( stage )
0: info = {"IF",if_pc, tb_if_din, next_if_id_exc,1'd1};
1: info = {"ID",if_id_pc,tb_if_id_din,next_id_qu_exc,if_id_occ};
2: info = {"Q ",tb_id_qu_pc,tb_id_qu_din,EXC_none,id_qu_occ};
3: info = {"DS",tb_ds_pc,tb_ds_din,EXC_none,iqi_something_ready};
4: info = {"RR",tb_qu_rr_pc,tb_qu_rr_din,EXC_none,qu_rr_occ};
5: info = {"EX",tb_rr_ex_pc,tb_rr_ex_din,EXC_none,rr_ex_occ};
6: info = {"WB",tb_ex_wb_pc,tb_ex_wb_din,8'b0, ex_wb_occ};
7: info = {"C ",rob_h_pc,tb_rob_h_din, rob_h_exc, rob_h_complete};
default `UNEXPECTED(info,stage);
endcase
{name,pc,din,exc,occ} = info;
stage = stage + 1;
end
for(valid = valid;
rob_idx != rob_tail && !valid;
valid =
~ ( din == tb_if_din
|| din == tb_if_id_din && if_id_occ
|| din == tb_id_qu_din && id_qu_occ
|| din == tb_ds_din && iqi_something_ready
|| din == tb_qu_rr_din && qu_rr_occ
|| din == tb_rr_ex_din && rr_ex_occ
|| din == tb_ex_wb_din && ex_wb_occ
|| din == tb_rob_h_din && rob_h_complete ) ) begin
name = " "; occ = 1; exc = 0;
{pc,din} = rob_main[rob_idx] >> PRF_lg + 5 + 1 + 1;
rob_idx = rob_idx + 1;
end
if( !valid ) stage = 32'bx;
end
endtask
///
/// SANITY CHECKS
///
integer tb_iqi_count;
always @( posedge clk ) if( tb_if_din !== 'bx ) begin:SSC
integer i;
reg [0:PRF_sze-1] pr_pending;
reg [0:PRF_sze-1] pr_in_flight;
reg [0:PRF_sze-1] pr_ref;
reg [`ROB_idxr] pr_ref_who [0:PRF_sze-1];
reg [`ROB_idxr] rob_idx;
reg [`PRF_idxr] dst, dest_qu_rr, dest_rr_ex;
reg done_1,done_2, pending;
reg [4:0] dest_a;
reg [`PRF_idxr] incumb;
integer new_pr_idx;
reg avail, idest;
reg [`IQI_idxr] rob_to_iq_idx [0:ROB_sze-1];
reg [`IQI_idxr] iq_idx;
reg [`BQ_pmr] shadow_bmask, compare_bmask;
reg qu_rr_pb, rr_ex_pb, pb;
reg [`BQ_idxr] qu_rr_bq_idx, rr_ex_bq_idx, bq_idx;
reg [0:PRF_sze-1] pr_in_id, pr_in_co;
new_pr_idx = id_qu_occ && id_qu_idest ? id_qu_dest_p : PRF_sze;
pr_pending = 0;
pr_in_flight = 0;
for(i=0; i<ROB_sze; i=i+1) rob_to_iq_idx[i] = 'bx;
tb_iqi_count = 0;
for(i=0; i<IQI_sze; i=i+1) begin
rob_idx = iqi[i] >> BQ_lg + 1 + 1 + 1 + 2 * 32;
if( iqi_occ[i] ) begin
rob_to_iq_idx[rob_idx] = i;
tb_iqi_count = tb_iqi_count + 1;
end
end
for( rob_idx = rob_head;
rob_idx != rob_tail;
rob_idx = rob_idx + 1 ) begin
dst = rob_dstp[rob_idx];
{idest,done_1,dest_a,incumb} = rob_main[rob_idx];
done_2 = rob_dexc[rob_idx];
pr_in_flight[dst] = idest;
pending = done_1 ^ done_2;
pr_pending[dst] = pending && idest;
avail = dst == new_pr_idx ? 0 : prf_avail[dst];
if( idest && pending === avail ) $stop;
iq_idx = rob_to_iq_idx[rob_idx];
if( pending && iqi_occ[iq_idx] !== 1 ) begin
dest_qu_rr = qu_rr_elt >> ROB_lg + BQ_lg + 1 + 1 + 1;
dest_rr_ex = rr_ex_elt >> ROB_lg + BQ_lg + 1 + 1 + 1;
if( ( !id_qu_occ || id_qu_dest_p !== dst )
&& ( ! qu_rr_occ || dest_qu_rr !== dst )
&& ( ! rr_ex_occ || dest_rr_ex !== dst )
&& ( ! ex_wb_occ || ex_wb_dest_p !== dst ) ) $stop;
end
end
shadow_bmask = 0;
compare_bmask = bmask_ins;
if( backup_id_map_sr[1] ) begin
compare_bmask[bq_tail] = 1;
if( bmask_ins[bq_tail] ) $stop;
end
for(i=0; i<IQI_sze; i=i+1) if( iqi_occ[i] ) begin:SSC1
reg await_rs, await_rt, rs_avail, rt_avail;
reg should_await_rs, should_await_rt;
reg [`PRF_idxr] rs, rt;
reg [2:0] alu_a_src, alu_b_src;
{rs, rt} = iqi[i] >> IQ_elt_sze - 2 * PRF_lg;
{alu_a_src, alu_b_src} = iqi[i] >> IQ_elt_sze - 2*PRF_lg - 43;
{await_rs,await_rt} = iqi_await >> {i,1'b0};
rs_avail = prf_avail[rs];
rt_avail = prf_avail[rt];
if( await_rs && rs_avail ) $stop;
if( await_rt && rt_avail ) $stop;
should_await_rs = alu_a_src === SRC_rs && !rs_avail;
if( should_await_rs !== await_rs ) $stop;
should_await_rt = alu_b_src === SRC_rt && !rt_avail;
if( should_await_rt !== await_rt ) $stop;
if( await_rs && !pr_in_flight[rs] ) $stop;
if( await_rs && !pr_pending[rs] ) $stop;
if( await_rt && !pr_in_flight[rt] ) $stop;
if( await_rt && !pr_pending[rt] ) $stop;
{bq_idx,pb} = iqi[i] >> 1 + 1 + 2 * 32;
if( pb && shadow_bmask[bq_idx] ) $stop;
if( pb ) shadow_bmask[bq_idx] = 1;
if( pb && compare_bmask[bq_idx] !== 1 ) $stop;
end
// More Branch Queue
{qu_rr_bq_idx,qu_rr_pb} = qu_rr_elt >> 2;
{rr_ex_bq_idx,rr_ex_pb} = rr_ex_elt >> 2;
`define CHECK(occ,bp,idx) if((occ)&&(bp))begin \
if(shadow_bmask[idx])$stop;\
if(compare_bmask[idx]!==1)$stop;shadow_bmask[idx]=1; end
//`CHECK(id_qu_occ,id_qu_bp,id_qu_bq_idx)
`CHECK(qu_rr_occ,qu_rr_pb,qu_rr_bq_idx)
`CHECK(rr_ex_occ,rr_ex_pb,rr_ex_bq_idx)
`CHECK(ex_wb_occ,ex_wb_bp,ex_wb_bq_idx)
`undef CHECK
if( backup_id_map_sr[1] ) shadow_bmask[bq_tail] = 1;
if( shadow_bmask !== compare_bmask ) $stop;
// Register Maps
pr_in_id = 0;
pr_in_co = 0;
pr_ref = 0;
for(i=0; i<32; i=i+1) begin
if( pr_in_id[reg_id_map[i]] ) $stop;
pr_in_id[reg_id_map[i]] = 1;
if( pr_in_co[reg_co_map[i]] ) $stop;
pr_in_co[reg_co_map[i]] = 1;
end
for( rob_idx = rob_head;
rob_idx != rob_tail;
rob_idx = rob_idx + 1 ) begin
dst = rob_dstp[rob_idx];
{idest,done_1,dest_a,incumb} = rob_main[rob_idx];
if( pr_ref[dst] ) $stop;
pr_ref[dst] = 1;
pr_ref_who[dst] = rob_idx;
if( pr_in_co[dst] ) $stop;
if( !idest && pr_in_id[dst] ) $stop;
if( idest && pr_in_id[incumb] ) $stop;
end
for( rob_idx = rob_idx; // [sic]
rob_idx != rob_head;
rob_idx = rob_idx + 1 ) begin
dst = rob_dstp[rob_idx];
if( pr_ref[dst] ) begin
$display("That's who:%d",pr_ref_who[dst]); $stop;
end
pr_ref[dst] = 1;
pr_ref_who[dst] = rob_idx;
if( {pr_in_id[dst],pr_in_co[dst]} !== 'b00 ) $stop;
end
end
always @( posedge clk ) if( iqi_something_ready ) begin:DB1
reg [`PRF_idxr] rs, rt;
reg [2:0] alu_a_src, alu_b_src;
{rs, rt} = iqi[iqi_ready_idx] >> IQ_elt_sze - 2 * PRF_lg;
{alu_a_src, alu_b_src} = iqi[iqi_ready_idx] >> IQ_elt_sze - 2*PRF_lg - 43;
if( alu_a_src === SRC_rs ) begin
if( rs === 'bx ) $stop;
if( prf_avail[rs] !== 1 ) $stop;
if( prf_value[rs] === 'bx ) $stop;
end
if( alu_b_src === SRC_rt ) begin
if( rt === 'bx ) $stop;
if( prf_avail[rt] !== 1 ) $stop;
if( prf_value[rt] === 'bx ) $stop;
end
end
// exemplar translate_on
endmodule
module reg_file(data_out_1, data_out_2, addr_1, addr_2,
addr_3, data_in_3, clk);
input [4:0] addr_1, addr_2, addr_3;
input [31:0] data_in_3;
input clk;
output [31:0] data_out_1, data_out_2;
reg [31:0] storage [0:31];
assign data_out_1 = addr_1 && addr_1 == addr_3 ? data_in_3 : storage[addr_1];
assign data_out_2 = addr_2 && addr_2 == addr_3 ? data_in_3 : storage[addr_2];
always @( posedge clk ) if( addr_3 ) storage[addr_3] <= data_in_3;
endmodule
module alu(alu_out,alu_a,alu_b,alu_op);
output [31:0] alu_out;
input [31:0] alu_a, alu_b;
input [4:0] alu_op;
reg [31:0] alu_out;
task unexpected;
inout [31:0] var;
input [10:0] control;
var = 0;
endtask
// Control Signal Value Names
parameter OP_xxx = 5'h0; // Don't care.
parameter OP_add = 5'h0;
parameter OP_sll = 5'h1;
parameter OP_srl = 5'h2;
parameter OP_xor = 5'h3;
parameter OP_sub = 5'h4;
parameter OP_or = 5'h5;
parameter OP_and = 5'h6;
parameter OP_slt = 5'h7;
parameter OP_seq = 5'h8;
parameter OP_b = 5'h9;
parameter OP_sne = 5'ha;
always @( alu_a or alu_b or alu_op )
case( alu_op )
OP_add : alu_out = alu_a + alu_b;
OP_and : alu_out = alu_a & alu_b;
OP_or : alu_out = alu_a | alu_b;
OP_xor : alu_out = alu_a ^ alu_b;
OP_sub : alu_out = alu_a - alu_b;
OP_slt : alu_out = {alu_a[31],alu_a} < {alu_b[31],alu_b};
OP_sll : alu_out = alu_b << alu_a[4:0];
OP_srl : alu_out = alu_b >> alu_a[4:0];
OP_seq : alu_out = alu_a == alu_b;
OP_sne : alu_out = alu_a != alu_b;
OP_b : alu_out = alu_b;
default : `UNEXPECTED(alu_out,alu_op);
endcase
endmodule
// exemplar translate_off
module system_p1(exc,reset,clk);
input reset,clk;
output [7:0] exc;
wire [31:0] cpu_data_out_2, addr_1, addr_2, mem_data_out_1, mem_data_out_2;
wire [2:0] mem_err_out_1, mem_err_out_2;
wire [1:0] size_2;
wire we_2;
cpu_p1 cpu1(exc,
cpu_data_out_2, addr_1, addr_2, size_2, we_2,
mem_data_out_1, mem_data_out_2,
mem_err_out_1,mem_err_out_2,
reset,clk);
memory_2p m1( mem_data_out_1, mem_err_out_1, addr_1,
mem_data_out_2 ,mem_err_out_2, addr_2, size_2, we_2,
cpu_data_out_2,
clk);
endmodule
// A makefile would better...
`include "mips_memory.v"
`include "mipspipetb.v"