OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [trunk/] [fpga/] [mc/] [src/] [cpu/] [cpu.v] - Diff between revs 288 and 290

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 288 Rev 290
Line 1... Line 1...
//
//
// cpu.v -- the ECO32 CPU
// cpu.v -- the ECO32 CPU
//
//
 
 
 
 
module cpu(clk, reset,
`timescale 1ns/10ps
           bus_en, bus_wr, bus_size, bus_addr,
`default_nettype none
           bus_data_in, bus_data_out, bus_wt,
 
           irq);
 
    input clk;                          // system clock
 
    input reset;                        // system reset
 
    output bus_en;                      // bus enable
 
    output bus_wr;                      // bus write
 
    output [1:0] bus_size;               // 00: byte, 01: halfword, 10: word
 
    output [31:0] bus_addr;              // bus address
 
    input [31:0] bus_data_in;            // bus data input, for reads
 
    output [31:0] bus_data_out;          // bus data output, for writes
 
    input bus_wt;                       // bus wait
 
    input [15:0] irq;                    // interrupt requests
 
 
 
  // program counter
 
  wire [31:0] pc;                // program counter
 
  wire pc_we;                   // pc write enable
 
  wire [2:0] pc_src;             // pc source selector
 
  wire [31:0] pc_next;           // value written into pc
 
 
 
  // bus & mmu
 
  wire [31:0] mar;               // memory address register
 
  wire mar_we;                  // mar write enable
 
  wire ma_src;                  // memory address source selector
 
  wire [2:0] mmu_fnc;            // mmu function
 
  wire [31:0] virt_addr; // virtual address
 
  wire [31:0] phys_addr; // physical address
 
  wire [31:0] mdor;              // memory data out register
 
  wire mdor_we;                 // mdor write enable
 
  wire [31:0] mdir;              // memory data in register
 
  wire mdir_we;                 // mdir write enable
 
  wire mdir_sx;                 // mdir sign-extend
 
 
 
  // instruction register & decoder
 
  wire ir_we;                   // ir write enable
 
  wire [5:0] opcode;             // opcode part of ir
 
  wire [4:0] reg1;               // register 1 part of ir
 
  wire [4:0] reg2;               // register 2 part of ir
 
  wire [4:0] reg3;               // register 3 part of ir
 
  wire [31:0] sx16;              // sign-extended 16-bit immediate
 
  wire [31:0] zx16;              // zero-extended 16-bit immediate
 
  wire [31:0] hi16;              // high 16-bit immediate
 
  wire [31:0] sx16s2;            // sign-extended 16-bit immediate << 2
 
  wire [31:0] sx26s2;            // sign-extended 26-bit immediate << 2
 
 
 
  // register file
 
  wire [4:0] reg_a1;             // register address 1
 
  wire [31:0] reg_do1;           // register data out 1
 
  wire [1:0] reg_src2;           // register source 2 selector
 
  wire [4:0] reg_a2;             // register address 2
 
  wire [31:0] reg_do2;           // register data out 2
 
  wire reg_we2;                 // register write enable 2
 
  wire reg_we2_prot;            // register write enable 2,
 
                                // protected against writes with a2 = 0
 
  wire [2:0] reg_di2_src;        // register data in 2 source selector
 
  wire [31:0] reg_di2;           // register data in 2
 
 
 
  // alu, shift, and muldiv units
 
  wire alu_src1;                // alu source 1 selector
 
  wire [31:0] alu_op1;           // alu operand 1
 
  wire [2:0] alu_src2;           // alu source 2 selector
 
  wire [31:0] alu_op2;           // alu operand 2
 
  wire [2:0] alu_fnc;            // alu function
 
  wire [31:0] alu_res;           // alu result
 
  wire alu_equ;                 // alu operand 1 = operand 2
 
  wire alu_ult;                 // alu operand 1 < operand 2 (unsigned)
 
  wire alu_slt;                 // alu operand 1 < operand 2 (signed)
 
  wire [1:0] shift_fnc;          // shift function
 
  wire [31:0] shift_res; // shift result
 
  wire [2:0] muldiv_fnc; // muldiv function
 
  wire muldiv_start;            // muldiv should start
 
  wire muldiv_done;             // muldiv has finished
 
  wire muldiv_error;            // muldiv detected division by zero
 
  wire [31:0] muldiv_res;        // muldiv result
 
 
 
  // special registers
 
  wire [2:0] sreg_num;           // special register number
 
  wire sreg_we;                 // special register write enable
 
  wire [31:0] sreg_di;           // special register data in
 
  wire [31:0] sreg_do;           // special register data out
 
  wire [31:0] psw;               // special register 0 (psw) contents
 
  wire psw_we;                  // psw write enable
 
  wire [31:0] psw_new;           // new psw contents
 
  wire [31:0] tlb_index; // special register 1 (tlb index) contents
 
  wire tlb_index_we;            // tlb index write enable
 
  wire [31:0] tlb_index_new;     // new tlb index contents
 
  wire [31:0] tlb_entry_hi;      // special register 2 (tlb entry hi) contents
 
  wire tlb_entry_hi_we;         // tlb entry hi write enable
 
  wire [31:0] tlb_entry_hi_new;  // new tlb entry hi contents
 
  wire [31:0] tlb_entry_lo;      // special register 3 (tlb entry lo) contents
 
  wire tlb_entry_lo_we;         // tlb entry lo write enable
 
  wire [31:0] tlb_entry_lo_new;  // new tlb entry lo contents
 
  wire [31:0] mmu_bad_addr;      // special register 4 (mmu bad addr) contents
 
  wire mmu_bad_addr_we;         // mmu bad addr write enable
 
  wire [31:0] mmu_bad_addr_new;  // new mmu bad addr contents
 
  wire [31:0] mmu_bad_accs;      // special register 5 (mmu bad accs) contents
 
  wire mmu_bad_accs_we;         // mmu bad accs write enable
 
  wire [31:0] mmu_bad_accs_new;  // new mmu bad accs contents
 
 
 
  // mmu & tlb
 
  wire tlb_kmissed;             // page not found in tlb, MSB of addr is 1
 
  wire tlb_umissed;             // page not found in tlb, MSB of addr is 0
 
  wire tlb_invalid;             // tlb entry is invalid
 
  wire tlb_wrtprot;             // frame is write-protected
 
 
 
  //------------------------------------------------------------
 
 
 
  // program counter
 
  assign pc_next = (pc_src == 3'b000) ? alu_res :
 
                   (pc_src == 3'b001) ? 32'hE0000000 :
 
                   (pc_src == 3'b010) ? 32'hE0000004 :
 
                   (pc_src == 3'b011) ? 32'hC0000004 :
 
                   (pc_src == 3'b100) ? 32'hE0000008 :
 
                   (pc_src == 3'b101) ? 32'hC0000008 :
 
                   32'hxxxxxxxx;
 
  pc pc1(clk, pc_we, pc_next, pc);
 
 
 
  // bus & mmu
 
  mar mar1(clk, mar_we, alu_res, mar);
 
  assign virt_addr = (ma_src == 0) ? pc : mar;
 
  mmu mmu1(clk, reset, mmu_fnc, virt_addr, phys_addr,
 
           tlb_index, tlb_index_new,
 
           tlb_entry_hi, tlb_entry_hi_new,
 
           tlb_entry_lo, tlb_entry_lo_new,
 
           tlb_kmissed, tlb_umissed,
 
           tlb_invalid, tlb_wrtprot);
 
  assign bus_addr = phys_addr;
 
  mdor mdor1(clk, mdor_we, reg_do2, mdor);
 
  assign bus_data_out = mdor;
 
  mdir mdir1(clk, mdir_we, bus_data_in, bus_size, mdir_sx, mdir);
 
 
 
  // instruction register & decoder
 
  ir ir1(clk,
 
         ir_we, bus_data_in,
 
         opcode, reg1, reg2, reg3,
 
         sx16, zx16, hi16, sx16s2, sx26s2);
 
 
 
  // register file
 
  assign reg_a1 = reg1;
 
  assign reg_a2 = (reg_src2 == 2'b00) ? reg2 :
 
                  (reg_src2 == 2'b01) ? reg3 :
 
                  (reg_src2 == 2'b10) ? 5'b11111 :
 
                  (reg_src2 == 2'b11) ? 5'b11110 :
 
                  5'bxxxxx;
 
  assign reg_we2_prot = reg_we2 & (| reg_a2[4:0]);
 
  assign reg_di2 = (reg_di2_src == 3'b000) ? alu_res :
 
                   (reg_di2_src == 3'b001) ? shift_res :
 
                   (reg_di2_src == 3'b010) ? muldiv_res :
 
                   (reg_di2_src == 3'b011) ? mdir :
 
                   (reg_di2_src == 3'b100) ? sreg_do :
 
                   32'hxxxxxxxx;
 
  regs regs1(clk,
 
             reg_a1, reg_do1,
 
             reg_a2, reg_do2, reg_we2_prot, reg_di2);
 
 
 
  // alu, shift, and muldiv units
 
  assign alu_op1 = (alu_src1 == 0) ? pc : reg_do1;
 
  assign alu_op2 = (alu_src2 == 3'b000) ? 32'h00000004 :
 
                   (alu_src2 == 3'b001) ? reg_do2 :
 
                   (alu_src2 == 3'b010) ? sx16 :
 
                   (alu_src2 == 3'b011) ? zx16 :
 
                   (alu_src2 == 3'b100) ? hi16 :
 
                   (alu_src2 == 3'b101) ? sx16s2 :
 
                   (alu_src2 == 3'b110) ? sx26s2 :
 
                   32'hxxxxxxxx;
 
  alu alu1(alu_op1, alu_op2, alu_fnc,
 
           alu_res, alu_equ, alu_ult, alu_slt);
 
  shift shift1(clk, alu_op1, alu_op2[4:0], shift_fnc, shift_res);
 
  muldiv muldiv1(clk, alu_op1, alu_op2, muldiv_fnc, muldiv_start,
 
                 muldiv_done, muldiv_error, muldiv_res);
 
 
 
  // special registers
 
  assign sreg_num = zx16[2:0];
 
  assign sreg_di = reg_do2;
 
  sregs sregs1(clk, reset,
 
               sreg_num, sreg_we, sreg_di, sreg_do,
 
               psw, psw_we, psw_new,
 
               tlb_index, tlb_index_we, tlb_index_new,
 
               tlb_entry_hi, tlb_entry_hi_we, tlb_entry_hi_new,
 
               tlb_entry_lo, tlb_entry_lo_we, tlb_entry_lo_new,
 
               mmu_bad_addr, mmu_bad_addr_we, mmu_bad_addr_new,
 
               mmu_bad_accs, mmu_bad_accs_we, mmu_bad_accs_new);
 
  assign mmu_bad_addr_new = virt_addr;
 
  assign mmu_bad_accs_we = mmu_bad_addr_we;
 
  assign mmu_bad_accs_new = { 29'b0, bus_wr, bus_size[1:0] };
 
 
 
  // ctrl
 
  ctrl ctrl1(clk, reset,
 
             opcode, alu_equ, alu_ult, alu_slt,
 
             bus_wt, bus_en, bus_wr, bus_size,
 
             pc_src, pc_we,
 
             mar_we, ma_src, mmu_fnc,
 
             mdor_we, mdir_we, mdir_sx, ir_we,
 
             reg_src2, reg_di2_src, reg_we2,
 
             alu_src1, alu_src2, alu_fnc, shift_fnc,
 
             muldiv_fnc, muldiv_start,
 
             muldiv_done, muldiv_error,
 
             sreg_we, irq, psw, psw_we, psw_new,
 
             virt_addr[31], virt_addr[1], virt_addr[0],
 
             tlb_kmissed, tlb_umissed,
 
             tlb_invalid, tlb_wrtprot,
 
             tlb_index_we, tlb_entry_hi_we,
 
             tlb_entry_lo_we, mmu_bad_addr_we);
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// ctrl -- the finite state machine within the CPU
 
//--------------------------------------------------------------
 
 
 
 
 
module ctrl(clk, reset,
 
            opcode, alu_equ, alu_ult, alu_slt,
 
            bus_wt, bus_en, bus_wr, bus_size,
 
            pc_src, pc_we,
 
            mar_we, ma_src, mmu_fnc,
 
            mdor_we, mdir_we, mdir_sx, ir_we,
 
            reg_src2, reg_di2_src, reg_we2,
 
            alu_src1, alu_src2, alu_fnc, shift_fnc,
 
            muldiv_fnc, muldiv_start,
 
            muldiv_done, muldiv_error,
 
            sreg_we, irq, psw, psw_we, psw_new,
 
            va_31, va_1, va_0,
 
            tlb_kmissed, tlb_umissed,
 
            tlb_invalid, tlb_wrtprot,
 
            tlb_index_we, tlb_entry_hi_we,
 
            tlb_entry_lo_we, mmu_bad_addr_we);
 
    input clk;
 
    input reset;
 
    input [5:0] opcode;
 
    input alu_equ;
 
    input alu_ult;
 
    input alu_slt;
 
    input bus_wt;
 
    output reg bus_en;
 
    output reg bus_wr;
 
    output reg [1:0] bus_size;
 
    output reg [2:0] pc_src;
 
    output reg pc_we;
 
    output reg mar_we;
 
    output reg ma_src;
 
    output reg [2:0] mmu_fnc;
 
    output reg mdor_we;
 
    output reg mdir_we;
 
    output reg mdir_sx;
 
    output reg ir_we;
 
    output reg [1:0] reg_src2;
 
    output reg [2:0] reg_di2_src;
 
    output reg reg_we2;
 
    output reg alu_src1;
 
    output reg [2:0] alu_src2;
 
    output reg [2:0] alu_fnc;
 
    output reg [1:0] shift_fnc;
 
    output reg [2:0] muldiv_fnc;
 
    output reg muldiv_start;
 
    input muldiv_done;
 
    input muldiv_error;
 
    output reg sreg_we;
 
    input [15:0] irq;
 
    input [31:0] psw;
 
    output reg psw_we;
 
    output reg [31:0] psw_new;
 
    input va_31, va_1, va_0;
 
    input tlb_kmissed;
 
    input tlb_umissed;
 
    input tlb_invalid;
 
    input tlb_wrtprot;
 
    output reg tlb_index_we;
 
    output reg tlb_entry_hi_we;
 
    output reg tlb_entry_lo_we;
 
    output reg mmu_bad_addr_we;
 
 
 
  wire type_rrr;                // instr type is RRR
 
  wire type_rrs;                // instr type is RRS
 
  wire type_rrh;                // instr type is RRH
 
  wire type_rhh;                // instr type is RHH
 
  wire type_rrb;                // instr type is RRB
 
  wire type_j;                  // instr type is J
 
  wire type_jr;                 // instr type is JR
 
  wire type_link;               // instr saves PC+4 in $31
 
  wire type_ld;                 // instr loads data
 
  wire type_st;                 // instr stores data
 
  wire type_ldst;               // instr loads or stores data
 
  wire [1:0] ldst_size;          // load/store transfer size
 
  wire type_shift;              // instr uses the shift unit
 
  wire type_muldiv;             // instr uses the muldiv unit
 
  wire type_fast;               // instr is not shift or muldiv
 
  wire type_mvfs;               // instr is mvfs
 
  wire type_mvts;               // instr is mvts
 
  wire type_rfx;                // instr is rfx
 
  wire type_trap;               // instr is trap
 
  wire type_tb;                 // instr is a TLB instr
 
  reg [4:0] state;               // cpu internal state
 
                                //  0: reset
 
                                //  1: fetch instr (addr xlat)
 
                                //  2: decode instr
 
                                //     increment pc by 4
 
                                //     possibly store pc+4 in $31
 
                                //  3: execute RRR-type instr
 
                                //  4: execute RRS-type instr
 
                                //  5: execute RRH-type instr
 
                                //  6: execute RHH-type instr
 
                                //  7: execute RRB-type instr (1)
 
                                //  8: execute RRB-type instr (2)
 
                                //  9: execute J-type instr
 
                                // 10: execute JR-type instr
 
                                // 11: execute LDST-type instr (1)
 
                                // 12: execute LD-type instr (addr xlat)
 
                                // 13: execute LD-type instr (3)
 
                                // 14: execute ST-type instr (addr xlat)
 
                                // 15: interrupt
 
                                // 16: extra state for RRR shift instr
 
                                // 17: extra state for RRH shift instr
 
                                // 18: extra state for RRR muldiv instr
 
                                // 19: extra state for RRS muldiv instr
 
                                // 20: extra state for RRH muldiv instr
 
                                // 21: execute mvfs instr
 
                                // 22: execute mvts instr
 
                                // 23: execute rfx instr
 
                                // 24: irq_trigger check for mvts and rfx
 
                                // 25: exception (locus is PC-4)
 
                                // 26: exception (locus is PC)
 
                                // 27: execute TLB instr
 
                                // 28: fetch instr (bus cycle)
 
                                // 29: execute LD-type instr (bus cycle)
 
                                // 30: execute ST-type instr (bus cycle)
 
                                // all other: unused
 
  reg branch;                   // take the branch iff true
 
  wire [15:0] irq_pending;       // the vector of pending unmasked irqs
 
  wire irq_trigger;             // true iff any pending irq is present
 
                                // and interrupts are globally enabled
 
  reg [3:0] irq_priority;        // highest priority of pending interrupts
 
  reg [3:0] exc_priority;        // exception, when entering state 25 or 26
 
  reg [7:0] bus_count;           // counter to detect bus timeout
 
  wire bus_timeout;             // bus timeout detected
 
  wire exc_prv_addr;            // privileged address exception detected
 
  wire exc_ill_addr;            // illegal address exception detected
 
  wire exc_tlb_but_wrtprot;     // any tlb exception but write protection
 
  wire exc_tlb_any;             // any tlb exception
 
 
 
  //------------------------------------------------------------
 
 
 
  // decode instr type
 
  assign type_rrr    = ((opcode == 6'h00) ||
 
                        (opcode == 6'h02) ||
 
                        (opcode == 6'h04) ||
 
                        (opcode == 6'h06) ||
 
                        (opcode == 6'h08) ||
 
                        (opcode == 6'h0A) ||
 
                        (opcode == 6'h0C) ||
 
                        (opcode == 6'h0E) ||
 
                        (opcode == 6'h10) ||
 
                        (opcode == 6'h12) ||
 
                        (opcode == 6'h14) ||
 
                        (opcode == 6'h16) ||
 
                        (opcode == 6'h18) ||
 
                        (opcode == 6'h1A) ||
 
                        (opcode == 6'h1C)) ? 1 : 0;
 
  assign type_rrs    = ((opcode == 6'h01) ||
 
                        (opcode == 6'h03) ||
 
                        (opcode == 6'h05) ||
 
                        (opcode == 6'h09) ||
 
                        (opcode == 6'h0D)) ? 1 : 0;
 
  assign type_rrh    = ((opcode == 6'h07) ||
 
                        (opcode == 6'h0B) ||
 
                        (opcode == 6'h0F) ||
 
                        (opcode == 6'h11) ||
 
                        (opcode == 6'h13) ||
 
                        (opcode == 6'h15) ||
 
                        (opcode == 6'h17) ||
 
                        (opcode == 6'h19) ||
 
                        (opcode == 6'h1B) ||
 
                        (opcode == 6'h1D)) ? 1 : 0;
 
  assign type_rhh    = (opcode == 6'h1F) ? 1 : 0;
 
  assign type_rrb    = ((opcode == 6'h20) ||
 
                        (opcode == 6'h21) ||
 
                        (opcode == 6'h22) ||
 
                        (opcode == 6'h23) ||
 
                        (opcode == 6'h24) ||
 
                        (opcode == 6'h25) ||
 
                        (opcode == 6'h26) ||
 
                        (opcode == 6'h27) ||
 
                        (opcode == 6'h28) ||
 
                        (opcode == 6'h29)) ? 1 : 0;
 
  assign type_j      = ((opcode == 6'h2A) ||
 
                        (opcode == 6'h2C)) ? 1 : 0;
 
  assign type_jr     = ((opcode == 6'h2B) ||
 
                        (opcode == 6'h2D)) ? 1 : 0;
 
  assign type_link   = ((opcode == 6'h2C) ||
 
                        (opcode == 6'h2D)) ? 1 : 0;
 
  assign type_ld     = ((opcode == 6'h30) ||
 
                        (opcode == 6'h31) ||
 
                        (opcode == 6'h32) ||
 
                        (opcode == 6'h33) ||
 
                        (opcode == 6'h34)) ? 1 : 0;
 
  assign type_st     = ((opcode == 6'h35) ||
 
                        (opcode == 6'h36) ||
 
                        (opcode == 6'h37)) ? 1 : 0;
 
  assign type_ldst   = type_ld | type_st;
 
  assign ldst_size   = ((opcode == 6'h30) ||
 
                        (opcode == 6'h35)) ? 2'b10 :
 
                       ((opcode == 6'h31) ||
 
                        (opcode == 6'h32) ||
 
                        (opcode == 6'h36)) ? 2'b01 :
 
                       ((opcode == 6'h33) ||
 
                        (opcode == 6'h34) ||
 
                        (opcode == 6'h37)) ? 2'b00 :
 
                       2'bxx;
 
  assign type_shift  = ((opcode == 6'h18) ||
 
                        (opcode == 6'h19) ||
 
                        (opcode == 6'h1A) ||
 
                        (opcode == 6'h1B) ||
 
                        (opcode == 6'h1C) ||
 
                        (opcode == 6'h1D)) ? 1 : 0;
 
  assign type_muldiv = ((opcode == 6'h04) ||
 
                        (opcode == 6'h05) ||
 
                        (opcode == 6'h06) ||
 
                        (opcode == 6'h07) ||
 
                        (opcode == 6'h08) ||
 
                        (opcode == 6'h09) ||
 
                        (opcode == 6'h0A) ||
 
                        (opcode == 6'h0B) ||
 
                        (opcode == 6'h0C) ||
 
                        (opcode == 6'h0D) ||
 
                        (opcode == 6'h0E) ||
 
                        (opcode == 6'h0F)) ? 1 : 0;
 
  assign type_fast   = ~(type_shift | type_muldiv);
 
  assign type_mvfs   = (opcode == 6'h38) ? 1 : 0;
 
  assign type_mvts   = (opcode == 6'h39) ? 1 : 0;
 
  assign type_rfx    = (opcode == 6'h2F) ? 1 : 0;
 
  assign type_trap   = (opcode == 6'h2E) ? 1 : 0;
 
  assign type_tb     = ((opcode == 6'h3A) ||
 
                        (opcode == 6'h3B) ||
 
                        (opcode == 6'h3C) ||
 
                        (opcode == 6'h3D)) ? 1 : 0;
 
 
 
  // state machine
 
  always @(posedge clk) begin
 
    if (reset == 1) begin
 
      state <= 0;
 
    end else begin
 
      case (state)
 
        5'd0:  // reset
 
          begin
 
            state <= 5'd1;
 
          end
 
        5'd1:  // fetch instr (addr xlat)
 
          begin
 
            if (exc_prv_addr) begin
 
              state <= 26;
 
              exc_priority <= 4'd9;
 
            end else
 
            if (exc_ill_addr) begin
 
              state <= 26;
 
              exc_priority <= 4'd8;
 
            end else begin
 
              state <= 5'd28;
 
            end
 
          end
 
        5'd2:  // decode instr
 
               // increment pc by 4
 
               // possibly store pc+4 in $31
 
          begin
 
            if (type_rrr) begin
 
              // RRR-type instruction
 
              state <= 5'd3;
 
            end else
 
            if (type_rrs) begin
 
              // RRS-type instruction
 
              state <= 5'd4;
 
            end else
 
            if (type_rrh) begin
 
              // RRH-type instruction
 
              state <= 5'd5;
 
            end else
 
            if (type_rhh) begin
 
              // RHH-type instruction
 
              state <= 5'd6;
 
            end else
 
            if (type_rrb) begin
 
              // RRB-type instr
 
              state <= 5'd7;
 
            end else
 
            if (type_j) begin
 
              // J-type instr
 
              state <= 5'd9;
 
            end else
 
            if (type_jr) begin
 
              // JR-type instr
 
              state <= 5'd10;
 
            end else
 
            if (type_ldst) begin
 
              // LDST-type instr
 
              state <= 5'd11;
 
            end else
 
            if (type_mvfs) begin
 
              // mvfs instr
 
              state <= 5'd21;
 
            end else
 
            if (type_mvts) begin
 
              // mvts instr
 
              if (psw[26] == 1) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd2;
 
              end else begin
 
                state <= 5'd22;
 
              end
 
            end else
 
            if (type_rfx) begin
 
              // rfx instr
 
              if (psw[26] == 1) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd2;
 
              end else begin
 
                state <= 5'd23;
 
              end
 
            end else
 
            if (type_trap) begin
 
              // trap instr
 
              state <= 5'd25;
 
              exc_priority <= 4'd4;
 
            end else
 
            if (type_tb) begin
 
              // TLB instr
 
              if (psw[26] == 1) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd2;
 
              end else begin
 
                state <= 5'd27;
 
              end
 
            end else begin
 
              // illegal instruction
 
              state <= 5'd25;
 
              exc_priority <= 4'd1;
 
            end
 
          end
 
        5'd3:  // execute RRR-type instr
 
          begin
 
            if (type_muldiv) begin
 
              state <= 5'd18;
 
            end else
 
            if (type_shift) begin
 
              state <= 5'd16;
 
            end else begin
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end
 
          end
 
        5'd4:  // execute RRS-type instr
 
          begin
 
            if (type_muldiv) begin
 
              state <= 5'd19;
 
            end else begin
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end
 
          end
 
        5'd5:  // execute RRH-type instr
 
          begin
 
            if (type_muldiv) begin
 
              state <= 5'd20;
 
            end else
 
            if (type_shift) begin
 
              state <= 5'd17;
 
            end else begin
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end
 
          end
 
        5'd6:  // execute RHH-type instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd7:  // execute RRB-type instr (1)
 
          begin
 
            if (branch) begin
 
              state <= 5'd8;
 
            end else begin
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end
 
          end
 
        5'd8:  // execute RRB-type instr (2)
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd9:  // execute J-type instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd10:  // execute JR-type instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd11:  // execute LDST-type instr (1)
 
          begin
 
            if (type_ld) begin
 
              state <= 5'd12;
 
            end else begin
 
              state <= 5'd14;
 
            end
 
          end
 
        5'd12:  // execute LD-type instr (addr xlat)
 
          begin
 
            if (exc_prv_addr) begin
 
              state <= 25;
 
              exc_priority <= 4'd9;
 
            end else
 
            if (exc_ill_addr) begin
 
              state <= 25;
 
              exc_priority <= 4'd8;
 
            end else begin
 
              state <= 5'd29;
 
            end
 
          end
 
        5'd13:  // execute LD-type instr (3)
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd14:  // execute ST-type instr (addr xlat)
 
          begin
 
            if (exc_prv_addr) begin
 
              state <= 25;
 
              exc_priority <= 4'd9;
 
            end else
 
            if (exc_ill_addr) begin
 
              state <= 25;
 
              exc_priority <= 4'd8;
 
            end else begin
 
              state <= 5'd30;
 
            end
 
          end
 
        5'd15:  // interrupt
 
          begin
 
            state <= 5'd1;
 
          end
 
        5'd16:  // extra state for RRR shift instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd17:  // extra state for RRH shift instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd18:  // extra state for RRR muldiv instr
 
          begin
 
            if (muldiv_done) begin
 
              if (muldiv_error) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd3;
 
              end else
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end else begin
 
              state <= 5'd18;
 
            end
 
          end
 
        5'd19:  // extra state for RRS muldiv instr
 
          begin
 
            if (muldiv_done) begin
 
              if (muldiv_error) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd3;
 
              end else
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end else begin
 
              state <= 5'd19;
 
            end
 
          end
 
        5'd20:  // extra state for RRH muldiv instr
 
          begin
 
            if (muldiv_done) begin
 
              if (muldiv_error) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd3;
 
              end else
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end else begin
 
              state <= 5'd20;
 
            end
 
          end
 
        5'd21:  // execute mvfs instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd22:  // execute mvts instr
 
          begin
 
            state <= 5'd24;
 
          end
 
        5'd23:  // execute rfx instr
 
          begin
 
            state <= 5'd24;
 
          end
 
        5'd24:  // irq_trigger check for mvts and rfx
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd25:  // exception (locus is PC-4)
 
          begin
 
            state <= 5'd1;
 
          end
 
        5'd26:  // exception (locus is PC)
 
          begin
 
            state <= 5'd1;
 
          end
 
        5'd27:  // execute TLB instr
 
          begin
 
            if (irq_trigger) begin
 
              state <= 5'd15;
 
            end else begin
 
              state <= 5'd1;
 
            end
 
          end
 
        5'd28:  // fetch instr (bus cycle)
 
          begin
 
            if (tlb_kmissed == 1 || tlb_umissed == 1) begin
 
              state <= 5'd26;
 
              exc_priority <= 4'd5;
 
            end else
 
            if (tlb_invalid == 1) begin
 
              state <= 5'd26;
 
              exc_priority <= 4'd7;
 
            end else
 
            if (bus_wt == 1) begin
 
              if (bus_timeout == 1) begin
 
                state <= 5'd26;
 
                exc_priority <= 4'd0;
 
              end else begin
 
                state <= 5'd28;
 
              end
 
            end else begin
 
              state <= 5'd2;
 
            end
 
          end
 
        5'd29:  // execute LD-type instr (bus cycle)
 
          begin
 
            if (tlb_kmissed == 1 || tlb_umissed == 1) begin
 
              state <= 5'd25;
 
              exc_priority <= 4'd5;
 
            end else
 
            if (tlb_invalid == 1) begin
 
              state <= 5'd25;
 
              exc_priority <= 4'd7;
 
            end else
 
            if (bus_wt == 1) begin
 
              if (bus_timeout == 1) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd0;
 
              end else begin
 
                state <= 5'd29;
 
              end
 
            end else begin
 
              state <= 5'd13;
 
            end
 
          end
 
        5'd30:  // execute ST-type instr (bus cycle)
 
          begin
 
            if (tlb_kmissed == 1 || tlb_umissed == 1) begin
 
              state <= 5'd25;
 
              exc_priority <= 4'd5;
 
            end else
 
            if (tlb_invalid == 1) begin
 
              state <= 5'd25;
 
              exc_priority <= 4'd7;
 
            end else
 
            if (tlb_wrtprot == 1) begin
 
              state <= 5'd25;
 
              exc_priority <= 4'd6;
 
            end else
 
            if (bus_wt == 1) begin
 
              if (bus_timeout == 1) begin
 
                state <= 5'd25;
 
                exc_priority <= 4'd0;
 
              end else begin
 
                state <= 5'd30;
 
              end
 
            end else begin
 
              if (irq_trigger) begin
 
                state <= 5'd15;
 
              end else begin
 
                state <= 5'd1;
 
              end
 
            end
 
          end
 
        default:  // all other states: unused
 
          begin
 
            state <= 5'd0;
 
          end
 
      endcase
 
    end
 
  end
 
 
 
  // bus timeout detector
 
  assign bus_timeout = (bus_count == 8'h00) ? 1 : 0;
 
  always @(posedge clk) begin
 
    if (bus_en == 1 && bus_wt == 1) begin
 
      // bus is waiting
 
      bus_count <= bus_count - 1;
 
    end else begin
 
      // bus is not waiting
 
      bus_count <= 8'hFF;
 
    end
 
  end
 
 
 
  // output logic
 
  always @(*) begin
 
    case (state)
 
      5'd0:  // reset
 
        begin
 
          pc_src = 3'b001;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd1:  // fetch instr (addr xlat)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'b0;
 
          mmu_fnc = (exc_prv_addr | exc_ill_addr) ? 3'b000 : 3'b001;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'b0;         // get bad_accs right in case of exc
 
          bus_size = 2'b10;      // enable illegal address detection
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = exc_prv_addr | exc_ill_addr;
 
        end
 
      5'd2:  // decode instr
 
             // increment pc by 4
 
             // possibly store pc+4 in $31
 
        begin
 
          pc_src = 3'b000;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = (type_link == 1) ? 2'b10 :
 
                     (type_rfx == 1) ? 2'b11 :
 
                     2'b00;
 
          reg_di2_src = (type_link == 1) ? 3'b000 : 3'bxxx;
 
          reg_we2 = (type_link == 1) ? 1'b1 : 1'b0;
 
          alu_src1 = 1'b0;
 
          alu_src2 = 3'b000;
 
          alu_fnc = 3'b000;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd3:  // execute RRR-type instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b01;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = type_fast;
 
          alu_src1 = 1'b1;
 
          alu_src2 = 3'b001;
 
          alu_fnc = { opcode[4], opcode[2], opcode[1] };
 
          shift_fnc = { opcode[2], opcode[1] };
 
          muldiv_fnc = { opcode[3], opcode[2], opcode[1] };
 
          muldiv_start = type_muldiv;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd4:  // execute RRS-type instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = type_fast;
 
          alu_src1 = 1'b1;
 
          alu_src2 = 3'b010;
 
          alu_fnc = { opcode[4], opcode[2], opcode[1] };
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = { opcode[3], opcode[2], opcode[1] };
 
          muldiv_start = type_muldiv;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd5:  // execute RRH-type instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = type_fast;
 
          alu_src1 = 1'b1;
 
          alu_src2 = 3'b011;
 
          alu_fnc = { opcode[4], opcode[2], opcode[1] };
 
          shift_fnc = { opcode[2], opcode[1] };
 
          muldiv_fnc = { opcode[3], opcode[2], opcode[1] };
 
          muldiv_start = type_muldiv;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd6:  // execute RHH-type instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'b100;
 
          alu_fnc = 3'b011;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd7:  // execute RRB-type instr (1)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'b1;
 
          alu_src2 = 3'b001;
 
          alu_fnc = 3'b001;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd8:  // execute RRB-type instr (2)
 
        begin
 
          pc_src = 3'b000;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'b0;
 
          alu_src2 = 3'b101;
 
          alu_fnc = 3'b000;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd9:  // execute J-type instr
 
        begin
 
          pc_src = 3'b000;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'b0;
 
          alu_src2 = 3'b110;
 
          alu_fnc = 3'b000;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd10:  // execute JR-type instr
 
        begin
 
          pc_src = 3'b000;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'b1;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'b010;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd11:  // execute LDST-type instr (1)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b1;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b1;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'b1;
 
          alu_src2 = 3'b010;
 
          alu_fnc = 3'b000;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd12:  // execute LD-type instr (addr xlat)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'b1;
 
          mmu_fnc = (exc_prv_addr | exc_ill_addr) ? 3'b000 : 3'b001;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'b0;         // get bad_accs right in case of exc
 
          bus_size = ldst_size;  // enable illegal address detection
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = exc_prv_addr | exc_ill_addr;
 
        end
 
      5'd13:  // execute LD-type instr (3)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = ldst_size;
 
          mdir_we = 1'b0;
 
          mdir_sx = opcode[0];
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b011;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd14:  // execute ST-type instr (addr xlat)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'b1;
 
          mmu_fnc = (exc_prv_addr | exc_ill_addr) ? 3'b000 : 3'b001;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'b1;         // get bad_accs right in case of exc
 
          bus_size = ldst_size;  // enable illegal address detection
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = exc_prv_addr | exc_ill_addr;
 
        end
 
      5'd15:  // interrupt
 
        begin
 
          pc_src = (psw[27] == 0) ? 3'b010 : 3'b011;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b11;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'b0;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'b010;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b1;
 
          psw_new = {
 
            psw[31:28],
 
            psw[27],
 
            1'b0, psw[26], psw[25],
 
            1'b0, psw[23], psw[22],
 
            1'b0, irq_priority,
 
            psw[15:0]
 
          };
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd16:  // extra state for RRR shift instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b01;
 
          reg_di2_src = 3'b001;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd17:  // extra state for RRH shift instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b001;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd18:  // extra state for RRR muldiv instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b01;
 
          reg_di2_src = 3'b010;
 
          reg_we2 = muldiv_done & ~muldiv_error;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd19:  // extra state for RRS muldiv instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b010;
 
          reg_we2 = muldiv_done & ~muldiv_error;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd20:  // extra state for RRH muldiv instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b010;
 
          reg_we2 = muldiv_done & ~muldiv_error;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd21:  // execute mvfs instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b00;
 
          reg_di2_src = 3'b100;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd22:  // execute mvts instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b1;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd23:  // execute rfx instr
 
        begin
 
          pc_src = 3'b000;
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'b001;
 
          alu_fnc = 3'b011;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b1;
 
          psw_new = {
 
            psw[31:28],
 
            psw[27],
 
            psw[25], psw[24], psw[24],
 
            psw[22], psw[21], psw[21],
 
            psw[20:16],
 
            psw[15:0]
 
          };
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd24:  // irq_trigger check for mvts and rfx
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd25:  // exception (locus is PC-4)
 
        begin
 
          pc_src = (psw[27] != 0) ?
 
                     ((tlb_umissed != 0) ? 3'b101 : 3'b011) :
 
                     ((tlb_umissed != 0) ? 3'b100 : 3'b010);
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b11;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'b0;
 
          alu_src2 = 3'b000;
 
          alu_fnc = 3'b001;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b1;
 
          psw_new = {
 
            psw[31:28],
 
            psw[27],
 
            1'b0, psw[26], psw[25],
 
            1'b0, psw[23], psw[22],
 
            1'b1, exc_priority,
 
            psw[15:0]
 
          };
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd26:  // exception (locus is PC)
 
        begin
 
          pc_src = (psw[27] != 0) ?
 
                     ((tlb_umissed != 0) ? 3'b101 : 3'b011) :
 
                     ((tlb_umissed != 0) ? 3'b100 : 3'b010);
 
          pc_we = 1'b1;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'b11;
 
          reg_di2_src = 3'b000;
 
          reg_we2 = 1'b1;
 
          alu_src1 = 1'b0;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'b010;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b1;
 
          psw_new = {
 
            psw[31:28],
 
            psw[27],
 
            1'b0, psw[26], psw[25],
 
            1'b0, psw[23], psw[22],
 
            1'b1, exc_priority,
 
            psw[15:0]
 
          };
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = 1'b0;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd27:  // execute TLB instr
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'bx;
 
          mmu_fnc = opcode[2:0];
 
          mdor_we = 1'b0;
 
          bus_en = 1'b0;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = (opcode[2:0] == 3'b010) ? 1 : 0;
 
          tlb_entry_hi_we = (opcode[2:0] == 3'b100) ? 1 : 0;
 
          tlb_entry_lo_we = (opcode[2:0] == 3'b100) ? 1 : 0;
 
          mmu_bad_addr_we = 1'b0;
 
        end
 
      5'd28:  // fetch instr (bus cycle)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'b0;        // hold vaddr for latching in bad addr reg
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = ~exc_tlb_but_wrtprot;
 
          bus_wr = 1'b0;
 
          bus_size = 2'b10;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b1;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = exc_tlb_but_wrtprot;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = exc_tlb_but_wrtprot;
 
        end
 
      5'd29:  // execute LD-type instr (bus cycle)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'b1;        // hold vaddr for latching in bad addr reg
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = ~exc_tlb_but_wrtprot;
 
          bus_wr = 1'b0;
 
          bus_size = ldst_size;
 
          mdir_we = 1'b1;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = exc_tlb_but_wrtprot;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = exc_tlb_but_wrtprot;
 
        end
 
      5'd30:  // execute ST-type instr (bus cycle)
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'b0;
 
          mar_we = 1'b0;
 
          ma_src = 1'b1;        // hold vaddr for latching in bad addr reg
 
          mmu_fnc = 3'b000;
 
          mdor_we = 1'b0;
 
          bus_en = ~exc_tlb_any;
 
          bus_wr = 1'b1;
 
          bus_size = ldst_size;
 
          mdir_we = 1'b0;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'b0;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'b0;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'b0;
 
          sreg_we = 1'b0;
 
          psw_we = 1'b0;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'b0;
 
          tlb_entry_hi_we = exc_tlb_any;
 
          tlb_entry_lo_we = 1'b0;
 
          mmu_bad_addr_we = exc_tlb_any;
 
        end
 
      default:  // all other states: unused
 
        begin
 
          pc_src = 3'bxxx;
 
          pc_we = 1'bx;
 
          mar_we = 1'bx;
 
          ma_src = 1'bx;
 
          mmu_fnc = 3'bxxx;
 
          mdor_we = 1'bx;
 
          bus_en = 1'bx;
 
          bus_wr = 1'bx;
 
          bus_size = 2'bxx;
 
          mdir_we = 1'bx;
 
          mdir_sx = 1'bx;
 
          ir_we = 1'bx;
 
          reg_src2 = 2'bxx;
 
          reg_di2_src = 3'bxxx;
 
          reg_we2 = 1'bx;
 
          alu_src1 = 1'bx;
 
          alu_src2 = 3'bxxx;
 
          alu_fnc = 3'bxxx;
 
          shift_fnc = 2'bxx;
 
          muldiv_fnc = 3'bxxx;
 
          muldiv_start = 1'bx;
 
          sreg_we = 1'bx;
 
          psw_we = 1'bx;
 
          psw_new = 32'hxxxxxxxx;
 
          tlb_index_we = 1'bx;
 
          tlb_entry_hi_we = 1'bx;
 
          tlb_entry_lo_we = 1'bx;
 
          mmu_bad_addr_we = 1'bx;
 
        end
 
    endcase
 
  end
 
 
 
  // branch logic
 
  always @(*) begin
 
    casex ( { opcode[3:0], alu_equ, alu_ult, alu_slt } )
 
      // eq
 
      7'b00000xx:  branch = 0;
 
      7'b00001xx:  branch = 1;
 
      // ne
 
      7'b00010xx:  branch = 1;
 
      7'b00011xx:  branch = 0;
 
      // le
 
      7'b00100x0:  branch = 0;
 
      7'b00101xx:  branch = 1;
 
      7'b0010xx1:  branch = 1;
 
      // leu
 
      7'b001100x:  branch = 0;
 
      7'b00111xx:  branch = 1;
 
      7'b0011x1x:  branch = 1;
 
      // lt
 
      7'b0100xx0:  branch = 0;
 
      7'b0100xx1:  branch = 1;
 
      // ltu
 
      7'b0101x0x:  branch = 0;
 
      7'b0101x1x:  branch = 1;
 
      // ge
 
      7'b0110xx0:  branch = 1;
 
      7'b0110xx1:  branch = 0;
 
      // geu
 
      7'b0111x0x:  branch = 1;
 
      7'b0111x1x:  branch = 0;
 
      // gt
 
      7'b10000x0:  branch = 1;
 
      7'b10001xx:  branch = 0;
 
      7'b1000xx1:  branch = 0;
 
      // gtu
 
      7'b100100x:  branch = 1;
 
      7'b10011xx:  branch = 0;
 
      7'b1001x1x:  branch = 0;
 
      // other
 
      default:     branch = 1'bx;
 
    endcase
 
  end
 
 
 
  // interrupts
 
  assign irq_pending = irq[15:0] & psw[15:0];
 
  assign irq_trigger = (| irq_pending) & psw[23];
 
  always @(*) begin
 
    if ((| irq_pending[15:8]) != 0) begin
 
      if ((| irq_pending[15:12]) != 0) begin
 
        if ((| irq_pending[15:14]) != 0) begin
 
          if (irq_pending[15] != 0) begin
 
            irq_priority = 4'd15;
 
          end else begin
 
            irq_priority = 4'd14;
 
          end
 
        end else begin
 
          if (irq_pending[13] != 0) begin
 
            irq_priority = 4'd13;
 
          end else begin
 
            irq_priority = 4'd12;
 
          end
 
        end
 
      end else begin
 
        if ((| irq_pending[11:10]) != 0) begin
 
          if (irq_pending[11] != 0) begin
 
            irq_priority = 4'd11;
 
          end else begin
 
            irq_priority = 4'd10;
 
          end
 
        end else begin
 
          if (irq_pending[9] != 0) begin
 
            irq_priority = 4'd9;
 
          end else begin
 
            irq_priority = 4'd8;
 
          end
 
        end
 
      end
 
    end else begin
 
      if ((| irq_pending[7:4]) != 0) begin
 
        if ((| irq_pending[7:6]) != 0) begin
 
          if (irq_pending[7] != 0) begin
 
            irq_priority = 4'd7;
 
          end else begin
 
            irq_priority = 4'd6;
 
          end
 
        end else begin
 
          if (irq_pending[5] != 0) begin
 
            irq_priority = 4'd5;
 
          end else begin
 
            irq_priority = 4'd4;
 
          end
 
        end
 
      end else begin
 
        if ((| irq_pending[3:2]) != 0) begin
 
          if (irq_pending[3] != 0) begin
 
            irq_priority = 4'd3;
 
          end else begin
 
            irq_priority = 4'd2;
 
          end
 
        end else begin
 
          if (irq_pending[1] != 0) begin
 
            irq_priority = 4'd1;
 
          end else begin
 
            irq_priority = 4'd0;
 
          end
 
        end
 
      end
 
    end
 
  end
 
 
 
  // exceptions
 
  assign exc_prv_addr = psw[26] & va_31;
 
  assign exc_ill_addr = (bus_size[0] & va_0) |
 
                        (bus_size[1] & va_0) |
 
                        (bus_size[1] & va_1);
 
  assign exc_tlb_but_wrtprot = tlb_kmissed | tlb_umissed | tlb_invalid;
 
  assign exc_tlb_any = exc_tlb_but_wrtprot | tlb_wrtprot;
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// pc -- the program counter
 
//--------------------------------------------------------------
 
 
 
 
 
module pc(clk, pc_we, pc_next, pc);
 
    input clk;
 
    input pc_we;
 
    input [31:0] pc_next;
 
    output reg [31:0] pc;
 
 
 
  always @(posedge clk) begin
 
    if (pc_we == 1) begin
 
      pc <= pc_next;
 
    end
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// mar -- the memory address register
 
//--------------------------------------------------------------
 
 
 
 
 
module mar(clk, mar_we, mar_next, mar);
 
    input clk;
 
    input mar_we;
 
    input [31:0] mar_next;
 
    output reg [31:0] mar;
 
 
 
  always @(posedge clk) begin
 
    if (mar_we == 1) begin
 
      mar <= mar_next;
 
    end
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// mdor -- the memory data out register
 
//--------------------------------------------------------------
 
 
 
 
 
module mdor(clk, mdor_we, mdor_next, mdor);
 
    input clk;
 
    input mdor_we;
 
    input [31:0] mdor_next;
 
    output reg [31:0] mdor;
 
 
 
  always @(posedge clk) begin
 
    if (mdor_we == 1) begin
 
      mdor <= mdor_next;
 
    end
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// mdir -- the memory data in register
 
//--------------------------------------------------------------
 
 
 
 
 
module mdir(clk, mdir_we, mdir_next, size, sx, mdir);
 
    input clk;
 
    input mdir_we;
 
    input [31:0] mdir_next;
 
    input [1:0] size;
 
    input sx;
 
    output reg [31:0] mdir;
 
 
 
  reg [31:0] data;
 
 
 
  always @(posedge clk) begin
 
    if (mdir_we == 1) begin
 
      data <= mdir_next;
 
    end
 
  end
 
 
 
  always @(*) begin
 
    case ({ size, sx })
 
      3'b000:
 
        begin
 
          mdir[31:0] = { 24'h000000, data[7:0] };
 
        end
 
      3'b001:
 
        begin
 
          if (data[7] == 1) begin
 
            mdir[31:0] = { 24'hFFFFFF, data[7:0] };
 
          end else begin
 
            mdir[31:0] = { 24'h000000, data[7:0] };
 
          end
 
        end
 
      3'b010:
 
        begin
 
          mdir[31:0] = { 16'h0000, data[15:0] };
 
        end
 
      3'b011:
 
        begin
 
          if (data[15] == 1) begin
 
            mdir[31:0] = { 16'hFFFF, data[15:0] };
 
          end else begin
 
            mdir[31:0] = { 16'h0000, data[15:0] };
 
          end
 
        end
 
      default:
 
        begin
 
          mdir[31:0] = data[31:0];
 
        end
 
    endcase
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// ir -- the instruction register and decoder
 
//--------------------------------------------------------------
 
 
 
 
 
module ir(clk,
 
          ir_we, instr,
 
          opcode, reg1, reg2, reg3,
 
          sx16, zx16, hi16, sx16s2, sx26s2);
 
    input clk;
 
    input ir_we;
 
    input [31:0] instr;
 
    output [5:0] opcode;
 
    output [4:0] reg1;
 
    output [4:0] reg2;
 
    output [4:0] reg3;
 
    output [31:0] sx16;
 
    output [31:0] zx16;
 
    output [31:0] hi16;
 
    output [31:0] sx16s2;
 
    output [31:0] sx26s2;
 
 
 
  reg [31:0] ir;
 
  wire [15:0] copy_sign_16;      // 16-bit copy of a 16-bit immediate's sign
 
  wire [3:0] copy_sign_26;       // 4-bit copy of a 26-bit immediate's sign
 
 
 
  always @(posedge clk) begin
 
    if (ir_we) begin
 
      ir <= instr;
 
    end
 
  end
 
 
 
  assign opcode[5:0] = ir[31:26];
 
  assign reg1[4:0] = ir[25:21];
 
  assign reg2[4:0] = ir[20:16];
 
  assign reg3[4:0] = ir[15:11];
 
  assign copy_sign_16[15:0] = (ir[15] == 1) ? 16'hFFFF : 16'h0000;
 
  assign copy_sign_26[3:0] = (ir[25] == 1) ? 4'hF : 4'h0;
 
  assign sx16[31:0] = { copy_sign_16[15:0], ir[15:0] };
 
  assign zx16[31:0] = { 16'h0000, ir[15:0] };
 
  assign hi16[31:0] = { ir[15:0], 16'h0000 };
 
  assign sx16s2[31:0] = { copy_sign_16[13:0], ir[15:0], 2'b00 };
 
  assign sx26s2[31:0] = { copy_sign_26[3:0], ir[25:0], 2'b00 };
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// regs -- the register file
 
//--------------------------------------------------------------
 
 
 
 
module cpu(clk, rst,
module regs(clk,
           bus_stb, bus_we, bus_addr,
            rn1, do1,
           bus_din, bus_dout, bus_ack,
            rn2, do2, we2, di2);
           bus_irq);
    input clk;
    input clk;                          // system clock
    input [4:0] rn1;
    input rst;                          // system reset
    output reg [31:0] do1;
    output bus_stb;                     // bus strobe
    input [4:0] rn2;
    output bus_we;                      // bus write enable
    output reg [31:0] do2;
    output [31:2] bus_addr;             // bus address (word address)
    input we2;
    input [31:0] bus_din;                // bus data input, for reads
    input [31:0] di2;
    output [31:0] bus_dout;              // bus data output, for writes
 
    input bus_ack;                      // bus acknowledge
  reg [31:0] r[0:31];
    input [15:0] bus_irq;                // bus interrupt requests
 
 
  always @(posedge clk) begin
  wire cpu_stb;
    do1 <= r[rn1];
  wire cpu_we;
    if (we2 == 0) begin
  wire [1:0] cpu_size;
      do2 <= r[rn2];
  wire [31:0] cpu_addr;
    end else begin
  wire [31:0] cpu_din;
      do2 <= di2;
  wire [31:0] cpu_dout;
      r[rn2] <= di2;
  wire cpu_ack;
    end
  wire [15:0] cpu_irq;
  end
 
 
  cpu_bus cpu_bus_1(
endmodule
    .clk(clk),
 
    .rst(rst),
 
    .bus_stb(bus_stb),
//--------------------------------------------------------------
    .bus_we(bus_we),
// alu -- the arithmetic/logic unit
    .bus_addr(bus_addr[31:2]),
//--------------------------------------------------------------
    .bus_din(bus_din[31:0]),
 
    .bus_dout(bus_dout[31:0]),
 
    .bus_ack(bus_ack),
module alu(a, b, fnc,
    .bus_irq(bus_irq[15:0]),
           res, equ, ult, slt);
    .cpu_stb(cpu_stb),
    input [31:0] a;
    .cpu_we(cpu_we),
    input [31:0] b;
    .cpu_size(cpu_size[1:0]),
    input [2:0] fnc;
    .cpu_addr(cpu_addr[31:0]),
    output [31:0] res;
    .cpu_din(cpu_din[31:0]),
    output equ;
    .cpu_dout(cpu_dout[31:0]),
    output ult;
    .cpu_ack(cpu_ack),
    output slt;
    .cpu_irq(cpu_irq[15:0])
 
  );
  wire [32:0] a1;
 
  wire [32:0] b1;
  cpu_core cpu_core_1(
  reg [32:0] res1;
    .clk(clk),
 
    .rst(rst),
  assign a1 = { 1'b0, a };
    .bus_stb(cpu_stb),
  assign b1 = { 1'b0, b };
    .bus_we(cpu_we),
 
    .bus_size(cpu_size[1:0]),
  always @(*) begin
    .bus_addr(cpu_addr[31:0]),
    case (fnc)
    .bus_din(cpu_din[31:0]),
      3'b000:  res1 = a1 + b1;
    .bus_dout(cpu_dout[31:0]),
      3'b001:  res1 = a1 - b1;
    .bus_ack(cpu_ack),
      3'b010:  res1 = a1;
    .bus_irq(cpu_irq[15:0])
      3'b011:  res1 = b1;
  );
      3'b100:  res1 = a1 & b1;
 
      3'b101:  res1 = a1 | b1;
 
      3'b110:  res1 = a1 ^ b1;
 
      3'b111:  res1 = a1 ~^ b1;
 
      default: res1 = 33'hxxxxxxxx;
 
    endcase
 
  end
 
 
 
  assign res = res1[31:0];
 
  assign equ = ~| res1[31:0];
 
  assign ult = res1[32];
 
  assign slt = res1[32] ^ a[31] ^ b[31];
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// shift -- the shift unit
 
//--------------------------------------------------------------
 
 
 
 
 
module shift(clk, data_in, shamt, fnc, data_out);
 
    input clk;
 
    input [31:0] data_in;
 
    input [4:0] shamt;
 
    input [1:0] fnc;
 
    output reg [31:0] data_out;
 
 
 
  always @(posedge clk) begin
 
    if (fnc == 2'b00) begin
 
      // sll
 
      data_out <= data_in << shamt;
 
    end else
 
    if (fnc == 2'b01) begin
 
      // slr
 
      data_out <= data_in >> shamt;
 
    end else
 
    if (fnc == 2'b10) begin
 
      // sar
 
      if (data_in[31] == 1) begin
 
        data_out <= ~(32'hFFFFFFFF >> shamt) |
 
                    (data_in >> shamt);
 
      end else begin
 
        data_out <= data_in >> shamt;
 
      end
 
    end else begin
 
      data_out <= 32'hxxxxxxxx;
 
    end
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// muldiv -- the multiplier/divide unit
 
//--------------------------------------------------------------
 
 
 
 
 
module muldiv(clk, a, b, fnc, start, done, error, res);
 
    input clk;
 
    input [31:0] a;
 
    input [31:0] b;
 
    input [2:0] fnc;
 
    input start;
 
    output reg done;
 
    output reg error;
 
    output reg [31:0] res;
 
 
 
  // fnc = 000    op = undefined
 
  //       001         undefined
 
  //       010         mul
 
  //       011         mulu
 
  //       100         div
 
  //       101         divu
 
  //       110         rem
 
  //       111         remu
 
 
 
  reg div;
 
  reg rem;
 
  reg [5:0] count;
 
  reg a_neg;
 
  reg b_neg;
 
  reg [31:0] b_abs;
 
  reg [64:0] q;
 
  wire [64:1] s;
 
  wire [64:0] d;
 
 
 
  assign s[64:32] = q[64:32] + { 1'b0, b_abs };
 
  assign s[31: 1] = q[31: 1];
 
  assign d[64:32] = q[64:32] - { 1'b0, b_abs };
 
  assign d[31: 0] = q[31: 0];
 
 
 
  always @(posedge clk) begin
 
    if (start == 1) begin
 
      if (fnc[2] == 1 && (| b[31:0]) == 0) begin
 
        // division by zero
 
        done <= 1;
 
        error <= 1;
 
      end else begin
 
        // operands are ok
 
        done <= 0;
 
        error <= 0;
 
      end
 
      div <= fnc[2];
 
      rem <= fnc[1];
 
      count <= 6'd0;
 
      if (fnc[0] == 0 && a[31] == 1) begin
 
        // negate first operand
 
        a_neg <= 1;
 
        if (fnc[2] == 0) begin
 
          // initialize q for multiplication
 
          q[64:32] <= 33'b0;
 
          q[31: 0] <= ~a + 1;
 
        end else begin
 
          // initialize q for division and remainder
 
          q[64:33] <= 32'b0;
 
          q[32: 1] <= ~a + 1;
 
          q[ 0: 0] <= 1'b0;
 
        end
 
      end else begin
 
        // use first operand as is
 
        a_neg <= 0;
 
        if (fnc[2] == 0) begin
 
          // initialize q for multiplication
 
          q[64:32] <= 33'b0;
 
          q[31: 0] <= a;
 
        end else begin
 
          // initialize q for division and remainder
 
          q[64:33] <= 32'b0;
 
          q[32: 1] <= a;
 
          q[ 0: 0] <= 1'b0;
 
        end
 
      end
 
      if (fnc[0] == 0 && b[31] == 1) begin
 
        // negate second operand
 
        b_neg <= 1;
 
        b_abs <= ~b + 1;
 
      end else begin
 
        // use second operand as is
 
        b_neg <= 0;
 
        b_abs <= b;
 
      end
 
    end else begin
 
      if (done == 0) begin
 
        // algorithm not yet finished
 
        if (div == 0) begin
 
          //
 
          // multiplication
 
          //
 
          if (count == 6'd32) begin
 
            // last step
 
            done <= 1;
 
            if (a_neg == b_neg) begin
 
              res <= q[31:0];
 
            end else begin
 
              res <= ~q[31:0] + 1;
 
            end
 
          end else begin
 
            // all other steps
 
            count <= count + 1;
 
            if (q[0] == 1) begin
 
              q <= { 1'b0, s[64:1] };
 
            end else begin
 
              q <= { 1'b0, q[64:1] };
 
            end
 
          end
 
        end else begin
 
          //
 
          // division and remainder
 
          //
 
          if (count == 6'd32) begin
 
            // last step
 
            done <= 1;
 
            if (rem == 0) begin
 
              // result <= quotient
 
              if (a_neg == b_neg) begin
 
                res <= q[31:0];
 
              end else begin
 
                res <= ~q[31:0] + 1;
 
              end
 
            end else begin
 
              // result <= remainder
 
              if (a_neg == 0) begin
 
                res <= q[64:33];
 
              end else begin
 
                res <= ~q[64:33] + 1;
 
              end
 
            end
 
          end else begin
 
            // all other steps
 
            count <= count + 1;
 
            if (d[64] == 0) begin
 
              q <= { d[63:0], 1'b1 };
 
            end else begin
 
              q <= { q[63:0], 1'b0 };
 
            end
 
          end
 
        end
 
      end
 
    end
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// sregs -- the special registers
 
//--------------------------------------------------------------
 
 
 
 
 
module sregs(clk, reset,
 
             rn, we, din, dout,
 
             psw, psw_we, psw_new,
 
             tlb_index, tlb_index_we, tlb_index_new,
 
             tlb_entry_hi, tlb_entry_hi_we, tlb_entry_hi_new,
 
             tlb_entry_lo, tlb_entry_lo_we, tlb_entry_lo_new,
 
             mmu_bad_addr, mmu_bad_addr_we, mmu_bad_addr_new,
 
             mmu_bad_accs, mmu_bad_accs_we, mmu_bad_accs_new);
 
    input clk;
 
    input reset;
 
    input [2:0] rn;
 
    input we;
 
    input [31:0] din;
 
    output [31:0] dout;
 
    output [31:0] psw;
 
    input psw_we;
 
    input [31:0] psw_new;
 
    output [31:0] tlb_index;
 
    input tlb_index_we;
 
    input [31:0] tlb_index_new;
 
    output [31:0] tlb_entry_hi;
 
    input tlb_entry_hi_we;
 
    input [31:0] tlb_entry_hi_new;
 
    output [31:0] tlb_entry_lo;
 
    input tlb_entry_lo_we;
 
    input [31:0] tlb_entry_lo_new;
 
    output [31:0] mmu_bad_addr;
 
    input mmu_bad_addr_we;
 
    input [31:0] mmu_bad_addr_new;
 
    output [31:0] mmu_bad_accs;
 
    input mmu_bad_accs_we;
 
    input [31:0] mmu_bad_accs_new;
 
 
 
  // rn = 000   register = PSW
 
  //      001              TLB index
 
  //      010              TLB entry high
 
  //      011              TLB entry low
 
  //      100              MMU bad address
 
  //      101              MMU bad access
 
  //      110              - not used -
 
  //      111              - not used -
 
 
 
  reg [31:0] sr[0:7];
 
 
 
  assign dout = sr[rn];
 
  assign psw = sr[0];
 
  assign tlb_index = sr[1];
 
  assign tlb_entry_hi = sr[2];
 
  assign tlb_entry_lo = sr[3];
 
  assign mmu_bad_addr = sr[4];
 
  assign mmu_bad_accs = sr[5];
 
 
 
  always @(posedge clk) begin
 
    if (reset == 1) begin
 
      sr[0] <= 32'h00000000;
 
    end else begin
 
      if (we == 1) begin
 
        sr[rn] <= din;
 
      end else begin
 
        if (psw_we) begin
 
          sr[0] <= psw_new;
 
        end
 
        if (tlb_index_we) begin
 
          sr[1] <= tlb_index_new;
 
        end
 
        if (tlb_entry_hi_we) begin
 
          sr[2] <= tlb_entry_hi_new;
 
        end
 
        if (tlb_entry_lo_we) begin
 
          sr[3] <= tlb_entry_lo_new;
 
        end
 
        if (mmu_bad_addr_we) begin
 
          sr[4] <= mmu_bad_addr_new;
 
        end
 
        if (mmu_bad_accs_we) begin
 
          sr[5] <= mmu_bad_accs_new;
 
        end
 
      end
 
    end
 
  end
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// mmu -- the memory management unit
 
//--------------------------------------------------------------
 
 
 
 
 
module mmu(clk, reset, fnc, virt, phys,
 
           tlb_index, tlb_index_new,
 
           tlb_entry_hi, tlb_entry_hi_new,
 
           tlb_entry_lo, tlb_entry_lo_new,
 
           tlb_kmissed, tlb_umissed,
 
           tlb_invalid, tlb_wrtprot);
 
    input clk;
 
    input reset;
 
    input [2:0] fnc;
 
    input [31:0] virt;
 
    output [31:0] phys;
 
    input [31:0] tlb_index;
 
    output [31:0] tlb_index_new;
 
    input [31:0] tlb_entry_hi;
 
    output [31:0] tlb_entry_hi_new;
 
    input [31:0] tlb_entry_lo;
 
    output [31:0] tlb_entry_lo_new;
 
    output tlb_kmissed;
 
    output tlb_umissed;
 
    output tlb_invalid;
 
    output tlb_wrtprot;
 
 
 
  // fnc = 000    no operation, hold output
 
  //       001    map virt to phys address
 
  //       010    tbs
 
  //       011    tbwr
 
  //       100    tbri
 
  //       101    tbwi
 
  //       110    undefined
 
  //       111    undefined
 
 
 
  wire map;
 
  wire tbs;
 
  wire tbwr;
 
  wire tbri;
 
  wire tbwi;
 
  reg [19:0] page;
 
  reg [11:0] offset;
 
  wire [19:0] tlb_page;
 
  wire tlb_miss;
 
  wire [4:0] tlb_found;
 
  wire tlb_enable;
 
  wire [19:0] tlb_frame;
 
  wire tlb_wbit;
 
  wire tlb_vbit;
 
  wire [4:0] rw_index;
 
  wire [19:0] r_page;
 
  wire [19:0] r_frame;
 
  wire w_enable;
 
  wire [19:0] w_page;
 
  wire [19:0] w_frame;
 
  wire direct;
 
  wire [17:0] frame;
 
  reg [4:0] random_index;
 
  reg tlb_miss_delayed;
 
 
 
  // decode function
 
  assign map = (fnc == 3'b001) ? 1 : 0;
 
  assign tbs = (fnc == 3'b010) ? 1 : 0;
 
  assign tbwr = (fnc == 3'b011) ? 1 : 0;
 
  assign tbri = (fnc == 3'b100) ? 1 : 0;
 
  assign tbwi = (fnc == 3'b101) ? 1 : 0;
 
 
 
  // latch virtual address
 
  always @(posedge clk) begin
 
    if (map == 1) begin
 
      page <= virt[31:12];
 
      offset <= virt[11:0];
 
    end
 
  end
 
 
 
  // create tlb instance
 
  assign tlb_page = (tbs == 1) ? tlb_entry_hi[31:12] : virt[31:12];
 
  assign tlb_enable = map;
 
  assign tlb_wbit = tlb_frame[1];
 
  assign tlb_vbit = tlb_frame[0];
 
  assign rw_index = (tbwr == 1) ? random_index : tlb_index[4:0];
 
  assign tlb_index_new = { tlb_miss, 26'b0, tlb_found };
 
  assign tlb_entry_hi_new = { ((tbri == 1) ? r_page : page),
 
                              tlb_entry_hi[11:0] };
 
  assign tlb_entry_lo_new = { tlb_entry_lo[31:30], r_frame[19:2],
 
                              tlb_entry_lo[11:2], r_frame[1:0] };
 
  assign w_enable = tbwr | tbwi;
 
  assign w_page = tlb_entry_hi[31:12];
 
  assign w_frame = { tlb_entry_lo[29:12], tlb_entry_lo[1:0] };
 
  tlb tlb1(tlb_page, tlb_miss, tlb_found,
 
           clk, tlb_enable, tlb_frame,
 
           rw_index, r_page, r_frame,
 
           w_enable, w_page, w_frame);
 
 
 
  // construct physical address
 
  assign direct = (page[19:18] == 2'b11) ? 1 : 0;
 
  assign frame = (direct == 1) ? page[17:0] : tlb_frame[19:2];
 
  assign phys = { 2'b00, frame, offset };
 
 
 
  // generate "random" index
 
  always @(posedge clk) begin
 
    if (reset == 1) begin
 
      // the index register is counting down
 
      // so we must start at topmost index
 
      random_index <= 5'd31;
 
    end else begin
 
      // decrement index register "randomly"
 
      // (whenever there is a mapping operation)
 
      // skip "fixed" entries (0..3)
 
      if (map == 1) begin
 
        if (random_index == 5'd4) begin
 
          random_index <= 5'd31;
 
        end else begin
 
          random_index <= random_index - 1;
 
        end
 
      end
 
    end
 
  end
 
 
 
  // generate TLB exceptions
 
  always @(posedge clk) begin
 
    if (map == 1) begin
 
      tlb_miss_delayed <= tlb_miss;
 
    end
 
  end
 
  assign tlb_kmissed = tlb_miss_delayed & ~direct & page[19];
 
  assign tlb_umissed = tlb_miss_delayed & ~direct & ~page[19];
 
  assign tlb_invalid = ~tlb_vbit & ~direct;
 
  assign tlb_wrtprot = ~tlb_wbit & ~direct;
 
 
 
endmodule
 
 
 
 
 
//--------------------------------------------------------------
 
// tlb -- the translation lookaside buffer
 
//--------------------------------------------------------------
 
 
 
 
 
module tlb(page_in, miss, found,
 
           clk, enable, frame_out,
 
           rw_index, r_page, r_frame,
 
           w_enable, w_page, w_frame);
 
    input [19:0] page_in;
 
    output miss;
 
    output [4:0] found;
 
    input clk;
 
    input enable;
 
    output reg [19:0] frame_out;
 
    input [4:0] rw_index;
 
    output reg [19:0] r_page;
 
    output reg [19:0] r_frame;
 
    input w_enable;
 
    input [19:0] w_page;
 
    input [19:0] w_frame;
 
 
 
  reg [19:0] page[0:31];
 
  reg [19:0] frame[0:31];
 
 
 
  wire [19:0] p00, p01, p02, p03;
 
  wire [19:0] p04, p05, p06, p07;
 
  wire [19:0] p08, p09, p10, p11;
 
  wire [19:0] p12, p13, p14, p15;
 
  wire [19:0] p16, p17, p18, p19;
 
  wire [19:0] p20, p21, p22, p23;
 
  wire [19:0] p24, p25, p26, p27;
 
  wire [19:0] p28, p29, p30, p31;
 
  wire [31:0] match;
 
 
 
  assign p00 = page[ 0];
 
  assign p01 = page[ 1];
 
  assign p02 = page[ 2];
 
  assign p03 = page[ 3];
 
  assign p04 = page[ 4];
 
  assign p05 = page[ 5];
 
  assign p06 = page[ 6];
 
  assign p07 = page[ 7];
 
  assign p08 = page[ 8];
 
  assign p09 = page[ 9];
 
  assign p10 = page[10];
 
  assign p11 = page[11];
 
  assign p12 = page[12];
 
  assign p13 = page[13];
 
  assign p14 = page[14];
 
  assign p15 = page[15];
 
  assign p16 = page[16];
 
  assign p17 = page[17];
 
  assign p18 = page[18];
 
  assign p19 = page[19];
 
  assign p20 = page[20];
 
  assign p21 = page[21];
 
  assign p22 = page[22];
 
  assign p23 = page[23];
 
  assign p24 = page[24];
 
  assign p25 = page[25];
 
  assign p26 = page[26];
 
  assign p27 = page[27];
 
  assign p28 = page[28];
 
  assign p29 = page[29];
 
  assign p30 = page[30];
 
  assign p31 = page[31];
 
 
 
  assign match[ 0] = (page_in == p00) ? 1 : 0;
 
  assign match[ 1] = (page_in == p01) ? 1 : 0;
 
  assign match[ 2] = (page_in == p02) ? 1 : 0;
 
  assign match[ 3] = (page_in == p03) ? 1 : 0;
 
  assign match[ 4] = (page_in == p04) ? 1 : 0;
 
  assign match[ 5] = (page_in == p05) ? 1 : 0;
 
  assign match[ 6] = (page_in == p06) ? 1 : 0;
 
  assign match[ 7] = (page_in == p07) ? 1 : 0;
 
  assign match[ 8] = (page_in == p08) ? 1 : 0;
 
  assign match[ 9] = (page_in == p09) ? 1 : 0;
 
  assign match[10] = (page_in == p10) ? 1 : 0;
 
  assign match[11] = (page_in == p11) ? 1 : 0;
 
  assign match[12] = (page_in == p12) ? 1 : 0;
 
  assign match[13] = (page_in == p13) ? 1 : 0;
 
  assign match[14] = (page_in == p14) ? 1 : 0;
 
  assign match[15] = (page_in == p15) ? 1 : 0;
 
  assign match[16] = (page_in == p16) ? 1 : 0;
 
  assign match[17] = (page_in == p17) ? 1 : 0;
 
  assign match[18] = (page_in == p18) ? 1 : 0;
 
  assign match[19] = (page_in == p19) ? 1 : 0;
 
  assign match[20] = (page_in == p20) ? 1 : 0;
 
  assign match[21] = (page_in == p21) ? 1 : 0;
 
  assign match[22] = (page_in == p22) ? 1 : 0;
 
  assign match[23] = (page_in == p23) ? 1 : 0;
 
  assign match[24] = (page_in == p24) ? 1 : 0;
 
  assign match[25] = (page_in == p25) ? 1 : 0;
 
  assign match[26] = (page_in == p26) ? 1 : 0;
 
  assign match[27] = (page_in == p27) ? 1 : 0;
 
  assign match[28] = (page_in == p28) ? 1 : 0;
 
  assign match[29] = (page_in == p29) ? 1 : 0;
 
  assign match[30] = (page_in == p30) ? 1 : 0;
 
  assign match[31] = (page_in == p31) ? 1 : 0;
 
 
 
  assign miss = ~(| match[31:0]);
 
 
 
  assign found[0] = match[ 1] | match[ 3] | match[ 5] | match[ 7] |
 
                    match[ 9] | match[11] | match[13] | match[15] |
 
                    match[17] | match[19] | match[21] | match[23] |
 
                    match[25] | match[27] | match[29] | match[31];
 
  assign found[1] = match[ 2] | match[ 3] | match[ 6] | match[ 7] |
 
                    match[10] | match[11] | match[14] | match[15] |
 
                    match[18] | match[19] | match[22] | match[23] |
 
                    match[26] | match[27] | match[30] | match[31];
 
  assign found[2] = match[ 4] | match[ 5] | match[ 6] | match[ 7] |
 
                    match[12] | match[13] | match[14] | match[15] |
 
                    match[20] | match[21] | match[22] | match[23] |
 
                    match[28] | match[29] | match[30] | match[31];
 
  assign found[3] = match[ 8] | match[ 9] | match[10] | match[11] |
 
                    match[12] | match[13] | match[14] | match[15] |
 
                    match[24] | match[25] | match[26] | match[27] |
 
                    match[28] | match[29] | match[30] | match[31];
 
  assign found[4] = match[16] | match[17] | match[18] | match[19] |
 
                    match[20] | match[21] | match[22] | match[23] |
 
                    match[24] | match[25] | match[26] | match[27] |
 
                    match[28] | match[29] | match[30] | match[31];
 
 
 
  always @(posedge clk) begin
 
    if (enable == 1) begin
 
      frame_out <= frame[found];
 
    end
 
  end
 
 
 
  always @(posedge clk) begin
 
    if (w_enable == 1) begin
 
      page[rw_index] <= w_page;
 
      frame[rw_index] <= w_frame;
 
    end else begin
 
      r_page <= page[rw_index];
 
      r_frame <= frame[rw_index];
 
    end
 
  end
 
 
 
endmodule
endmodule
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.