package treecorel2

import chisel3._
import chisel3.util._

class EXU extends Module with InstConfig {
  val io = IO(new Bundle {
    val globalEn   = Input(Bool())
    val mtip       = Input(Bool())
    val stall      = Output(Bool())
    val id2ex      = Flipped(new ID2EXIO)
    val bypassMem  = Flipped(new WBDATAIO)
    val bypassWb   = Flipped(new WBDATAIO)
    val ex2mem     = new EX2MEMIO
    val nxtPC      = new NXTPCIO
    val branchInfo = new BRANCHIO
  })

  protected val exReg     = RegEnable(io.id2ex, WireInit(0.U.asTypeOf(new ID2EXIO())), io.globalEn)
  protected val valid     = exReg.valid
  protected val inst      = exReg.inst
  protected val pc        = exReg.pc
  protected val branIdx   = exReg.branIdx
  protected val predTaken = exReg.predTaken
  protected val isa       = exReg.isa

  // handle bypass signal
  protected val bypassMemSrc1En = io.bypassMem.wen && (rs1 === io.bypassMem.wdest) && (rs1 =/= 0.U)
  protected val bypassMemSrc2En = io.bypassMem.wen && (rs2 === io.bypassMem.wdest) && (rs2 =/= 0.U)
  protected val bypassWbSrc1En  = io.bypassWb.wen  && (rs1 === io.bypassWb.wdest)  && (rs1 =/= 0.U)
  protected val bypassWbSrc2En  = io.bypassWb.wen  && (rs2 === io.bypassWb.wdest)  && (rs2 =/= 0.U)
  protected val src1            = Mux(bypassMemSrc1En, io.bypassMem.data, Mux(bypassWbSrc1En, io.bypassWb.data, exReg.src1))
  protected val src2            = Mux(bypassMemSrc2En, io.bypassMem.data, Mux(bypassWbSrc2En, io.bypassWb.data, exReg.src2))

  protected val alu = Module(new ALU)
  alu.io.isa  := isa
  alu.io.imm  := imm
  alu.io.src1 := src1
  alu.io.src2 := src2
  protected val aluRes = alu.io.res

  // protected val mdu = Module(new MDU)
  // mdu.io.isa  := isa
  // mdu.io.src1 := src1
  // mdu.io.src2 := src2
  // protected val mduRes = mdu.io.res

  // protected val agu = Module(new AGU)
  // agu.io.isa  := isa
  // agu.io.src1 := src1
  // agu.io.src2 := src2
  // protected val aguRes = agu.io.res

  protected val beu = Module(new BEU)
  beu.io.isa        := isa
  beu.io.imm        := imm
  beu.io.src1       := src1
  beu.io.src2       := src2
  beu.io.pc         := pc
  beu.io.branIdx    := branIdx
  beu.io.branchInfo <> io.branchInfo
  protected val branch = beu.io.branch
  protected val tgt    = beu.io.tgt

  protected val link  = SignExt(((isa === instJAL) | (isa === instJALR)).asUInt, 64) & (pc + 4.U)
  protected val auipc = SignExt((isa === instAUIPC).asUInt, 64) & (pc + imm)

  protected val csrReg     = Module(new CSRReg)
  protected val csrData    = csrReg.io.data
  protected val timeIntrEn = csrReg.io.timeIntrEn
  protected val ecallEn    = csrReg.io.ecallEn
  csrReg.io.globalEn := io.globalEn
  csrReg.io.pc       := pc
  csrReg.io.inst     := Mux(valid, inst, NOPInst)
  csrReg.io.src      := src1
  csrReg.io.mtip     := io.mtip

  io.nxtPC.trap  := valid && (timeIntrEn || ecallEn)
  io.nxtPC.mtvec := csrReg.io.csrState.mtvec
  io.nxtPC.mret  := valid && (isa       === instMRET)
  io.nxtPC.mepc  := csrReg.io.csrState.mepc
  // (pred, fact)--->(NT, T) or (T, NT)
  protected val predNTfactT = branch  && !predTaken
  protected val predTfactNT = !branch && predTaken
  io.nxtPC.branch := valid && (predNTfactT     || predTfactNT)
  io.nxtPC.tgt    := Mux(valid && predNTfactT, tgt, Mux(valid && predTfactNT, pc + 4.U, 0.U(XLen.W)))
  io.stall        := valid && (io.nxtPC.branch || timeIntrEn || ecallEn || (isa === instMRET))

  io.ex2mem.valid        := Mux(timeIntrEn, false.B, valid)
  io.ex2mem.inst         := inst
  io.ex2mem.pc           := pc
  io.ex2mem.branIdx      := branIdx
  io.ex2mem.predTaken    := predTaken
  io.ex2mem.isa          := isa
  io.ex2mem.src1         := src1
  io.ex2mem.src2         := src2
  io.ex2mem.imm          := imm
  io.ex2mem.wen          := wen
  io.ex2mem.wdest        := wdest
  io.ex2mem.aluRes       := aluRes
  io.ex2mem.branch       := branch
  io.ex2mem.tgt          := tgt
  io.ex2mem.link         := link
  io.ex2mem.auipc        := auipc
  io.ex2mem.csrData      := csrData
  io.ex2mem.timeIntrEn   := timeIntrEn
  io.ex2mem.ecallEn      := ecallEn
  io.ex2mem.csr.mstatus  := csrReg.io.csrState.mstatus
  io.ex2mem.csr.mcause   := csrReg.io.csrState.mcause
  io.ex2mem.csr.mepc     := csrReg.io.csrState.mepc
  io.ex2mem.csr.mie      := csrReg.io.csrState.mie
  io.ex2mem.csr.mscratch := csrReg.io.csrState.mscratch
  io.ex2mem.csr.medeleg  := csrReg.io.csrState.medeleg
  io.ex2mem.csr.mtvec    := csrReg.io.csrState.mtvec
  io.ex2mem.csr.mhartid  := 0.U
  io.ex2mem.csr.mcycle   := 0.U
  io.ex2mem.csr.mip      := 0.U
}

  protected val imm       = exReg.imm
  protected val wen       = exReg.wen
  protected val rs1       = exReg.inst(19, 15)


package treecorel2

import chisel3._
import chisel3.util._

class Multiplier(val len: Int, val latency: Int = 0) extends Module {
  val io = IO(new Bundle {
    val en    = Input(Bool())
    val flush = Input(Bool())
    val done  = Output(Bool())
    val src1  = Input(UInt(len.W))
    val src2  = Input(UInt(len.W))
    val res   = Output(UInt((len * 2).W))
  })

  require(latency >= 0)

  protected val res = io.src1 * io.src2

  def generatePipe(en: Bool, data: UInt, latency: Int): (Bool, UInt) = {
    if (latency == 0) {
      (en, data)

    } else {
      val done = RegNext(Mux(io.flush, false.B, en), false.B)
      val bits = RegEnable(data, en)
      generatePipe(done, bits, latency - 1)
    }


package treecorel2

import chisel3._
import chisel3.util._

class CacheCoreIO extends Bundle {
  val abort = Input(Bool())
  val req   = Flipped(Valid(new CacheReqIO))
  val resp  = Valid(new CacheRespIO)
}

class CacheMemReqIO extends Bundle with InstConfig {
  val id   = UInt(4.W)
  val cmd  = UInt(4.W)
  val addr = UInt(XLen.W)
  val data = UInt(XLen.W)
  val len  = UInt(2.W)
}

class CacheMemRespIO extends Bundle with InstConfig {
  val id   = UInt(4.W)
  val cmd  = UInt(4.W)
  val data = UInt(XLen.W)

}

class CacheMemIO extends Bundle {
  val req  = Decoupled(new CacheMemReqIO)
  val resp = Flipped(Decoupled(new CacheMemRespIO))
}

class Cache(val cacheType: String) extends Module with InstConfig {
  val io = IO(new Bundle {
    val core = new CacheCoreIO
    val mem  = new CacheMemIO
  })
}

class CacheReqIO extends Bundle with InstConfig {
  val addr = UInt(XLen.W)
  val data = UInt(XLen.W) // for write
  val mask = UInt((XLen / 8).W) // for write
}


package treecorel2

import chisel3._
import chisel3.util._

class SOCAXI4ARWIO extends Bundle with AXI4Config {
  val addr  = Output(UInt(32.W))
  val id    = Output(UInt(AxiIdLen.W))
  val len   = Output(UInt(AxiLen.W))
  val size  = Output(UInt(AxiSizeLen.W))
  val burst = Output(UInt(AxiBurstLen.W))
}

class AXI4ARWIO extends SOCAXI4ARWIO {
  override val addr = Output(UInt(XLen.W))
  val prot          = Output(UInt(AxiProtLen.W))
  val user          = Output(UInt(AxiUserLen.W))
  val lock          = Output(Bool())
  val cache         = Output(UInt(AxiCacheLen.W))
  val qos           = Output(UInt(AxiQosLen.W))
}

class SOCAXI4WIO extends Bundle with AXI4Config {
  val data = Output(UInt(XLen.W))
  val strb = Output(UInt(AxiStrb.W))
  val last = Output(Bool())
}

class SOCAXI4BIO extends Bundle with AXI4Config {
  val resp = Output(UInt(AxiRespLen.W))
  val id   = Output(UInt(AxiIdLen.W))
}

class AXI4BIO extends SOCAXI4BIO {
  val user = Output(UInt(AxiUserLen.W))
}

class SOCAXI4RIO extends Bundle with AXI4Config {
  val resp = Output(UInt(AxiRespLen.W))
  val data = Output(UInt(XLen.W))
  val last = Output(Bool())
  val id   = Output(UInt(AxiIdLen.W))
}

class AXI4RIO extends SOCAXI4RIO {
  val user = Output(UInt(AxiUserLen.W))
}

class SOCAXI4IO extends Bundle {
  val aw = Decoupled(new SOCAXI4ARWIO)
  val w  = Decoupled(new SOCAXI4WIO)
  val b  = Flipped(Decoupled(new SOCAXI4BIO))
  val ar = Decoupled(new SOCAXI4ARWIO)
  val r  = Flipped(Decoupled(new SOCAXI4RIO))
}

class AXI4IO extends SOCAXI4IO {
  override val aw = Decoupled(new AXI4ARWIO)
  override val w  = Decoupled(new AXI4WIO)
  override val b  = Flipped(Decoupled(new AXI4BIO))
  override val ar = Decoupled(new AXI4ARWIO)
  override val r  = Flipped(Decoupled(new AXI4RIO))
}


package treecorel2

import chisel3._
import chisel3.util._

class BRANCHIO extends Bundle with IOConfig {
  val branch = Output(Bool()) // prev inst is a b/j
  val jump   = Output(Bool()) // is 'jal' or 'jalr'

  val tgt    = Output(UInt(XLen.W)) // prev branch tgt
}

  val taken  = Output(Bool()) // is prev branch taken
  val idx    = Output(UInt(GHRLen.W)) // prev idx of PHT(GHRLen)


package treecorel2

import chisel3._
import chisel3.util._

class COREIO extends Bundle {

  val globalEn = Output(Bool())
  val fetch    = Flipped(new IFIO)
  val ld       = Flipped(new LDIO)
  val sd       = Flipped(new SDIO)
}


class IFIO extends Bundle with IOConfig {
  val en   = Output(Bool())
  val addr = Output(UInt(XLen.W))
  val data = Input(UInt(InstLen.W))
}


package treecorel2

import chisel3._
import chisel3.util._

class LDIO extends Bundle with IOConfig {
  val en   = Output(Bool())
  val addr = Output(UInt(XLen.W))
  val data = Input(UInt(XLen.W))
  val size = Output(UInt(LDSize.W))
}

class SDIO extends Bundle with IOConfig {
  val en   = Output(Bool())

  val addr = Output(UInt(XLen.W))
  val data = Output(UInt(XLen.W))


class WBDATAIO extends Bundle with IOConfig {
  val wen   = Output(Bool())
  val wdest = Output(UInt(RegfileLen.W))
  val data  = Output(UInt(XLen.W))
}


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VCompare.scala
*       Author          :       yexc
*       Revision        :       2019/04/12
*       Company         :       UC TECH IP
*       Department      :       STG
*       Description     :       compare data
*
*       io.vsrc1e       :       input, bundle of vectors, data, SEW relative, operand 2
*       io.vsrc2e       :       input, bundle of vectors, data, SEW relative, operand 1
*       io.cmpFun       :       input[CmpFun_SZ-1:0], control, function select
*       io.sign         :       input, control, show whether operands are signed values or not
*       io.vlmul        :       input[VLMUL_SZ-1:0], control, vlmul field from vtype CSR
*       io.vCmpOut      :       output, bundle of vectors, data, elements 1 bit width, compare result
*       io.vMinMaxOut   :       output, bundle of vectors, data, SEW relative, Min/Max ones between two values
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

class VCompare(params: VPUParams) extends VModule(params) {
  val io = IO(new Bundle {
    // Input
    val vsrc1e     = Input(new SEWVec)
    val vsrc2e     = Input(new SEWVec)
    val cmpFun     = Input(UInt(CmpFun_SZ.W))
    val sign       = Input(Bool())
    val vlmul      = Input(UInt(VLMUL_SZ.W))
    // Output
    val vCmpOut    = Output(new SEW1wVec)
    val vMinMaxOut = Output(new SEWVec)
  })

  def equal(src1: UInt, src2: UInt): Bool = src1 === src2

  def cmp(src1: UInt, src2: UInt, fun: UInt, sign: Bool): Bool = {
    val equal_wire = Wire(Bool())
    val less_wire = Wire(Bool())
    val greater_wire = Wire(Bool())

    equal_wire := equal(src1, src2)
    less_wire := less(src1, src2, sign)
    greater_wire := Mux(equal_wire, false.B, ~less_wire)

    MuxCase(false.B, Array((fun === "b000".U) -> equal_wire,
                           (fun === "b001".U) -> ~equal_wire,
                           (fun === "b010".U) -> less_wire,
                           (fun === "b011".U) -> (less_wire | equal_wire),
                           (fun === "b100".U) -> greater_wire,
                           (fun === "b101".U) -> less_wire,
                           (fun === "b110".U) -> greater_wire
           ))
    }

  // compare bit output
  for(i <- 0 until e8Depth)
      io.vCmpOut.e8(i) := Mux(cmp(io.vsrc2e.e8(i), io.vsrc1e.e8(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e16Depth)
      io.vCmpOut.e16(i) := Mux(cmp(io.vsrc2e.e16(i), io.vsrc1e.e16(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e32Depth)
      io.vCmpOut.e32(i) := Mux(cmp(io.vsrc2e.e32(i), io.vsrc1e.e32(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e64Depth)
      io.vCmpOut.e64(i) := Mux(cmp(io.vsrc2e.e64(i), io.vsrc1e.e64(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e128Depth)
      io.vCmpOut.e128(i) := Mux(cmp(io.vsrc2e.e128(i), io.vsrc1e.e128(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e256Depth)
      io.vCmpOut.e256(i) := Mux(cmp(io.vsrc2e.e256(i), io.vsrc1e.e256(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e512Depth)
      io.vCmpOut.e512(i) := Mux(cmp(io.vsrc2e.e512(i), io.vsrc1e.e512(i), io.cmpFun, io.sign), 1.U, 0.U)

  for(i <- 0 until e1024Depth)
      io.vCmpOut.e1024(i) := Mux(cmp(io.vsrc2e.e1024(i), io.vsrc1e.e1024(i), io.cmpFun, io.sign), 1.U, 0.U)

  // select min/max value
  for(i <- 0 until e8Depth)
      io.vMinMaxOut.e8(i) := Mux(io.vCmpOut.e8(i) === 1.U, io.vsrc2e.e8(i), io.vsrc1e.e8(i))

  for(i <- 0 until e16Depth)
      io.vMinMaxOut.e16(i) := Mux(io.vCmpOut.e16(i) === 1.U, io.vsrc2e.e16(i), io.vsrc1e.e16(i))

  for(i <- 0 until e32Depth)
      io.vMinMaxOut.e32(i) := Mux(io.vCmpOut.e32(i) === 1.U, io.vsrc2e.e32(i), io.vsrc1e.e32(i))

  for(i <- 0 until e64Depth)
      io.vMinMaxOut.e64(i) := Mux(io.vCmpOut.e64(i) === 1.U, io.vsrc2e.e64(i), io.vsrc1e.e64(i))

  for(i <- 0 until e128Depth)
      io.vMinMaxOut.e128(i) := Mux(io.vCmpOut.e128(i) === 1.U, io.vsrc2e.e128(i), io.vsrc1e.e128(i))

  for(i <- 0 until e256Depth)
      io.vMinMaxOut.e256(i) := Mux(io.vCmpOut.e256(i) === 1.U, io.vsrc2e.e256(i), io.vsrc1e.e256(i))

  for(i <- 0 until e512Depth)
      io.vMinMaxOut.e512(i) := Mux(io.vCmpOut.e512(i) === 1.U, io.vsrc2e.e512(i), io.vsrc1e.e512(i))

  for(i <- 0 until e1024Depth)
      io.vMinMaxOut.e1024(i) := Mux(io.vCmpOut.e1024(i) === 1.U, io.vsrc2e.e1024(i), io.vsrc1e.e1024(i))
}

def less(src1: UInt, src2: UInt, sign: Bool): Bool = Mux(sign, src1.asSInt < src2.asSInt, src1 < src2)


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VDmemResp.scala
*       Author          :       sujy
*       Revision        :       2019/06/18
*       Company         :       UC TECH IP
*       Department      :       MAG
*       Description     :       VPU DCache response handling module
                                (using finite machine)
*
*       io.en           :       input, ...
*       io.din          :       input[width-1:0], ...
*       io.dout         :       output[width-1:0], ...
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

class VDmemResp(params: VPUParams, tagBits: Int, addrBits: Int) extends VModule(params) {
  val dataBits  = XLEN max FLEN
  val dataBytes = dataBits/8
  val sizeBits  = log2Ceil(log2Ceil(dataBytes)+1)

  val io = IO(new Bundle{
    val wd     = Input(Bool())
    val lumop  = Input(UInt(5.W))
    //input, CSR ctrl signals
    val vsew   = Input(UInt(VSEW_SZ.W))
    val vlmul  = Input(UInt(VLMUL_SZ.W))
    val vl     = Input(UInt(XLEN.W))    //decimal
    //input, other ctrl signals
    val vm      = Input(UInt(1.W))
    val sign    = Input(Bool())
    val majFun  = Input(UInt(MajFun_SZ.W))
    val nFields = Input(UInt(NFIELDS_SZ.W))
    //input, DCache response interface
    val respValid   = Input(Bool())
    val respTag     = Input(UInt(tagBits.W))   //7.W
    val respSize     = Input(UInt(sizeBits.W))
    val respHasData = Input(Bool())
    val respData    = Input(UInt(dataBits.W))      // XLEN.W
    //input, DCache status signals
    val mEnable = Input(Bool())    //DCache enable flag
    val mDone   = Input(Bool())    //DCache data transfer complete flag
    val faultFirst = Input(Bool())
    val stopLoad   = Input(Bool())
    val killm      = Input(Bool())
    //input, result of last inst
    val vdvs3e = Input(new FullSEWVec)
//    val v0m    = Input(new MLENVec)
    val v0e    = Input(new FullSEW1wVec)

    //output
    val vRecvOver = Output(Bool())
    val vRecvOut  = Output(UInt((VLEN*8).W))
  })

  //construct a FIFO buffer
  class bufferIO extends Bundle{
    val wen   = Bool()
    val waddr = UInt(log2Ceil(VLEN).W)
    val wdata = UInt(XLEN.W)
    val raddr = UInt(log2Ceil(VLEN).W)
    val rdata = UInt(XLEN.W)
  }

  val elemNumWidth = log2Ceil(VLEN) + 1

  val vm    = Wire(UInt(1.W))
  val vsew  = Wire(UInt(VSEW_SZ.W))
  val vlmul = Wire(UInt(VLMUL_SZ.W))
  val vl    = Wire(UInt(XLEN.W))

  vm    := Mux(io.lumop === UStrideWhole, 1.U, io.vm)
  vsew  := Mux(io.lumop === UStrideWhole, 0.U, io.vsew)
  vlmul := Mux(io.lumop === UStrideWhole, 0.U, io.vlmul)
  vl    := Mux(io.lumop === UStrideWhole, (VLEN/8).U, io.vl)

  val buf   = Wire(new bufferIO)
  val dpram = Mem(VLEN, UInt(XLEN.W))
  val rcnt  = RegInit(0.U((elemNumWidth-1).W))

  val isLoad   = Wire(Bool())
  val mEnable  = Wire(Bool())
  val mDone    = Wire(Bool())

  val extdData = Wire(UInt(XLEN.W))

//  val v0e = Wire(new FullSEW1wVec)   // [TODO] can be simplified by using vwidth.io.v0e

  val recvData8  = Wire(UInt(8.W))
  val recvData16 = Wire(UInt(16.W))
  val recvData32 = Wire(UInt(32.W))
  val recvData64 = Wire(UInt(64.W))
  val recvOver   = Wire(Bool())
  val recvOut    = RegInit(0.U((VLEN*8).W))  //output register

  //--define a finite state machine-
  val s_idle :: s_write :: s_read :: s_done :: Nil = Enum(4)
  val state = RegInit(s_idle)

  //--for-SEGLS--------
  val readDone  = Wire(Bool())
  val elemNum   = RegInit(0.U(elemNumWidth.W))
  val maskIndex = Wire(UInt(log2Ceil(VLEN).W))

  //--segment-load-configuration----
  if(SEGLS){
    val vlmax     = Wire(UInt((elemNumWidth).W))
    val eleOffset = Wire(UInt((log2Ceil(VLEN)+1).W))
    val elemCnt   = RegInit(0.U((elemNumWidth-1).W))
    val maskCnt   = RegInit(0.U((elemNumWidth-1).W))
    val remainReg = RegInit(0.U(3.W))
    val isValid   = Wire(Bool())  // see whether data from buffer should be written to receive reg or not

    vlmax     := 1.U << (log2Ceil(VLEN).U + vlmul - vsew - 3.U)
    eleOffset := VLEN.U >> (vsew + 3.U - vlmul)
    readDone  := remainReg === 0.U && elemCnt === 0.U
    isValid   := rcnt - (eleOffset * remainReg) < vl

    val nFieldsReal  = Wire(UInt(NFIELDS_SZ.W))
    nFieldsReal := Mux(io.majFun === IsAMO, 0.U, io.nFields)
//    elemNum := (vl * (nFieldsReal +& 1.U))(elemNumWidth-1, 0)   //origin
    elemNum := (vlmax * (nFieldsReal +& 1.U))(elemNumWidth-1, 0)

    maskIndex := Mux(nFieldsReal === 0.U, buf.raddr, maskCnt)

    when(state === s_write){
      elemCnt   := vlmax - 1.U
      maskCnt   := vl - 1.U
      remainReg := nFieldsReal
    }
    when(state === s_read ){
      elemCnt   := Mux(elemCnt > 0.U, elemCnt - 1.U, vlmax - 1.U)
      maskCnt   := Mux(elemCnt >= vl, maskCnt, Mux((maskCnt > 0.U), maskCnt - 1.U, vl - 1.U))
      remainReg := Mux(elemCnt === 0.U, remainReg - 1.U, remainReg)
    }

    recvData8  := Mux(isValid, Mux(io.v0e.e8(maskIndex).toBool , buf.rdata(7,0) , io.vdvs3e.e8(buf.raddr) ), 0.U)
    recvData16 := Mux(isValid, Mux(io.v0e.e16(maskIndex).toBool, buf.rdata(15,0), io.vdvs3e.e16(buf.raddr)), 0.U)
    recvData32 := Mux(isValid, Mux(io.v0e.e32(maskIndex).toBool, buf.rdata(31,0), io.vdvs3e.e32(buf.raddr)), 0.U)
    if(XLEN == 64 && ELEN >= 64)
      recvData64 := Mux(isValid, Mux(io.v0e.e64(maskIndex).toBool, buf.rdata(63,0), io.vdvs3e.e64(buf.raddr)), 0.U)
    else
      recvData64 := 0.U
  }
  else{
    readDone := rcnt === 0.U
    elemNum := vl(elemNumWidth-1, 0)
    maskIndex := buf.raddr

    recvData8  := Mux(io.v0e.e8(maskIndex).toBool , buf.rdata(7,0) , io.vdvs3e.e8(buf.raddr) )
    recvData16 := Mux(io.v0e.e16(maskIndex).toBool, buf.rdata(15,0), io.vdvs3e.e16(buf.raddr))
    recvData32 := Mux(io.v0e.e32(maskIndex).toBool, buf.rdata(31,0), io.vdvs3e.e32(buf.raddr))
    if(XLEN == 64 && ELEN >= 64)
      recvData64 := Mux(io.v0e.e64(maskIndex).toBool, buf.rdata(63,0), io.vdvs3e.e64(buf.raddr))
    else
      recvData64 := 0.U
  }

  //--extend received data----------
  extdData := MuxCase(0.U, Array()
    ++ Array((io.respSize === 0.U) -> Mux(io.sign,
                                         Cat(Fill(XLEN-8, io.respData(7)), io.respData(7,0)),
                                         Cat(0.U((XLEN-8).W)             , io.respData(7,0))),
             (io.respSize === 1.U) -> Mux(io.sign,
                                         Cat(Fill(XLEN-16, io.respData(15)), io.respData(15,0)),
                                         Cat(0.U((XLEN-16).W)              , io.respData(15,0))))
    ++ (if(XLEN == 32)
          Array((io.respSize === 2.U) -> io.respData(31,0))
        else if(XLEN == 64 && ELEN >= 64)
          Array((io.respSize === 2.U) -> Mux(io.sign,
                                            Cat(Fill(XLEN-32, io.respData(31)), io.respData(31,0)),
                                            Cat(0.U((XLEN-32).W)              , io.respData(31,0))),
                (io.respSize === 3.U) -> io.respData(63,0))
        else Nil))

  //--buffer initialization---------
  buf.wen   := isLoad && io.respValid && io.respHasData && vl =/= 0.U && !io.stopLoad && !io.faultFirst
  buf.waddr := io.respTag
  buf.wdata := extdData
  buf.raddr := rcnt
  buf.rdata := 0.U
  recvOver  := false.B

  isLoad  := io.majFun === IsLoad || (io.majFun === IsAMO && io.wd)
  mEnable := isLoad && io.mEnable   //valid only if current inst is 'load'
  mDone   := isLoad && io.mDone     //valid only if current inst is 'load'

  //--buffer controller-------------
  switch(state){
    is(s_idle){
      when(io.killm || io.faultFirst)
        { state := s_idle }
      .elsewhen(io.majFun === IsAMO && !io.wd)
        { state := s_idle }
      .elsewhen(vl =/= 0.U && mEnable || (io.majFun === IsAMO && io.wd))

    }
    is(s_write){
      when(io.killm)
        { state := s_idle }
      .elsewhen(mDone || io.stopLoad)
        { state := s_read }
    }
    is(s_read){
      when(io.killm)
        { state := s_idle }
      .elsewhen(readDone)
        { state := s_done }
    }
    is(s_done) { state := s_idle }
  }

  when(state === s_idle){
    recvOut := 0.U
  }
  when(state === s_write) {
    rcnt := elemNum - 1.U
    when(buf.wen) { dpram(buf.waddr) := buf.wdata }
  }
  when(state === s_read) {
    rcnt      := Mux(rcnt === 0.U, elemNum - 1.U, rcnt - 1.U)
    buf.rdata := dpram(buf.raddr)

    recvOut   := MuxCase(0.U, Array()
      ++ Array((vsew === 0.U) -> (recvOut << 8  | recvData8 ),
               (vsew === 1.U) -> (recvOut << 16 | recvData16),
               (vsew === 2.U) -> (recvOut << 32 | recvData32))
      ++ (if(XLEN == 64 && ELEN >= 64)
         Array((vsew === 3.U) -> (recvOut << 64 | recvData64))
         else Nil))
  }
  when(state === s_done){
    recvOver := true.B
    recvOut  := 0.U
  }

  //--output------------------------
  io.vRecvOver := recvOver
  io.vRecvOut  := Mux(recvOver, recvOut, 0.U)

}


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VDmemSplitSplit.scala
*       Author          :       liangzh
*       Revision        :       2019/06/24
*       Company         :       UC TECH IP
*       Department      :       MAG
*       Description     :       split 8VLEN data to SEW or MLEN width data
*
*       io.vs2Data      :       input[8VLEN-1:0], data, to be split
*       io.vdvs3Data    :       input[8VLEN-1:0], data, to be split
*       io.v0Mask       :       input[VLEN-1:0], data, to be split
*       io.vs2e         :       output bundle of vectors, data, split vs2Data into SEW width
*       io.vdvs3e       :       output bundle of vectors, data, split vdvs3Data into SEW width
*       io.v0m          :       output bundle of vectors, data, split v0Mask into MLEN width
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

class VDmemSplit(params: VPUParams) extends VModule(params) {
  val io = IO(new Bundle {
    val vs2Data   = Input(UInt((8*VLEN).W))
    val vdvs3Data = Input(UInt((8*VLEN).W))
    val v0Mask    = Input(UInt(VLEN.W))

    val vs2e      = Output(new FullSEWVec)
    val vdvs3e    = Output(new FullSEWVec)

    val v0m       = Output(new MLENVec)
  })

    for(i <- 0 until E512Depth)  io.vs2e.e512(i)    := io.vs2Data(512*(i+1)-1, 512*i)
    for(i <- 0 until E1024Depth) io.vs2e.e1024(i)   := io.vs2Data(1024*(i+1)-1, 1024*i)
//split vdvs3Data into SEW width vectors
    for(i <- 0 until E8Depth)    io.vdvs3e.e8(i)    := io.vdvs3Data(8*(i+1)-1, 8*i)
    for(i <- 0 until E16Depth)   io.vdvs3e.e16(i)   := io.vdvs3Data(16*(i+1)-1, 16*i)
    for(i <- 0 until E32Depth)   io.vdvs3e.e32(i)   := io.vdvs3Data(32*(i+1)-1, 32*i)
    for(i <- 0 until E64Depth)   io.vdvs3e.e64(i)   := io.vdvs3Data(64*(i+1)-1, 64*i)
    for(i <- 0 until E128Depth)  io.vdvs3e.e128(i)  := io.vdvs3Data(128*(i+1)-1, 128*i)
    for(i <- 0 until E256Depth)  io.vdvs3e.e256(i)  := io.vdvs3Data(256*(i+1)-1, 256*i)
    for(i <- 0 until E512Depth)  io.vdvs3e.e512(i)  := io.vdvs3Data(512*(i+1)-1, 512*i)
    for(i <- 0 until E1024Depth) io.vdvs3e.e1024(i) := io.vdvs3Data(1024*(i+1)-1, 1024*i)
//split v0Mask into MLEN width vectors
    for(i <- 0 until m1Depth)    io.v0m.m1(i)       := io.v0Mask(i)
    for(i <- 0 until m2Depth)    io.v0m.m2(i)       := io.v0Mask(2*i)
    for(i <- 0 until m4Depth)    io.v0m.m4(i)       := io.v0Mask(4*i)
    for(i <- 0 until m8Depth)    io.v0m.m8(i)       := io.v0Mask(8*i)
    for(i <- 0 until m16Depth)   io.v0m.m16(i)      := io.v0Mask(16*i)
    for(i <- 0 until m32Depth)   io.v0m.m32(i)      := io.v0Mask(32*i)
    for(i <- 0 until m64Depth)   io.v0m.m64(i)      := io.v0Mask(64*i)
    for(i <- 0 until m128Depth)  io.v0m.m128(i)     := io.v0Mask(128*i)
    for(i <- 0 until m256Depth)  io.v0m.m256(i)     := io.v0Mask(256*i)
    for(i <- 0 until m512Depth)  io.v0m.m512(i)     := io.v0Mask(512*i)
    for(i <- 0 until m1024Depth) io.v0m.m1024(i)    := io.v0Mask(1024*i)
}

//split vs2Data into SEW width vectors
    for(i <- 0 until E8Depth)    io.vs2e.e8(i)      := io.vs2Data(8*(i+1)-1, 8*i)
    for(i <- 0 until E16Depth)   io.vs2e.e16(i)     := io.vs2Data(16*(i+1)-1, 16*i)
    for(i <- 0 until E32Depth)   io.vs2e.e32(i)     := io.vs2Data(32*(i+1)-1, 32*i)


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VFDivSqrt.scala
*       Author          :       yexc
*       Revision        :       2020/01/13
*       Company         :       UC TECH IP
*       Department      :
*       Description     :
*
*       io.en           :       input, ...
*       io.din          :       input[width-1:0], ...
*       io.dout         :       output[width-1:0], ...
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

import vpu.DataGating._
import vpu.HardFloatHelper._
import vpu.Packing._
import vpu.util._

//class VFDivSqrt(params: VPUParams)(implicit p: Parameters) extends VModule(params)(p) {
class VFDivSqrt(params: VPUParams) extends VModule(params) {
    class VFDUFn(sz_op: Int) extends Bundle {
      val rm = UInt(VPUConstants.FRM_SZ.W)
      val op = UInt(sz_op.W)

      def dgate(valid: Bool) = DataGating.dgate(valid, this.asUInt).asTypeOf(this.cloneType)

      override def cloneType = new VFDUFn(sz_op).asInstanceOf[this.type]
    }

   class VFDivSqrtOperand extends Bundle {
      val fn = new VFDUFn(FDivFun_SZ)
      val vsrc1e = new FUCBVec
      val vsrc2e = new FUCBVec
      val v0en   = new FSEW1wVec
      override def cloneType = new VFDivSqrtOperand().asInstanceOf[this.type]
     }

    class VFDivSqrtResult extends Bundle {
       val vFDivSqrtOut = new FUCBVec
       //val exc      = UInt(VPUConstants.FFLAGS_SZ.W)
       val exc      = new FFLAGSVec
       override def cloneType = new VFDivSqrtResult().asInstanceOf[this.type]
     }

  val io = IO(new Bundle {
     val vsew  = Input(UInt(VSEW_SZ.W))
     val kill  = Input(Bool())
     val req   = Flipped(Decoupled(new VFDivSqrtOperand))
     val resp  = Decoupled(new VFDivSqrtResult)
  })

  val fn = io.req.bits.fn

  val f16_vsrc1 = io.req.bits.vsrc1e.f16
  val f16_vsrc2 = io.req.bits.vsrc2e.f16
  val f16_en  = io.req.bits.v0en.f16

  val f32_vsrc1 = io.req.bits.vsrc1e.f32
  val f32_vsrc2 = io.req.bits.vsrc2e.f32
  val f32_en  = io.req.bits.v0en.f32

  val f64_vsrc1 = io.req.bits.vsrc1e.f64
  val f64_vsrc2 = io.req.bits.vsrc2e.f64
  val f64_en  = io.req.bits.v0en.f64

  val f128_vsrc1 = io.req.bits.vsrc1e.f128
  val f128_vsrc2 = io.req.bits.vsrc2e.f128
  val f128_en  = io.req.bits.v0en.f128

  val enableFlagPre = Wire(Bool())
  val enableFlagReg = RegInit(false.B)

  enableFlagPre := Mux(io.req.fire(), true.B, Mux(io.resp.fire(), false.B, enableFlagReg))
  enableFlagReg := enableFlagPre

  val results =
         List((FPS, f32_vsrc1, f32_vsrc2, f32_en, f32Depth, recode_sp _, ieee_sp _, (8, 24))) ++
 (F16).option((FPH, f16_vsrc1, f16_vsrc2, f16_en, f16Depth, recode_hp _, ieee_hp _, (5, 11))) ++
 (F64).option((FPD, f64_vsrc1, f64_vsrc2, f64_en, f64Depth, recode_dp _, ieee_dp _, (11, 53))) ++
(F128).option((FPQ, f128_vsrc1,f128_vsrc2,f128_en,f128Depth,recode_qp _, ieee_qp _, (16, 112))) map {
     case (fp, vsrc1, vsrc2, v0en, fDepth, recode, ieee, (exp, sig)) => {
       val outData = Wire(Vec(fDepth, UInt((exp+sig+1).W)))
       val outValid = Wire(Vec(fDepth, Bool()))
       val inReady = Wire(Vec(fDepth, Bool()))
       val exc = Wire(Vec(fDepth, UInt(5.W)))
       val transValidPre = Wire(Vec(fDepth, Bool()))
       val transValidReg = RegInit(VecInit(Seq.fill(fDepth)(false.B)))
       for(i <- 0 until fDepth)
       {
         val divSqrt = Module(new hardfloat.DivSqrtRecFN_small(exp, sig, 0))
         val name = "DivSqrt_f" + (exp+sig).toString
         divSqrt.suggestName(name)
         val valid = (io.vsew === fp) && io.req.valid
         val lhs = MuxCase(0.U, Array(
              fn.op_is(FDivFun_Div)  -> vsrc2(i),
              fn.op_is(FDivFun_RDiv) -> vsrc1(i),
              fn.op_is(FDivFun_Sqrt) -> vsrc2(i)
           ))
         val rhs = MuxCase(0.U, Array(
              fn.op_is(FDivFun_Div)  -> vsrc1(i),
              fn.op_is(FDivFun_RDiv) -> vsrc2(i),
              fn.op_is(FDivFun_Sqrt) -> vsrc2(i)
           ))
         divSqrt.io.inValid := Pipe(true.B, (v0en(i) === 1.U) && valid, 1).bits
         divSqrt.io.sqrtOp := Pipe(true.B, fn.op_is(FDivFun_Sqrt), 1).bits
         divSqrt.io.a := (RegNext(lhs, 0.U))
         divSqrt.io.b := (RegNext(rhs, 0.U))
         divSqrt.io.roundingMode := RegNext(io.req.bits.fn.rm, 0.U)
         divSqrt.io.detectTininess := hardfloat.consts.tininess_afterRounding

         outValid(i) := MuxCase(false.B, Array(
            fn.op_is(FDivFun_Sqrt) -> divSqrt.io.outValid_sqrt,
            fn.op_is(FDivFun_Div, FDivFun_RDiv) -> divSqrt.io.outValid_div
         ))
         inReady(i) := divSqrt.io.inReady
         outData(i) := (divSqrt.io.out)
         exc(i) := divSqrt.io.exceptionFlags
         transValidPre(i) := Mux(io.resp.fire(), false.B,
               Mux(outValid(i) || (!(v0en(i) === 1.U) && valid && enableFlagPre), true.B, transValidReg(i)))
         transValidReg(i) := transValidPre(i)
      }

      //(outData, exc, outValid, inReady)
      (outData, exc, transValidReg, inReady)
     }
   }

  (F32, F16, F64, F128) match {
    case (true, false, false, false) => { // F32
     for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := (results(0)._1)(i)
     //io.resp.bits.exc := results(0)._2.reduce(_|_)
     io.resp.bits.exc.exc32 := results(0)._2
     io.resp.valid := results(0)._3.reduce(_&&_)
     io.req.ready := results(0)._4.reduce(_&&_)
    }
    case (true, true, false, false) => { // F32, F16
     for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := (results(0)._1)(i)
     for(i <- 0 until f16Depth)    io.resp.bits.vFDivSqrtOut.f16(i) := (results(1)._1)(i)
     //io.resp.bits.exc := MuxCase(0.U, Array(
     //  (io.vsew === FPS) -> results(0)._2.reduce(_|_),
     //  (io.vsew === FPH) -> results(1)._2.reduce(_|_)
     //))
     io.resp.bits.exc.exc32 := results(0)._2
     io.resp.bits.exc.exc16 := results(1)._2
     io.resp.valid := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._3.reduce(_&&_),
       (io.vsew === FPH) -> results(1)._3.reduce(_&&_)
     ))
     io.req.ready := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._4.reduce(_&&_),
       (io.vsew === FPH) -> results(1)._4.reduce(_&&_)
     ))
    }
    case (true, false, true, false) => { // F32, F64
     //for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := dgate(io.resp.valid, (results(0)._1)(i))
     //for(i <- 0 until f64Depth)    io.resp.bits.vFDivSqrtOut.f64(i) := dgate(io.resp.valid, (results(1)._1)(i))
     for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := (results(0)._1)(i)
     for(i <- 0 until f64Depth)    io.resp.bits.vFDivSqrtOut.f64(i) := (results(1)._1)(i)
     //io.resp.bits.exc := MuxCase(0.U, Array(
     //  (io.vsew === FPS) -> results(0)._2.reduce(_|_),
     //  (io.vsew === FPD) -> results(1)._2.reduce(_|_)
     //))
     io.resp.bits.exc.exc32 := results(0)._2
     io.resp.bits.exc.exc64 := results(1)._2
     io.resp.valid := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._3.reduce(_&&_),
       (io.vsew === FPD) -> results(1)._3.reduce(_&&_)
      ))
     io.req.ready := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._4.reduce(_&&_),
       (io.vsew === FPD) -> results(1)._4.reduce(_&&_)
     ))
    }
    case (true, true, true, false) => { // F32, F16, F64
     for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := (results(0)._1)(i)
     for(i <- 0 until f16Depth)    io.resp.bits.vFDivSqrtOut.f16(i) := (results(1)._1)(i)
     for(i <- 0 until f64Depth)    io.resp.bits.vFDivSqrtOut.f64(i) := (results(2)._1)(i)
     //io.resp.bits.exc := MuxCase(0.U, Array(
     //  (io.vsew === FPS) -> results(0)._2.reduce(_|_),
     //  (io.vsew === FPH) -> results(1)._2.reduce(_|_),
     //  (io.vsew === FPD) -> results(2)._2.reduce(_|_)
     //))
     io.resp.bits.exc.exc32 := results(0)._2
     io.resp.bits.exc.exc16 := results(1)._2
     io.resp.bits.exc.exc64 := results(2)._2
     io.resp.valid := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._3.reduce(_&&_),
       (io.vsew === FPH) -> results(1)._3.reduce(_&&_),
       (io.vsew === FPD) -> results(2)._3.reduce(_&&_)
     ))
     io.req.ready := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._4.reduce(_&&_),
       (io.vsew === FPH) -> results(1)._4.reduce(_&&_),
       (io.vsew === FPD) -> results(2)._4.reduce(_&&_)
     ))
    }
    case (true, false, true, true) => { // F32, F64, F128
     for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := (results(0)._1)(i)
     for(i <- 0 until f64Depth)    io.resp.bits.vFDivSqrtOut.f64(i) := (results(1)._1)(i)
     for(i <- 0 until f128Depth)    io.resp.bits.vFDivSqrtOut.f128(i) := (results(2)._1)(i)
     //io.resp.bits.exc := MuxCase(0.U, Array(
     //  (io.vsew === FPS) -> results(0)._2.reduce(_|_),
     //  (io.vsew === FPD) -> results(1)._2.reduce(_|_),
     //  (io.vsew === FPQ) -> results(2)._2.reduce(_|_)
     //))
     io.resp.bits.exc.exc32 := results(0)._2
     io.resp.bits.exc.exc64 := results(1)._2
     io.resp.bits.exc.exc128 := results(2)._2
     io.resp.valid := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._3.reduce(_&&_),
       (io.vsew === FPD) -> results(1)._3.reduce(_&&_),
       (io.vsew === FPQ) -> results(2)._3.reduce(_&&_)
     ))
     io.req.ready := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._4.reduce(_&&_),
       (io.vsew === FPD) -> results(1)._4.reduce(_&&_),
       (io.vsew === FPQ) -> results(2)._4.reduce(_&&_)
     ))
    }
    case (true, true, true, true) => { // F32, F16, F64, F128
     for(i <- 0 until f32Depth)    io.resp.bits.vFDivSqrtOut.f32(i) := (results(0)._1)(i)
     for(i <- 0 until f16Depth)    io.resp.bits.vFDivSqrtOut.f16(i) := (results(1)._1)(i)
     for(i <- 0 until f64Depth)    io.resp.bits.vFDivSqrtOut.f64(i) := (results(2)._1)(i)
     for(i <- 0 until f128Depth)   io.resp.bits.vFDivSqrtOut.f128(i) := (results(3)._1)(i)
     //io.resp.bits.exc := MuxCase(0.U, Array(
     //  (io.vsew === FPS) -> results(0)._2.reduce(_|_),
     //  (io.vsew === FPH) -> results(1)._2.reduce(_|_),
     //  (io.vsew === FPD) -> results(2)._2.reduce(_|_),
     //  (io.vsew === FPQ) -> results(3)._2.reduce(_|_)
     //))
     io.resp.bits.exc.exc32 := results(0)._2
     io.resp.bits.exc.exc16 := results(1)._2
     io.resp.bits.exc.exc64 := results(2)._2
     io.resp.bits.exc.exc128 := results(3)._2
     io.resp.valid := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._3.reduce(_&&_),
       (io.vsew === FPH) -> results(1)._3.reduce(_&&_),
       (io.vsew === FPD) -> results(2)._3.reduce(_&&_),
       (io.vsew === FPQ) -> results(3)._2.reduce(_|_)
     ))
     io.req.ready := MuxCase(false.B, Array(
       (io.vsew === FPS) -> results(0)._4.reduce(_&&_),
       (io.vsew === FPH) -> results(1)._4.reduce(_&&_),
       (io.vsew === FPD) -> results(2)._4.reduce(_&&_),
       (io.vsew === FPQ) -> results(3)._2.reduce(_|_)
     ))
    }
    case _ => {
     // do nothing
    }
  }

}

def op_is(ops: UInt*) = ops.toList.map(x => {op === x}).reduceLeft(_ || _)


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VFSignInject.scala
*       Author          :       liangzh
*       Revision        :       2020/01/04
*       Company         :       UC TECH IP
*       Department      :       MAG
*       Description     :       floating-point sign-inject module
*
*       io.vsrc1f       :       input, bundle of vectors, data, UCB relative, sign-inject operand 2
*       io.vsrc2f       :       input, bundle of vertors, data, UCB relative, sign-inject operand 1
*       io.fsgnjFun     :       input[FSgnJFun_SZ-1:0], control, function select
*       io.vFSgnJOut    :       output, bundle of vectors, data, UCB relative, sign-inject result
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

class VFSignInject(params: VPUParams) extends VModule(params) {
  val io = IO(new Bundle {
    val vsrc1f    = Input(new FUCBVec)
    val vsrc2f    = Input(new FUCBVec)
    val fsgnjFun  = Input(UInt(FSgnJFun_SZ.W))
    val vFSgnJOut = Output(new FUCBVec)
  })

  }
  for(i <- 0 until f64Depth) {
    io.vFSgnJOut.f64(i) := MuxCase(Cat(io.vsrc1f.f64(i)(64), io.vsrc2f.f64(i)(63,0)),
                            Array((io.fsgnjFun === FSgnJFun_Not) -> Cat(~io.vsrc1f.f64(i)(64), io.vsrc2f.f64(i)(63,0)),
                                  (io.fsgnjFun === FSgnJFun_Xor) -> Cat(io.vsrc1f.f64(i)(64) ^ io.vsrc2f.f64(i)(64), io.vsrc2f.f64(i)(63,0))))
  }
  for(i <- 0 until f128Depth) {
    io.vFSgnJOut.f128(i) := MuxCase(Cat(io.vsrc1f.f128(i)(128), io.vsrc2f.f128(i)(127,0)),
                             Array((io.fsgnjFun === FSgnJFun_Not) -> Cat(~io.vsrc1f.f128(i)(128), io.vsrc2f.f128(i)(127,0)),
                                   (io.fsgnjFun === FSgnJFun_Xor) -> Cat(io.vsrc1f.f128(i)(128) ^ io.vsrc2f.f128(i)(128), io.vsrc2f.f128(i)(127,0))))
  }
}

  for(i <- 0 until f16Depth) {
    io.vFSgnJOut.f16(i) := MuxCase(Cat(io.vsrc1f.f16(i)(16), io.vsrc2f.f16(i)(15,0)),
                            Array((io.fsgnjFun === FSgnJFun_Not) -> Cat(~io.vsrc1f.f16(i)(16), io.vsrc2f.f16(i)(15,0)),
                                  (io.fsgnjFun === FSgnJFun_Xor) -> Cat(io.vsrc1f.f16(i)(16) ^ io.vsrc2f.f16(i)(16), io.vsrc2f.f16(i)(15,0))))
  }


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VFWidthConvert.scala
*       Author          :       liangzh
*       Revision        :       2020/01/09
*       Company         :       UC TECH IP
*       Department      :       MAG
*       Description     :       convert floating-point vector elements' width
*
*       io.reqValid     :       input, control, request valid
*       io.isSrc12SEW   :       input, control, showing whether source 1 is double SEW width or not
*       io.isSrc22SEW   :       input, control, showing whether source 2 is double SEW width or not
*       io.isVd2SEW     :       input, control, showing whether destination is double SEW width or not
*       io.src1Typ      :       ipnut[Src1Typ_SZ-1:0], control, showing the type of source 1 is which type: vector, scalar or immediate
*       io.majFun       :       input[MajFun_SZ-1:0], control, showing which major function the inst is
*       io.fcvtFun      :       input[FCvtFun_SZ-1:0], control, showing function of a floating-point convert inst
*       io.frm          :       input[FRM_SZ-1:0], control, floating-point rounding mode
*       io.fromXData1   :       input[XLEN-1:0], data, from rocket GPR data
*       io.fromFData    :       input[FLEN:0], data, from FPU floating-point registers data
*       io.vs1e         :       input, bundle of vectors, data, SEW relative, to be width convert source 1
*       io.vs2e         :       input, bundle of vectors, data, SEW relative, to be width convert source 2
*       io.vdvs3e       :       input, bundle of vectors, data, SEW relative, to be recode to UCB pattern destination
*       io.respValid    :       output, control, showing output data valid
*       io.vsrc1f       :       output, bundle of vectors, data, UCB relative, width converted source 1
*       io.vsrc2f       :       output, bundle of vectors, data, UCB relative, width converted source 2
*       io.vdvs3f       :       output, bundle of vectors, data, UCB relative, UCB recoded destination
*       io.vFtoFExc     :       output, bundle of vectors, data, elements all FFLAGS_SZ bits, fflags from width convert process
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

class VFWidthConvert(params: VPUParams) extends VModule(params) with HasFPUParameters {
  val io = IO(new Bundle {
    val reqValid   = Input(Bool())
    val isSrc12SEW = Input(Bool())
    val isSrc22SEW = Input(Bool())
    val isVd2SEW   = Input(Bool())
    val src1Typ    = Input(UInt(Src1Typ_SZ.W))
    val majFun     = Input(UInt(MajFun_SZ.W))
    val fcvtFun    = Input(UInt(FCvtFun_SZ.W))
    val frm        = Input(UInt(VPUConstants.FRM_SZ.W))

    val fromXData1 = Input(UInt(XLEN.W))
    val fromFData  = Input(UInt((FLEN+1).W))
    val vs1e       = Input(new SEWVec)
    val vs2e       = Input(new SEWVec)
    val vdvs3e     = Input(new SEWVec)

    val respValid  = Output(new Bool())
    val vsrc1f     = Output(new FUCBVec)
    val vsrc2f     = Output(new FUCBVec)
    val vdvs3f     = Output(new FUCBVec)
    val vFtoFExc   = Output(new FFLAGSVec)
  })

  val isV1Origin  = io.src1Typ === Src1_Vs && (!io.isVd2SEW || io.isSrc12SEW)
  val isV1to2SEW  = io.src1Typ === Src1_Vs && io.isVd2SEW
  val isF1toSEW   = io.src1Typ === Src1_Fs && !io.isVd2SEW
  val isF1to2SEW  = io.src1Typ === Src1_Fs && io.isVd2SEW

  val isV2Origin  = io.majFun === IsFCvt && (io.fcvtFun =/= FCvtFun_F2WF && io.fcvtFun =/= FCvtFun_F2NF) ||
                    io.majFun =/= IsFCvt && (io.isSrc22SEW || !io.isVd2SEW)
  val isV2to2SEW  = io.majFun === IsFCvt && io.fcvtFun === FCvtFun_F2WF ||
                    io.majFun =/= IsFCvt && !io.isSrc22SEW && io.isVd2SEW
  val isV2toHSEW  = io.majFun === IsFCvt && io.fcvtFun === FCvtFun_F2NF

  val vsrc1f    = RegInit(0.U.asTypeOf(new FUCBVec))
  val vsrc2f    = RegInit(0.U.asTypeOf(new FUCBVec))
  val vFtoFExc  = RegInit(0.U.asTypeOf(new FFLAGSVec))
  val respValid = RegNext(io.reqValid, false.B)

  val qNaN16  = Cat(~(0.U(7.W)), 0.U(9.W))
  val qNaN32  = Cat(~(0.U(10.W)), 0.U(22.W))
  val qNaN64  = Cat(~(0.U(13.W)), 0.U(51.W))
  val qNaN128 = Cat(~(0.U(17.W)), 0.U(111.W))
  val ucb33   = unbox(io.fromFData, false.B, Some(FType.S))
  val ucb65   = unbox(io.fromFData, false.B, Some(FType.D))

  def F33ToH1: UInt = unbox(io.fromFData, false.B, Some(FType.H))
  def F65ToH1: UInt = unbox(io.fromFData, false.B, Some(FType.H))
  def F32ToH1: UInt = FType.H.recode(Mux(io.fromXData1(31,16).andR, io.fromXData1(15,0), qNaN16))
  def F64ToH1: UInt = FType.H.recode(Mux(io.fromXData1(63,16).andR, io.fromXData1(15,0), qNaN16))
  def FH1: UInt = if(!ZFINX && FLEN == 32)      F33ToH1
                  else if(!ZFINX && FLEN == 64) F65ToH1
                  else if(ZFINX && XLEN == 32)  F32ToH1
                  else                          F64ToH1

  def F33ToS1: UInt = ucb33
  def F65ToS1: UInt = ucb33
  def F32ToS1: UInt = FType.S.recode(io.fromXData1)

  def FS1: UInt = if(!ZFINX && FLEN == 32)      F33ToS1
                  else if(!ZFINX && FLEN == 64) F65ToS1
                  else if(ZFINX && XLEN == 32)  F32ToS1
                  else                          F64ToS1

  def F33ToD1: UInt = box(ucb33, FType.D)
  def F65ToD1: UInt = ucb65
  def F32ToD1: UInt = FType.D.recode(Cat(~(0.U(32.W)), io.fromXData1))
  def F64ToD1: UInt = FType.D.recode(io.fromXData1)
  def FD1: UInt = if(!ZFINX && FLEN == 32)      F33ToD1
                  else if(!ZFINX && FLEN == 64) F65ToD1
                  else if(ZFINX && XLEN == 32)  F32ToD1
                  else                          F64ToD1

  def F33ToQ1: UInt = box(ucb33, FType.Q)
  def F65ToQ1: UInt = box(ucb65, FType.Q)
  def F32ToQ1: UInt = FType.Q.recode(Cat(~(0.U(96.W)), io.fromXData1))
  def F64ToQ1: UInt = FType.Q.recode(Cat(~(0.U(64.W)), io.fromXData1))
  def FQ1: UInt = if(!ZFINX && FLEN == 32)      F33ToQ1
                  else if(!ZFINX && FLEN == 64) F65ToQ1
                  else if(ZFINX && XLEN == 32)  F32ToQ1
                  else                          F64ToQ1

  def HToS(ucbH: UInt): UInt = {
    val htos = Module(new hardfloat.RecFNToRecFN(FType.H.exp, FType.H.sig, FType.S.exp, FType.S.sig))
    htos.io.in := ucbH
    htos.io.roundingMode := io.frm
    htos.io.detectTininess := hardfloat.consts.tininess_afterRounding
    htos.io.out
  }
  def SToD(ucbS: UInt): UInt = {
    val stod = Module(new hardfloat.RecFNToRecFN(FType.S.exp, FType.S.sig, FType.D.exp, FType.D.sig))
    stod.io.in := ucbS
    stod.io.roundingMode := io.frm
    stod.io.detectTininess := hardfloat.consts.tininess_afterRounding
    stod.io.out
  }
  def DToQ(ucbD: UInt): UInt = {
    val dtoq = Module(new hardfloat.RecFNToRecFN(FType.D.exp, FType.D.sig, FType.Q.exp, FType.Q.sig))
    dtoq.io.in := ucbD
    dtoq.io.roundingMode := io.frm
    dtoq.io.detectTininess := hardfloat.consts.tininess_afterRounding
    dtoq.io.out
  }
  def SToH(ucbS: UInt): UInt = {
    val stoh = Module(new hardfloat.RecFNToRecFN(FType.S.exp, FType.S.sig, FType.H.exp, FType.H.sig))
    stoh.io.in := ucbS
    stoh.io.roundingMode := io.frm
    stoh.io.detectTininess := hardfloat.consts.tininess_afterRounding
    Cat(stoh.io.out, stoh.io.exceptionFlags)
  }
  def DToS(ucbD: UInt): UInt = {
    val dtos = Module(new hardfloat.RecFNToRecFN(FType.D.exp, FType.D.sig, FType.S.exp, FType.S.sig))
    dtos.io.in := ucbD
    dtos.io.roundingMode := io.frm
    dtos.io.detectTininess := hardfloat.consts.tininess_afterRounding
    Cat(dtos.io.out, dtos.io.exceptionFlags)
  }
  def QToD(ucbQ: UInt): UInt = {
    val qtod = Module(new hardfloat.RecFNToRecFN(FType.Q.exp, FType.Q.sig, FType.D.exp, FType.D.sig))
    qtod.io.in := ucbQ
    qtod.io.roundingMode := io.frm
    qtod.io.detectTininess := hardfloat.consts.tininess_afterRounding
    Cat(qtod.io.out, qtod.io.exceptionFlags)
  }
/////*convert vs1's width SEW to 2SEW and fs1's width to SEW for floating-point operation*////
  for(i <- 0 until f16Depth)
    vsrc1f.f16(i) := MuxCase(FType.H.qNaN, Array(isV1Origin -> FType.H.recode(io.vs1e.e16(i)),
                                                 isF1toSEW  -> FH1))

  for(i <- 0 until f32Depth)
    vsrc1f.f32(i) := MuxCase(FType.S.qNaN,
                       Array(isV1Origin -> FType.S.recode(io.vs1e.e32(i)),
                             isF1toSEW  -> FS1)
                     ++ (if(FSEW16) Array(isV1to2SEW -> HToS(FType.H.recode(io.vs1e.e16(i))),
                                          isF1to2SEW -> HToS(FH1))
                         else Nil))

  for(i <- 0 until f64Depth)
    vsrc1f.f64(i) := MuxCase(FType.D.qNaN,
                       Array(isV1Origin -> FType.D.recode(io.vs1e.e64(i)),
                             isF1toSEW  -> FD1,
                             isV1to2SEW -> SToD(FType.S.recode(io.vs1e.e32(i))),
                             isF1to2SEW -> SToD(FS1)))

  for(i <- 0 until f128Depth)
    vsrc1f.f128(i) := MuxCase(FType.Q.qNaN,
                        Array(isV1Origin -> FType.Q.recode(io.vs1e.e128(i)),
                              isF1toSEW  -> FQ1,
                              isV1to2SEW -> DToQ(FType.D.recode(io.vs1e.e64(i))),
                              isF1to2SEW -> DToQ(FD1)))

////////*convert vs2's width SEW to 2SEW or 2SEW to SEW for floating-point operation*/////////
//half precision
  for(i <- 0 until f16Depth/2) {
    val fexc17 = MuxCase(Cat(FType.H.qNaN, 0.U(5.W)),
                   Array(isV2Origin -> Cat(FType.H.recode(io.vs2e.e16(i)), 0.U(5.W)),
                         isV2toHSEW -> SToH(FType.S.recode(io.vs2e.e32(i)))))
    vsrc2f.f16(i)     := fexc17(21,5)
    vFtoFExc.exc16(i) := fexc17(4,0)
  }
  for(i <- f16Depth/2 until f16Depth) {
    vsrc2f.f16(i)     := FType.H.recode(io.vs2e.e16(i))
    vFtoFExc.exc16(i) := 0.U(5.W)
  }
//single precision
  for(i <- 0 until f32Depth/2) {
    val fexc33 = MuxCase(Cat(FType.S.qNaN, 0.U(5.W)),
                   Array(isV2Origin -> Cat(FType.S.recode(io.vs2e.e32(i)), 0.U(5.W)))
                 ++ (if(FSEW16)        Array(isV2to2SEW -> Cat(HToS(FType.H.recode(io.vs2e.e16(i))), 0.U(5.W))) else Nil)
                 ++ (if(FSEWMAX >= 64) Array(isV2toHSEW -> DToS(FType.D.recode(io.vs2e.e64(i))))                else Nil))
    vsrc2f.f32(i)     := fexc33(37,5)
    vFtoFExc.exc32(i) := fexc33(4,0)
  }
  for(i <- f32Depth/2 until f32Depth) {
    vsrc2f.f32(i) := MuxCase(FType.S.qNaN,
                       Array(isV2Origin -> FType.S.recode(io.vs2e.e32(i)))
                     ++ (if(FSEW16)  Array(isV2to2SEW -> HToS(FType.H.recode(io.vs2e.e16(i)))) else Nil))
    vFtoFExc.exc32(i) := 0.U(5.W)
  }
//double precision
  for(i <- 0 until f64Depth/2) {
    val fexc65 = MuxCase(Cat(FType.D.qNaN, 0.U(5.W)),
                   Array(isV2Origin -> Cat(FType.D.recode(io.vs2e.e64(i)), 0.U(5.W)),
                         isV2to2SEW -> Cat(SToD(FType.S.recode(io.vs2e.e32(i))), 0.U(5.W)))
                 ++ (if(FSEWMAX == 128) Array(isV2toHSEW -> QToD(FType.Q.recode(io.vs2e.e128(i)))) else Nil))
    vsrc2f.f64(i)     := fexc65(68,5)
    vFtoFExc.exc64(i) := fexc65(4,0)
  }
  for(i <- f64Depth/2 until f64Depth) {
    vsrc2f.f64(i) := MuxCase(FType.D.qNaN,
                       Array(isV2Origin -> FType.D.recode(io.vs2e.e64(i)),
                             isV2to2SEW -> SToD(FType.S.recode(io.vs2e.e32(i)))))
    vFtoFExc.exc64(i) := 0.U(5.W)
  }
//quadruple precision
  for(i <- 0 until f128Depth) {
    vsrc2f.f128(i) := MuxCase(FType.Q.qNaN,
                        Array(isV2Origin -> FType.Q.recode(io.vs2e.e128(i)),
                              isV2to2SEW -> DToQ(FType.D.recode(io.vs2e.e64(i)))))
    vFtoFExc.exc128(i) := 0.U(5.W)
  }

  io.vsrc1f    := vsrc1f
  io.vsrc2f    := vsrc2f
  io.vFtoFExc  := vFtoFExc
  io.respValid := respValid
  for(i <- 0 until f16Depth)  io.vdvs3f.f16(i)  := FType.H.recode(io.vdvs3e.e16(i))
  for(i <- 0 until f32Depth)  io.vdvs3f.f32(i)  := FType.S.recode(io.vdvs3e.e32(i))
  for(i <- 0 until f64Depth)  io.vdvs3f.f64(i)  := FType.D.recode(io.vdvs3e.e64(i))
  for(i <- 0 until f128Depth) io.vdvs3f.f128(i) := FType.Q.recode(io.vdvs3e.e128(i))

}

def F64ToS1: UInt = FType.S.recode(Mux(io.fromXData1(63,32).andR, io.fromXData1(31,0), qNaN32))


// See LICENSE.UCTECHIP for license details.
// See LICENSE.SZU for license details.
/************************************************************
*
*       Filename        :       VPUIO.scala
*       Author          :       liangzh
*       Revision        :       2019/04/26
*       Company         :       UC TECH IP
*       Department      :       MAG
*       Description     :       io port for top module VPU
*
*       io.core.resp.toXData         :       output[XLEN-1:0], data, result from VPU to write in Rocket GPR
*       io.core.resp.rd              :       output[4:0], data, address of writing result to GPR
*
*       io.core.req.valid            :       input, control, showing inst or data valid
*       io.core.req.ready            :       output, control, showing vpu is ready to receive an inst or data
*       io.core.req.bits.inst        :       input[31:0], control, vector instruction
*       io.core.fromXData1           :       input[XLEN-1:0], data, from GPR, corresponds to rs1
*       io.core.fromXData2           :       input[XLEN-1:0], data, from GPR, corresponds to rs2
*
*       io.core.fflags_ready         :       output, control, showing whether CSR fflags is ready to be read
*       io.core.vcsr_fflags.valid    :       output, control, floating-point fflags output valid
*       io.core.vcsr_fflags.bits     :       output[FFLAGS_SZ-1:0], data, fflags
*       io.core.vcsr_frm             :       input[FRM_SZ-1:0], data, floating-point rounding mode
*       io.core.vxsat_ready          :       output, control, showing whether CSR vxsat is ready to be read
*       io.core.vcsr_vxsat.valid     :       output, control, fixed-point overflow flag output valid
*       io.core.vcsr_vxsat.bits      :       output[XSAT_SZ-1:0], data, fixed-point overflow flag
*       io.core.vcsr_vxrm            :       input[XRM_SZ-1:0], data, fixed-point rounding mode
*       io.core.vcsr_vstart          :       output[log2Ceil(VLEN)-1:0], data, value to write CSR vstart
*       io.core.vcsr_vl              :       output[XLEN-1:0], data, value to write CSR vl
*       io.core.vcsr_vtype           :       output[XLEN-1:0], data, value to write CSR vtype
*
*       io.core.ctrl_killx           :       input, control, kill the vector instruction executed at EXE stage
*     	io.core.ctrl_killm           :       input, control, kill the vector instruction executed at MEM stage
*       io.core.ctrl_killw           :       input, control, kill the vector instruction executed at WB stage
*       io.core.eret                 :       input, control, take the trap finish
*       io.core.vxcpt_precise        :       output, control, precise exception signal generated at VPU, it connect to WB stage
*       io.core.vxcpt_imprecise      :       output, control, imprecise exception signal generated at VPU, it connect to ID stage
*       io.core.vxcpt_imprecise_resp :       input, control, inform VPU that exception has been received
*       io.core.vcause               :       output[XLEN-1:0], data, exception cause
*       io.core.vmtval               :       output[XLEN-1:0], data,
*       io.core.vnack                :       output, control, imform Rocket that a vector inst has not been executed
*       io.core.dcache_blocked       :       output, control, showing VPU is occupying DCache
*
*       io.fpu.req.fromFData         :       input[FLEN-1:0], data, from floating-point registers, corresponds to rs1
*       io.fpu.req.rs1               :       output[4:0], data, address for reading rs1 from floating-point registers
*
*       io.fpu.resp.valid            :       output, control, showing address and data valid
*       io.fpu.resp.ready            :       input, control, showing ready to receive address and data
*       io.fpu.resp.bits.toFData     :       output[FLEN-1:0], data, result from VPU to FPU
*       io.fpu.resp.bits.rd          :       output[4:0], data, address of writing result to floating-point registers
*
*       io.respValid                 :       input, control, showing DCache response valid
*       io.respTag                   :       input[6:0], control, return tag of request for in order receive
*       io.respSize                  :       input[2:0], control, data width
*       io.respHasData               :       input, control, showing response has data
*       io.respData                  :       input[XLEN-1:0], data, response data
*       io.respS2Xcpt                :       input HellaCacheExceptions, data, response exception information
*
*       io.reqReady                  :       input, control, showing DCache is ready to receive a request
*       io.s2Nack                    :       input, control, not-acknowledge request
*       io.reqValid                  :       output, control, showing request valid
*       io.reqAddr                   :       output[XLEN-1:0], control, address of memory data
*       io.reqTag                    :       output[6:0], control, tag of request for in order receive
*       io.reqCmd                    :       output[4:0], control, showing load or store action
*       io.reqSize                   :       output[2:0], control, data width
*       io.s1Data                    :       output[XLEN-1:0], data, data to store in memory
*       io.s1Kill                    :       output, control, kill s1 stage of DCache
*
************************************************************/
package vpu

import chisel3._
import chisel3.util._

////////////////////////////////////VPU-Rocket//////////////////////////////////
//response signals from VPU to Rocket
class VPUCoreResponse(val XLEN: Int) extends Bundle {
  val toXData = UInt(XLEN.W)
  val rd      = UInt(5.W)

  override def cloneType = new VPUCoreResponse(XLEN).asInstanceOf[this.type]
}
//request signals from Rocket to VPU
class VPUCoreRequest extends Bundle {
  val inst       = UInt(32.W)
}

//VPU-Rocket communication IO
class VPUCoreIO(val VLEN: Int, val XLEN: Int) extends Bundle {
  val resp                 = Output(new VPUCoreResponse(XLEN))
  val req                  = Flipped(Decoupled(new VPUCoreRequest))
  val fromXData1           = Input(UInt(XLEN.W))
  val fromXData2           = Input(UInt(XLEN.W))

  val fflags_ready         = Output(Bool())
  val vcsr_fflags          = Valid(UInt(VPUConstants.FFLAGS_SZ.W))
  val vcsr_frm             = Input(UInt(VPUConstants.FRM_SZ.W))
  val vxsat_ready          = Output(Bool())
  val vcsr_vxsat           = Valid(UInt(VPUConstants.XSAT_SZ.W))
  val vcsr_vxrm            = Input(UInt(VPUConstants.XRM_SZ.W))
  val vcsr_vstart          = Output(UInt(log2Ceil(VLEN).W))
  val vcsr_vl              = Output(UInt(XLEN.W))
  val vcsr_vtype           = Output(UInt(XLEN.W))

  val ctrl_killx           = Input(Bool())
  val ctrl_killm           = Input(Bool())
  val ctrl_killw           = Input(Bool())

  val eret                 = Input(Bool())
  val vxcpt_precise        = Output(Bool())
  val vxcpt_imprecise      = Output(Bool())
  val vxcpt_imprecise_resp = Input(Bool())
  val vcause               = Output(UInt(XLEN.W))
  val vmtval               = Output(UInt(XLEN.W))
  val vnack                = Output(Bool())
  val dcache_blocked       = Output(Bool())

  override def cloneType = new VPUCoreIO(VLEN, XLEN).asInstanceOf[this.type]
}

////////////////////////////////////VPU-FPU/////////////////////////////////////
//request signals from VPU to FPU
class VPUFPUResponse(val FLEN: Int) extends Bundle {
  val toFData = UInt((FLEN+1).W)
  val rd      = UInt(5.W)

}
//response signals from FPU to VPU
class VPUFPURequest(val FLEN: Int) extends Bundle {
  val fromFData = Input(UInt((FLEN+1).W))
  val rs1       = Output(UInt(5.W))

  override def cloneType = new VPUFPURequest(FLEN).asInstanceOf[this.type]
}

//VPU-FPU communication IO
class VPUFPUIO(val FLEN: Int) extends Bundle {
  val req  = new VPUFPURequest(FLEN)
  val resp = Decoupled(new VPUFPUResponse(FLEN))

  override def cloneType = new VPUFPUIO(FLEN).asInstanceOf[this.type]
}

/////////////////////////////////Rocket HellaCache IO///////////////////////////
class AlignmentExceptions extends Bundle {
	val ld = Bool()
	val st = Bool()
}

class HellaCacheExceptions extends Bundle {
	val ma = new AlignmentExceptions
	val pf = new AlignmentExceptions
	val ae = new AlignmentExceptions
}

////////////////////////////////////VPU IO//////////////////////////////////////
class VPUIO(VLEN: Int, XLEN: Int, FLEN: Int, tagBits: Int, addrBits: Int) extends Bundle {
  val dataBits  = XLEN max FLEN
  val dataBytes = dataBits/8
  val sizeBits  = log2Ceil(log2Ceil(dataBytes)+1)

  val core        = new VPUCoreIO(VLEN, XLEN)
  val fpu         = new VPUFPUIO(FLEN)
  //temporary input
  val reqReady    = Input(Bool())
  val s2Nack      = Input(UInt(1.W))
  val respValid   = Input(Bool())
  val respTag     = Input(UInt(tagBits.W))
  val respSize    = Input(UInt(sizeBits.W))
  val respHasData = Input(Bool())
  val respData    = Input(UInt(dataBits.W))
  val respS2Xcpt  = Input(new HellaCacheExceptions)
  //temporary output
  val reqValid    = Output(Bool())
  val reqAddr     = Output(UInt(addrBits.W))
  val reqTag      = Output(UInt(tagBits.W))
  val reqCmd      = Output(UInt(5.W))
  val reqSize     = Output(UInt(sizeBits.W))
  val s1Kill      = Output(Bool())
  val s1Data      = Output(UInt(dataBits.W))

  override def cloneType = new VPUIO(VLEN, XLEN, FLEN, tagBits, addrBits).asInstanceOf[this.type]
}

override def cloneType = new VPUFPUResponse(FLEN).asInstanceOf[this.type]