/// 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"