[RISCV] Cleanup unsupported instructions EBREAK

// Copyright (c) 2017 Min Chen. All Rights Reserved
// Author: Min Chen

// ================================================================
// ISA defs for UC Berkeley RISC V
//
// References (from riscv.org):
//   "The RISC-V Instruction Set Manual
//    Volume I: User-Level ISA, Version 2.2, May 7, 2017"
//    Waterman, Lee, Patterson and Asanovic
//
//   "The RISC-V Instruction Set Manual
//    Volume II: Privileged Architecture, Version 1.10, May 7, 2017"
//    Waterman, Lee, Avizienis, Patterson and Asanovic
//
// ================================================================

package ISA_Decls;

// ================================================================
// BSV library imports

import DefaultValue :: *;
import Vector       :: *;
import BuildVector  :: *;

// ================================================================
// BSV project imports

// None

// ================================================================

typedef 32 XLEN;

typedef TMul#(2, XLEN)  XLEN_2;     // Double-width for multiplications
Integer xlen = valueOf(XLEN);

// ----------------

typedef  8  Bits_per_Byte;

typedef  Bit#(XLEN)  Word;          // Raw (unsigned) register data
typedef  Int#(XLEN)  Word_S;        // Signed register data

typedef  Word        Addr;          // addresses/pointers

typedef TDiv#(XLEN, Bits_per_Byte)  Bytes_per_Word;
typedef TLog#(Bytes_per_Word)       Bits_per_Word_Byte_Index;

// ================================================================
// Instruction fields

typedef  Bit#(32)    Instr;
typedef  Bit#(7)     Opcode;
typedef  Bit#(5)     RegName;       // 32 registers, 0..31
typedef  32          NumRegs;
Integer  numRegs = valueOf(NumRegs);

function  Opcode     instr_opcode (Instr x); return x[6:0]; endfunction

function  Bit#(3)    instr_funct3 (Instr x); return x[14:12]; endfunction
function  Bit#(5)    instr_funct5 (Instr x); return x[31:27]; endfunction
function  Bit#(7)    instr_funct7 (Instr x); return x[31:25]; endfunction
function  Bit#(10)   instr_funct10(Instr x); return { x[31:25], x[14:12] }; endfunction

function  RegName    instr_rd     (Instr x); return x[11:7]; endfunction
function  RegName    instr_rs1    (Instr x); return x[19:15]; endfunction
function  RegName    instr_rs2    (Instr x); return x[24:20]; endfunction
function  RegName    instr_rs3    (Instr x); return x[31:27]; endfunction     // {F,D} Extension
function  CSR_Addr   instr_csr    (Instr x); return unpack(x[31:20]); endfunction

function  Bit#(12)   instr_I_imm12 (Instr x); return x[31:20]; endfunction
function  Bit#(12)   instr_S_imm12 (Instr x); return { x[31:25], x[11:7] }; endfunction
function  Bit#(13)   instr_SB_imm13(Instr x); return { x[31], x[7], x[30:25], x[11:8], 1'b0 }; endfunction
function  Bit#(20)   instr_U_imm20 (Instr x); return x[31:12]; endfunction
function  Bit#(21)   instr_UJ_imm21(Instr x); return { x[31], x[19:12], x[20], x[30:21], 1'b0 }; endfunction

// For FENCE decode
function  Bit#(4)   instr_pred(Instr x); return x[27:24]; endfunction
function  Bit#(4)   instr_succ(Instr x); return x[23:20]; endfunction

// For AMO decode
function  Bit#(2)   instr_aqrl(Instr x); return x[26:25]; endfunction

// ----------------
// Decoded instructions

typedef struct {
   Opcode   opcode;

   RegName  rd;
   RegName  rs1;
   RegName  rs2;
   RegName  rs3;
   CSR_Addr csr;

   Bit#(3)  funct3;
   Bit#(5)  funct5;
   Bit#(7)  funct7;
   Bit#(10) funct10;

   Bit#(12) imm12_I;
   Bit#(12) imm12_S;
   Bit#(13) imm13_SB;
   Bit#(20) imm20_U;
   Bit#(21) imm21_UJ;

   //Bit#(4)  pred;
   //Bit#(4)  succ;

   //Bit#(2)  aqrl;

   Addr     pc;
} Decoded_Instr deriving(FShow, Bits);

function Decoded_Instr fv_decode(Addr _pc, Instr instr);
   return Decoded_Instr {
            opcode:     instr_opcode   (instr),
            rd:         instr_rd       (instr),
            rs1:        instr_rs1      (instr),
            rs2:        instr_rs2      (instr),
            rs3:        instr_rs3      (instr),
            csr:        instr_csr      (instr),

            funct3:     instr_funct3   (instr),
            funct5:     instr_funct5   (instr),
            funct7:     instr_funct7   (instr),
            funct10:    instr_funct10  (instr),

            imm12_I:    instr_I_imm12  (instr),
            imm12_S:    instr_S_imm12  (instr),
            imm13_SB:   instr_SB_imm13 (instr),
            imm20_U:    instr_U_imm20  (instr),
            imm21_UJ:   instr_UJ_imm21 (instr),

            //pred:      instr_pred     (instr),
            //succ:      instr_succ     (instr),

            //aqrl:      instr_aqrl     (instr),
            pc:         _pc
          };
endfunction

// ----------------
// Write Back Stage

typedef union tagged {
   Word     Value;
   Bit#(3)  Funct3;
} Exec2WbValue_t deriving(Bits);

typedef struct {
   RegName  rd;
   Exec2WbValue_t rd_value;
} Exec2Wb_t deriving(Bits);

// ================================================================
// Symbolic register names

RegName x0  =  0;    RegName x1  =  1;    RegName x2  =  2;    RegName x3  =  3;
RegName x4  =  4;    RegName x5  =  5;    RegName x6  =  6;    RegName x7  =  7;
RegName x8  =  8;    RegName x9  =  9;    RegName x10 = 10;    RegName x11 = 11;
RegName x12 = 12;    RegName x13 = 13;    RegName x14 = 14;    RegName x15 = 15;
RegName x16 = 16;    RegName x17 = 17;    RegName x18 = 18;    RegName x19 = 19;
RegName x20 = 20;    RegName x21 = 21;    RegName x22 = 22;    RegName x23 = 23;
RegName x24 = 24;    RegName x25 = 25;    RegName x26 = 26;    RegName x27 = 27;
RegName x28 = 28;    RegName x29 = 29;    RegName x30 = 30;    RegName x31 = 31;

// Register names used in calling convention

RegName reg_ra = 1;

RegName reg_s0 = 8;   RegName reg_s1 = 9;   RegName reg_s2  = 18; RegName reg_s3  = 19;
RegName reg_s4 = 20;  RegName reg_s5 = 21;  RegName reg_s6  = 22; RegName reg_s7  = 23;
RegName reg_s8 = 24;  RegName reg_s9 = 25;  RegName reg_s10 = 26; RegName reg_s11 = 27;

RegName reg_sp = 2;
RegName reg_tp = 4;

RegName reg_a0 = 10;  RegName reg_a1 = 11;  RegName reg_a2 = 12;  RegName reg_a3 = 13;
RegName reg_a4 = 14;  RegName reg_a5 = 15;  RegName reg_a6 = 16;  RegName reg_a7 = 17;

RegName reg_t0 = 5;   RegName reg_t1 = 6;   RegName reg_t2 = 7;   RegName reg_t3 = 28;
RegName reg_t4 = 29;  RegName reg_t5 = 30;  RegName reg_t6 = 31;

RegName reg_gp = 3;

String regNameABI[32] = {
   "zero", "ra", "sp",  "gp",  "tp", "t0", "t1", "t2",
   "s0",   "s1", "a0",  "a1",  "a2", "a3", "a4", "a5",
   "a6",   "a7", "s2",  "s3",  "s4", "s5", "s6", "s7",
   "s8",   "s9", "s10", "s11", "t3", "t4", "t5", "t6"
};

// ================================================================
// Data sizes for LOAD/STORE

typedef enum {
   BITS8,
   BITS16,
   BITS32
} Mem_Data_Size deriving(Eq, Bits, FShow);

Addr imemSt = 'h00000;
Addr dmemSt = 'h10000;

// ================================================================
// LOAD/STORE instructions

Bit#(2) f3_SIZE_B = 2'b00;
Bit#(2) f3_SIZE_H = 2'b01;
Bit#(2) f3_SIZE_W = 2'b10;
Bit#(2) f3_SIZE_D = 2'b11;

// ----------------
// Load instructions

Opcode op_LOAD = 7'b00_000_11;

Bit#(3) f3_LB  = 3'b000;
Bit#(3) f3_LH  = 3'b001;
Bit#(3) f3_LW  = 3'b010;
Bit#(3) f3_LD  = 3'b011;
Bit#(3) f3_LBU = 3'b100;
Bit#(3) f3_LHU = 3'b101;
Bit#(3) f3_LWU = 3'b110;

// ----------------
// Store instructions

Opcode op_STORE = 7'b01_000_11;

Bit#(3) f3_SB  = 3'b000;
Bit#(3) f3_SH  = 3'b001;
Bit#(3) f3_SW  = 3'b010;
Bit#(3) f3_SD  = 3'b011;

// ================================================================
// Memory Model

Opcode op_MISC_MEM = 7'b00_011_11;

Bit#(3) f3_FENCE   = 3'b000;
Bit#(3) f3_FENCE_I = 3'b001;

// ================================================================
// Integer Register-Immediate Instructions

Opcode op_OP_IMM = 7'b00_100_11;

Bit#(3) f3_ADDI  = 3'b000;
Bit#(3) f3_SLLI  = 3'b001;
Bit#(3) f3_SLTI  = 3'b010;
Bit#(3) f3_SLTIU = 3'b011;
Bit#(3) f3_XORI  = 3'b100;
Bit#(3) f3_SRxI  = 3'b101; Bit#(3) f3_SRLI  = 3'b101; Bit#(3) f3_SRAI  = 3'b101;
Bit#(3) f3_ORI   = 3'b110;
Bit#(3) f3_ANDI  = 3'b111;

// ================================================================
// Integer Register-Register Instructions

Opcode op_OP = 7'b01_100_11;

Bit#(10) f10_ADD    = 10'b000_0000_000;
Bit#(10) f10_SUB    = 10'b010_0000_000;
Bit#(10) f10_SLL    = 10'b000_0000_001;
Bit#(10) f10_SLT    = 10'b000_0000_010;
Bit#(10) f10_SLTU   = 10'b000_0000_011;
Bit#(10) f10_XOR    = 10'b000_0000_100;
Bit#(10) f10_SRL    = 10'b000_0000_101;
Bit#(10) f10_SRA    = 10'b010_0000_101;
Bit#(10) f10_OR     = 10'b000_0000_110;
Bit#(10) f10_AND    = 10'b000_0000_111;

Bit#(7) f7_MUL_DIV_REM = 7'b000_0001;

Bit#(3) f3_MUL    = 3'b000;
Bit#(3) f3_MULH   = 3'b001;
Bit#(3) f3_MULHSU = 3'b010;
Bit#(3) f3_MULHU  = 3'b011;
Bit#(3) f3_DIV    = 3'b100;
Bit#(3) f3_DIVU   = 3'b101;
Bit#(3) f3_REM    = 3'b110;
Bit#(3) f3_REMU   = 3'b111;

// ================================================================
// LUI, AUIPC

Opcode op_LUI   = 7'b01_101_11;
Opcode op_AUIPC = 7'b00_101_11;

// ================================================================
// Control transfer

Opcode  op_BRANCH = 7'b11_000_11;

Bit#(3) f3_BEQ   = 3'b000;
Bit#(3) f3_BNE   = 3'b001;
Bit#(3) f3_BLT   = 3'b100;
Bit#(3) f3_BGE   = 3'b101;
Bit#(3) f3_BLTU  = 3'b110;
Bit#(3) f3_BGEU  = 3'b111;

Opcode op_JAL  = 7'b11_011_11;

Opcode op_JALR = 7'b11_001_11;

// ================================================================
// System Instructions
Opcode op_SYSTEM = 7'b11_100_11;

// sub-opcodes: (in funct3 field)
Bit#(3)   f3_PRIV       = 3'b000;
Bit#(3)   f3_CSRRW      = 3'b001;
Bit#(3)   f3_CSRRS      = 3'b010;
Bit#(3)   f3_CSRRC      = 3'b011;
Bit#(3)   f3_CSRRWI     = 3'b101;
Bit#(3)   f3_CSRRSI     = 3'b110;
Bit#(3)   f3_CSRRCI     = 3'b111;

// Wait for Interrupt
Bit#(12) f12_WFI       = 12'b0001_0000_0010;

function Bool is_SYSTEM_PRIV(Instr instr);
   return(   (instr_opcode(instr) == op_SYSTEM)
          && (instr_funct3(instr) == f3_PRIV));
endfunction

// ================================================================
// Control/Status register addresses

typedef Bit#(12) CSR_Addr;

// ----------------
// User-level CSRs

CSR_Addr   csr_FFLAGS   = 'h001;    // Floating-point accrued exceptions
CSR_Addr   csr_FRM      = 'h002;    // Floating-point Dynamic Rounding Mode
CSR_Addr   csr_FCSR     = 'h003;    // Floating-point Control and Status Register

CSR_Addr   csr_CYCLE    = 'hc00;    // Cycle counter for RDCYCLE
CSR_Addr   csr_TIME     = 'hc01;    // Timer for RDTIME
CSR_Addr   csr_INSTRET  = 'hc02;    // Instructions retired, for RDINSTRET

CSR_Addr   csr_CYCLEH   = 'hc80;    // Upper 32 bits of CYCLE (RV32I only)
CSR_Addr   csr_TIMEH    = 'hc81;    // Upper 32 bits of TIME (RV32I only)
CSR_Addr   csr_INSTRETH = 'hc82;    // Upper 32 bits of INSTRET (RV32I only)

// ----------------
// Supervisor-level CSRs

CSR_Addr   csr_SSTATUS  = 'h100;    // status
CSR_Addr   csr_STVEC    = 'h101;    // trap handler base address
CSR_Addr   csr_SIE      = 'h104;    // interrupt-enable
CSR_Addr   csr_STIMECMP = 'h121;    // wall-clock timer compare value

CSR_Addr   csr_STIME    = 'hD01;    // wall-clock timer compare value
CSR_Addr   csr_STIMEH   = 'hD81;    // upper 32b of STIME (RV32I only)

CSR_Addr   csr_SSCRATCH = 'h140;    // scratch reg for supervisor trap handlers
CSR_Addr   csr_SEPC     = 'h141;    // exception program counter
CSR_Addr   csr_SCAUSE   = 'hD42;    // trap cause
CSR_Addr   csr_SBADADDR = 'hD43;    // bad address
CSR_Addr   csr_SIP      = 'h144;    // interrupt pending

CSR_Addr   csr_SPTBR    = 'h180;    // Page-table base register
CSR_Addr   csr_SASID    = 'h181;    // Address-space ID

CSR_Addr   csr_CYCLEW   = 'h900;    // CYCLE; writeable
CSR_Addr   csr_TIMEW    = 'h901;    // TIME, writeable
CSR_Addr   csr_INSTRETW = 'h902;    // INSTRET, writeable

CSR_Addr   csr_CYCLEHW  = 'h980;    // CYCLEH, writeable
CSR_Addr   csr_TIMEHW   = 'h981;    // TIMEH, writeable
CSR_Addr   csr_INSTRETHW= 'h982;    // INSTRETH, writeable

// ----------------
// Hypervisor-level CSRs

CSR_Addr   csr_HSTATUS  = 'h200;    // status
CSR_Addr   csr_HTVEC    = 'h201;    // trap handler base address
CSR_Addr   csr_HTDELEG  = 'h202;    // trap delegation
CSR_Addr   csr_HIE      = 'h204;    // interrupt-enable
CSR_Addr   csr_HTIMECMP = 'h221;    // wall-clock timer compare value

CSR_Addr   csr_HTIME    = 'hE01;    // wall-clock timer compare value
CSR_Addr   csr_HTIMEH   = 'hE81;    // upper 32b of HTIME (RV32I only)

CSR_Addr   csr_HSCRATCH = 'h240;    // scratch reg for hypervisor trap handlers
CSR_Addr   csr_HEPC     = 'h241;    // exception program counter
CSR_Addr   csr_HCAUSE   = 'h242;    // trap cause
CSR_Addr   csr_HBADADDR = 'h243;    // bad address

CSR_Addr   csr_STIMEW   = 'hA01;    // STIME writeable
CSR_Addr   csr_STIMEHW  = 'hA81;    // STIMEH, writeable

// ----------------
// Machine-level CSRs

CSR_Addr   csr_MCPUID   = 'hF00;    // CPU description
CSR_Addr   csr_MIMPID   = 'hF01;    // Vendor ID and version number
CSR_Addr   csr_MHARTID  = 'hF10;    // Hardware thread ID

CSR_Addr   csr_MSTATUS  = 'h300;    // status
CSR_Addr   csr_MTVEC    = 'h301;    // trap handler base address
CSR_Addr   csr_MTDELEG  = 'h302;    // trap delegation
CSR_Addr   csr_MIE      = 'h304;    // interrupt-enable
CSR_Addr   csr_MTIMECMP = 'h321;    // wall-clock timer compare value

CSR_Addr   csr_MTIME    = 'h701;    // wall-clock timer compare value
CSR_Addr   csr_MTIMEH   = 'h741;    // upper 32b of HTIME (RV32I only)

CSR_Addr   csr_MSCRATCH = 'h340;    // scratch reg for machine trap handlers
CSR_Addr   csr_MEPC     = 'h341;    // exception program counter
CSR_Addr   csr_MCAUSE   = 'h342;    // trap cause
CSR_Addr   csr_MBADADDR = 'h343;    // bad address
CSR_Addr   csr_MIP      = 'h344;    // interrupt pending

CSR_Addr   csr_MBASE    = 'h380;    // base
CSR_Addr   csr_MBOUND   = 'h381;    // bound
CSR_Addr   csr_MIBASE   = 'h382;    // instruction base
CSR_Addr   csr_MIBOUND  = 'h383;    // instruction bound
CSR_Addr   csr_MDBASE   = 'h384;    // data base
CSR_Addr   csr_MDBOUND  = 'h385;    // data bound

CSR_Addr   csr_HTIMEW   = 'hB01;    // HTIME writeable
CSR_Addr   csr_HTIMEHW  = 'hB81;    // HTIMEH, writeable

CSR_Addr   csr_DCSR     = 'h7B0;    // Test input / output register

// ----------------
// Bit-fields of the CSR_MSTATUS register

Integer mstatus_SD_index   = xlen-1;
Integer mstatus_VM_hi      = 21;        Integer mstatus_VM_lo      = 17;
Integer mstatus_MPRV_index = 16;
Integer mstatus_XS_hi      = 15;        Integer mstatus_XS_lo   = 14;
Integer mstatus_FS_hi      = 13;        Integer mstatus_FS_lo   = 12;
Integer mstatus_PRV3_hi    = 11;        Integer mstatus_PRV3_lo = 10;
Integer mstatus_IE3_index  =  9;
Integer mstatus_PRV2_hi    =  8;        Integer mstatus_PRV2_lo = 7;
Integer mstatus_IE2_index  =  6;
Integer mstatus_PRV1_hi    =  5;        Integer mstatus_PRV1_lo = 4;
Integer mstatus_IE1_index  =  3;
Integer mstatus_PRV_hi     =  2;        Integer mstatus_PRV_lo  = 1;
Integer mstatus_IE_index   =  0;

// ----------------
// Standard mtvec and reset vector values
// MTVEC reg can be hardwired to hi or lo value
// reset value should correspond.

Word mtvec_std_hi = (~ 'h01FF);    // = 0xFFFF_FFE00
Word mtvec_std_lo = 'h0100;

`ifdef MTVEC_STD_HI
   Word mtvec_reset_value = mtvec_std_hi;
`else
   Word mtvec_reset_value = mtvec_std_lo;
`endif

Word pc_reset_value = (mtvec_reset_value + 'h100);    // 'h0200 or 'hFFFF_FF00

// ----------------
// MIP and MIE fields (interrupt pending, interrupt enable)

// External interrupt
Integer mxi_index = 19;
Integer hxi_index = 18;
Integer sxi_index = 17;

// Timer interrupts
Integer mti_index = 7;
Integer hti_index = 6;
Integer sti_index = 5;    // Also in SIP reg

// Software interrupts
Integer msi_index = 3;
Integer hsi_index = 2;
Integer ssi_index = 1;    // Also in SIE reg

// ----------------
// MCAUSE (reason for exception)

Integer mcause_interrupt_index  = xlen - 1;
Integer mcause_zero_index       = 4;
Integer mcause_exc_code_hi      = 3;    Integer mcause_exc_code_lo   = 0;

typedef Bit#(4) Exc_Code;

// When Interrupt = 0 (trap)

Exc_Code exc_code_MISALIGNED_FETCH     = 4'h0;
Exc_Code exc_code_FAULT_FETCH          = 4'h1;
Exc_Code exc_code_ILLEGAL_INSTRUCTION  = 4'h2;
Exc_Code exc_code_BREAKPOINT           = 4'h3;

Exc_Code exc_code_MISALIGNED_LOAD      = 4'h4;
Exc_Code exc_code_FAULT_LOAD           = 4'h5;

Exc_Code exc_code_MISALIGNED_STORE_AMO = 4'h6;
Exc_Code exc_code_FAULT_STORE_AMO      = 4'h7;

Exc_Code exc_code_ECALL_FROM_U         = 4'h8;
Exc_Code exc_code_ECALL_FROM_S         = 4'h9;
Exc_Code exc_code_ECALL_FROM_H         = 4'hA;
Exc_Code exc_code_ECALL_FROM_M         = 4'hB;

// When Interrupt = 1 (interrupt)

Exc_Code exc_code_SW_INTERRUPT         = 4'h0;
Exc_Code exc_code_TIMER_INTERRUPT      = 4'h1;

Maybe#(Exc_Code) m_trap_none           = tagged Invalid;
Maybe#(Exc_Code) m_trap_illegal_instr  = tagged Valid exc_code_ILLEGAL_INSTRUCTION;

function Action show_Trap_Exc_Code (Exc_Code exc);
   action
      case (exc)
         exc_code_MISALIGNED_FETCH:     $write("MISALIGNED_FETCH");
         exc_code_FAULT_FETCH:          $write("FAULT_FETCH");
         exc_code_ILLEGAL_INSTRUCTION:  $write("ILLEGAL_INSTRUCTION");
         exc_code_BREAKPOINT:           $write("BREAKPOINT");
         exc_code_MISALIGNED_LOAD:      $write("MISALIGNED_LOAD");
         exc_code_FAULT_LOAD:           $write("FAULT_LOAD");
         exc_code_MISALIGNED_STORE_AMO: $write("MISALIGNED_STORE_AMO");
         exc_code_FAULT_STORE_AMO:      $write("FAULT_STORE_AMO");
         exc_code_ECALL_FROM_U:         $write("ECALL_FROM_U");
         exc_code_ECALL_FROM_S:         $write("ECALL_FROM_S");
         exc_code_ECALL_FROM_H:         $write("ECALL_FROM_H");
         exc_code_ECALL_FROM_M:         $write("ECALL_FROM_M");
         default:                       $write("unknown Exc_Code 0x%0h", exc);
      endcase
   endaction
endfunction

// ----------------
// Bit-fields of the CSR_SSTATUS register

function bit                  sstatus_sd     (Word sstatus_val); return sstatus_val[xlen-1]; endfunction
function Bit#(TSub#(XLEN,18)) sstatus_mbz_17 (Word sstatus_val); return sstatus_val [xlen-2:17]; endfunction
function bit                  sstatus_mprv   (Word sstatus_val); return sstatus_val[16]; endfunction
function Bit#(2)              sstatus_xs     (Word sstatus_val); return sstatus_val[15:14]; endfunction
function Bit#(2)              sstatus_fs     (Word sstatus_val); return sstatus_val[13:12]; endfunction
function Bit#(7)              sstatus_mbz_5  (Word sstatus_val); return sstatus_val[11:5]; endfunction
function bit                  sstatus_ps     (Word sstatus_val); return sstatus_val[4]; endfunction
function bit                  sstatus_pie    (Word sstatus_val); return sstatus_val[3]; endfunction
function Bit#(2)              sstatus_mbz_1  (Word sstatus_val); return sstatus_val[2:1]; endfunction
function bit                  sstatus_ie     (Word sstatus_val); return sstatus_val[0]; endfunction

// ----------------
// SCAUSE (reason for exception)

function bit scause_interrupt(Word scause_val); return scause_val[xlen-1]; endfunction
function Bit#(TSub#(XLEN,5)) scause_mbz_5(Word scause_val); return scause_val[xlen-2:4]; endfunction
function Bit#(4) scause_exception_code(Word scause_val); return scause_val[3:0]; endfunction

// ================================================================

endpackage

// Copyright (c) 2017 Min Chen. All Rights Reserved
// Author: Min Chen

// ================================================================
// ISA defs for UC Berkeley RISC V
//
// References (from riscv.org):
//   "The RISC-V Instruction Set Manual
//    Volume I: User-Level ISA, Version 2.2, May 7, 2017"
//    Waterman, Lee, Patterson and Asanovic
//
//   "The RISC-V Instruction Set Manual
//    Volume II: Privileged Architecture, Version 1.10, May 7, 2017"
//    Waterman, Lee, Avizienis, Patterson and Asanovic
//
// ================================================================

package ISA_Decls;

// ================================================================
// BSV library imports

import DefaultValue :: *;
import Vector       :: *;
import BuildVector  :: *;

// ================================================================
// BSV project imports

// None

// ================================================================

typedef 32 XLEN;

typedef TMul#(2, XLEN)  XLEN_2;     // Double-width for multiplications
Integer xlen = valueOf(XLEN);

// ----------------

typedef  8  Bits_per_Byte;

typedef  Bit#(XLEN)  Word;          // Raw (unsigned) register data
typedef  Int#(XLEN)  Word_S;        // Signed register data

typedef  Word        Addr;          // addresses/pointers

typedef TDiv#(XLEN, Bits_per_Byte)  Bytes_per_Word;
typedef TLog#(Bytes_per_Word)       Bits_per_Word_Byte_Index;

// ================================================================
// Instruction fields

typedef  Bit#(32)    Instr;
typedef  Bit#(7)     Opcode;
typedef  Bit#(5)     RegName;       // 32 registers, 0..31
typedef  32          NumRegs;
Integer  numRegs = valueOf(NumRegs);

function  Opcode     instr_opcode (Instr x); return x[6:0]; endfunction

function  Bit#(3)    instr_funct3 (Instr x); return x[14:12]; endfunction
function  Bit#(5)    instr_funct5 (Instr x); return x[31:27]; endfunction
function  Bit#(7)    instr_funct7 (Instr x); return x[31:25]; endfunction
function  Bit#(10)   instr_funct10(Instr x); return { x[31:25], x[14:12] }; endfunction

function  RegName    instr_rd     (Instr x); return x[11:7]; endfunction
function  RegName    instr_rs1    (Instr x); return x[19:15]; endfunction
function  RegName    instr_rs2    (Instr x); return x[24:20]; endfunction
function  RegName    instr_rs3    (Instr x); return x[31:27]; endfunction     // {F,D} Extension
function  CSR_Addr   instr_csr    (Instr x); return unpack(x[31:20]); endfunction

function  Bit#(12)   instr_I_imm12 (Instr x); return x[31:20]; endfunction
function  Bit#(12)   instr_S_imm12 (Instr x); return { x[31:25], x[11:7] }; endfunction
function  Bit#(13)   instr_SB_imm13(Instr x); return { x[31], x[7], x[30:25], x[11:8], 1'b0 }; endfunction
function  Bit#(20)   instr_U_imm20 (Instr x); return x[31:12]; endfunction
function  Bit#(21)   instr_UJ_imm21(Instr x); return { x[31], x[19:12], x[20], x[30:21], 1'b0 }; endfunction

// For FENCE decode
function  Bit#(4)   instr_pred(Instr x); return x[27:24]; endfunction
function  Bit#(4)   instr_succ(Instr x); return x[23:20]; endfunction

// For AMO decode
function  Bit#(2)   instr_aqrl(Instr x); return x[26:25]; endfunction

// ----------------
// Decoded instructions

typedef struct {
   Opcode   opcode;

   RegName  rd;
   RegName  rs1;
   RegName  rs2;
   RegName  rs3;
   CSR_Addr csr;

   Bit#(3)  funct3;
   Bit#(5)  funct5;
   Bit#(7)  funct7;
   Bit#(10) funct10;

   Bit#(12) imm12_I;
   Bit#(12) imm12_S;
   Bit#(13) imm13_SB;
   Bit#(20) imm20_U;
   Bit#(21) imm21_UJ;

   //Bit#(4)  pred;
   //Bit#(4)  succ;

   //Bit#(2)  aqrl;

   Addr     pc;
} Decoded_Instr deriving(FShow, Bits);

function Decoded_Instr fv_decode(Addr _pc, Instr instr);
   return Decoded_Instr {
            opcode:     instr_opcode   (instr),
            rd:         instr_rd       (instr),
            rs1:        instr_rs1      (instr),
            rs2:        instr_rs2      (instr),
            rs3:        instr_rs3      (instr),
            csr:        instr_csr      (instr),

            funct3:     instr_funct3   (instr),
            funct5:     instr_funct5   (instr),
            funct7:     instr_funct7   (instr),
            funct10:    instr_funct10  (instr),

            imm12_I:    instr_I_imm12  (instr),
            imm12_S:    instr_S_imm12  (instr),
            imm13_SB:   instr_SB_imm13 (instr),
            imm20_U:    instr_U_imm20  (instr),
            imm21_UJ:   instr_UJ_imm21 (instr),

            //pred:      instr_pred     (instr),
            //succ:      instr_succ     (instr),

            //aqrl:      instr_aqrl     (instr),
            pc:         _pc
          };
endfunction

// ----------------
// Write Back Stage

typedef union tagged {
   Word     Value;
   Bit#(3)  Funct3;
} Exec2WbValue_t deriving(Bits);

typedef struct {
   RegName  rd;
   Exec2WbValue_t rd_value;
} Exec2Wb_t deriving(Bits);

// ================================================================
// Symbolic register names

RegName x0  =  0;    RegName x1  =  1;    RegName x2  =  2;    RegName x3  =  3;
RegName x4  =  4;    RegName x5  =  5;    RegName x6  =  6;    RegName x7  =  7;
RegName x8  =  8;    RegName x9  =  9;    RegName x10 = 10;    RegName x11 = 11;
RegName x12 = 12;    RegName x13 = 13;    RegName x14 = 14;    RegName x15 = 15;
RegName x16 = 16;    RegName x17 = 17;    RegName x18 = 18;    RegName x19 = 19;
RegName x20 = 20;    RegName x21 = 21;    RegName x22 = 22;    RegName x23 = 23;
RegName x24 = 24;    RegName x25 = 25;    RegName x26 = 26;    RegName x27 = 27;
RegName x28 = 28;    RegName x29 = 29;    RegName x30 = 30;    RegName x31 = 31;

// Register names used in calling convention

RegName reg_ra = 1;

RegName reg_s0 = 8;   RegName reg_s1 = 9;   RegName reg_s2  = 18; RegName reg_s3  = 19;
RegName reg_s4 = 20;  RegName reg_s5 = 21;  RegName reg_s6  = 22; RegName reg_s7  = 23;
RegName reg_s8 = 24;  RegName reg_s9 = 25;  RegName reg_s10 = 26; RegName reg_s11 = 27;

RegName reg_sp = 2;
RegName reg_tp = 4;

RegName reg_a0 = 10;  RegName reg_a1 = 11;  RegName reg_a2 = 12;  RegName reg_a3 = 13;
RegName reg_a4 = 14;  RegName reg_a5 = 15;  RegName reg_a6 = 16;  RegName reg_a7 = 17;

RegName reg_t0 = 5;   RegName reg_t1 = 6;   RegName reg_t2 = 7;   RegName reg_t3 = 28;
RegName reg_t4 = 29;  RegName reg_t5 = 30;  RegName reg_t6 = 31;

RegName reg_gp = 3;

String regNameABI[32] = {
   "zero", "ra", "sp",  "gp",  "tp", "t0", "t1", "t2",
   "s0",   "s1", "a0",  "a1",  "a2", "a3", "a4", "a5",
   "a6",   "a7", "s2",  "s3",  "s4", "s5", "s6", "s7",
   "s8",   "s9", "s10", "s11", "t3", "t4", "t5", "t6"
};

// ================================================================
// Data sizes for LOAD/STORE

typedef enum {
   BITS8,
   BITS16,
   BITS32
} Mem_Data_Size deriving(Eq, Bits, FShow);

Addr imemSt = 'h00000;
Addr dmemSt = 'h10000;

// ================================================================
// LOAD/STORE instructions

Bit#(2) f3_SIZE_B = 2'b00;
Bit#(2) f3_SIZE_H = 2'b01;
Bit#(2) f3_SIZE_W = 2'b10;
Bit#(2) f3_SIZE_D = 2'b11;

// ----------------
// Load instructions

Opcode op_LOAD = 7'b00_000_11;

Bit#(3) f3_LB  = 3'b000;
Bit#(3) f3_LH  = 3'b001;
Bit#(3) f3_LW  = 3'b010;
Bit#(3) f3_LD  = 3'b011;
Bit#(3) f3_LBU = 3'b100;
Bit#(3) f3_LHU = 3'b101;
Bit#(3) f3_LWU = 3'b110;

// ----------------
// Store instructions

Opcode op_STORE = 7'b01_000_11;

Bit#(3) f3_SB  = 3'b000;
Bit#(3) f3_SH  = 3'b001;
Bit#(3) f3_SW  = 3'b010;
Bit#(3) f3_SD  = 3'b011;

// ================================================================
// Memory Model

Opcode op_MISC_MEM = 7'b00_011_11;

Bit#(3) f3_FENCE   = 3'b000;
Bit#(3) f3_FENCE_I = 3'b001;

// ================================================================
// Integer Register-Immediate Instructions

Opcode op_OP_IMM = 7'b00_100_11;

Bit#(3) f3_ADDI  = 3'b000;
Bit#(3) f3_SLLI  = 3'b001;
Bit#(3) f3_SLTI  = 3'b010;
Bit#(3) f3_SLTIU = 3'b011;
Bit#(3) f3_XORI  = 3'b100;
Bit#(3) f3_SRxI  = 3'b101; Bit#(3) f3_SRLI  = 3'b101; Bit#(3) f3_SRAI  = 3'b101;
Bit#(3) f3_ORI   = 3'b110;
Bit#(3) f3_ANDI  = 3'b111;

// ================================================================
// Integer Register-Register Instructions

Opcode op_OP = 7'b01_100_11;

Bit#(10) f10_ADD    = 10'b000_0000_000;
Bit#(10) f10_SUB    = 10'b010_0000_000;
Bit#(10) f10_SLL    = 10'b000_0000_001;
Bit#(10) f10_SLT    = 10'b000_0000_010;
Bit#(10) f10_SLTU   = 10'b000_0000_011;
Bit#(10) f10_XOR    = 10'b000_0000_100;
Bit#(10) f10_SRL    = 10'b000_0000_101;
Bit#(10) f10_SRA    = 10'b010_0000_101;
Bit#(10) f10_OR     = 10'b000_0000_110;
Bit#(10) f10_AND    = 10'b000_0000_111;

Bit#(7) f7_MUL_DIV_REM = 7'b000_0001;

Bit#(3) f3_MUL    = 3'b000;
Bit#(3) f3_MULH   = 3'b001;
Bit#(3) f3_MULHSU = 3'b010;
Bit#(3) f3_MULHU  = 3'b011;
Bit#(3) f3_DIV    = 3'b100;
Bit#(3) f3_DIVU   = 3'b101;
Bit#(3) f3_REM    = 3'b110;
Bit#(3) f3_REMU   = 3'b111;

// ================================================================
// LUI, AUIPC

Opcode op_LUI   = 7'b01_101_11;
Opcode op_AUIPC = 7'b00_101_11;

// ================================================================
// Control transfer

Opcode  op_BRANCH = 7'b11_000_11;

Bit#(3) f3_BEQ   = 3'b000;
Bit#(3) f3_BNE   = 3'b001;
Bit#(3) f3_BLT   = 3'b100;
Bit#(3) f3_BGE   = 3'b101;
Bit#(3) f3_BLTU  = 3'b110;
Bit#(3) f3_BGEU  = 3'b111;

Opcode op_JAL  = 7'b11_011_11;

Opcode op_JALR = 7'b11_001_11;

// ================================================================
// System Instructions
Opcode op_SYSTEM = 7'b11_100_11;

Instr break_instr = { f12_EBREAK, 5'b00000, 3'b000, 5'b00000, op_SYSTEM };

// sub-opcodes: (in funct3 field)
Bit#(3)   f3_PRIV       = 3'b000;
Bit#(3)   f3_CSRRW      = 3'b001;
Bit#(3)   f3_CSRRS      = 3'b010;
Bit#(3)   f3_CSRRC      = 3'b011;
Bit#(3)   f3_CSRRWI     = 3'b101;
Bit#(3)   f3_CSRRSI     = 3'b110;
Bit#(3)   f3_CSRRCI     = 3'b111;

// Wait for Interrupt
Bit#(12) f12_WFI       = 12'b0001_0000_0010;

function Bool is_SYSTEM_PRIV(Instr instr);
   return(   (instr_opcode(instr) == op_SYSTEM)
          && (instr_funct3(instr) == f3_PRIV));
endfunction

// ================================================================
// Control/Status register addresses

typedef Bit#(12) CSR_Addr;

// ----------------
// User-level CSRs

CSR_Addr   csr_FFLAGS   = 'h001;    // Floating-point accrued exceptions
CSR_Addr   csr_FRM      = 'h002;    // Floating-point Dynamic Rounding Mode
CSR_Addr   csr_FCSR     = 'h003;    // Floating-point Control and Status Register

CSR_Addr   csr_CYCLE    = 'hc00;    // Cycle counter for RDCYCLE
CSR_Addr   csr_TIME     = 'hc01;    // Timer for RDTIME
CSR_Addr   csr_INSTRET  = 'hc02;    // Instructions retired, for RDINSTRET

CSR_Addr   csr_CYCLEH   = 'hc80;    // Upper 32 bits of CYCLE (RV32I only)
CSR_Addr   csr_TIMEH    = 'hc81;    // Upper 32 bits of TIME (RV32I only)
CSR_Addr   csr_INSTRETH = 'hc82;    // Upper 32 bits of INSTRET (RV32I only)

// ----------------
// Supervisor-level CSRs

CSR_Addr   csr_SSTATUS  = 'h100;    // status
CSR_Addr   csr_STVEC    = 'h101;    // trap handler base address
CSR_Addr   csr_SIE      = 'h104;    // interrupt-enable
CSR_Addr   csr_STIMECMP = 'h121;    // wall-clock timer compare value

CSR_Addr   csr_STIME    = 'hD01;    // wall-clock timer compare value
CSR_Addr   csr_STIMEH   = 'hD81;    // upper 32b of STIME (RV32I only)

CSR_Addr   csr_SSCRATCH = 'h140;    // scratch reg for supervisor trap handlers
CSR_Addr   csr_SEPC     = 'h141;    // exception program counter
CSR_Addr   csr_SCAUSE   = 'hD42;    // trap cause
CSR_Addr   csr_SBADADDR = 'hD43;    // bad address
CSR_Addr   csr_SIP      = 'h144;    // interrupt pending

CSR_Addr   csr_SPTBR    = 'h180;    // Page-table base register
CSR_Addr   csr_SASID    = 'h181;    // Address-space ID

CSR_Addr   csr_CYCLEW   = 'h900;    // CYCLE; writeable
CSR_Addr   csr_TIMEW    = 'h901;    // TIME, writeable
CSR_Addr   csr_INSTRETW = 'h902;    // INSTRET, writeable

CSR_Addr   csr_CYCLEHW  = 'h980;    // CYCLEH, writeable
CSR_Addr   csr_TIMEHW   = 'h981;    // TIMEH, writeable
CSR_Addr   csr_INSTRETHW= 'h982;    // INSTRETH, writeable

// ----------------
// Hypervisor-level CSRs

CSR_Addr   csr_HSTATUS  = 'h200;    // status
CSR_Addr   csr_HTVEC    = 'h201;    // trap handler base address
CSR_Addr   csr_HTDELEG  = 'h202;    // trap delegation
CSR_Addr   csr_HIE      = 'h204;    // interrupt-enable
CSR_Addr   csr_HTIMECMP = 'h221;    // wall-clock timer compare value

CSR_Addr   csr_HTIME    = 'hE01;    // wall-clock timer compare value
CSR_Addr   csr_HTIMEH   = 'hE81;    // upper 32b of HTIME (RV32I only)

CSR_Addr   csr_HSCRATCH = 'h240;    // scratch reg for hypervisor trap handlers
CSR_Addr   csr_HEPC     = 'h241;    // exception program counter
CSR_Addr   csr_HCAUSE   = 'h242;    // trap cause
CSR_Addr   csr_HBADADDR = 'h243;    // bad address

CSR_Addr   csr_STIMEW   = 'hA01;    // STIME writeable
CSR_Addr   csr_STIMEHW  = 'hA81;    // STIMEH, writeable

// ----------------
// Machine-level CSRs

CSR_Addr   csr_MCPUID   = 'hF00;    // CPU description
CSR_Addr   csr_MIMPID   = 'hF01;    // Vendor ID and version number
CSR_Addr   csr_MHARTID  = 'hF10;    // Hardware thread ID

CSR_Addr   csr_MSTATUS  = 'h300;    // status
CSR_Addr   csr_MTVEC    = 'h301;    // trap handler base address
CSR_Addr   csr_MTDELEG  = 'h302;    // trap delegation
CSR_Addr   csr_MIE      = 'h304;    // interrupt-enable
CSR_Addr   csr_MTIMECMP = 'h321;    // wall-clock timer compare value

CSR_Addr   csr_MTIME    = 'h701;    // wall-clock timer compare value
CSR_Addr   csr_MTIMEH   = 'h741;    // upper 32b of HTIME (RV32I only)

CSR_Addr   csr_MSCRATCH = 'h340;    // scratch reg for machine trap handlers
CSR_Addr   csr_MEPC     = 'h341;    // exception program counter
CSR_Addr   csr_MCAUSE   = 'h342;    // trap cause
CSR_Addr   csr_MBADADDR = 'h343;    // bad address
CSR_Addr   csr_MIP      = 'h344;    // interrupt pending

CSR_Addr   csr_MBASE    = 'h380;    // base
CSR_Addr   csr_MBOUND   = 'h381;    // bound
CSR_Addr   csr_MIBASE   = 'h382;    // instruction base
CSR_Addr   csr_MIBOUND  = 'h383;    // instruction bound
CSR_Addr   csr_MDBASE   = 'h384;    // data base
CSR_Addr   csr_MDBOUND  = 'h385;    // data bound

CSR_Addr   csr_HTIMEW   = 'hB01;    // HTIME writeable
CSR_Addr   csr_HTIMEHW  = 'hB81;    // HTIMEH, writeable

CSR_Addr   csr_DCSR     = 'h7B0;    // Test input / output register

// ----------------
// Bit-fields of the CSR_MSTATUS register

Integer mstatus_SD_index   = xlen-1;
Integer mstatus_VM_hi      = 21;        Integer mstatus_VM_lo      = 17;
Integer mstatus_MPRV_index = 16;
Integer mstatus_XS_hi      = 15;        Integer mstatus_XS_lo   = 14;
Integer mstatus_FS_hi      = 13;        Integer mstatus_FS_lo   = 12;
Integer mstatus_PRV3_hi    = 11;        Integer mstatus_PRV3_lo = 10;
Integer mstatus_IE3_index  =  9;
Integer mstatus_PRV2_hi    =  8;        Integer mstatus_PRV2_lo = 7;
Integer mstatus_IE2_index  =  6;
Integer mstatus_PRV1_hi    =  5;        Integer mstatus_PRV1_lo = 4;
Integer mstatus_IE1_index  =  3;
Integer mstatus_PRV_hi     =  2;        Integer mstatus_PRV_lo  = 1;
Integer mstatus_IE_index   =  0;

// ----------------
// Standard mtvec and reset vector values
// MTVEC reg can be hardwired to hi or lo value
// reset value should correspond.

Word mtvec_std_hi = (~ 'h01FF);    // = 0xFFFF_FFE00
Word mtvec_std_lo = 'h0100;

`ifdef MTVEC_STD_HI
   Word mtvec_reset_value = mtvec_std_hi;
`else
   Word mtvec_reset_value = mtvec_std_lo;
`endif

Word pc_reset_value = (mtvec_reset_value + 'h100);    // 'h0200 or 'hFFFF_FF00

// ----------------
// MIP and MIE fields (interrupt pending, interrupt enable)

// External interrupt
Integer mxi_index = 19;
Integer hxi_index = 18;
Integer sxi_index = 17;

// Timer interrupts
Integer mti_index = 7;
Integer hti_index = 6;
Integer sti_index = 5;    // Also in SIP reg

// Software interrupts
Integer msi_index = 3;
Integer hsi_index = 2;
Integer ssi_index = 1;    // Also in SIE reg

// ----------------
// MCAUSE (reason for exception)

Integer mcause_interrupt_index  = xlen - 1;
Integer mcause_zero_index       = 4;
Integer mcause_exc_code_hi      = 3;    Integer mcause_exc_code_lo   = 0;

typedef Bit#(4) Exc_Code;

// When Interrupt = 0 (trap)

Exc_Code exc_code_MISALIGNED_FETCH     = 4'h0;
Exc_Code exc_code_FAULT_FETCH          = 4'h1;
Exc_Code exc_code_ILLEGAL_INSTRUCTION  = 4'h2;
Exc_Code exc_code_BREAKPOINT           = 4'h3;

Exc_Code exc_code_MISALIGNED_LOAD      = 4'h4;
Exc_Code exc_code_FAULT_LOAD           = 4'h5;

Exc_Code exc_code_MISALIGNED_STORE_AMO = 4'h6;
Exc_Code exc_code_FAULT_STORE_AMO      = 4'h7;

Exc_Code exc_code_ECALL_FROM_U         = 4'h8;
Exc_Code exc_code_ECALL_FROM_S         = 4'h9;
Exc_Code exc_code_ECALL_FROM_H         = 4'hA;
Exc_Code exc_code_ECALL_FROM_M         = 4'hB;

// When Interrupt = 1 (interrupt)

Exc_Code exc_code_SW_INTERRUPT         = 4'h0;
Exc_Code exc_code_TIMER_INTERRUPT      = 4'h1;

Maybe#(Exc_Code) m_trap_none           = tagged Invalid;
Maybe#(Exc_Code) m_trap_illegal_instr  = tagged Valid exc_code_ILLEGAL_INSTRUCTION;

function Action show_Trap_Exc_Code (Exc_Code exc);
   action
      case (exc)
         exc_code_MISALIGNED_FETCH:     $write("MISALIGNED_FETCH");
         exc_code_FAULT_FETCH:          $write("FAULT_FETCH");
         exc_code_ILLEGAL_INSTRUCTION:  $write("ILLEGAL_INSTRUCTION");
         exc_code_BREAKPOINT:           $write("BREAKPOINT");
         exc_code_MISALIGNED_LOAD:      $write("MISALIGNED_LOAD");
         exc_code_FAULT_LOAD:           $write("FAULT_LOAD");
         exc_code_MISALIGNED_STORE_AMO: $write("MISALIGNED_STORE_AMO");
         exc_code_FAULT_STORE_AMO:      $write("FAULT_STORE_AMO");
         exc_code_ECALL_FROM_U:         $write("ECALL_FROM_U");
         exc_code_ECALL_FROM_S:         $write("ECALL_FROM_S");
         exc_code_ECALL_FROM_H:         $write("ECALL_FROM_H");
         exc_code_ECALL_FROM_M:         $write("ECALL_FROM_M");
         default:                       $write("unknown Exc_Code 0x%0h", exc);
      endcase
   endaction
endfunction

// ----------------
// Bit-fields of the CSR_SSTATUS register

function bit                  sstatus_sd     (Word sstatus_val); return sstatus_val[xlen-1]; endfunction
function Bit#(TSub#(XLEN,18)) sstatus_mbz_17 (Word sstatus_val); return sstatus_val [xlen-2:17]; endfunction
function bit                  sstatus_mprv   (Word sstatus_val); return sstatus_val[16]; endfunction
function Bit#(2)              sstatus_xs     (Word sstatus_val); return sstatus_val[15:14]; endfunction
function Bit#(2)              sstatus_fs     (Word sstatus_val); return sstatus_val[13:12]; endfunction
function Bit#(7)              sstatus_mbz_5  (Word sstatus_val); return sstatus_val[11:5]; endfunction
function bit                  sstatus_ps     (Word sstatus_val); return sstatus_val[4]; endfunction
function bit                  sstatus_pie    (Word sstatus_val); return sstatus_val[3]; endfunction
function Bit#(2)              sstatus_mbz_1  (Word sstatus_val); return sstatus_val[2:1]; endfunction
function bit                  sstatus_ie     (Word sstatus_val); return sstatus_val[0]; endfunction

// ----------------
// SCAUSE (reason for exception)

function bit scause_interrupt(Word scause_val); return scause_val[xlen-1]; endfunction
function Bit#(TSub#(XLEN,5)) scause_mbz_5(Word scause_val); return scause_val[xlen-2:4]; endfunction
function Bit#(4) scause_exception_code(Word scause_val); return scause_val[3:0]; endfunction

// ================================================================

endpackage


reduce critical path in mkMemSlaveEngine

Change-Id: I1f09a818f0ba8520556000912116ac35df625ec1

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;

import AxiMasterSlave :: *;

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface MemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8));

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpWriteHeaderFifo <- mkFIFOF;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
    MIMO#(4,busWidthWords,8,Bit#(32)) completionMimo <- mkMIMO(mimoCfg);
    MIMO#(4,busWidthWords,8,TLPTag) completionTagMimo <- mkMIMO(mimoCfg);
    MIMO#(busWidthWords,4,8,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    Reg#(Bit#(9)) writeBurstCount <- mkReg(0);
    Reg#(TLPLength)  writeDwCount <- mkReg(0);
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    function Integer tlpWordCount(TLPData#(16) tlp);
       if (tlp.be == 16'h0000)
	  return 0;
       else if (tlp.be == 16'h000f || tlp.be == 16'hf000)
	  return 1;
       else if (tlp.be == 16'h00ff || tlp.be == 16'hff00)
	  return 2;
       else if (tlp.be == 16'h0fff || tlp.be == 16'hfff0)
	  return 3;
       else if (tlp.be == 16'hffff)
	  return 4;
       else
	  return 0;
    endfunction

   rule writeHeaderTlp if (!writeInProgress);
      let tlp = tlpWriteHeaderFifo.first;

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);
      TLPLength dwCount = hdr_4dw.length;

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      Bool sendit = False;
      if (hdr_3dw.format == MEM_WRITE_3DW_DATA && writeDataMimo.deqReadyN(1)) begin
	 dwCount = hdr_3dw.length;
	 Vector#(4, Bit#(32)) v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
	 tlp.be = 16'hffff;
	 if (dwCount == 1)
	    tlp.eof = True;
	 dwCount = dwCount - 1;
	 tlp.data = pack(hdr_3dw);
	 sendit = True;
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA) begin
	 // retry until the data is available in writeDataMimo
      end
      if (hdr_4dw.format == MEM_WRITE_4DW_DATA && writeDataMimo.deqReadyN(1)) begin
	 tlp.be = 16'hffff;
	 sendit = True;
      end
      else if (hdr_4dw.format == MEM_WRITE_4DW_DATA) begin
	 sendit = False;
      end
      else begin
	 sendit = True;
      end
      if (sendit) begin
	 tlpWriteHeaderFifo.deq();
	 tlpOutFifo.enq(tlp);
	 $display("writeHeaderTlp dwCount=%d", dwCount);
	 writeDwCount <= dwCount;
	 writeInProgress <= (dwCount != 0);
	 if (dwCount == 0) begin
	    doneTag.enq(writeTag.first());
	    writeTag.deq();
	 end
      end
   endrule

   rule writeTlps if (writeInProgress);
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);
      Bool sendit = False;
      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      if (writeDwCount > 4 && writeDataMimo.deqReadyN(4)) begin
	 v = writeDataMimo.first();

	 writeDataMimo.deq(4);
	 writeDwCount <= writeDwCount - 4;
	 tlp.eof = False;
	 tlp.be = 16'hffff;
	 sendit = True;
      end
      else if (writeDwCount <= 4 && writeDataMimo.deqReadyN(unpack(truncate(writeDwCount)))) begin
	 v = writeDataMimo.first();
	 writeDataMimo.deq(unpack(truncate(writeDwCount)));
	 writeDwCount <= 0;
	 writeInProgress <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 $display("writeDwCount=%d will be zero", writeDwCount);
	 tlp.eof = True;
	 if (writeDwCount == 4)
	    tlp.be = 16'hffff;
	 else if (writeDwCount == 3)
	    tlp.be = 16'hfff0;
	 else if (writeDwCount == 2)
	    tlp.be = 16'hff00;
	 else if (writeDwCount == 1)
	    tlp.be = 16'hf000;
	 sendit = True;
      end
      else begin
	 // wait for more data in writeDataMimo
	 $display("waiting for more data dwCount=%d count=%d writeBurstCount=%d enqReady=%d",
	    writeDwCount, writeDataMimo.count(), writeBurstCount, writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));
      end
      if (sendit) begin
	 for (Integer i = 0; i < 4; i = i + 1)
	    tlp.data[(i+1)*32-1:i*32] = byteSwap(v[3-i]);
	 tlpOutFifo.enq(tlp);
      end
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   rule handleTlpIn;
      let tlp = tlpInFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);

      if (!tlp.sof) begin
	 let count = tlpWordCount(tlp);
	 // if sof is false, then count will be at least 1
	 function Bit#(32) f(Integer i);
	    begin
	       if (i < count)
		  return tlpvec[3-i];
	       else
		  return 32'hbad0beef;
	    end
	 endfunction
	 vec = genWith(f);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReadyN(fromInteger(count))
	    && completionTagMimo.enqReadyN(fromInteger(count)))
	    begin
	       completionMimo.enq(fromInteger(count), vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(fromInteger(count), tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReadyN(1)
	       && completionTagMimo.enqReadyN(1)) begin
	    vec[0] = hdr_3dw.data;
	    completionMimo.enq(1, vec);
            TLPTag tag = hdr_completion.tag;
	    lastTag <= tag;
	    completionTagMimo.enq(1, replicate(tag));
	    handled = True;
      end
      //$display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled)
	 tlpInFifo.deq();
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface MemSlave slave;
   interface MemWriteServer write_server;
      interface Put writeReq;
         method Action put(MemRequest#(40) req)
	      if (writeBurstCount == 0);

	      let burstLen = req.burstLen >> beat_shift;
	      let addr = req.addr;
	      let awid = req.tag;

	      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*(extend(burstLen));
	      TLPData#(16) tlp = defaultValue;
	      tlp.sof = True;
	      tlp.eof = False;
	      tlp.hit = 7'h00;
	      tlp.be = 16'hffff;

	      $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	      if ((addr >> 32) != 0) begin
		 TLPMemory4DWHeader hdr_4dw = defaultValue;
		 hdr_4dw.format = MEM_WRITE_4DW_DATA;
		 hdr_4dw.tag = extend(awid);
		 hdr_4dw.reqid = my_id;
		 hdr_4dw.nosnoop = SNOOPING_REQD;
		 hdr_4dw.addr = addr[40-1:2];
		 hdr_4dw.length = tlplen;
		 hdr_4dw.firstbe = 4'hf;
		 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
		 tlp.data = pack(hdr_4dw);
	      end
	      else begin
		 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
		 hdr_3dw.format = MEM_WRITE_3DW_DATA;
		 hdr_3dw.tag = extend(awid);
		 hdr_3dw.reqid = my_id;
		 hdr_3dw.nosnoop = SNOOPING_REQD;
		 hdr_3dw.addr = addr[32-1:2];
		 hdr_3dw.length = tlplen;
		 hdr_3dw.firstbe = 4'hf;
		 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

		 tlp.be = 16'hfff0; // no data word in this TLP

		 tlp.data = pack(hdr_3dw);
	      end
	      tlpWriteHeaderFifo.enq(tlp);
	      writeBurstCount <= zeroExtend(burstLen);
	      writeTag.enq(extend(awid));
           endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeBurstCount > 0 && writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	      writeBurstCount <= writeBurstCount - 1;
	      Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	      writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
           endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(ObjectTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface MemReadServer read_server;
      interface Put readReq;
         method Action put(MemRequest#(40) req) if (!writeInProgress && !writeDataMimo.deqReadyN(1));
	      let burstLen = req.burstLen >> beat_shift;
	      let addr = req.addr;
	      let arid = req.tag;

	       TLPData#(16) tlp = defaultValue;
	       tlp.sof = True;
	       tlp.eof = True;
	       tlp.hit = 7'h00;
	       TLPLength tlplen = fromInteger(valueOf(busWidthWords))*(extend(burstLen));
	       if (addr[39:32] != 0) begin
		   TLPMemory4DWHeader hdr_4dw = defaultValue;
		   hdr_4dw.format = MEM_READ_4DW_NO_DATA;
		   hdr_4dw.tag = extend(arid);
		   hdr_4dw.reqid = my_id;
		   hdr_4dw.nosnoop = SNOOPING_REQD;
		   hdr_4dw.addr = addr[40-1:2];
		   hdr_4dw.length = tlplen;
		   hdr_4dw.firstbe = 4'hf;
		   hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
		   tlp.data = pack(hdr_4dw);
		   tlp.be = 16'hffff;
	       end
	       else begin
		   TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
		   hdr_3dw.format = MEM_READ_3DW_NO_DATA;
		   hdr_3dw.tag = extend(arid);
		   hdr_3dw.reqid = my_id;
		   hdr_3dw.nosnoop = SNOOPING_REQD;
		   hdr_3dw.addr = addr[32-1:2];
		   hdr_3dw.length = tlplen;
		   hdr_3dw.firstbe = 4'hf;
		   hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
		   tlp.data = pack(hdr_3dw);
		   tlp.be = 16'hfff0;
	       end
	       tlpOutFifo.enq(tlp);
           endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReadyN(fromInteger(valueOf(busWidthWords)))
									&& completionTagMimo.deqReadyN(fromInteger(valueOf(busWidthWords))));
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq(fromInteger(valueOf(busWidthWords)));
	      completionTagMimo.deq(fromInteger(valueOf(busWidthWords)));
              Bit#(buswidth) v = 0;
	      for (Integer i = 0; i < valueOf(busWidthWords); i = i+1)
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
	      return MemData { data: v, tag: truncate(tag_v[0])};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;

import AxiMasterSlave :: *;

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface MemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8));

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpWriteHeaderFifo <- mkFIFOF;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
    MIMO#(4,busWidthWords,8,Bit#(32)) completionMimo <- mkMIMO(mimoCfg);
    MIMO#(4,busWidthWords,8,TLPTag) completionTagMimo <- mkMIMO(mimoCfg);
    MIMO#(busWidthWords,4,8,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    Reg#(Bit#(9)) writeBurstCount <- mkReg(0);
    Reg#(TLPLength)  writeDwCount <- mkReg(0);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    function Integer tlpWordCount(TLPData#(16) tlp);
       if (tlp.be == 16'h0000)
	  return 0;
       else if (tlp.be == 16'h000f || tlp.be == 16'hf000)
	  return 1;
       else if (tlp.be == 16'h00ff || tlp.be == 16'hff00)
	  return 2;
       else if (tlp.be == 16'h0fff || tlp.be == 16'hfff0)
	  return 3;
       else if (tlp.be == 16'hffff)
	  return 4;
       else
	  return 0;
    endfunction

   rule writeHeaderTlp if (writeDwCount == 0 && writeDataMimo.deqReadyN(1));
      let tlp = tlpWriteHeaderFifo.first;

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);
      TLPLength dwCount = hdr_4dw.length;

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      Bool sendit = False;
      if (hdr_3dw.format == MEM_WRITE_3DW_DATA && writeDataMimo.deqReadyN(1)) begin
	 dwCount = hdr_3dw.length;
	 Vector#(4, Bit#(32)) v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
	 tlp.be = 16'hffff;
	 if (dwCount == 1)
	    tlp.eof = True;
	 dwCount = dwCount - 1;
	 tlp.data = pack(hdr_3dw);
	 sendit = True;
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA) begin
	 // retry until the data is available in writeDataMimo
      end
      if (hdr_4dw.format == MEM_WRITE_4DW_DATA && writeDataMimo.deqReadyN(1)) begin
	 tlp.be = 16'hffff;
	 sendit = True;
      end
      else if (hdr_4dw.format == MEM_WRITE_4DW_DATA) begin
	 sendit = False;
      end
      else begin
	 sendit = True;
      end
      if (sendit) begin
	 tlpWriteHeaderFifo.deq();
	 tlpOutFifo.enq(tlp);
	 $display("writeHeaderTlp dwCount=%d", dwCount);
	 writeDwCount <= dwCount;
	 if (dwCount == 0) begin
	    doneTag.enq(writeTag.first());
	    writeTag.deq();
	 end
      end
   endrule

   rule writeTlps if (writeDwCount > 0);
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);
      Bool sendit = False;
      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      if (writeDwCount > 4 && writeDataMimo.deqReadyN(4)) begin
	 v = writeDataMimo.first();

	 writeDataMimo.deq(4);
	 writeDwCount <= writeDwCount - 4;
	 tlp.eof = False;
	 tlp.be = 16'hffff;
	 sendit = True;
      end
      else if (writeDwCount <= 4 && writeDataMimo.deqReadyN(unpack(truncate(writeDwCount)))) begin
	 v = writeDataMimo.first();
	 writeDataMimo.deq(unpack(truncate(writeDwCount)));
	 writeDwCount <= 0;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 $display("writeDwCount=%d will be zero", writeDwCount);
	 tlp.eof = True;
	 if (writeDwCount == 4)
	    tlp.be = 16'hffff;
	 else if (writeDwCount == 3)
	    tlp.be = 16'hfff0;
	 else if (writeDwCount == 2)
	    tlp.be = 16'hff00;
	 else if (writeDwCount == 1)
	    tlp.be = 16'hf000;
	 sendit = True;
      end
      else begin
	 // wait for more data in writeDataMimo
	 $display("waiting for more data dwCount=%d count=%d writeBurstCount=%d enqReady=%d",
	    writeDwCount, writeDataMimo.count(), writeBurstCount, writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));
      end
      if (sendit) begin
	 for (Integer i = 0; i < 4; i = i + 1)
	    tlp.data[(i+1)*32-1:i*32] = byteSwap(v[3-i]);
	 tlpOutFifo.enq(tlp);
      end
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   rule handleTlpIn;
      let tlp = tlpInFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);

      if (!tlp.sof) begin
	 let count = tlpWordCount(tlp);
	 // if sof is false, then count will be at least 1
	 function Bit#(32) f(Integer i);
	    begin
	       if (i < count)
		  return tlpvec[3-i];
	       else
		  return 32'hbad0beef;
	    end
	 endfunction
	 vec = genWith(f);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReadyN(fromInteger(count))
	    && completionTagMimo.enqReadyN(fromInteger(count)))
	    begin
	       completionMimo.enq(fromInteger(count), vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(fromInteger(count), tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReadyN(1)
	       && completionTagMimo.enqReadyN(1)) begin
	    vec[0] = hdr_3dw.data;
	    completionMimo.enq(1, vec);
            TLPTag tag = hdr_completion.tag;
	    lastTag <= tag;
	    completionTagMimo.enq(1, replicate(tag));
	    handled = True;
      end
      //$display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled)
	 tlpInFifo.deq();
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface MemSlave slave;
   interface MemWriteServer write_server;
      interface Put writeReq;
         method Action put(MemRequest#(40) req)
	      if (writeBurstCount == 0);

	      let burstLen = req.burstLen >> beat_shift;
	      let addr = req.addr;
	      let awid = req.tag;

	      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*(extend(burstLen));
	      TLPData#(16) tlp = defaultValue;
	      tlp.sof = True;
	      tlp.eof = False;
	      tlp.hit = 7'h00;
	      tlp.be = 16'hffff;

	      $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	      if ((addr >> 32) != 0) begin
		 TLPMemory4DWHeader hdr_4dw = defaultValue;
		 hdr_4dw.format = MEM_WRITE_4DW_DATA;
		 hdr_4dw.tag = extend(awid);
		 hdr_4dw.reqid = my_id;
		 hdr_4dw.nosnoop = SNOOPING_REQD;
		 hdr_4dw.addr = addr[40-1:2];
		 hdr_4dw.length = tlplen;
		 hdr_4dw.firstbe = 4'hf;
		 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
		 tlp.data = pack(hdr_4dw);
	      end
	      else begin
		 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
		 hdr_3dw.format = MEM_WRITE_3DW_DATA;
		 hdr_3dw.tag = extend(awid);
		 hdr_3dw.reqid = my_id;
		 hdr_3dw.nosnoop = SNOOPING_REQD;
		 hdr_3dw.addr = addr[32-1:2];
		 hdr_3dw.length = tlplen;
		 hdr_3dw.firstbe = 4'hf;
		 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

		 tlp.be = 16'hfff0; // no data word in this TLP

		 tlp.data = pack(hdr_3dw);
	      end
	      tlpWriteHeaderFifo.enq(tlp);
	      writeBurstCount <= zeroExtend(burstLen);
	      writeTag.enq(extend(awid));
           endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeBurstCount > 0 && writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	      writeBurstCount <= writeBurstCount - 1;
	      Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	      writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
           endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(ObjectTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface MemReadServer read_server;
      interface Put readReq;
         method Action put(MemRequest#(40) req) if (writeDwCount == 0 && !writeDataMimo.deqReadyN(1));
	      let burstLen = req.burstLen >> beat_shift;
	      let addr = req.addr;
	      let arid = req.tag;

	       TLPData#(16) tlp = defaultValue;
	       tlp.sof = True;
	       tlp.eof = True;
	       tlp.hit = 7'h00;
	       TLPLength tlplen = fromInteger(valueOf(busWidthWords))*(extend(burstLen));
	       if (addr[39:32] != 0) begin
		   TLPMemory4DWHeader hdr_4dw = defaultValue;
		   hdr_4dw.format = MEM_READ_4DW_NO_DATA;
		   hdr_4dw.tag = extend(arid);
		   hdr_4dw.reqid = my_id;
		   hdr_4dw.nosnoop = SNOOPING_REQD;
		   hdr_4dw.addr = addr[40-1:2];
		   hdr_4dw.length = tlplen;
		   hdr_4dw.firstbe = 4'hf;
		   hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
		   tlp.data = pack(hdr_4dw);
		   tlp.be = 16'hffff;
	       end
	       else begin
		   TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
		   hdr_3dw.format = MEM_READ_3DW_NO_DATA;
		   hdr_3dw.tag = extend(arid);
		   hdr_3dw.reqid = my_id;
		   hdr_3dw.nosnoop = SNOOPING_REQD;
		   hdr_3dw.addr = addr[32-1:2];
		   hdr_3dw.length = tlplen;
		   hdr_3dw.firstbe = 4'hf;
		   hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
		   tlp.data = pack(hdr_3dw);
		   tlp.be = 16'hfff0;
	       end
	       tlpOutFifo.enq(tlp);
           endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReadyN(fromInteger(valueOf(busWidthWords)))
									&& completionTagMimo.deqReadyN(fromInteger(valueOf(busWidthWords))));
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq(fromInteger(valueOf(busWidthWords)));
	      completionTagMimo.deq(fromInteger(valueOf(busWidthWords)));
              Bit#(buswidth) v = 0;
	      for (Integer i = 0; i < valueOf(busWidthWords); i = i+1)
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
	      return MemData { data: v, tag: truncate(tag_v[0])};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine


remove unused imports

remove unused imports

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import BuildVector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import ClientServer::*;
import GetPut::*;
import HostInterface::*;
import MemTypes::*;
import Pipe::*;

typedef TDiv#(DataBusWidth,32) WordsPerBeat;

interface MemcopyRequest;
   method Action startCopy(Bit#(32) readPointer, Bit#(32) writePointer, Bit#(32) numWords, Bit#(32) numReqs, Bit#(32) burstLen);
endinterface

interface MemcopyIndication;
   method Action copyDone(Bit#(32) v);
   method Action copyProgress(Bit#(32) v);
endinterface

interface Memcopy;
   interface MemcopyRequest request;
   interface Vector#(1, MemReadClient#(64)) readClients;
   interface Vector#(1, MemWriteClient#(64)) writeClients;
endinterface

module  mkMemcopy#(MemcopyIndication indication) (Memcopy);
   Reg#(SGLId)   readPointer <- mkReg(0);
   Reg#(SGLId)   writePointer <- mkReg(0);
   Reg#(Bit#(32))        numReqs <- mkReg(0);
   Reg#(Bit#(32))        numDone <- mkReg(0);
   Reg#(Bit#(MemOffsetSize)) reqOffset <- mkReg(0);
   Reg#(Bit#(3))                   tag <- mkReg(0);
   Reg#(Bit#(32))             numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   Reg#(Bit#(32))              srcGens <- mkReg(0);

   FIFO#(MemRequest) readReqFifo <- mkFIFO();
   FIFO#(MemRequest) writeReqFifo <- mkFIFO();
   FIFO#(MemData#(DataBusWidth))   dataFifo <- mkSizedBRAMFIFO(1024);
   FIFO#(Bit#(MemTagSize)) doneFifo <- mkFIFO();

   let verboseProgress = False;

   rule startReqRule if (numReqs != 0);
      readReqFifo.enq(MemRequest { sglId: readPointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });
      writeReqFifo.enq(MemRequest { sglId: writePointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });

      numReqs <= numReqs - 1;
      reqOffset <= reqOffset + extend(burstLenBytes);
      tag <= tag + 1;
      //$display("start numReqs", numReqs);
   endrule

   rule finish;
      let donetag <- toGet(doneFifo).get();
      //$display("finished num todo=%d", numDone);
      if (numDone == 1) begin
         indication.copyDone(0);
      end
      numDone <= numDone - 1;
      if (verboseProgress)
	 indication.copyProgress(extend(donetag));
   endrule

   MemReadClient#(64) readClient = (interface MemReadClient;
      interface Get readReq = toGet(readReqFifo);
      interface Put readData = toPut(dataFifo);
   endinterface );
   MemWriteClient#(64) writeClient = (interface MemWriteClient;
      interface Get writeReq = toGet(writeReqFifo);
      interface Get writeData = toGet(dataFifo);
      interface Put writeDone = toPut(doneFifo);
   endinterface );

   interface MemcopyRequest request;
       method Action startCopy(Bit#(32) rp, Bit#(32) wp, Bit#(32) nw, Bit#(32) nreq, Bit#(32) bl);
	  $dumpvars();
          $display("startCopy readPointer=%d writePointer=%d numWords=%d (%d) numReqs=%d burstLen=%d", rp, wp, nw, nreq*bl, nreq, bl);
          readPointer <= rp;
          writePointer <= wp;
          numWords  <= nw;
          burstLenBytes <= truncate(bl);
	  numReqs <= nreq;
	  numDone <= nreq;
       endmethod
   endinterface
   interface readClients = vec(readClient);
   interface writeClients = vec(writeClient);

endmodule

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import BuildVector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import ClientServer::*;
import GetPut::*;
import HostInterface::*;
import MemTypes::*;
import MemwriteEngine::*;
import Pipe::*;
import AddressGenerator::*;

typedef TDiv#(DataBusWidth,32) WordsPerBeat;

interface MemcopyRequest;
   method Action startCopy(Bit#(32) readPointer, Bit#(32) writePointer, Bit#(32) numWords, Bit#(32) numReqs, Bit#(32) burstLen);
endinterface

interface MemcopyIndication;
   method Action copyDone(Bit#(32) v);
   method Action copyProgress(Bit#(32) v);
endinterface

interface Memcopy;
   interface MemcopyRequest request;
   interface Vector#(1, MemReadClient#(64)) readClients;
   interface Vector#(1, MemWriteClient#(64)) writeClients;
endinterface

module  mkMemcopy#(MemcopyIndication indication) (Memcopy);
   Reg#(SGLId)   readPointer <- mkReg(0);
   Reg#(SGLId)   writePointer <- mkReg(0);
   Reg#(Bit#(32))        numReqs <- mkReg(0);
   Reg#(Bit#(32))        numDone <- mkReg(0);
   Reg#(Bit#(MemOffsetSize)) reqOffset <- mkReg(0);
   Reg#(Bit#(3))                   tag <- mkReg(0);
   Reg#(Bit#(32))             numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   Reg#(Bit#(32))              srcGens <- mkReg(0);

   FIFO#(MemRequest) readReqFifo <- mkFIFO();
   FIFO#(MemRequest) writeReqFifo <- mkFIFO();
   FIFO#(MemData#(DataBusWidth))   dataFifo <- mkSizedBRAMFIFO(1024);
   FIFO#(Bit#(MemTagSize)) doneFifo <- mkFIFO();

   let verboseProgress = False;

   rule startReqRule if (numReqs != 0);
      readReqFifo.enq(MemRequest { sglId: readPointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });
      writeReqFifo.enq(MemRequest { sglId: writePointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });

      numReqs <= numReqs - 1;
      reqOffset <= reqOffset + extend(burstLenBytes);
      tag <= tag + 1;
      //$display("start numReqs", numReqs);
   endrule

   rule finish;
      let donetag <- toGet(doneFifo).get();
      //$display("finished num todo=%d", numDone);
      if (numDone == 1) begin
         indication.copyDone(0);
      end
      numDone <= numDone - 1;
      if (verboseProgress)
	 indication.copyProgress(extend(donetag));
   endrule

   MemReadClient#(64) readClient = (interface MemReadClient;
      interface Get readReq = toGet(readReqFifo);
      interface Put readData = toPut(dataFifo);
   endinterface );
   MemWriteClient#(64) writeClient = (interface MemWriteClient;
      interface Get writeReq = toGet(writeReqFifo);
      interface Get writeData = toGet(dataFifo);
      interface Put writeDone = toPut(doneFifo);
   endinterface );

   interface MemcopyRequest request;
       method Action startCopy(Bit#(32) rp, Bit#(32) wp, Bit#(32) nw, Bit#(32) nreq, Bit#(32) bl);
	  $dumpvars();
          $display("startCopy readPointer=%d writePointer=%d numWords=%d (%d) numReqs=%d burstLen=%d", rp, wp, nw, nreq*bl, nreq, bl);
          readPointer <= rp;
          writePointer <= wp;
          numWords  <= nw;
          burstLenBytes <= truncate(bl);
	  numReqs <= nreq;
	  numDone <= nreq;
       endmethod
   endinterface
   interface readClients = vec(readClient);
   interface writeClients = vec(writeClient);

endmodule


updated EthPma.bsv

updated EthPma.bsv

// Copyright (c) 2014 Cornell University.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package EthPma;

import Clocks                               ::*;
import Vector                               ::*;
import Connectable                          ::*;

import ConnectalClocks                      ::*;
import ALTERA_ETH_PMA_WRAPPER               ::*;
import ALTERA_ETH_PMA_RECONFIG_WRAPPER      ::*;
import ALTERA_ETH_PMA_RESET_CONTROL_WRAPPER ::*;

interface PhyMgmtIfc;
   method Action      phy_mgmt_address(Bit#(7) v);
   method Action      phy_mgmt_read(Bit#(1) v);
   method Bit#(32)    phy_mgmt_readdata;
   method Bit#(1)     phy_mgmt_waitrequest;
   method Action      phy_mgmt_write(Bit#(1) v);
   method Action      phy_mgmt_write_data(Bit#(32) v);
endinterface

interface Status#(numeric type np);
   method Vector#(np, Bit#(1))     tx_ready;
   method Vector#(np, Bit#(1))     rx_ready;
   method Vector#(np, Bit#(1))     pll_locked;
   method Vector#(np, Bit#(1))     rx_is_lockedtodata;
   method Vector#(np, Bit#(1))     rx_is_lockedtoref;
endinterface

interface Serial#(numeric type np);
   method Bit#(np)    tx_serial_data;
   method Action      rx_serial_data(Bit#(np) v);
endinterface

interface Parallel#(numeric type np);
   method Vector#(np, Bit#(40)) rx_parallel_data;
   method Action                tx_parallel_data(Vector#(np, Bit#(40)) v);
endinterface

(* always_ready, always_enabled *)
interface EthPmaIfc#(numeric type np);
   interface Vector#(np, Clock) tx_clkout;
   interface Vector#(np, Clock) rx_clkout;
   interface PhyMgmtIfc         phy_mgmt;
   interface Status#(np)        status;
   interface Serial#(np)        serial;
   interface Parallel#(np)      parallel;
endinterface

module mkEthPma#(Clock phy_mgmt_clk, Clock pll_ref_clk, Reset phy_mgmt_reset, Reset pll_ref_reset)(EthPmaIfc#(np)) provisos (Add#(np, unused, 4));

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   EthXcvrWrap         xcvr  <- mkEthXcvrWrap();
   EthXcvrReconfigWrap cfg   <- mkEthXcvrReconfigWrap(phy_mgmt_clk, phy_mgmt_reset, phy_mgmt_reset);
   EthXcvrResetWrap    rst   <- mkEthXcvrResetWrap(phy_mgmt_clk, phy_mgmt_reset, phy_mgmt_reset);

   C2B c2b <- mkC2B(pll_ref_clk);
   rule xcvr_clk;
      xcvr.tx.pll_refclk(c2b.o);
      xcvr.rx.cdr_refclk(c2b.o);
   endrule

   rule xcvr_reconfig;
      cfg.reconfig.from_xcvr(xcvr.reconfig.from_xcvr);
      xcvr.reconfig.to_xcvr(cfg.reconfig.to_xcvr);
   endrule

   rule xcvr_reset;
      xcvr.rx.analogreset(rst.rx.analogreset);
      xcvr.rx.digitalreset(rst.rx.digitalreset);
      xcvr.tx.analogreset(rst.tx.analogreset);
      xcvr.tx.digitalreset(rst.tx.digitalreset);
      rst.rx.cal_busy(xcvr.rx.cal_busy);
      rst.tx.cal_busy(xcvr.tx.cal_busy);
      rst.rx.is_lockedtodata(xcvr.rx.is_lockedtodata);
      rst.pll.locked(xcvr.pll.locked);
      xcvr.pll.powerdown(rst.pll.powerdown);
   endrule

   rule xcvr_const;
      rst.pll.select(2'b11);
      xcvr.rx.set_locktodata(4'b0);
      xcvr.rx.set_locktoref(4'b0);
   endrule

   /* connect all three components */
   Vector#(np, B2C1) tx_clk;
   Vector#(np, B2C1) rx_clk;
   for (Integer i=0; i < valueOf(np); i=i+1) begin
      tx_clk[i] <- mkB2C1();
      rx_clk[i] <- mkB2C1();
   end

   rule out_pma_clk;
      for (Integer i=0; i < valueOf(np); i=i+1) begin
         tx_clk[i].inputclock(xcvr.tx.pma_clkout[i]);
         rx_clk[i].inputclock(xcvr.rx.pma_clkout[i]);
      end
   endrule

   Vector#(np, Clock) out_tx_clk;
   Vector#(np, Clock) out_rx_clk;
   for (Integer i=0; i< valueOf(np); i=i+1) begin
      out_tx_clk[i] = tx_clk[i].c;
      out_rx_clk[i] = rx_clk[i].c;
   end

   Vector#(np, Wire#(Bit#(1))) rx_serial_wires <- replicateM(mkDWire(0));

   function Bit#(1) getBit(Bit#(n) data, Integer i);
      return data[i];
   endfunction

   interface tx_clkout = out_tx_clk;
   interface rx_clkout = out_rx_clk;

   interface Status status;
      method Vector#(np, Bit#(1)) rx_ready();
         Vector#(np, Bit#(1)) ret_val = map(getBit(rst.rx.ready), genVector);
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) tx_ready();
         Vector#(np, Bit#(1)) ret_val = map(getBit(rst.tx.ready), genVector);
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) pll_locked();
         Vector#(np, Bit#(1)) ret_val = map(getBit(xcvr.pll.locked), genVector);
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) rx_is_lockedtodata();
         Vector#(np, Bit#(1)) ret_val = map(getBit(xcvr.rx.is_lockedtodata), genVector);
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) rx_is_lockedtoref();
         Vector#(np, Bit#(1)) ret_val = map(getBit(xcvr.rx.is_lockedtoref), genVector);
         return ret_val;
      endmethod
   endinterface

   interface PhyMgmtIfc phy_mgmt;
      method Action phy_mgmt_address(v);
         cfg.reconfig.mgmt_address(v);
      endmethod

      method Action phy_mgmt_read(v);
         cfg.reconfig.mgmt_read(v);
      endmethod

      method Bit#(32) phy_mgmt_readdata;
         return cfg.reconfig.mgmt_readdata;
      endmethod

      method Bit#(1) phy_mgmt_waitrequest;
         return cfg.reconfig.mgmt_waitrequest;
      endmethod

      method Action phy_mgmt_write(v);
         cfg.reconfig.mgmt_write(v);
      endmethod

      method Action phy_mgmt_write_data(v);
         cfg.reconfig.mgmt_writedata(v);
      endmethod
   endinterface

   interface Serial serial;
      method Bit#(np) tx_serial_data;
         Vector#(np, Bit#(1)) ret = map(getBit(xcvr.tx.serial_data), genVector);
         return pack(ret);
      endmethod

      method Action rx_serial_data (v);
         let rxb = pack(v);
`ifdef USE_4_PORTS
         Bit#(4) ret_val = {rxb[3], rxb[2], rxb[1], rxb[0]};
`elsif USE_2_PORTS
         Bit#(2) ret_val = {rxb[1], rxb[0]};
`endif
         xcvr.rx.serial_data(ret_val);
      endmethod
   endinterface

   interface Parallel parallel;
      method Vector#(np, Bit#(40)) rx_parallel_data;
         Vector#(np, Bit#(40)) ret_val;
         for(Integer i=0; i < valueOf(np); i = i+1) begin
            ret_val[i] = unpack(xcvr.rx.pma_parallel_data)[39 + 80 * i : 80 * i];
         end
         return ret_val;
      endmethod

      method Action tx_parallel_data(v);
         let txp = pack(v);
`ifdef USE_4_PORTS
         Bit#(320) ret_val = {40'h0, txp[159:120], 40'h0, txp[119:80],
                              40'h0, txp[79:40],   40'h0, txp[39:0]};
`elsif USE_2_PORTS
         Bit#(320) ret_val = {160'h0,
                              40'h0, txp[79:40],   40'h0, txp[39:0]};
`endif
         xcvr.tx.pma_parallel_data(ret_val);
      endmethod
   endinterface
endmodule

`ifdef USE_4_PORTS
typedef EthPmaIfc#(4) EthPmaIfc4;
(* synthesize *)
module mkEthPma4#(Clock mgmt_clk, Clock ref_clk, Reset mgmt_reset, Reset ref_reset) (EthPmaIfc4);
   EthPmaIfc4 _a <- mkEthPma(mgmt_clk, ref_clk, mgmt_reset, ref_reset); return _a;
endmodule
`elsif USE_2_PORTS
typedef EthPmaIfc#(2) EthPmaIfc2;
(* synthesize *)
module mkEthPma2#(Clock mgmt_clk, Clock ref_clk, Reset mgmt_reset, Reset ref_reset) (EthPmaIfc2);
   EthPmaIfc2 _a <- mkEthPma(mgmt_clk, ref_clk, mgmt_reset, ref_reset); return _a;
endmodule
`endif

endpackage: EthPma

// Copyright (c) 2014 Cornell University.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package EthPma;

import Clocks                               ::*;
import Vector                               ::*;
import Connectable                          ::*;

import ConnectalClocks                      ::*;
import ALTERA_ETH_PMA_WRAPPER               ::*;
import ALTERA_ETH_PMA_RECONFIG_WRAPPER      ::*;
import ALTERA_ETH_PMA_RESET_CONTROL_WRAPPER ::*;

interface PhyMgmtIfc;
   method Action      phy_mgmt_address(Bit#(7) v);
   method Action      phy_mgmt_read(Bit#(1) v);
   method Bit#(32)    phy_mgmt_readdata;
   method Bit#(1)     phy_mgmt_waitrequest;
   method Action      phy_mgmt_write(Bit#(1) v);
   method Action      phy_mgmt_write_data(Bit#(32) v);
endinterface

interface Status#(numeric type np);
   method Vector#(np, Bit#(1))     tx_ready;
   method Vector#(np, Bit#(1))     rx_ready;
   method Vector#(np, Bit#(1))     pll_locked;
   method Vector#(np, Bit#(1))     rx_is_lockedtodata;
   method Vector#(np, Bit#(1))     rx_is_lockedtoref;
endinterface

interface Serial#(numeric type np);
   method Bit#(np)    tx_serial_data;
`ifdef USE_4_PORTS
   method Action      rx_serial_data(Bit#(4) v);
`elsif USE_2_PORTS
   method Action      rx_serial_data(Bit#(2) v);
`endif
endinterface

interface Parallel#(numeric type np);
   method Vector#(np, Bit#(40)) rx_parallel_data;
`ifdef USE_4_PORTS
   method Action                tx_parallel_data(Vector#(np, Bit#(40)) v);
`elsif USE_2_PORTS
   method Action                tx_parallel_data(Vector#(np, Bit#(40)) v);
`endif
endinterface

(* always_ready, always_enabled *)
interface EthPmaIfc#(numeric type np);
   interface Vector#(np, Clock) tx_clkout;
   interface Vector#(np, Clock) rx_clkout;
   interface PhyMgmtIfc         phy_mgmt;
   interface Status#(np)        status;
   interface Serial#(np)        serial;
   interface Parallel#(np)      parallel;
endinterface

module mkEthPma#(Clock phy_mgmt_clk, Clock pll_ref_clk, Reset phy_mgmt_reset, Reset pll_ref_reset)(EthPmaIfc#(np));

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   EthXcvrWrap         xcvr  <- mkEthXcvrWrap();
   EthXcvrReconfigWrap cfg   <- mkEthXcvrReconfigWrap(phy_mgmt_clk, phy_mgmt_reset, phy_mgmt_reset);
   EthXcvrResetWrap    rst   <- mkEthXcvrResetWrap(phy_mgmt_clk, phy_mgmt_reset, phy_mgmt_reset);

   C2B c2b <- mkC2B(pll_ref_clk);
   rule xcvr_clk;
      xcvr.tx.pll_refclk(c2b.o);
      xcvr.rx.cdr_refclk(c2b.o);
   endrule

   rule xcvr_reconfig;
      cfg.reconfig.from_xcvr(xcvr.reconfig.from_xcvr);
      xcvr.reconfig.to_xcvr(cfg.reconfig.to_xcvr);
   endrule

   rule xcvr_reset;
      xcvr.rx.analogreset(rst.rx.analogreset);
      xcvr.rx.digitalreset(rst.rx.digitalreset);
      xcvr.tx.analogreset(rst.tx.analogreset);
      xcvr.tx.digitalreset(rst.tx.digitalreset);
      rst.rx.cal_busy(xcvr.rx.cal_busy);
      rst.tx.cal_busy(xcvr.tx.cal_busy);
      rst.rx.is_lockedtodata(xcvr.rx.is_lockedtodata);
      rst.pll.locked(xcvr.pll.locked);
      xcvr.pll.powerdown(rst.pll.powerdown);
   endrule

   rule xcvr_const;
      rst.pll.select(2'b11);
      xcvr.rx.set_locktodata(4'b0);
      xcvr.rx.set_locktoref(4'b0);
   endrule

   /* connect all three components */
   Vector#(np, B2C1) tx_clk;
   Vector#(np, B2C1) rx_clk;
   for (Integer i=0; i < valueOf(np); i=i+1) begin
      tx_clk[i] <- mkB2C1();
      rx_clk[i] <- mkB2C1();
   end

   rule out_pma_clk;
      for (Integer i=0; i < valueOf(np); i=i+1) begin
         tx_clk[i].inputclock(xcvr.tx.pma_clkout[i]);
         rx_clk[i].inputclock(xcvr.rx.pma_clkout[i]);
      end
   endrule

   Vector#(np, Clock) out_tx_clk;
   Vector#(np, Clock) out_rx_clk;
   for (Integer i=0; i< valueOf(np); i=i+1) begin
      out_tx_clk[i] = tx_clk[i].c;
      out_rx_clk[i] = rx_clk[i].c;
   end

   Vector#(np, Wire#(Bit#(1))) rx_serial_wires <- replicateM(mkDWire(0));

   interface tx_clkout = out_tx_clk;
   interface rx_clkout = out_rx_clk;

   interface Status status;
      method Vector#(np, Bit#(1)) rx_ready();
         Vector#(np, Bit#(1)) ret_val;
         for(Integer i=0; i< valueOf(np); i=i+1) begin
            ret_val[i] = rst.rx.ready[i];
         end
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) tx_ready();
         Vector#(np, Bit#(1)) ret_val;
         for(Integer i=0; i< valueOf(np); i=i+1) begin
            ret_val[i] = rst.tx.ready[i];
         end
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) pll_locked();
         Vector#(np, Bit#(1)) ret_val;
         for(Integer i=0; i< valueOf(np); i=i+1) begin
            ret_val[i] = xcvr.pll.locked[i];
         end
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) rx_is_lockedtodata();
         Vector#(np, Bit#(1)) ret_val;
         for(Integer i=0; i< valueOf(np); i=i+1) begin
            ret_val[i] = xcvr.rx.is_lockedtodata[i];
         end
         return ret_val;
      endmethod

      method Vector#(np, Bit#(1)) rx_is_lockedtoref();
         Vector#(np, Bit#(1)) ret_val;
         for(Integer i=0; i< valueOf(np); i=i+1) begin
            ret_val[i] = xcvr.rx.is_lockedtoref[i];
         end
         return ret_val;
      endmethod
   endinterface

   interface PhyMgmtIfc phy_mgmt;
      method Action phy_mgmt_address(v);
         cfg.reconfig.mgmt_address(v);
      endmethod

      method Action phy_mgmt_read(v);
         cfg.reconfig.mgmt_read(v);
      endmethod

      method Bit#(32) phy_mgmt_readdata;
         return cfg.reconfig.mgmt_readdata;
      endmethod

      method Bit#(1) phy_mgmt_waitrequest;
         return cfg.reconfig.mgmt_waitrequest;
      endmethod

      method Action phy_mgmt_write(v);
         cfg.reconfig.mgmt_write(v);
      endmethod

      method Action phy_mgmt_write_data(v);
         cfg.reconfig.mgmt_writedata(v);
      endmethod
   endinterface

   interface Serial serial;
      method Bit#(np) tx_serial_data;
         Vector#(np, Bit#(1)) ret;
         for (Integer i=0; i < valueOf(np); i=i+1) begin //Rewrite with map
            ret[i] = xcvr.tx.serial_data[i];
         end
         return pack(ret);
      endmethod

      method Action rx_serial_data (v);
         xcvr.rx.serial_data(v);
      endmethod
   endinterface

   interface Parallel parallel;
      method Vector#(np, Bit#(40)) rx_parallel_data;
         Vector#(np, Bit#(40)) ret_val;
         for(Integer i=0; i < valueOf(np); i = i+1) begin
            ret_val[i] = unpack(xcvr.rx.pma_parallel_data)[39:0];
         end
         return ret_val;
      endmethod

//      method Action tx_parallel_data(v);
//         Vector#(np, Bit#(40)) ret_val;
//         for(Integer i=0; i < valueOf(np); i = i+1) begin
//            ret_val[i] = v[i];
//         end
//         xcvr.tx.pma_parallel_data(ret_val);
//      endmethod
   endinterface
endmodule

`ifdef USE_4_PORTS
typedef EthPmaIfc#(4) EthPmaIfc4;
(* synthesize *)
module mkEthPma4#(Clock mgmt_clk, Clock ref_clk, Reset mgmt_reset, Reset ref_reset) (EthPmaIfc4);
   EthPmaIfc4 _a <- mkEthPma(mgmt_clk, ref_clk, mgmt_reset, ref_reset); return _a;
endmodule
`elsif USE_2_PORTS
typedef EthPmaIfc#(2) EthPmaIfc2;
(* synthesize *)
module mkEthPma2#(Clock mgmt_clk, Clock ref_clk, Reset mgmt_reset, Reset ref_reset) (EthPmaIfc2);
   EthPmaIfc2 _a <- mkEthPma(mgmt_clk, ref_clk, mgmt_reset, ref_reset); return _a;
endmodule
`endif

endpackage: EthPma