{
  val fpIssueParams = issueParams.find(_.iqType == IQT_FP.litValue).get
  val dispatchWidth = fpIssueParams.dispatchWidth
  val numLlPorts = memWidth
  val numWakeupPorts = fpIssueParams.issueWidth + numLlPorts
  val fpPregSz = log2Ceil(numFpPhysRegs)

  val io = IO(new Bundle {
    val brupdate         = Input(new BrUpdateInfo())
    val flush_pipeline   = Input(Bool())
    val fcsr_rm          = Input(UInt(width=freechips.rocketchip.tile.FPConstants.RM_SZ.W))
    val status           = Input(new freechips.rocketchip.rocket.MStatus())

    val dis_uops         = Vec(dispatchWidth, Flipped(Decoupled(new MicroOp)))

    // +1 for recoding.
    val ll_wports        = Flipped(Vec(memWidth, Decoupled(new ExeUnitResp(fLen+1))))// from memory unit
    val from_int         = Flipped(Decoupled(new ExeUnitResp(fLen+1)))// from integer RF
    val to_sdq           = Decoupled(new ExeUnitResp(fLen))           // to Load/Store Unit
    val to_int           = Decoupled(new ExeUnitResp(xLen))           // to integer RF

    val wakeups          = Vec(numWakeupPorts, Valid(new ExeUnitResp(fLen+1)))
    val wb_valids        = Input(Vec(numWakeupPorts, Bool()))
    val wb_pdsts         = Input(Vec(numWakeupPorts, UInt(width=fpPregSz.W)))

    val debug_tsc_reg    = Input(UInt(width=xLen.W))
    val debug_wb_wdata   = Output(Vec(numWakeupPorts, UInt((fLen+1).W)))
  })

  //**********************************
  // construct all of the modules

  val exe_units      = new boom.v3.exu.ExecutionUnits(fpu=true)
  val issue_unit     = Module(new IssueUnitCollapsing(
                         issueParams.find(_.iqType == IQT_FP.litValue).get,
                         numWakeupPorts))
  issue_unit.suggestName("fp_issue_unit")
  val fregfile       = Module(new RegisterFileSynthesizable(numFpPhysRegs,
                         exe_units.numFrfReadPorts,
                         exe_units.numFrfWritePorts + memWidth,
                         fLen+1,
                         // No bypassing for any FP units, + memWidth for ll_wb
                         Seq.fill(exe_units.numFrfWritePorts + memWidth){ false }
                         ))
  val fregister_read = Module(new RegisterRead(
                         issue_unit.issueWidth,
                         exe_units.withFilter(_.readsFrf).map(_.supportedFuncUnits).toSeq,
                         exe_units.numFrfReadPorts,
                         exe_units.withFilter(_.readsFrf).map(x => 3).toSeq,
                         0, // No bypass for FP
                         0,
                         fLen+1))

  require (exe_units.count(_.readsFrf) == issue_unit.issueWidth)
  require (exe_units.numFrfWritePorts + numLlPorts == numWakeupPorts)

  //*************************************************************
  // Issue window logic

  val iss_valids = Wire(Vec(exe_units.numFrfReaders, Bool()))
  val iss_uops   = Wire(Vec(exe_units.numFrfReaders, new MicroOp()))

  issue_unit.io.tsc_reg := io.debug_tsc_reg
  issue_unit.io.brupdate := io.brupdate
  issue_unit.io.flush_pipeline := io.flush_pipeline
  // Don't support ld-hit speculation to FP window.
  for (w <- 0 until memWidth) {
    issue_unit.io.spec_ld_wakeup(w).valid := false.B
    issue_unit.io.spec_ld_wakeup(w).bits := 0.U
  }
  issue_unit.io.ld_miss := false.B

  require (exe_units.numTotalBypassPorts == 0)

  //-------------------------------------------------------------
  // **** Dispatch Stage ****
  //-------------------------------------------------------------

  // Input (Dispatch)
  for (w <- 0 until dispatchWidth) {
    issue_unit.io.dis_uops(w) <> io.dis_uops(w)
  }

  //-------------------------------------------------------------
  // **** Issue Stage ****
  //-------------------------------------------------------------

  // Output (Issue)
  for (i <- 0 until issue_unit.issueWidth) {
    iss_valids(i) := issue_unit.io.iss_valids(i)
    iss_uops(i) := issue_unit.io.iss_uops(i)

    var fu_types = exe_units(i).io.fu_types
    if (exe_units(i).supportedFuncUnits.fdiv) {
      val fdiv_issued = iss_valids(i) && iss_uops(i).fu_code_is(FU_FDV)
      fu_types = fu_types & RegNext(~Mux(fdiv_issued, FU_FDV, 0.U))
    }
    issue_unit.io.fu_types(i) := fu_types

    require (exe_units(i).readsFrf)
  }

  // Wakeup
  for ((writeback, issue_wakeup) <- io.wakeups zip issue_unit.io.wakeup_ports) {
    issue_wakeup.valid := writeback.valid
    issue_wakeup.bits.pdst  := writeback.bits.uop.pdst
    issue_wakeup.bits.poisoned := false.B
  }
  issue_unit.io.pred_wakeup_port.valid := false.B
  issue_unit.io.pred_wakeup_port.bits := DontCare

  //-------------------------------------------------------------
  // **** Register Read Stage ****
  //-------------------------------------------------------------

  // Register Read <- Issue (rrd <- iss)
  fregister_read.io.rf_read_ports <> fregfile.io.read_ports
  fregister_read.io.prf_read_ports map { port => port.data := false.B }

  fregister_read.io.iss_valids <> iss_valids
  fregister_read.io.iss_uops := iss_uops

  fregister_read.io.brupdate := io.brupdate
  fregister_read.io.kill := io.flush_pipeline

  //-------------------------------------------------------------
  // **** Execute Stage ****
  //-------------------------------------------------------------

  exe_units.map(_.io.brupdate := io.brupdate)

  for ((ex,w) <- exe_units.withFilter(_.readsFrf).map(x=>x).zipWithIndex) {
    ex.io.req <> fregister_read.io.exe_reqs(w)
    require (!ex.bypassable)
  }
  require (exe_units.numTotalBypassPorts == 0)

  //-------------------------------------------------------------
  // **** Writeback Stage ****
  //-------------------------------------------------------------

  val ll_wbarb = Module(new Arbiter(new ExeUnitResp(fLen+1), 2))

  // Hookup load writeback -- and recode FP values.
  ll_wbarb.io.in(0) <> io.ll_wports(0)
  ll_wbarb.io.in(0).bits.data := recode(io.ll_wports(0).bits.data,
                                        io.ll_wports(0).bits.uop.mem_size =/= 2.U)

  val ifpu_resp = io.from_int
  ll_wbarb.io.in(1) <> ifpu_resp

  // Cut up critical path by delaying the write by a cycle.
  // Wakeup signal is sent on cycle S0, write is now delayed until end of S1,
  // but Issue happens on S1 and RegRead doesn't happen until S2 so we're safe.
  fregfile.io.write_ports(0) := RegNext(WritePort(ll_wbarb.io.out, fpregSz, fLen+1, RT_FLT))

  assert (ll_wbarb.io.in(0).ready) // never backpressure the memory unit.
  when (ifpu_resp.valid) { assert (ifpu_resp.bits.uop.rf_wen && ifpu_resp.bits.uop.dst_rtype === RT_FLT) }

  var w_cnt = 1
  for (i <- 1 until memWidth) {
    fregfile.io.write_ports(w_cnt) := RegNext(WritePort(io.ll_wports(i), fpregSz, fLen+1, RT_FLT))
    fregfile.io.write_ports(w_cnt).bits.data := RegNext(recode(io.ll_wports(i).bits.data,
                                                               io.ll_wports(i).bits.uop.mem_size =/= 2.U))
    w_cnt += 1
  }
  for (eu <- exe_units) {
    if (eu.writesFrf) {
      fregfile.io.write_ports(w_cnt).valid     := eu.io.fresp.valid && eu.io.fresp.bits.uop.rf_wen
      fregfile.io.write_ports(w_cnt).bits.addr := eu.io.fresp.bits.uop.pdst
      fregfile.io.write_ports(w_cnt).bits.data := eu.io.fresp.bits.data
      eu.io.fresp.ready                        := true.B
      when (eu.io.fresp.valid) {
        assert(eu.io.fresp.ready, "No backpressuring the FPU")
        assert(eu.io.fresp.bits.uop.rf_wen, "rf_wen must be high here")
        assert(eu.io.fresp.bits.uop.dst_rtype === RT_FLT, "wb type must be FLT for fpu")
      }
      w_cnt += 1
    }
  }
  require (w_cnt == fregfile.io.write_ports.length)

  val fpiu_unit = exe_units.fpiu_unit
  val fpiu_is_sdq = fpiu_unit.io.ll_iresp.bits.uop.uopc === uopSTA
  io.to_int.valid := fpiu_unit.io.ll_iresp.fire && !fpiu_is_sdq
  io.to_sdq.valid := fpiu_unit.io.ll_iresp.fire &&  fpiu_is_sdq
  io.to_int.bits  := fpiu_unit.io.ll_iresp.bits
  io.to_sdq.bits  := fpiu_unit.io.ll_iresp.bits
  fpiu_unit.io.ll_iresp.ready := io.to_sdq.ready && io.to_int.ready

  //-------------------------------------------------------------
  //-------------------------------------------------------------
  // **** Commit Stage ****
  //-------------------------------------------------------------
  //-------------------------------------------------------------

  io.wakeups(0).valid := ll_wbarb.io.out.valid
  io.wakeups(0).bits := ll_wbarb.io.out.bits
  ll_wbarb.io.out.ready := true.B

  w_cnt = 1
  for (i <- 1 until memWidth) {
    io.wakeups(w_cnt) := io.ll_wports(i)
    io.wakeups(w_cnt).bits.data := recode(io.ll_wports(i).bits.data,
      io.ll_wports(i).bits.uop.mem_size =/= 2.U)
    w_cnt += 1
  }
  for (eu <- exe_units) {
    if (eu.writesFrf) {
      val exe_resp = eu.io.fresp
      val wb_uop = eu.io.fresp.bits.uop
      val wport = io.wakeups(w_cnt)
      wport.valid := exe_resp.valid && wb_uop.dst_rtype === RT_FLT
      wport.bits := exe_resp.bits

      w_cnt += 1

      assert(!(exe_resp.valid && wb_uop.uses_ldq))
      assert(!(exe_resp.valid && wb_uop.uses_stq))
      assert(!(exe_resp.valid && wb_uop.is_amo))
    }
  }

  for ((wdata, wakeup) <- io.debug_wb_wdata zip io.wakeups) {
    wdata := ieee(wakeup.bits.data)
  }

  exe_units.map(_.io.fcsr_rm := io.fcsr_rm)
  exe_units.map(_.io.status := io.status)

  //-------------------------------------------------------------
  // **** Flush Pipeline ****
  //-------------------------------------------------------------
  // flush on exceptions, miniexeptions, and after some special instructions

  for (w <- 0 until exe_units.length) {
    exe_units(w).io.req.bits.kill := io.flush_pipeline
  }

  override def toString: String =
    (BoomCoreStringPrefix("===FP Pipeline===") + "\n"
    + fregfile.toString
    + BoomCoreStringPrefix(
      "Num Wakeup Ports      : " + numWakeupPorts,
      "Num Bypass Ports      : " + exe_units.numTotalBypassPorts))
}

class FpPipeline(implicit p: Parameters) extends BoomModule with tile.HasFPUParameters


//******************************************************************************
// Copyright (c) 2015 - 2019, The Regents of the University of California (Regents).
// All Rights Reserved. See LICENSE and LICENSE.SiFive for license details.
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Rename Map Table
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

package boom.v3.exu

import chisel3._
import chisel3.util._
import boom.v3.common._
import boom.v3.util._
import org.chipsalliance.cde.config.Parameters

class MapReq(val lregSz: Int) extends Bundle
{
  val lrs1 = UInt(lregSz.W)
  val lrs2 = UInt(lregSz.W)
  val lrs3 = UInt(lregSz.W)
  val ldst = UInt(lregSz.W)
}

class MapResp(val pregSz: Int) extends Bundle
{
  val prs1 = UInt(pregSz.W)
  val prs2 = UInt(pregSz.W)
  val prs3 = UInt(pregSz.W)
  val stale_pdst = UInt(pregSz.W)
}

class RemapReq(val lregSz: Int, val pregSz: Int) extends Bundle
{
  val ldst = UInt(lregSz.W)
  val pdst = UInt(pregSz.W)
  val valid = Bool()
}

class RenameMapTable(
  val plWidth: Int,
  val numLregs: Int,
  val numPregs: Int,
  val bypass: Boolean,
  val float: Boolean)
  (implicit p: Parameters) extends BoomModule
{
  val pregSz = log2Ceil(numPregs)

  val io = IO(new BoomBundle()(p) {
    // Logical sources -> physical sources.
    val map_reqs    = Input(Vec(plWidth, new MapReq(lregSz)))
    val map_resps   = Output(Vec(plWidth, new MapResp(pregSz)))

    // Remapping an ldst to a newly allocated pdst?
    val remap_reqs  = Input(Vec(plWidth, new RemapReq(lregSz, pregSz)))

    // Dispatching branches: need to take snapshots of table state.
    val ren_br_tags = Input(Vec(plWidth, Valid(UInt(brTagSz.W))))

    // Signals for restoring state following misspeculation.
    val brupdate      = Input(new BrUpdateInfo)
    val rollback    = Input(Bool())
  })

  // The map table register array and its branch snapshots.
  val map_table = RegInit(VecInit(Seq.fill(numLregs){0.U(pregSz.W)}))
  val br_snapshots = Reg(Vec(maxBrCount, Vec(numLregs, UInt(pregSz.W))))

  // The intermediate states of the map table following modification by each pipeline slot.
  val remap_table = Wire(Vec(plWidth+1, Vec(numLregs, UInt(pregSz.W))))

  // Uops requesting changes to the map table.
  val remap_pdsts = io.remap_reqs map (_.pdst)
  val remap_ldsts_oh = io.remap_reqs map (req => UIntToOH(req.ldst) & Fill(numLregs, req.valid.asUInt))

  // Figure out the new mappings seen by each pipeline slot.
  for (i <- 0 until numLregs) {
    if (i == 0 && !float) {
      for (j <- 0 until plWidth+1) {
        remap_table(j)(i) := 0.U
      }
    } else {
      val remapped_row = (remap_ldsts_oh.map(ldst => ldst(i)) zip remap_pdsts)
        .scanLeft(map_table(i)) {case (pdst, (ldst, new_pdst)) => Mux(ldst, new_pdst, pdst)}

      for (j <- 0 until plWidth+1) {
        remap_table(j)(i) := remapped_row(j)
      }
    }
  }

  // Create snapshots of new mappings.
  for (i <- 0 until plWidth) {
    when (io.ren_br_tags(i).valid) {
      br_snapshots(io.ren_br_tags(i).bits) := remap_table(i+1)
    }
  }

  when (io.brupdate.b2.mispredict) {
    // Restore the map table to a branch snapshot.
    map_table := br_snapshots(io.brupdate.b2.uop.br_tag)
  } .otherwise {
    // Update mappings.
    map_table := remap_table(plWidth)
  }

  // Read out mappings.
  for (i <- 0 until plWidth) {
    io.map_resps(i).prs1       := (0 until i).foldLeft(map_table(io.map_reqs(i).lrs1)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).lrs1, io.remap_reqs(k).pdst, p))
    io.map_resps(i).prs2       := (0 until i).foldLeft(map_table(io.map_reqs(i).lrs2)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).lrs2, io.remap_reqs(k).pdst, p))
    io.map_resps(i).prs3       := (0 until i).foldLeft(map_table(io.map_reqs(i).lrs3)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).lrs3, io.remap_reqs(k).pdst, p))
    io.map_resps(i).stale_pdst := (0 until i).foldLeft(map_table(io.map_reqs(i).ldst)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).ldst, io.remap_reqs(k).pdst, p))

  }

  // Don't flag the creation of duplicate 'p0' mappings during rollback.
  // These cases may occur soon after reset, as all maptable entries are initialized to 'p0'.
  io.remap_reqs map (req => (req.pdst, req.valid)) foreach {case (p,r) =>
    assert (!r || !map_table.contains(p) || p === 0.U && io.rollback, "[maptable] Trying to write a duplicate mapping.")}
}

if (!float) io.map_resps(i).prs3 := DontCare


package boom.v3.ifu

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._

import boom.v3.common._
import boom.v3.util.{BoomCoreStringPrefix, WrapInc}
import scala.math.min

  with HasBoomFrontendParameters
{
  val bims  = Vec(bankWidth, UInt(2.W))
}

case class BoomBIMParams(
  nSets: Int = 2048
)

class BIMBranchPredictorBank(params: BoomBIMParams = BoomBIMParams())(implicit p: Parameters) extends BranchPredictorBank()(p)
{
  override val nSets = params.nSets

  require(isPow2(nSets))

  val nWrBypassEntries = 2

  def bimWrite(v: UInt, taken: Bool): UInt = {
    val old_bim_sat_taken  = v === 3.U
    val old_bim_sat_ntaken = v === 0.U
    Mux(old_bim_sat_taken  &&  taken, 3.U,
      Mux(old_bim_sat_ntaken && !taken, 0.U,
      Mux(taken, v + 1.U, v - 1.U)))
  }
  val s2_meta           = Wire(new BIMMeta)
  override val metaSz   = s2_meta.asUInt.getWidth

  val doing_reset = RegInit(true.B)
  val reset_idx = RegInit(0.U(log2Ceil(nSets).W))
  reset_idx := reset_idx + doing_reset
  when (reset_idx === (nSets-1).U) { doing_reset := false.B }

  val data  = SyncReadMem(nSets, Vec(bankWidth, UInt(2.W)))

  val mems = Seq(("bim", nSets, bankWidth * 2))

  val s2_req_rdata    = RegNext(data.read(s0_idx   , s0_valid))

  val s2_resp         = Wire(Vec(bankWidth, Bool()))

  for (w <- 0 until bankWidth) {

    s2_resp(w)        := s2_valid && s2_req_rdata(w)(1) && !doing_reset
    s2_meta.bims(w)   := s2_req_rdata(w)
  }

  val s1_update_wdata   = Wire(Vec(bankWidth, UInt(2.W)))
  val s1_update_wmask   = Wire(Vec(bankWidth, Bool()))
  val s1_update_meta    = s1_update.bits.meta.asTypeOf(new BIMMeta)
  val s1_update_index   = s1_update_idx

  val wrbypass_idxs = Reg(Vec(nWrBypassEntries, UInt(log2Ceil(nSets).W)))
  val wrbypass      = Reg(Vec(nWrBypassEntries, Vec(bankWidth, UInt(2.W))))
  val wrbypass_enq_idx = RegInit(0.U(log2Ceil(nWrBypassEntries).W))

  val wrbypass_hits = VecInit((0 until nWrBypassEntries) map { i =>
    !doing_reset &&
    wrbypass_idxs(i) === s1_update_index(log2Ceil(nSets)-1,0)
  })
  val wrbypass_hit = wrbypass_hits.reduce(_||_)
  val wrbypass_hit_idx = PriorityEncoder(wrbypass_hits)

  for (w <- 0 until bankWidth) {
    s1_update_wmask(w)         := false.B
    s1_update_wdata(w)         := DontCare

    val update_pc = s1_update.bits.pc + (w << 1).U

    when (s1_update.bits.br_mask(w) ||
      (s1_update.bits.cfi_idx.valid && s1_update.bits.cfi_idx.bits === w.U)) {
      val was_taken = (
        s1_update.bits.cfi_idx.valid &&
        (s1_update.bits.cfi_idx.bits === w.U) &&
        (
          (s1_update.bits.cfi_is_br && s1_update.bits.br_mask(w) && s1_update.bits.cfi_taken) ||
          s1_update.bits.cfi_is_jal
        )
      )
      val old_bim_value = Mux(wrbypass_hit, wrbypass(wrbypass_hit_idx)(w), s1_update_meta.bims(w))

      s1_update_wmask(w)     := true.B

      s1_update_wdata(w)     := bimWrite(old_bim_value, was_taken)
    }

  }

  when (doing_reset || (s1_update.valid && s1_update.bits.is_commit_update)) {
    data.write(
      Mux(doing_reset, reset_idx, s1_update_index),
      Mux(doing_reset, VecInit(Seq.fill(bankWidth) { 2.U }), s1_update_wdata),
      Mux(doing_reset, (~(0.U(bankWidth.W))), s1_update_wmask.asUInt).asBools
    )
  }
  when (s1_update_wmask.reduce(_||_) && s1_update.valid && s1_update.bits.is_commit_update) {
    when (wrbypass_hit) {
      wrbypass(wrbypass_hit_idx) := s1_update_wdata
    } .otherwise {
      wrbypass(wrbypass_enq_idx)      := s1_update_wdata
      wrbypass_idxs(wrbypass_enq_idx) := s1_update_index
      wrbypass_enq_idx := WrapInc(wrbypass_enq_idx, nWrBypassEntries)
    }
  }

  for (w <- 0 until bankWidth) {
    io.resp.f2(w).taken := s2_resp(w)
    io.resp.f3(w).taken := RegNext(io.resp.f2(w).taken)
  }
  io.f3_meta := RegNext(s2_meta.asUInt)
}

class BIMMeta(implicit p: Parameters) extends BoomBundle()(p)


package boom.v3.ifu

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._

import boom.v3.common._
import boom.v3.util.{BoomCoreStringPrefix}

import scala.math.min

case class BoomLoopPredictorParams(
  nWays: Int = 4,
  threshold: Int = 7
)

class LoopBranchPredictorBank(implicit p: Parameters) extends BranchPredictorBank()(p)
{
  val tagSz = 10
  override val nSets = 16

  class LoopMeta extends Bundle {
    val s_cnt   = UInt(10.W)
  }

  class LoopEntry extends Bundle {
    val tag   = UInt(tagSz.W)
    val conf  = UInt(3.W)
    val age   = UInt(3.W)
    val p_cnt = UInt(10.W)
    val s_cnt = UInt(10.W)
  }

  class LoopBranchPredictorColumn extends Module {

    val io = IO(new Bundle {
      val f2_req_valid = Input(Bool())
      val f2_req_idx  = Input(UInt())
      val f3_req_fire = Input(Bool())

      val f3_pred_in  = Input(Bool())
      val f3_pred     = Output(Bool())
      val f3_meta     = Output(new LoopMeta)

      val update_mispredict = Input(Bool())
      val update_repair     = Input(Bool())
      val update_idx   = Input(UInt())
      val update_resolve_dir = Input(Bool())
      val update_meta  = Input(new LoopMeta)
    })

    val doing_reset = RegInit(true.B)
    val reset_idx = RegInit(0.U(log2Ceil(nSets).W))
    reset_idx := reset_idx + doing_reset

    val entries = Reg(Vec(nSets, new LoopEntry))
    val f2_entry = WireInit(entries(io.f2_req_idx))
    when (io.update_repair && io.update_idx === io.f2_req_idx) {
      f2_entry.s_cnt := io.update_meta.s_cnt
    } .elsewhen (io.update_mispredict && io.update_idx === io.f2_req_idx) {
      f2_entry.s_cnt := 0.U
    }
    val f3_entry = RegNext(f2_entry)
    val f3_scnt  = Mux(io.update_repair && io.update_idx === RegNext(io.f2_req_idx),
      io.update_meta.s_cnt,
      f3_entry.s_cnt)
    val f3_tag   = RegNext(io.f2_req_idx(tagSz+log2Ceil(nSets)-1,log2Ceil(nSets)))

    io.f3_pred := io.f3_pred_in
    io.f3_meta.s_cnt := f3_scnt

    when (f3_entry.tag === f3_tag) {
      when (f3_scnt === f3_entry.p_cnt && f3_entry.conf === 7.U) {
        io.f3_pred := !io.f3_pred_in
      }
    }

    val f4_fire  = RegNext(io.f3_req_fire)
    val f4_entry = RegNext(f3_entry)
    val f4_tag   = RegNext(f3_tag)
    val f4_scnt  = RegNext(f3_scnt)
    val f4_idx   = RegNext(RegNext(io.f2_req_idx))

    when (f4_fire) {
      when (f4_entry.tag === f4_tag) {
        when (f4_scnt === f4_entry.p_cnt && f4_entry.conf === 7.U) {
          entries(f4_idx).age   := 7.U
          entries(f4_idx).s_cnt := 0.U
        } .otherwise {
          entries(f4_idx).s_cnt := f4_scnt + 1.U
          entries(f4_idx).age   := Mux(f4_entry.age === 7.U, 7.U, f4_entry.age + 1.U)
        }
      }
    }

    val entry = entries(io.update_idx)
    val tag = io.update_idx(tagSz+log2Ceil(nSets)-1,log2Ceil(nSets))
    val tag_match = entry.tag === tag
    val ctr_match = entry.p_cnt === io.update_meta.s_cnt
    val wentry = WireInit(entry)

    when (io.update_mispredict && !doing_reset) {

      // Learned, tag match -> decrement confidence
      when (entry.conf === 7.U && tag_match) {
        wentry.s_cnt := 0.U
        wentry.conf  := 0.U

      // Learned, no tag match -> do nothing? Don't evict super-confident entries?
      } .elsewhen (entry.conf === 7.U && !tag_match) {

      // Confident, tag match, ctr_match -> increment confidence, reset counter
      } .elsewhen (entry.conf =/= 0.U && tag_match && ctr_match) {
        wentry.conf  := entry.conf + 1.U
        wentry.s_cnt := 0.U

      // Confident, tag match, no ctr match -> zero confidence, reset counter, set previous counter
      } .elsewhen (entry.conf =/= 0.U && tag_match && !ctr_match) {
        wentry.conf  := 0.U
        wentry.s_cnt := 0.U
        wentry.p_cnt := io.update_meta.s_cnt

      // Confident, no tag match, age is 0 -> replace this entry with our own, set our age high to avoid ping-pong
      } .elsewhen (entry.conf =/= 0.U && !tag_match && entry.age === 0.U) {
        wentry.tag   := tag
        wentry.conf  := 1.U
        wentry.s_cnt := 0.U
        wentry.p_cnt := io.update_meta.s_cnt

      // Confident, no tag match, age > 0 -> decrement age
      } .elsewhen (entry.conf =/= 0.U && !tag_match && entry.age =/= 0.U) {
        wentry.age := entry.age - 1.U

      // Unconfident, tag match, ctr match -> increment confidence
      } .elsewhen (entry.conf === 0.U && tag_match && ctr_match) {
        wentry.conf  := 1.U
        wentry.age   := 7.U
        wentry.s_cnt := 0.U

      // Unconfident, tag match, no ctr match -> set previous counter
      } .elsewhen (entry.conf === 0.U && tag_match && !ctr_match) {
        wentry.p_cnt := io.update_meta.s_cnt
        wentry.age   := 7.U
        wentry.s_cnt := 0.U

      // Unconfident, no tag match -> set previous counter and tag
      } .elsewhen (entry.conf === 0.U && !tag_match) {
        wentry.tag   := tag
        wentry.conf  := 1.U
        wentry.age   := 7.U
        wentry.s_cnt := 0.U
        wentry.p_cnt := io.update_meta.s_cnt
      }

      entries(io.update_idx) := wentry
    } .elsewhen (io.update_repair && !doing_reset) {
      when (tag_match && !(f4_fire && io.update_idx === f4_idx)) {
        wentry.s_cnt := io.update_meta.s_cnt
        entries(io.update_idx) := wentry
      }
    }

    when (doing_reset) {
      entries(reset_idx) := (0.U).asTypeOf(new LoopEntry)
   }

  }

  val columns = Seq.fill(bankWidth) { Module(new LoopBranchPredictorColumn) }
  val mems = Nil // TODO fix
  val f3_meta = Wire(Vec(bankWidth, new LoopMeta))
  override val metaSz = f3_meta.asUInt.getWidth

  val update_meta = s1_update.bits.meta.asTypeOf(Vec(bankWidth, new LoopMeta))

  for (w <- 0 until bankWidth) {
    columns(w).io.f2_req_valid := s2_valid
    columns(w).io.f2_req_idx  := s2_idx
    columns(w).io.f3_req_fire := (s3_valid && s3_mask(w) && io.f3_fire &&
      RegNext(io.resp_in(0).f2(w).predicted_pc.valid && io.resp_in(0).f2(w).is_br))

    columns(w).io.f3_pred_in  := io.resp_in(0).f3(w).taken
    io.resp.f3(w).taken       := columns(w).io.f3_pred

    columns(w).io.update_mispredict      := (s1_update.valid &&
                                             s1_update.bits.br_mask(w) &&
                                             s1_update.bits.is_mispredict_update &&
                                             s1_update.bits.cfi_mispredicted)
    columns(w).io.update_repair          := (s1_update.valid &&
                                             s1_update.bits.br_mask(w) &&
                                            s1_update.bits.is_repair_update)
    columns(w).io.update_idx             := s1_update_idx
    columns(w).io.update_resolve_dir     := s1_update.bits.cfi_taken
    columns(w).io.update_meta            := update_meta(w)

    f3_meta(w) := columns(w).io.f3_meta
  }

  io.f3_meta := f3_meta.asUInt

}

when (reset_idx === (nSets-1).U) { doing_reset := false.B }


package boom.v3.ifu

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._

import boom.v3.common._
import boom.v3.exu.{CommitExceptionSignals}
import boom.v3.util.{BoomCoreStringPrefix}

class SwBranchPredictorBank(implicit p: Parameters) extends BranchPredictorBank()(p)
{
  val mems = Nil
  for (w <- 0 until bankWidth) {
    val btb_harness = Module(new BTBHarness)
    val pred_harness = Module(new BranchPredictorHarness)

    btb_harness.io.clock := clock
    btb_harness.io.reset := reset.asBool

    pred_harness.io.clock := clock
    pred_harness.io.reset := reset.asBool

    btb_harness.io.req_valid := s1_valid
    btb_harness.io.req_pc    := bankAlign(s1_pc) + (w << 1).U
    btb_harness.io.req_hist  := io.f1_ghist

    pred_harness.io.req_valid := s1_valid
    pred_harness.io.req_pc    := bankAlign(s1_pc) + (w << 1).U
    pred_harness.io.req_hist  := io.f1_ghist

    btb_harness.io.update_valid  := io.update.valid && io.update.bits.is_commit_update && io.update.bits.cfi_idx.valid && (w == 0).B
    btb_harness.io.update_pc     := io.update.bits.pc + (io.update.bits.cfi_idx.bits << 1)
    btb_harness.io.update_hist   := io.update.bits.ghist
    btb_harness.io.update_target := io.update.bits.target
    btb_harness.io.update_is_br  := io.update.bits.cfi_is_br
    btb_harness.io.update_is_jal := io.update.bits.cfi_is_jal

    pred_harness.io.update_valid := io.update.valid && io.update.bits.is_commit_update && io.update.bits.br_mask(w)
    pred_harness.io.update_pc    := io.update.bits.pc + (w << 1).U
    pred_harness.io.update_hist  := io.update.bits.ghist
    pred_harness.io.update_taken := w.U === io.update.bits.cfi_idx.bits &&
                                      io.update.bits.cfi_idx.valid && io.update.bits.cfi_taken

    io.resp.f2(w).taken              := pred_harness.io.req_taken
    io.resp.f2(w).predicted_pc.valid := btb_harness.io.req_target_valid
    io.resp.f2(w).predicted_pc.bits  := btb_harness.io.req_target_pc
    io.resp.f2(w).is_br              := btb_harness.io.req_is_br  && btb_harness.io.req_target_valid
    io.resp.f2(w).is_jal             := btb_harness.io.req_is_jal && btb_harness.io.req_target_valid

    // The Harness to software assumes output comes out in f2
    io.resp.f3(w).is_br := RegNext(pred_harness.io.req_taken)
    io.resp.f3(w).taken := RegNext(pred_harness.io.req_taken)
  }
}

class BranchPredictorHarness(implicit p: Parameters)
    extends BlackBox with HasBlackBoxResource {
  val io = IO(new Bundle {
    val clock = Input(Clock())
    val reset = Input(Bool())

    val req_valid = Input(Bool())
    val req_pc = Input(UInt(64.W))
    val req_hist = Input(UInt(64.W))
    val req_taken = Output(Bool())

    val update_valid = Input(Bool())
    val update_pc = Input(UInt(64.W))
    val update_hist = Input(UInt(64.W))
    val update_taken = Input(Bool())
  })

    extends BlackBox with HasBlackBoxResource {
  val io = IO(new Bundle {
    val clock = Input(Clock())
    val reset = Input(Bool())

    val req_valid = Input(Bool())
    val req_pc = Input(UInt(64.W))
    val req_hist = Input(UInt(64.W))
    val req_target_valid = Output(Bool())
    val req_target_pc = Output(UInt(64.W))
    val req_is_br = Output(Bool())
    val req_is_jal = Output(Bool())

    val update_valid = Input(Bool())
    val update_pc = Input(UInt(64.W))
    val update_hist = Input(UInt(64.W))
    val update_target = Input(UInt(64.W))
    val update_is_br = Input(Bool())
    val update_is_jal = Input(Bool())
  })

  addResource("/vsrc/btb_harness.v")
  addResource("/csrc/btb_sw.cc")
}

  addResource("/vsrc/predictor_harness.v")
  addResource("/csrc/predictor_sw.cc")
}


//******************************************************************************
// Copyright (c) 2015 - 2019, The Regents of the University of California (Regents).
// All Rights Reserved. See LICENSE and LICENSE.SiFive for license details.
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Utility Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

package boom.v3.util

import chisel3._
import chisel3.util._

import freechips.rocketchip.rocket.Instructions._
import freechips.rocketchip.rocket._
import freechips.rocketchip.util.{Str}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.tile.{TileKey}

import boom.v3.common.{MicroOp}
import boom.v3.exu.{BrUpdateInfo}

/**
 * Object to XOR fold a input register of fullLength into a compressedLength.
 */
object Fold
{
  def apply(input: UInt, compressedLength: Int, fullLength: Int): UInt = {
    val clen = compressedLength
    val hlen = fullLength
    if (hlen <= clen) {
      input
    } else {
      var res = 0.U(clen.W)
      var remaining = input.asUInt
      for (i <- 0 to hlen-1 by clen) {
        val len = if (i + clen > hlen ) (hlen - i) else clen
        require(len > 0)
        res = res(clen-1,0) ^ remaining(len-1,0)
        remaining = remaining >> len.U
      }
      res
    }
  }
}

/**
 * Object to check if MicroOp was killed due to a branch mispredict.
 * Uses "Fast" branch masks
 */
object IsKilledByBranch
{
  def apply(brupdate: BrUpdateInfo, uop: MicroOp): Bool = {
    return maskMatch(brupdate.b1.mispredict_mask, uop.br_mask)
  }

  def apply(brupdate: BrUpdateInfo, uop_mask: UInt): Bool = {
    return maskMatch(brupdate.b1.mispredict_mask, uop_mask)
  }
}

/**
 * Object to return new MicroOp with a new BR mask given a MicroOp mask
 * and old BR mask.
 */
object GetNewUopAndBrMask
{
  def apply(uop: MicroOp, brupdate: BrUpdateInfo)
    (implicit p: Parameters): MicroOp = {
    val newuop = WireInit(uop)
    newuop.br_mask := uop.br_mask & ~brupdate.b1.resolve_mask
    newuop
  }
}

/**
 * Object to return a BR mask given a MicroOp mask and old BR mask.
 */
object GetNewBrMask
{
   def apply(brupdate: BrUpdateInfo, uop: MicroOp): UInt = {
     return uop.br_mask & ~brupdate.b1.resolve_mask
   }

   def apply(brupdate: BrUpdateInfo, br_mask: UInt): UInt = {
     return br_mask & ~brupdate.b1.resolve_mask
   }
}

object UpdateBrMask
{
  def apply(brupdate: BrUpdateInfo, uop: MicroOp): MicroOp = {
    val out = WireInit(uop)
    out.br_mask := GetNewBrMask(brupdate, uop)
    out
  }
  def apply[T <: boom.v3.common.HasBoomUOP](brupdate: BrUpdateInfo, bundle: T): T = {
    val out = WireInit(bundle)
    out.uop.br_mask := GetNewBrMask(brupdate, bundle.uop.br_mask)
    out
  }
  def apply[T <: boom.v3.common.HasBoomUOP](brupdate: BrUpdateInfo, bundle: Valid[T]): Valid[T] = {
    val out = WireInit(bundle)
    out.bits.uop.br_mask := GetNewBrMask(brupdate, bundle.bits.uop.br_mask)
    out.valid := bundle.valid && !IsKilledByBranch(brupdate, bundle.bits.uop.br_mask)
    out
  }
}

/**
 * Object to check if at least 1 bit matches in two masks
 */
object maskMatch
{
  def apply(msk1: UInt, msk2: UInt): Bool = (msk1 & msk2) =/= 0.U
}

/**
 * Object to clear one bit in a mask given an index
 */
object clearMaskBit
{
  def apply(msk: UInt, idx: UInt): UInt = (msk & ~(1.U << idx))(msk.getWidth-1, 0)
}

/**
 * Object to shift a register over by one bit and concat a new one
 */
object PerformShiftRegister
{
  def apply(reg_val: UInt, new_bit: Bool): UInt = {
    reg_val := Cat(reg_val(reg_val.getWidth-1, 0).asUInt, new_bit.asUInt).asUInt
    reg_val
  }
}

/**
 * Object to shift a register over by one bit, wrapping the top bit around to the bottom
 * (XOR'ed with a new-bit), and evicting a bit at index HLEN.
 * This is used to simulate a longer HLEN-width shift register that is folded
 * down to a compressed CLEN.
 */
object PerformCircularShiftRegister
{
  def apply(csr: UInt, new_bit: Bool, evict_bit: Bool, hlen: Int, clen: Int): UInt = {
    val carry = csr(clen-1)
    val newval = Cat(csr, new_bit ^ carry) ^ (evict_bit << (hlen % clen).U)
    newval
  }
}

/**
 * Object to increment an input value, wrapping it if
 * necessary.
 */
object WrapAdd
{
  // "n" is the number of increments, so we wrap at n-1.
  def apply(value: UInt, amt: UInt, n: Int): UInt = {
    if (isPow2(n)) {
      (value + amt)(log2Ceil(n)-1,0)
    } else {
      val sum = Cat(0.U(1.W), value) + Cat(0.U(1.W), amt)
      Mux(sum >= n.U,
          sum - n.U,
          sum)
    }
  }
}

/**
 * Object to decrement an input value, wrapping it if
 * necessary.
 */
object WrapSub
{
  // "n" is the number of increments, so we wrap to n-1.
  def apply(value: UInt, amt: Int, n: Int): UInt = {
    if (isPow2(n)) {
       (value - amt.U)(log2Ceil(n)-1,0)
    } else {
      val v = Cat(0.U(1.W), value)
      val b = Cat(0.U(1.W), amt.U)
      Mux(value >= amt.U,
          value - amt.U,
          n.U - amt.U + value)
    }
  }
}

/**
 * Object to increment an input value, wrapping it if
 * necessary.
 */
object WrapInc
{
  // "n" is the number of increments, so we wrap at n-1.
  def apply(value: UInt, n: Int): UInt = {
    if (isPow2(n)) {
      (value + 1.U)(log2Ceil(n)-1,0)
    } else {
      val wrap = (value === (n-1).U)
      Mux(wrap, 0.U, value + 1.U)
    }
  }
}

/**
 * Object to decrement an input value, wrapping it if
 * necessary.
 */
object WrapDec
{
  // "n" is the number of increments, so we wrap at n-1.
  def apply(value: UInt, n: Int): UInt = {
    if (isPow2(n)) {
      (value - 1.U)(log2Ceil(n)-1,0)
    } else {
      val wrap = (value === 0.U)
      Mux(wrap, (n-1).U, value - 1.U)
    }
  }
}

/**
 * Object to mask off lower bits of a PC to align to a "b"
 * Byte boundary.
 */
object AlignPCToBoundary
{
  def apply(pc: UInt, b: Int): UInt = {
    // Invert for scenario where pc longer than b
    //   (which would clear all bits above size(b)).
    ~(~pc | (b-1).U)
  }
}

/**
 * Object to rotate a signal left by one
 */
object RotateL1
{
  def apply(signal: UInt): UInt = {
    val w = signal.getWidth
    val out = Cat(signal(w-2,0), signal(w-1))

    return out
  }
}

/**
 * Object to sext a value to a particular length.
 */
object Sext
{
  def apply(x: UInt, length: Int): UInt = {
    if (x.getWidth == length) return x
    else return Cat(Fill(length-x.getWidth, x(x.getWidth-1)), x)
  }
}

/**
 * Object to translate from BOOM's special "packed immediate" to a 32b signed immediate
 * Asking for U-type gives it shifted up 12 bits.
 */
object ImmGen
{
  import boom.v3.common.{LONGEST_IMM_SZ, IS_B, IS_I, IS_J, IS_S, IS_U}
  def apply(ip: UInt, isel: UInt): SInt = {
    val sign = ip(LONGEST_IMM_SZ-1).asSInt
    val i30_20 = Mux(isel === IS_U, ip(18,8).asSInt, sign)
    val i19_12 = Mux(isel === IS_U || isel === IS_J, ip(7,0).asSInt, sign)
    val i11    = Mux(isel === IS_U, 0.S,
                 Mux(isel === IS_J || isel === IS_B, ip(8).asSInt, sign))
    val i10_5  = Mux(isel === IS_U, 0.S, ip(18,14).asSInt)
    val i4_1   = Mux(isel === IS_U, 0.S, ip(13,9).asSInt)
    val i0     = Mux(isel === IS_S || isel === IS_I, ip(8).asSInt, 0.S)

    return Cat(sign, i30_20, i19_12, i11, i10_5, i4_1, i0).asSInt
  }
}

/**
 * Object to get the FP rounding mode out of a packed immediate.
 */
object ImmGenRm { def apply(ip: UInt): UInt = { return ip(2,0) } }

/**
 * Object to get the FP function fype from a packed immediate.
 * Note: only works if !(IS_B or IS_S)
 */
object ImmGenTyp { def apply(ip: UInt): UInt = { return ip(9,8) } }

/**
 * Object to see if an instruction is a JALR.
 */
object DebugIsJALR
{
  def apply(inst: UInt): Bool = {
    // TODO Chisel not sure why this won't compile
//    val is_jalr = rocket.DecodeLogic(inst, List(Bool(false)),
//                                     Array(
//                                     JALR -> Bool(true)))
    inst(6,0) === "b1100111".U
  }
}

/**
 * Object to take an instruction and output its branch or jal target. Only used
 * for a debug assert (no where else would we jump straight from instruction
 * bits to a target).
 */
object DebugGetBJImm
{
  def apply(inst: UInt): UInt = {
    // TODO Chisel not sure why this won't compile
    //val csignals =
    //rocket.DecodeLogic(inst,
    //                    List(Bool(false), Bool(false)),
    //      Array(
    //         BEQ     -> List(Bool(true ), Bool(false)),
    //         BNE     -> List(Bool(true ), Bool(false)),
    //         BGE     -> List(Bool(true ), Bool(false)),
    //         BGEU    -> List(Bool(true ), Bool(false)),
    //         BLT     -> List(Bool(true ), Bool(false)),
    //         BLTU    -> List(Bool(true ), Bool(false))
    //      ))
    //val is_br :: nothing :: Nil = csignals

    val is_br = (inst(6,0) === "b1100011".U)

    val br_targ = Cat(Fill(12, inst(31)), Fill(8,inst(31)), inst(7), inst(30,25), inst(11,8), 0.U(1.W))
    val jal_targ= Cat(Fill(12, inst(31)), inst(19,12), inst(20), inst(30,25), inst(24,21), 0.U(1.W))

    Mux(is_br, br_targ, jal_targ)
  }
}

/**
 * Object to return the lowest bit position after the head.
 */
object AgePriorityEncoder
{
  def apply(in: Seq[Bool], head: UInt): UInt = {
    val n = in.size
    val width = log2Ceil(in.size)
    val n_padded = 1 << width
    val temp_vec = (0 until n_padded).map(i => if (i < n) in(i) && i.U >= head else false.B) ++ in
    val idx = PriorityEncoder(temp_vec)
    idx(width-1, 0) //discard msb
  }
}

/**
  * Object to determine whether queue
  * index i0 is older than index i1.
 */
object IsOlder
{
  def apply(i0: UInt, i1: UInt, head: UInt) = ((i0 < i1) ^ (i0 < head) ^ (i1 < head))
}

/**
 * Set all bits at or below the highest order '1'.
 */
object MaskLower
{
  def apply(in: UInt) = {
    val n = in.getWidth
    (0 until n).map(i => in >> i.U).reduce(_|_)
  }
}

/**
 * Set all bits at or above the lowest order '1'.
 */
object MaskUpper
{
  def apply(in: UInt) = {
    val n = in.getWidth
    (0 until n).map(i => (in << i.U)(n-1,0)).reduce(_|_)
  }
}

/**
 * Transpose a matrix of Chisel Vecs.
 */
object Transpose
{
  def apply[T <: chisel3.Data](in: Vec[Vec[T]]) = {
    val n = in(0).size
    VecInit((0 until n).map(i => VecInit(in.map(row => row(i)))))
  }
}

/**
  * N-wide one-hot priority encoder.
 */
object SelectFirstN
{
  def apply(in: UInt, n: Int) = {
    val sels = Wire(Vec(n, UInt(in.getWidth.W)))
    var mask = in

    for (i <- 0 until n) {
      sels(i) := PriorityEncoderOH(mask)
      mask = mask & ~sels(i)
    }

    sels
  }
}

/**
 * Connect the first k of n valid input interfaces to k output interfaces.
 */
class Compactor[T <: chisel3.Data](n: Int, k: Int, gen: T) extends Module
{
  require(n >= k)

  val io = IO(new Bundle {
    val in  = Vec(n, Flipped(DecoupledIO(gen)))
    val out = Vec(k,         DecoupledIO(gen))
  })

  if (n == k) {
    io.out <> io.in
  } else {
    val counts = io.in.map(_.valid).scanLeft(1.U(k.W)) ((c,e) => Mux(e, (c<<1)(k-1,0), c))
    val sels = Transpose(VecInit(counts map (c => VecInit(c.asBools)))) map (col =>
                 (col zip io.in.map(_.valid)) map {case (c,v) => c && v})
    val in_readys = counts map (row => (row.asBools zip io.out.map(_.ready)) map {case (c,r) => c && r} reduce (_||_))
    val out_valids = sels map (col => col.reduce(_||_))
    val out_data = sels map (s => Mux1H(s, io.in.map(_.bits)))

    in_readys zip io.in foreach {case (r,i) => i.ready := r}
    out_valids zip out_data zip io.out foreach {case ((v,d),o) => o.valid := v; o.bits := d}
  }
}

/**
 * Create a queue that can be killed with a branch kill signal.
 * Assumption: enq.valid only high if not killed by branch (so don't check IsKilled on io.enq).
 */
class BranchKillableQueue[T <: boom.v3.common.HasBoomUOP](gen: T, entries: Int, flush_fn: boom.v3.common.MicroOp => Bool = u => true.B, flow: Boolean = true)
  (implicit p: org.chipsalliance.cde.config.Parameters)
  extends boom.v3.common.BoomModule()(p)
  with boom.v3.common.HasBoomCoreParameters
{
  val io = IO(new Bundle {
    val enq     = Flipped(Decoupled(gen))
    val deq     = Decoupled(gen)

    val brupdate  = Input(new BrUpdateInfo())
    val flush   = Input(Bool())

    val empty   = Output(Bool())
    val count   = Output(UInt(log2Ceil(entries).W))
  })

  val ram     = Mem(entries, gen)
  val valids  = RegInit(VecInit(Seq.fill(entries) {false.B}))
  val uops    = Reg(Vec(entries, new MicroOp))

  val enq_ptr = Counter(entries)
  val deq_ptr = Counter(entries)
  val maybe_full = RegInit(false.B)

  val ptr_match = enq_ptr.value === deq_ptr.value
  io.empty := ptr_match && !maybe_full
  val full = ptr_match && maybe_full
  val do_enq = WireInit(io.enq.fire)
  val do_deq = WireInit((io.deq.ready || !valids(deq_ptr.value)) && !io.empty)

  for (i <- 0 until entries) {
    val mask = uops(i).br_mask
    val uop  = uops(i)
    valids(i)  := valids(i) && !IsKilledByBranch(io.brupdate, mask) && !(io.flush && flush_fn(uop))
    when (valids(i)) {
      uops(i).br_mask := GetNewBrMask(io.brupdate, mask)
    }
  }

  when (do_enq) {
    ram(enq_ptr.value)          := io.enq.bits
    valids(enq_ptr.value)       := true.B //!IsKilledByBranch(io.brupdate, io.enq.bits.uop)
    uops(enq_ptr.value)         := io.enq.bits.uop
    uops(enq_ptr.value).br_mask := GetNewBrMask(io.brupdate, io.enq.bits.uop)
    enq_ptr.inc()
  }

  when (do_deq) {
    valids(deq_ptr.value) := false.B
    deq_ptr.inc()
  }

  when (do_enq =/= do_deq) {
    maybe_full := do_enq
  }

  io.enq.ready := !full

  val out = Wire(gen)
  out             := ram(deq_ptr.value)
  out.uop         := uops(deq_ptr.value)
  io.deq.valid            := !io.empty && valids(deq_ptr.value) && !IsKilledByBranch(io.brupdate, out.uop) && !(io.flush && flush_fn(out.uop))
  io.deq.bits             := out
  io.deq.bits.uop.br_mask := GetNewBrMask(io.brupdate, out.uop)

  // For flow queue behavior.
  if (flow) {
    when (io.empty) {
      io.deq.valid := io.enq.valid //&& !IsKilledByBranch(io.brupdate, io.enq.bits.uop)
      io.deq.bits := io.enq.bits
      io.deq.bits.uop.br_mask := GetNewBrMask(io.brupdate, io.enq.bits.uop)

      do_deq := false.B
      when (io.deq.ready) { do_enq := false.B }
    }
  }
  private val ptr_diff = enq_ptr.value - deq_ptr.value
  if (isPow2(entries)) {
    io.count := Cat(maybe_full && ptr_match, ptr_diff)
  }
  else {
    io.count := Mux(ptr_match,
                    Mux(maybe_full,
                        entries.asUInt, 0.U),
                    Mux(deq_ptr.value > enq_ptr.value,
                        entries.asUInt + ptr_diff, ptr_diff))
  }
}

// ------------------------------------------
// Printf helper functions
// ------------------------------------------

object BoolToChar
{
  /**
   * Take in a Chisel Bool and convert it into a Str
   * based on the Chars given
   *
   * @param c_bool Chisel Bool
   * @param trueChar Scala Char if bool is true
   * @param falseChar Scala Char if bool is false
   * @return UInt ASCII Char for "trueChar" or "falseChar"
   */
  def apply(c_bool: Bool, trueChar: Char, falseChar: Char = '-'): UInt = {
    Mux(c_bool, Str(trueChar), Str(falseChar))
  }
}

object CfiTypeToChars
{
  /**
   * Get a Vec of Strs that can be used for printing
   *
   * @param cfi_type specific cfi type
   * @return Vec of Strs (must be indexed to get specific char)
   */
  def apply(cfi_type: UInt) = {
    val strings = Seq("----", "BR  ", "JAL ", "JALR")
    val multiVec = VecInit(for(string <- strings) yield { VecInit(for (c <- string) yield { Str(c) }) })
    multiVec(cfi_type)
  }
}

object BpdTypeToChars
{
  /**
   * Get a Vec of Strs that can be used for printing
   *
   * @param bpd_type specific bpd type
   * @return Vec of Strs (must be indexed to get specific char)
   */
  def apply(bpd_type: UInt) = {
    val strings = Seq("BR  ", "JUMP", "----", "RET ", "----", "CALL", "----", "----")
    val multiVec = VecInit(for(string <- strings) yield { VecInit(for (c <- string) yield { Str(c) }) })
    multiVec(bpd_type)
  }
}

object RobTypeToChars
{
  /**
   * Get a Vec of Strs that can be used for printing
   *
   * @param rob_type specific rob type
   * @return Vec of Strs (must be indexed to get specific char)
   */
  def apply(rob_type: UInt) = {
    val strings = Seq("RST", "NML", "RBK", " WT")
    val multiVec = VecInit(for(string <- strings) yield { VecInit(for (c <- string) yield { Str(c) }) })
    multiVec(rob_type)
  }
}

object XRegToChars
{
  /**
   * Get a Vec of Strs that can be used for printing
   *
   * @param xreg specific register number
   * @return Vec of Strs (must be indexed to get specific char)
   */
  def apply(xreg: UInt) = {
    val strings = Seq(" x0", " 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")
    val multiVec = VecInit(for(string <- strings) yield { VecInit(for (c <- string) yield { Str(c) }) })
    multiVec(xreg)
  }
}

{
  /**
   * Get a Vec of Strs that can be used for printing
   *
   * @param fpreg specific register number
   * @return Vec of Strs (must be indexed to get specific char)
   */
  def apply(fpreg: UInt) = {
    val strings = Seq(" ft0", " ft1", " ft2", " ft3",
                      " ft4", " ft5", " ft6", " ft7",
                      " fs0", " fs1", " fa0", " fa1",
                      " fa2", " fa3", " fa4", " fa5",
                      " fa6", " fa7", " fs2", " fs3",
                      " fs4", " fs5", " fs6", " fs7",
                      " fs8", " fs9", "fs10", "fs11",
                      " ft8", " ft9", "ft10", "ft11")
    val multiVec = VecInit(for(string <- strings) yield { VecInit(for (c <- string) yield { Str(c) }) })
    multiVec(fpreg)
  }
}

object BoomCoreStringPrefix
{
  /**
  * Add prefix to BOOM strings (currently only adds the hartId)
  *
  * @param strs list of strings
  * @return String combining the list with the prefix per line
  */
  def apply(strs: String*)(implicit p: Parameters) = {
    val prefix = "[C" + s"${p(TileKey).tileId}" + "] "
    strs.map(str => prefix + str + "\n").mkString("")
  }
}


//******************************************************************************
// Copyright (c) 2015 - 2018, The Regents of the University of California (Regents).
// All Rights Reserved. See LICENSE and LICENSE.SiFive for license details.
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// RISCV Processor Issue Logic
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

package boom.v4.exu

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.util.{Str}

import boom.v4.common._
import boom.v4.util.{BoolToChar}

case class IssueParams(
  dispatchWidth: Int = 1,
  issueWidth: Int = 1,
  numEntries: Int = 8,
  useFullIssueSel: Boolean = true,
  numSlowEntries: Int = 0,
  useMatrixIssue: Boolean = true,
  iqType: Int
)

abstract class IssueUnit(
  val params: IssueParams,
  val numWakeupPorts: Int
)(implicit p: Parameters)
  extends BoomModule
{
  val numIssueSlots = params.numEntries
  val issueWidth = params.issueWidth
  val iqType = params.iqType
  val dispatchWidth = params.dispatchWidth

  val io = IO(new Bundle {
    val dis_uops         = Vec(dispatchWidth, Flipped(Decoupled(new MicroOp)))

    val iss_uops         = Output(Vec(issueWidth, Valid(new MicroOp())))
    val wakeup_ports     = Flipped(Vec(numWakeupPorts, Valid(new Wakeup)))
    val pred_wakeup_port = Flipped(Valid(UInt(log2Ceil(ftqSz).W)))

    val child_rebusys    = Input(UInt(aluWidth.W))

    // tell the issue unit what each execution pipeline has in terms of functional units
    val fu_types         = Input(Vec(issueWidth, Vec(FC_SZ, Bool())))

    val brupdate         = Input(new BrUpdateInfo())
    val flush_pipeline   = Input(Bool())
    val squash_grant     = Input(Bool())

    val tsc_reg          = Input(UInt(xLen.W))

    // For the speculative non-interference (SNI) implementation
    val rob_head = Input(UInt(robAddrSz.W))
    val rob_pnr_idx = Input(UInt(robAddrSz.W))
  })

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

  def getType: String =
    if (iqType == IQ_ALU) "alu"
    else if (iqType == IQ_MEM) "mem"
    else if (iqType == IQ_FP) " fp"
    else if (iqType == IQ_UNQ) "unique"
    else "unknown"
}

{
  def apply(params: IssueParams, numWakeupPorts: Int, useColumnIssueUnit: Boolean, useSingleWideDispatch: Boolean)(implicit p: Parameters): IssueUnit = {
    if (useColumnIssueUnit)
      Module(new IssueUnitBanked(params, numWakeupPorts, useSingleWideDispatch))
    else
      if (params.useMatrixIssue) {
        Module(new IssueUnitAgeMatrix(params, numWakeupPorts))
      } else {
        Module(new IssueUnitCollapsing(params, numWakeupPorts))
      }
  }

}


//******************************************************************************
// Copyright (c) 2015 - 2019, The Regents of the University of California (Regents).
// All Rights Reserved. See LICENSE and LICENSE.SiFive for license details.
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Rename Map Table
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

package boom.v4.exu

import chisel3._
import chisel3.util._
import boom.v4.common._
import boom.v4.util._
import org.chipsalliance.cde.config.Parameters

class MapReq(val lregSz: Int) extends Bundle
{
  val lrs1 = UInt(lregSz.W)
  val lrs2 = UInt(lregSz.W)
  val lrs3 = UInt(lregSz.W)
  val ldst = UInt(lregSz.W)
}

class MapResp(val pregSz: Int) extends Bundle
{
  val prs1 = UInt(pregSz.W)
  val prs2 = UInt(pregSz.W)
  val prs3 = UInt(pregSz.W)
  val stale_pdst = UInt(pregSz.W)
}

class RemapReq(val lregSz: Int, val pregSz: Int) extends Bundle
{
  val ldst = UInt(lregSz.W)
  val pdst = UInt(pregSz.W)
  val valid = Bool()
}

class RenameMapTable(
  val plWidth: Int,
  val numLregs: Int,
  val numPregs: Int,
  val bypass: Boolean,
  val float: Boolean)
  (implicit p: Parameters) extends BoomModule
{
  val pregSz = log2Ceil(numPregs)

  val io = IO(new BoomBundle()(p) {
    // Logical sources -> physical sources.
    val map_reqs    = Input(Vec(plWidth, new MapReq(lregSz)))
    val map_resps   = Output(Vec(plWidth, new MapResp(pregSz)))

    // Remapping an ldst to a newly allocated pdst?
    val remap_reqs  = Input(Vec(plWidth, new RemapReq(lregSz, pregSz)))
    val com_remap_reqs = Input(Vec(plWidth, new RemapReq(lregSz, pregSz)))

    // Dispatching branches: need to take snapshots of table state.
    val ren_br_tags = Input(Vec(plWidth+1, Valid(UInt(brTagSz.W))))

    // Signals for restoring state following misspeculation.
    val brupdate      = Input(new BrUpdateInfo)
    val rollback    = Input(Bool())
  })

  // The map table register array and its branch snapshots.
  val map_table = RegInit(VecInit((0 until numLregs) map { i => i.U(pregSz.W) }))

  val br_snapshots = Reg(Vec(maxBrCount, Vec(numLregs, UInt(pregSz.W))))

  // The intermediate states of the map table following modification by each pipeline slot.
  val remap_table = Wire(Vec(plWidth+1, Vec(numLregs, UInt(pregSz.W))))
  val com_remap_table = Wire(Vec(plWidth+1, Vec(numLregs, UInt(pregSz.W))))

  // Uops requesting changes to the map table.
  val remap_pdsts = io.remap_reqs map (_.pdst)
  val remap_ldsts_oh = io.remap_reqs map (req => UIntToOH(req.ldst) & Fill(numLregs, req.valid.asUInt))

  val com_remap_pdsts = io.com_remap_reqs map (_.pdst)
  val com_remap_ldsts_oh = io.com_remap_reqs map (req => UIntToOH(req.ldst) & Fill(numLregs, req.valid.asUInt))

  // Figure out the new mappings seen by each pipeline slot.
  for (i <- 0 until numLregs) {
    val remapped_row = (remap_ldsts_oh.map(ldst => ldst(i)) zip remap_pdsts)
      .scanLeft(map_table(i)) {case (pdst, (ldst, new_pdst)) => Mux(ldst, new_pdst, pdst)}

    val com_remapped_row = (com_remap_ldsts_oh.map(ldst => ldst(i)) zip com_remap_pdsts)
      .scanLeft(com_map_table(i)) {case (pdst, (ldst, new_pdst)) => Mux(ldst, new_pdst, pdst)}

    for (j <- 0 until plWidth+1) {
      remap_table(j)(i) := remapped_row(j)
      com_remap_table(j)(i) := com_remapped_row(j)
    }
  }

  // Create snapshots of new mappings.
  if (enableSuperscalarSnapshots) {
    for (i <- 0 until plWidth+1) {
      when (io.ren_br_tags(i).valid) {
        br_snapshots(io.ren_br_tags(i).bits) := remap_table(i)
      }
    }
  } else {
    assert(PopCount(io.ren_br_tags.map(_.valid)) <= 1.U)
    val do_br_snapshot = io.ren_br_tags.map(_.valid).reduce(_||_)
    val br_snapshot_tag   = Mux1H(io.ren_br_tags.map(_.valid), io.ren_br_tags.map(_.bits))
    val br_snapshot_table = Mux1H(io.ren_br_tags.map(_.valid), remap_table)
    when (do_br_snapshot) {
      br_snapshots(br_snapshot_tag) := br_snapshot_table
    }
  }

  when (io.brupdate.b2.mispredict) {
    // Restore the map table to a branch snapshot.
    map_table := br_snapshots(io.brupdate.b2.uop.br_tag)
  } .elsewhen (io.rollback) {
    map_table := com_map_table
  } .otherwise {
    // Update mappings.
    map_table := remap_table(plWidth)
  }
  com_map_table := com_remap_table(plWidth)

  // Read out mappings.
  for (i <- 0 until plWidth) {
    io.map_resps(i).prs1       := (0 until i).foldLeft(map_table(io.map_reqs(i).lrs1)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).lrs1, io.remap_reqs(k).pdst, p))
    io.map_resps(i).prs2       := (0 until i).foldLeft(map_table(io.map_reqs(i).lrs2)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).lrs2, io.remap_reqs(k).pdst, p))
    io.map_resps(i).prs3       := (0 until i).foldLeft(map_table(io.map_reqs(i).lrs3)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).lrs3, io.remap_reqs(k).pdst, p))
    io.map_resps(i).stale_pdst := (0 until i).foldLeft(map_table(io.map_reqs(i).ldst)) ((p,k) =>
      Mux(bypass.B && io.remap_reqs(k).valid && io.remap_reqs(k).ldst === io.map_reqs(i).ldst, io.remap_reqs(k).pdst, p))

    if (!float) io.map_resps(i).prs3 := DontCare
  }

  // Don't flag the creation of duplicate 'p0' mappings during rollback.
  // These cases may occur soon after reset, as all maptable entries are initialized to 'p0'.
  io.remap_reqs map (req => (req.pdst, req.valid)) foreach {case (p,r) =>
    assert (!r || !map_table.contains(p), "[maptable] Trying to write a duplicate mapping.")}
}

val com_map_table = RegInit(VecInit((0 until numLregs) map { i => i.U(pregSz.W) }))


//> using scala "2.13.16"
//> using repository sonatype-s01:snapshots
//> using dep "org.chipsalliance::chisel::7.0.0-M2+508-57ab35eb-SNAPSHOT"
//> using plugin "org.chipsalliance:::chisel-plugin::7.0.0-M2+508-57ab35eb-SNAPSHOT"
//> using options "-unchecked", "-deprecation", "-language:reflectiveCalls", "-feature", "-Xcheckinit", "-Xfatal-warnings", "-Ywarn-dead-code", "-Ywarn-unused", "-Ymacro-annotations"

package boom.v4.util

import chisel3._
import chisel3.util.{log2Ceil,log2Floor, Cat,Mux1H}
import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public}
import circt.stage.ChiselStage

@instantiable
class ParallelFindOne(decodeWidth : Int, favor: Boolean) extends Module {

  @public val bitmask = IO(Input(UInt(decodeWidth.W)))
  @public val success = IO(Output(new Bool()))
  @public val index = IO(Output(UInt(log2Ceil(decodeWidth).W)))

  // must be log of 2
  require(log2Ceil(decodeWidth) == log2Floor(decodeWidth))

  if (decodeWidth ==2 ) {
    success := bitmask.orR
    if (favor) {
      index := bitmask(1)
    } else {
      index := !bitmask(0)
    }
    // index := Mux1H(Seq(
    //   bitmask(1) -> 1.U(1.W),
    //   bitmask(0) -> 0.U(1.W)
    // )) // Note: not truly parallel for lack of X
  } else {
    val decoder_def = Definition(new ParallelFindOne(decodeWidth / 2, favor))
    val lower_dec = Instance(decoder_def)
    val upper_dec = Instance(decoder_def)

    val lower_success = Wire(Bool())
    val upper_success = Wire(Bool())
    val lower_index = Wire(UInt((log2Ceil(decodeWidth)-1).W))
    val upper_index = Wire(UInt((log2Ceil(decodeWidth)-1).W))
    lower_dec.bitmask := bitmask(decodeWidth/2-1, 0)
    upper_dec.bitmask := bitmask(decodeWidth-1, decodeWidth/2)
    lower_success := lower_dec.success
    upper_success := upper_dec.success
    lower_index := lower_dec.index
    upper_index := upper_dec.index
    success := lower_success | upper_success
    if (favor) {
      index := Mux(upper_success, Cat(1.U(1.W), upper_index), Cat(0.U(1.W), lower_index))
    } else {
      index := Mux(lower_success, Cat(0.U(1.W), lower_index), Cat(1.U(1.W), upper_index))
    }
    // index := Mux1H(Seq(
    //   upper_success ->Cat(1.U(1.W), upper_index),
    //   lower_success -> Cat(0.U(1.W), lower_index)
    // ))
  }
}

object ParallelFindOne {
  def apply(bv: UInt, favor: Boolean) : (Bool, UInt) = {
    val widthRoundUp = scala.math.pow(2, (log2Ceil(bv.getWidth))).intValue
    val pfo = Module(new ParallelFindOne(widthRoundUp, favor))
    pfo.bitmask := bv
//    assert(pfo.index < bv.getWidth.U,"non-pow2 index out of range")
    (pfo.success, pfo.index)
  }
}

class testmodule extends Module {
  val input = IO(Input(UInt(4.W)))
  val success = IO(Output(Bool()))
  val index = IO(Output(UInt(2.W)))

  val (a, b) = ParallelFindOne(input, true)
  success := a
  index := b

//   (success, index)  :=
}

object Elaborate extends App {

  println(ChiselStage.emitSystemVerilog(new testmodule))
//  println(ChiselStage.emitFIRRTLDialect(new ParallelFindOne(4)))
//  println(ChiselStage.emitSystemVerilog(new PrefixedMux))

}

override val desiredName = s"Parallel_${decodeWidth}_f${favor}_FindOne"


// See LICENSE for license details.

import chisel3._

/**
  * Logic gate (Vector version)
  */
class LogicGatesVec extends Module {
  val io = IO(new Bundle {
    /** Input from switch */
    val switches = Input(Vec(2, Bool()))
    /** Output to LED */
    val leds = Output(Vec(7, Bool()))
  })

  io.leds(0) :=  ~io.switches(0)                    // NOT

  io.leds(6) := ~(io.switches(0) ^ io.switches(1))  // NXOR
}

object LogicGatesVec extends App {
  chisel3.Driver.execute(args, () => new LogicGatesVec())
}

  io.leds(1) :=   io.switches(0) & io.switches(1)   // AND
  io.leds(2) :=   io.switches(0) | io.switches(1)   // OR
  io.leds(3) := ~(io.switches(0) & io.switches(1))  // NAND


// See LICENSE for license details.

import chisel3._

/**
  * Compare operation
  */
class IntCompare extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W)) // Input A
    val b = Input(UInt(4.W)) // Input B
    val bit_ope = Output(Bool())
    val bit_reduction = Output(Bool())
    val equal_ope = Output(Bool())
    val equal_5 = Output(Bool())
    val not_5 = Output(Bool())
  })

  // Compare by bit, if there is even one difference, they are not equal
  io.bit_ope := ~(io.a(0) ^ io.b(0) | io.a(1) ^ io.b(1) | io.a(2) ^ io.b(2) | io.a(3) ^ io.b(3))

  // Bitwise comparison of "a" and "b" can be done like "a ^ b".
  // Since it is hard to write like "a (0) | a (1) | a (2) | a (3)", the ". orR" operator is defined.
  io.bit_reduction := ~((io.a ^ io.b).orR)

  // Since Chisel also has an equality operator, it does not actually do the troublesome thing like the above.
  io.equal_ope := io.a === io.b

  // You can also compare with numeric literals. Match the missing bits to the larger one.
  io.equal_5 := io.a === 5.U

object IntCompare extends App {
  chisel3.Driver.execute(args, () => new IntCompare())
}

  // Inequality operator is "=/=".
  io.not_5 := io.a =/= 5.U


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** Left shifter
  */
class LeftShifter extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(4.W))
    // Since the input is 4 bits, 2 bits are sufficient for
    // specifying the shift amount
    val shiftAmount = Input(UInt(2.W))
    val out = Output(UInt(4.W))
  })

  // The output of the least significant bit becomes the least
  // significant bit of input when the shift amount is 0, and
  // becomes 0 otherwise.
  val mux0 = Module(new Mux4)
  mux0.io.selector := io.shiftAmount
  mux0.io.in_0 := io.in(0)
  mux0.io.in_1 := 0.U
  mux0.io.in_2 := 0.U
  mux0.io.in_3 := 0.U

  val mux1 = Module(new Mux4)
  mux1.io.selector := io.shiftAmount
  mux1.io.in_0 := io.in(1)
  mux1.io.in_1 := io.in(0)
  mux1.io.in_2 := 0.U
  mux1.io.in_3 := 0.U

  val mux2 = Module(new Mux4)
  mux2.io.selector := io.shiftAmount
  mux2.io.in_0 := io.in(2)
  mux2.io.in_1 := io.in(1)
  mux2.io.in_2 := io.in(0)
  mux2.io.in_3 := 0.U

  val mux3 = Module(new Mux4)
  mux3.io.selector := io.shiftAmount
  mux3.io.in_0 := io.in(3)
  mux3.io.in_1 := io.in(2)
  mux3.io.in_2 := io.in(1)
  mux3.io.in_3 := io.in(0)

  io.out := Cat(mux3.io.out, mux2.io.out, mux1.io.out, mux0.io.out)
}

/**
  * Object to output Verilog file of Mux4.
  */

object LeftShifter extends App {
  chisel3.Driver.execute(args, () => new LeftShifter)
}


// See LICENSE for license details.

import chisel3._

/** Multiplexer.
  * If selecter is 0, output the value of in_0, otherwise in_1.
  */
class Mux2 extends Module {
  val io = IO(new Bundle {
    val selector = Input(UInt(1.W))
    val in_0 = Input(UInt(1.W))
    val in_1 = Input(UInt(1.W))
    val out = Output(UInt(1.W))
  })

  io.out := (~io.selector & io.in_0) | (io.selector & io.in_1)
}

/** Companion object of Mux2
  */
object Mux2 {
/** Multiplexer
  * @param selector 1-bit select signal
  * @param in_0     1-bit input signal
  * @param in_1     1-bit input signal
  *
  * @return If selecter is 0, output the value of in_0, otherwise in_1.
  */
  def apply(selector: UInt, in_0: UInt, in_1: UInt): UInt = {
    val mux2 = Module(new Mux2())

    mux2.io.selector := selector
    mux2.io.in_0 := in_0
    mux2.io.in_1 := in_1
    mux2.io.out


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** Adder (4bit)
  */
class Adder4Bit extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))

    /* By connecting the adders together, it is possible to create a more multi-bit adder. */
    val carryIn = Input(UInt(1.W))

    val sum = Output(UInt(4.W))
    val carryOut = Output(UInt(1.W))
  })

  /*
   * Generate Adders for 4 bits.
   */
  val adder0 = Module(new FullAdder)
  adder0.io.a := io.a(0)
  adder0.io.b := io.b(0)
  adder0.io.carryIn := io.carryIn

  val adder1 = Module(new FullAdder)
  adder1.io.a := io.a(1)
  adder1.io.b := io.b(1)
  adder1.io.carryIn := adder0.io.carryOut // The carry output of the lower digit propagates

  val adder2 = Module(new FullAdder)
  adder2.io.a := io.a(2)
  adder2.io.b := io.b(2)
  adder2.io.carryIn := adder1.io.carryOut

  val adder3 = Module(new FullAdder)
  adder3.io.a := io.a(3)
  adder3.io.b := io.b(3)
  adder3.io.carryIn := adder2.io.carryOut

  // Concatenate the sum of each digit
  io.sum := Cat(adder3.io.sum, adder2.io.sum, adder1.io.sum, adder0.io.sum)

  io.carryOut := adder3.io.carryOut
}

/** Adder (4bit). "for loop" version
  */
class Adder4BitFor extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val carryIn = Input(UInt(1.W))
    val sum = Output(UInt(4.W))
    val carryOut = Output(UInt(1.W))
  })

  val fullAdders = VecInit(Seq.fill(4){ Module(new FullAdder).io }) // [Caution] we pass "io"
  val carries = Wire(Vec(5, UInt(1.W)))
  val sum = Wire(Vec(4, UInt(1.W)))

  carries(0) := io.carryIn

  for (i <- 0 until 4) {
    fullAdders(i).a := io.a(i)
    fullAdders(i).b := io.b(i)
    fullAdders(i).carryIn := carries(i)
    sum(i) := fullAdders(i).sum
    carries(i + 1) := fullAdders(i).carryOut
  }

  io.sum := sum.asUInt
  io.carryOut := carries(4)
}

/** adder
  *
  * @param n bit width
  */
class Adder(n: Int) extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(n.W))
    val b = Input(UInt(n.W))
    val carryIn = Input(UInt(1.W))
    val sum = Output(UInt(n.W))
    val carryOut = Output(UInt(1.W))
  })

  /** contructor with default bit width
    */
  def this() = this(4)

  val carries = Wire(Vec(n + 1, UInt(1.W)))
  val sum = Wire(Vec(n, UInt(1.W)))

  carries(0) := io.carryIn

  for (i <- 0 until n) {
    fullAdders(i).a := io.a(i)
    fullAdders(i).b := io.b(i)
    fullAdders(i).carryIn := carries(i)
    sum(i) := fullAdders(i).sum
    carries(i + 1) := fullAdders(i).carryOut
  }

  io.sum := sum.asUInt
  io.carryOut := carries(n)
}

class AdderLED extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val seg7LEDBundle = Output(new Seg7LEDBundle)
    val overflowLED = Output(UInt(1.W)) // Lights the LED when overflow occurs
  })

  val seg7LED = Module(new Seg7LED1Digit)
  val adder = Module(new Adder4Bit)
  adder.io.a := io.a
  adder.io.b := io.b
  // Since there is no carry input of the least significant digit, 0 is assigned
  adder.io.carryIn := 0.U

  seg7LED.io.num := adder.io.sum

  io.seg7LEDBundle := seg7LED.io.seg7led
  io.overflowLED := adder.io.carryOut
}

class AdderLEDFor extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val seg7LEDBundle = Output(new Seg7LEDBundle)
    val overflowLED = Output(UInt(1.W)) // light LED when overflow occur
  })

  val seg7LED = Module(new Seg7LED1Digit)
  val adder = Module(new Adder4BitFor)
  adder.io.a := io.a
  adder.io.b := io.b
  // Since there is no carry input of the least significant digit, 0 is assigned
  adder.io.carryIn := 0.U

  seg7LED.io.num := adder.io.sum

  io.seg7LEDBundle := seg7LED.io.seg7led
  io.overflowLED := adder.io.carryOut
}

/**
  * Objcect to output Verilog file
  */
object AdderLED extends App {
  chisel3.Driver.execute(args, () => new AdderLED)
}

object AdderLEDFor extends App {
  chisel3.Driver.execute(args, () => new AdderLEDFor)
}

object Adder extends App {
  // generate 8 bit adder.
  chisel3.Driver.execute(args, () => new Adder(8))
}

val fullAdders = VecInit(Seq.fill(n){ Module(new FullAdder).io })


// See LICENSE for license details.

import chisel3._

/** SR Latch
  */
class SRLatch extends Module {
  val io = IO(new Bundle {
    val set = Input(Bool())
    val reset = Input(Bool())
    val q = Output(Bool())
    val notQ = Output(Bool())
  })

  io.q    := ~(io.reset | io.notQ)
  io.notQ := ~(io.set   | io.q)
}

object SRLatch extends App {
  chisel3.Driver.execute(args, () => new SRLatch)
}


// See LICENSE for license details.

import chisel3._

/** SR Latch
  */
class SRLatch extends Module {
  val io = IO(new Bundle {

    val notQ = Output(Bool())
  })

  io.q    := ~(io.reset | io.notQ)
  io.notQ := ~(io.set   | io.q)
}

object SRLatch extends App {
  chisel3.Driver.execute(args, () => new SRLatch)
}

    val set = Input(Bool())
    val reset = Input(Bool())


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** Bundle for 7-segment LED
  */
class Seg7LEDBundle extends Bundle {
  /** For glowing each segment. Make 0 to 7 correspond to CA to CG. It lights when it is 0, and goes out when it is 1. */

  /** For digit selection. The digit which is 1 glows up. */
  val anodes = Output(UInt(8.W))
}

/** 7 segment LED (8 digit)
  */
class Seg7LED extends Module {
  val io = IO(new Bundle {
    // allocate 8 digit 4 bit values.
    val digits = Input(Vec(8, UInt(4.W)))
    val seg7led = Output(new Seg7LEDBundle)
  })

  /* Counter of time to switch each digit.
   * First argument is condition to count up.
   * Second argument is the number counting up. (n, count from 0 to n-1)
   * Return value is taple of number of counter and
   * signal that becomes ture.B when counter equals to n - 1.
   * If condition is true.B, count every clock. */
  val (digitChangeCount, digitChange) = Counter(true.B, 100000)

  val (digitIndex, digitWrap) = Counter(digitChange, 8) // Digit to display
  val digitNum = io.digits(digitIndex)        // number of display digit

  io.seg7led.cathodes := MuxCase("b111_1111".U,
    Array(                   // gfe_dcba is order of cathodes
      (digitNum === "h0".U) -> "b100_0000".U,
      (digitNum === "h1".U) -> "b111_1001".U,
      (digitNum === "h2".U) -> "b010_0100".U,
      (digitNum === "h3".U) -> "b011_0000".U,
      (digitNum === "h4".U) -> "b001_1001".U,
      (digitNum === "h5".U) -> "b001_0010".U,
      (digitNum === "h6".U) -> "b000_0010".U,
      (digitNum === "h7".U) -> "b101_1000".U,
      (digitNum === "h8".U) -> "b000_0000".U,
      (digitNum === "h9".U) -> "b001_0000".U,
      (digitNum === "ha".U) -> "b000_1000".U,
      (digitNum === "hb".U) -> "b000_0011".U,
      (digitNum === "hc".U) -> "b100_0110".U,
      (digitNum === "hd".U) -> "b010_0001".U,
      (digitNum === "he".U) -> "b000_0110".U,
      (digitNum === "hf".U) -> "b000_1110".U))

  val anodes = RegInit("b1111_1110".U(8.W))
  when (digitChange) {
    // Rotate shift when switching display digit
    anodes := Cat(anodes(6, 0), anodes(7))
  }
  io.seg7led.anodes := anodes

  io.seg7led.decimalPoint := 1.U         // Do not light the decimal point.
}

  val cathodes = Output(UInt(7.W))
  /** For decimal point. It lights when it is 0, and goes out when it is 1.  */


// See LICENSE for license details.

import chisel3._
import chisel3.util._

class CharDispBundle extends Bundle {
  val row = Input(UInt(5.W))
  val col = Input(UInt(7.W))
  val charCode = Input(UInt(8.W))
  val color = Input(UInt(8.W))
}

class CharVramWriter extends Module {
  val io = IO(new Bundle{
    val charData = Flipped(Decoupled(new CharDispBundle))
    val vramData = Decoupled(new VramDataBundle)
  })

  /* State machine definition */
  val sIdle :: sRomRead :: sShiftRegLoad :: sVramWrite :: Nil = Enum(4)
  val state = RegInit(sIdle)

  // Coordinates in the character being processed
  val xInChar = RegInit(0.U(3.W))
  val yInChar = RegInit(0.U(4.W))

  val charRom = Module(new CharRom)
  charRom.io.clka := clock
  charRom.io.ena := true.B
  charRom.io.addra := io.charData.bits.charCode * 16.U + yInChar

  val pxShiftReg = Module(new ShiftRegisterPISO(8))
  pxShiftReg.io.d := charRom.io.douta
  pxShiftReg.io.load := state === sShiftRegLoad
  pxShiftReg.io.enable := state === sVramWrite

  // State transition
  switch (state) {
    is (sIdle) {

    }
    is (sShiftRegLoad) {
      state := sVramWrite
      xInChar := 0.U
    }
    is (sVramWrite) {
      when (xInChar === 7.U) {
        when (yInChar === 15.U) {
          state := sIdle
        } .otherwise {
          state := sRomRead
          yInChar := yInChar + 1.U
        }
      } .otherwise {
        xInChar := xInChar + 1.U
      }
    }
  }

  // VRAM address of upper left point of character
  val pxBaseAddr = (VGA.hDispMax * 16).U * io.charData.bits.row + 8.U * io.charData.bits.col
  io.vramData.bits.addr := pxBaseAddr + VGA.hDispMax.U * yInChar + xInChar
  io.vramData.bits.data := Mux(pxShiftReg.io.shiftOut, io.charData.bits.color, 0.U)
  io.vramData.valid := state === sVramWrite

  io.charData.ready := state === sIdle
}

      when (io.charData.valid) {
        state := sRomRead
        yInChar := 0.U
      }


// See LICENSE for license details.

import chisel3._
import chisel3.util._

object Uart {
  val clock_freq = 70000000
  val trans_bps = 115200
}

import Uart._

/** UART
  */
class Uart extends Module {
  val io = IO(new Bundle {
    val rxData = Input(Bool())
    val txData = Output(Bool())
    val rts = Output(Bool())
    val cts = Input(Bool())
    val receiveData = Decoupled(UInt(8.W))
    val sendData = Flipped(Decoupled(UInt(8.W)))
  })

  val uartRx = Module(new UartRx)
  uartRx.io.rxData := io.rxData
  io.receiveData <> uartRx.io.receiveData

  val txQueue = Module(new Queue(UInt(8.W), 64))
  txQueue.io.enq <> io.sendData

  val uartTx = Module(new UartTx)
  io.txData := uartTx.io.txData
  uartTx.io.sendData <> txQueue.io.deq

  io.rts := false.B
}

/** UART Transmitter
  */
class UartTx extends Module {
  val io = IO(new Bundle {
    val sendData = Flipped(Decoupled(UInt(8.W)))
    val txData   = Output(Bool())
  })

  /* State machine definition */
  val sIdle :: sStartBit :: sSend :: sStopBit :: Nil = Enum(4)
  val state = RegInit(sIdle)

  // Counter for state transition
  val (txCount, txEnable) = Counter(true.B, clock_freq / trans_bps)
  // Counter for 8-bit transmission
  val sendCount = Reg(UInt(3.W))
  // Shift register for transmission data
  val shiftReg = Module(new ShiftRegisterPISO(8))
  shiftReg.io.d      := Reverse(io.sendData.bits)
  shiftReg.io.load   := state === sIdle && io.sendData.valid
  shiftReg.io.enable := state === sSend && txEnable

  // State transition
  when (state === sIdle && io.sendData.valid)  {
    state := sStartBit
    txCount := 0.U
  } .elsewhen (txEnable) {
    switch (state) {
      is (sStartBit) {
        state := sSend
        sendCount := 0.U
      }
      is (sSend) {
        when (sendCount === 7.U) {
          state := sStopBit

        state := sIdle
      }
    }
  }

  io.sendData.ready := state === sIdle

  io.txData := MuxCase(true.B, Array(
    (state === sStartBit) -> false.B,
    (state === sSend)     -> shiftReg.io.shiftOut,
    (state === sStopBit)  -> true.B))
}

/** UART receiver
  */
class UartRx extends Module {
  val io = IO(new Bundle {
    val rxData = Input(Bool())
    val receiveData = Decoupled(UInt(8.W))
  })

  /* State machine definition */
  val sIdle :: sStartBit :: sReceive :: sStopBit :: Nil = Enum(4)
  val state = RegInit(sIdle)

  // Counter for state transition
  val (rxCount, rxEnable) = Counter(true.B, clock_freq / trans_bps)
  // Counter for half a cycle of 1 bit
  val (rxHalfCount, rxHalfEnable) = Counter(true.B, clock_freq / trans_bps / 2)
  // Counter for 8-bit receiving
  val receiveCount = Reg(UInt(3.W))

  val shiftReg = Module(new ShiftRegisterSIPO(8))
  shiftReg.io.shiftIn := io.rxData
  shiftReg.io.enable  := state === sReceive && rxEnable

  val rDataValid = RegInit(false.B)
  val start = NegEdge(Synchronizer(io.rxData))

  // State transition
  when (state === sIdle && start) {
    state := sStartBit
    rxHalfCount := 0.U
  } .elsewhen (state === sStartBit && rxHalfEnable) {
    state := sReceive
    rxCount := 0.U
    receiveCount := 0.U
  } .elsewhen (rxEnable) {
    switch (state) {
      is (sReceive) {
        when (receiveCount === 7.U) {
          state := sStopBit
        } .otherwise {
          receiveCount := receiveCount + 1.U
        }
      }
      is (sStopBit) {
        when (rxEnable) {
          state := sIdle
        }
      }
    }
  }

  when (state === sStopBit && rxEnable) {
    rDataValid := true.B
  } .elsewhen (io.receiveData.ready) {
    rDataValid := false.B
  }

  io.receiveData.bits := Reverse(shiftReg.io.q)
  io.receiveData.valid := rDataValid
}

        } .otherwise {
          sendCount := sendCount + 1.U
        }


// See LICENSE for license details.

import chisel3._

/**
  * 各種論理演算(ベクトル版)
  */
class LogicGatesVec extends Module {
  val io = IO(new Bundle {
    /** スイッチの入力 */
    val switches = Input(Vec(2, Bool()))
    /** LEDへの出力 */
    val leds = Output(Vec(7, Bool()))
  })

  io.leds(0) :=  ~io.switches(0)                    // NOT
  io.leds(1) :=   io.switches(0) & io.switches(1)   // AND
  io.leds(2) :=   io.switches(0) | io.switches(1)   // OR
  io.leds(3) := ~(io.switches(0) & io.switches(1))  // NAND
  io.leds(4) := ~(io.switches(0) | io.switches(1))  // NOR
  io.leds(5) :=   io.switches(0) ^ io.switches(1)   // XOR

}

object LogicGatesVec extends App {
  chisel3.Driver.execute(args, () => new LogicGatesVec())
}

io.leds(6) := ~(io.switches(0) ^ io.switches(1))  // NXOR


// See LICENSE for license details.

import chisel3._

/** 4入力マルチプレクサ。
  * selectorの値で、0から3を選択します。
  */
class Mux4 extends Module {
  val io = IO(new Bundle {
    val selector = Input(UInt(2.W))
    val in_0 = Input(UInt(1.W))
    val in_1 = Input(UInt(1.W))
    val in_2 = Input(UInt(1.W))
    val in_3 = Input(UInt(1.W))
    val out = Output(UInt(1.W))
  })

  io.out := Mux2(io.selector(1),
    Mux2(io.selector(0), io.in_0, io.in_1),
    Mux2(io.selector(0), io.in_2, io.in_3))
}

/**
  * Mux4のVerilogファイルを生成するための、オブジェクト
  */

object Mux4 extends App {
  chisel3.Driver.execute(args, () => new Mux4())
}


// See LICENSE for license details.

import chisel3._

/** 全加算器
  */
class FullAdder extends Module {
  /** 入出力の信号線を定義 */
  val io = IO(new Bundle {
    val a = Input(UInt(1.W))
    val b = Input(UInt(1.W))
    val carryIn = Input(UInt(1.W))
    val sum = Output(UInt(1.W))
    val carryOut = Output(UInt(1.W))
  })

  // まず同一桁の足し算
  val halfAddr = Module(new HalfAdder)
  halfAddr.io.a := io.a
  halfAddr.io.b := io.b

  // 同一桁の合計と桁上げ入力の足し算
  val halfAddrCarry = Module(new HalfAdder)
  halfAddrCarry.io.a := halfAddr.io.sum
  halfAddrCarry.io.b := io.carryIn

  io.sum := halfAddrCarry.io.sum

  // 2つの半加算器の結果のどちらかでも桁上げ出力が発生していたら、全体として桁上げ
  io.carryOut := halfAddr.io.carryOut | halfAddrCarry.io.carryOut
}

/**
  * Verilogファイルを生成するための、オブジェクト
  */

object FullAdder extends App {
  chisel3.Driver.execute(args, () => new FullAdder)
}


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** 加算器(4bit)
  */
class Adder4Bit extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))

    /* この加算器同士を繋いで、更に多ビットの加算器を作れるようにする。 */
    val carryIn = Input(UInt(1.W))

    val sum = Output(UInt(4.W))
    val carryOut = Output(UInt(1.W))
  })

  /*
   * 4ビット分のAdderを生成する。
   */
  val adder0 = Module(new FullAdder)
  adder0.io.a := io.a(0)
  adder0.io.b := io.b(0)
  adder0.io.carryIn := io.carryIn

  val adder1 = Module(new FullAdder)
  adder1.io.a := io.a(1)
  adder1.io.b := io.b(1)
  adder1.io.carryIn := adder0.io.carryOut // 下位の桁の桁上げ出力が伝搬してくる

  val adder2 = Module(new FullAdder)
  adder2.io.a := io.a(2)
  adder2.io.b := io.b(2)
  adder2.io.carryIn := adder1.io.carryOut

  val adder3 = Module(new FullAdder)
  adder3.io.a := io.a(3)
  adder3.io.b := io.b(3)
  adder3.io.carryIn := adder2.io.carryOut

  // 各桁の合計を連結する
  io.sum := Cat(adder3.io.sum, adder2.io.sum, adder1.io.sum, adder0.io.sum)

  io.carryOut := adder3.io.carryOut
}

/** 加算器(4bit)。forループ版
  */
class Adder4BitFor extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val carryIn = Input(UInt(1.W))
    val sum = Output(UInt(4.W))
    val carryOut = Output(UInt(1.W))
  })

  val carries = Wire(Vec(5, UInt(1.W)))
  val sum = Wire(Vec(4, UInt(1.W)))

  carries(0) := io.carryIn

  for (i <- 0 until 4) {
    fullAdders(i).a := io.a(i)
    fullAdders(i).b := io.b(i)
    fullAdders(i).carryIn := carries(i)
    sum(i) := fullAdders(i).sum
    carries(i + 1) := fullAdders(i).carryOut
  }

  io.sum := sum.asUInt
  io.carryOut := carries(4)
}

class AdderLED extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val seg7LEDBundle = Output(new Seg7LEDBundle)
    val overflowLED = Output(UInt(1.W)) // 桁溢れが発生したらLEDを点灯させる
  })

  val seg7LED = Module(new Seg7LED1Digit)
  val adder = Module(new Adder4Bit)
  adder.io.a := io.a
  adder.io.b := io.b
  adder.io.carryIn := 0.U // 最下位桁の桁上げ入力は存在しないので0を割り当て

  seg7LED.io.num := adder.io.sum

  io.seg7LEDBundle := seg7LED.io.seg7led
  io.overflowLED := adder.io.carryOut
}

class AdderLEDFor extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val seg7LEDBundle = Output(new Seg7LEDBundle)
    val overflowLED = Output(UInt(1.W)) // 桁溢れが発生したらLEDを点灯させる
  })

  val seg7LED = Module(new Seg7LED1Digit)
  val adder = Module(new Adder4BitFor)
  adder.io.a := io.a
  adder.io.b := io.b
  adder.io.carryIn := 0.U // 最下位桁の桁上げ入力は存在しないので0を割り当て

  seg7LED.io.num := adder.io.sum

  io.seg7LEDBundle := seg7LED.io.seg7led
  io.overflowLED := adder.io.carryOut
}

/**
  * Verilogファイルを生成するための、オブジェクト
  */
object AdderLED extends App {
  chisel3.Driver.execute(args, () => new AdderLED)
}

object AdderLEDFor extends App {
  chisel3.Driver.execute(args, () => new AdderLEDFor)
}

val fullAdders = VecInit(Seq.fill(4){ Module(new FullAdder).io }) // [注意]ioを渡している


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** 左シフタ。
  */
class LeftShifter extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(4.W))
    val shiftAmount = Input(UInt(2.W)) // 入力が4ビットなので、2ビットで十分
    val out = Output(UInt(4.W))
  })

  // 最下位ビットはシフト量が0の時に入力最下位ビットを出力。それ以外は0になる。
  val mux0 = Module(new Mux4)
  mux0.io.selector := io.shiftAmount
  mux0.io.in_0 := io.in(0)
  mux0.io.in_1 := 0.U
  mux0.io.in_2 := 0.U
  mux0.io.in_3 := 0.U

  val mux1 = Module(new Mux4)
  mux1.io.selector := io.shiftAmount

  mux1.io.in_3 := 0.U

  val mux2 = Module(new Mux4)
  mux2.io.selector := io.shiftAmount
  mux2.io.in_0 := io.in(2)
  mux2.io.in_1 := io.in(1)
  mux2.io.in_2 := io.in(0)
  mux2.io.in_3 := 0.U

  val mux3 = Module(new Mux4)
  mux3.io.selector := io.shiftAmount
  mux3.io.in_0 := io.in(3)
  mux3.io.in_1 := io.in(2)
  mux3.io.in_2 := io.in(1)
  mux3.io.in_3 := io.in(0)

  io.out := Cat(mux3.io.out, mux2.io.out, mux1.io.out, mux0.io.out)
}

/**
  * Verilogファイルを生成するための、オブジェクト
  */
object LeftShifter extends App {
  chisel3.Driver.execute(args, () => new LeftShifter)
}

  mux1.io.in_0 := io.in(1)
  mux1.io.in_1 := io.in(0)


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** 乗算器(4bit)
  */
class Multiplier4Bit extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val result = Output(UInt(8.W))
  })

  // 各桁の計算をする
  val digit0 = Wire(UInt(4.W))
  val digit1 = Wire(UInt(4.W))
  val digit2 = Wire(UInt(4.W))
  val digit3 = Wire(UInt(4.W))
  digit0 := io.a & Fill(4, io.b(0)) // b(0)を4つコピーしてからANDをとる
  digit1 := io.a & Fill(4, io.b(1))
  digit2 := io.a & Fill(4, io.b(2))
  digit3 := io.a & Fill(4, io.b(3))

  // 0桁目と1桁目の足し算
  val adder1 = Module(new Adder4Bit)
  adder1.io.a := digit1
  adder1.io.b := Cat(0.U, digit0(3, 1)) // digit0の3〜1ビット目を使っている
  adder1.io.carryIn := 0.U              // 桁上げ入力は不要

  // 1桁目の足し算の結果と2桁目の足し算
  val adder2 = Module(new Adder4Bit)
  adder2.io.a := digit2
  adder2.io.b := Cat(adder1.io.carryOut, adder1.io.sum(3, 1))
  adder2.io.carryIn := 0.U

  val adder3 = Module(new Adder4Bit)
  adder3.io.a := digit3
  adder3.io.b := Cat(adder2.io.carryOut, adder2.io.sum(3, 1))
  adder3.io.carryIn := 0.U

  io.result := Cat(adder3.io.carryOut, adder3.io.sum,
    adder2.io.sum(0), adder1.io.sum(0), digit0(0))
}

/** 乗算器(4bit)
  */
class Multiplier4Bit2 extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(4.W))
    val b = Input(UInt(4.W))
    val result = Output(UInt(8.W))
  })

  val digits = VecInit(
    for (i <- 0 until 4) yield { io.a & Fill(4, io.b(i)) }
  )

  val adders = VecInit(Seq.fill(3){ Module(new Adder4Bit).io })
  for (i <- 0 until 3) {
    adders(i).a := digits(i + 1)
    if (i == 0) {
      adders(i).b := Cat(0.U, digits(i)(3, 1)) // digits(0)(3, 1)はdigits(0).apply(3, 1)の略
    } else {
      adders(i).b := Cat(adders(i - 1).carryOut, adders(i - 1).sum(3, 1))
    }
    adders(i).carryIn := 0.U              // 桁上げ入力は不要
  }

  io.result := Cat(adders(2).carryOut, adders(2).sum,
    adders(1).sum(0), adders(0).sum(0), digits(0)(0))
}

/** 乗算器
  *
  * @param n ビット幅
  */
class Multiplier(n: Int) extends Module {
  val io = IO(new Bundle {
    val a = Input(UInt(n.W))
    val b = Input(UInt(n.W))
    val result = Output(UInt((2 * n).W))
  })

  val digits = VecInit(
    for (i <- 0 until n) yield { io.a & Fill(n,  io.b(i)) }
  )

  val adders = VecInit(Seq.fill(n - 1){ Module(new Adder4Bit).io })
  for (i <- 0 until (n - 1)) {
    adders(i).a := digits(i + 1)
    if (i == 0) {
      // digits(0)(n - 1, 1)はdigits(0).apply(n - 1, 1)の略
      adders(i).b := Cat(0.U, digits(i)(n - 1, 1))
    } else {
      adders(i).b := Cat(adders(i - 1).carryOut, adders(i - 1).sum(n - 1, 1))
    }
    adders(i).carryIn := 0.U              // 桁上げ入力は不要
  }

  io.result := Cat(adders(n - 2).carryOut, adders(n - 2).sum(n - 1, 1), adderLsbs, digits(0)(0))
}

object Multiplier4Bit extends App {
  chisel3.Driver.execute(args, () => new Multiplier4Bit)
}

object Multiplier4Bit2 extends App {
  chisel3.Driver.execute(args, () => new Multiplier4Bit2)
}

object Multiplier extends App {
  chisel3.Driver.execute(args, () => new Multiplier(4))
}

val adderLsbs = Cat(for (i <- (n - 2) to 0 by -1) yield { adders(i).sum(0) })


// See LICENSE for license details.

import chisel3._

/** SRラッチ
  */
class SRLatch extends Module {
  val io = IO(new Bundle {
    val set = Input(Bool())
    val reset = Input(Bool())
    val q = Output(Bool())
    val notQ = Output(Bool())
  })

  io.q    := ~(io.reset | io.notQ)
  io.notQ := ~(io.set   | io.q)
}


// See LICENSE for license details.

import chisel3._

/** Dラッチ
  */
class DLatch extends Module {
  val io = IO(new Bundle {
    val data = Input(Bool())
    val enable = Input(Bool())
    val q = Output(Bool())
  })

  val srLatch = Module(new SRLatch)
  srLatch.io.reset := io.enable & ~io.data
  srLatch.io.set   := io.enable &  io.data

  io.q := srLatch.io.q
}

object DLatch extends App {
  chisel3.Driver.execute(args, () => new DLatch)
}


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** ストップウォッチ
  */
class Stopwatch extends Module {
  val io = IO(new Bundle {
    val startStop = Input(Bool())
    val seg7led = Output(new Seg7LEDBundle)
  })

  val running = RegInit(false.B)
  when (Debounce(io.startStop)) {
    running := ~running
  }

  val (clockNum, centimalSec) = Counter(running, 1000000) // 1Mクロック(1/100秒)分カウント
  val (cSec, oneSec) = Counter(centimalSec, 100)  // 1秒カウント
  val (sec, oneMin)  = Counter(oneSec, 60)        // 60秒カウント
  val (min, oneHour) = Counter(oneMin, 60)        // 60分カウント
  val (hour, oneDay) = Counter(oneHour, 24)       // 24時間カウント

  val seg7LED = Module(new Seg7LED)
  seg7LED.io.digits := VecInit(List(cSec % 10.U, (cSec / 10.U)(3, 0), sec % 10.U, (sec / 10.U)(3, 0),
    min % 10.U, (min / 10.U)(3, 0), hour % 10.U, (hour / 10.U)(3, 0)))

  io.seg7led := seg7LED.io.seg7led
}

object Stopwatch extends App {
  chisel3.Driver.execute(args, () => new Stopwatch)
}


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** UART
  */
class Uart extends Module {
  val io = IO(new Bundle {

  val uartRx = Module(new UartRx)
  uartRx.io.rxData := io.rxData
  io.receiveData <> uartRx.io.receiveData

  val uartTx = Module(new UartTx)
  io.txData := uartTx.io.txData
  uartTx.io.sendData <> io.sendData

  io.rts := false.B
}

/** UART送信
  */
class UartTx extends Module {
  val io = IO(new Bundle {
    val sendData = Flipped(Decoupled(UInt(8.W)))
    val txData   = Output(Bool())
  })

  /* ステート・マシン定義 */
  val sIdle :: sStartBit :: sSend :: sStopBit :: Nil = Enum(4)
  val state = RegInit(sIdle)

  val (txCount, txEnable) = Counter(true.B, 100000000 / 115200) // 状態遷移用カウンタ
  val sendCount = Reg(UInt(3.W))                      // 8ビット送信
  val shiftReg = Module(new ShiftRegisterPISO(8))     // 送信データ用シフトレジスタ
  shiftReg.io.d      := Reverse(io.sendData.bits)
  shiftReg.io.load   := io.sendData.valid
  shiftReg.io.enable := state === sSend && txEnable

  // 状態遷移
  when (state === sIdle && io.sendData.valid)  {
    state := sStartBit
    txCount := 0.U
  } .elsewhen (txEnable) {
    switch (state) {
      is (sStartBit) {
        state := sSend
        sendCount := 0.U
      }
      is (sSend) {
        when (sendCount === 7.U) {
          state := sStopBit
        } .otherwise {
          sendCount := sendCount + 1.U
        }
      }
      is (sStopBit) {
        state := sIdle
      }
    }
  }

  io.sendData.ready := state === sIdle

  io.txData := MuxCase(true.B, Array(
    (state === sStartBit) -> false.B,
    (state === sSend)     -> shiftReg.io.shiftOut,
    (state === sStopBit)  -> true.B))
}

/** UART受信
  */
class UartRx extends Module {
  val io = IO(new Bundle {
    val rxData = Input(Bool())
    val receiveData = Decoupled(UInt(8.W))
  })

  /* ステート・マシン定義 */
  val sIdle :: sStartBit :: sReceive :: sStopBit :: Nil = Enum(4)
  val state = RegInit(sIdle)

  val (rxCount, rxEnable) = Counter(true.B, 100000000 / 115200) // 状態遷移用カウンタ
  val (rxHalfCount, rxHalfEnable) = Counter(true.B, 100000000 / 115200 / 2) // 1/2ビット周期カウンタ
  val receiveCount = Reg(UInt(3.W))                    // 8ビット受信

  val shiftReg = Module(new ShiftRegisterSIPO(8))
  shiftReg.io.shiftIn := io.rxData
  shiftReg.io.enable  := state === sReceive && rxEnable

  val rDataValid = RegInit(false.B)
  val start = NegEdge(Synchronizer(io.rxData))

  // 状態遷移
  when (state === sIdle && start) {
    state := sStartBit
    rxHalfCount := 0.U
  } .elsewhen (state === sStartBit && rxHalfEnable) {
    state := sReceive
    rxCount := 0.U
    receiveCount := 0.U
  } .elsewhen (rxEnable) {
    switch (state) {
      is (sReceive) {
        when (receiveCount === 7.U) {
          state := sStopBit
        } .otherwise {
          receiveCount := receiveCount + 1.U
        }
      }
      is (sStopBit) {
        when (rxEnable) {
          state := sIdle
        }
      }
    }
  }

  when (state === sStopBit && rxEnable) {
    rDataValid := true.B
  } .elsewhen (io.receiveData.ready) {
    rDataValid := false.B
  }

  io.receiveData.bits := Reverse(shiftReg.io.q)
  io.receiveData.valid := rDataValid
}

    val rxData = Input(Bool())
    val txData = Output(Bool())
    val rts = Output(Bool())
    val cts = Input(Bool())


// See LICENSE for license details.

import chisel3._
import chisel3.util._

/** 入力の立ち下がりを検出します。
  */
class NegEdge extends Module {
  val io = IO(new Bundle {

  val reg = RegNext(io.d, false.B)

  io.pulse := reg && !io.d
}

object NegEdge {
  def apply(d: Bool): Bool = {
    val negEdge = Module(new NegEdge)
    negEdge.io.d := d
    negEdge.io.pulse
  }
}

    val d = Input(Bool())
    val pulse = Output(Bool())


package lab7
import chisel3._
import chisel3.util._
class ex1 extends Module {
    val io = IO (new Bundle {

    val in2 = Flipped(Decoupled(UInt(8.W))) //ready-> output , valid->input
    val out = Decoupled(UInt(8.W)) // ready-> input, valid->output
    })
    io.in1.ready:=0.B
    io.in2.ready:=0.B

    val q1= Queue(io.in1,4)
    val q2= Queue(io.in2,4)
    val arb_noPriority = Module (new RRArbiter ( UInt () , 2) )
// connect the inputs to different producers
    arb_noPriority . io . in (0) <> q1
    arb_noPriority . io . in (1) <> q2
    io.out <> arb_noPriority.io.out
}

val in1 = Flipped(Decoupled(UInt(8.W))) //ready-> output , valid->input


package lab8
import chisel3 . _
import chisel3.util._

class MaskedReadWriteSmem extends Module {
val width : Int = 8
    val io = IO (new Bundle {
    val enable = Input ( Bool () )
    val write = Input ( Bool () )
    val addr = Input ( UInt (10. W ) )
    val mask = Input ( Vec (4 , Bool () ) )
    val dataIn = Input ( Vec (4 , UInt ( width . W ) ) )
    val dataOut = Output ( Vec (4 , UInt ( width . W ) ) )
    })
// Create a 32 - bit wide memory that is byte - masked
    val mem = SyncReadMem (1024 , Vec (4 , UInt ( width . W ) ) )
    val sel= Cat(io.mask(3),io.mask(2),io.mask(1),io.mask(0)).asUInt
   // io.dataOut:=mem.read(io.addr,io.enable)

   val data= Reg(Vec(4,UInt(width.W)))
   when (io.write){

    when(io.mask(2)){
         data(2):=io.dataIn(3)
    }.otherwise{
         data(2):=0.U(width.W)
    }
    when(io.mask(1)){
         data(1):=io.dataIn(3)
    }.otherwise{
         data(1):=0.U(width.W)
    }
    when(io.mask(0)){
         data(0):=io.dataIn(3)
    }.otherwise{
         data(0):=0.U(width.W)
    }
    mem.write(io.addr,data)
   }
    io.dataOut := mem.read(io.addr,io.enable)
}

    when(io.mask(3)){
         data(3):=io.dataIn(3)
    }.otherwise{


package labs
import chisel3._

class mux extends Module{
    val io=IO(new Bundle{
        val a=Input(UInt(4.W))
        val b=Input(UInt(4.W))
        val sel=Input(UInt(3.W))
        val x=Output(UInt(4.W))

    })

        io.x:=io.a & io.b
    }.elsewhen(io.sel===3.U){
        io.x:=io.a | io.b
    }.elsewhen(io.sel===4.U){
        io.x:=io.a ^ io.b
    }.elsewhen(io.sel===5.U){
        io.x:= ~(io.a ^ io.b)
    }.otherwise{
        io.x:=0.U
    }
}

    when(io.sel===0.U){
        io.x:=io.a + io.b
    }.elsewhen(io.sel===1.U){


package labs
import chisel3._
import chisel3.util._

class EncoderIO extends Bundle {
    val in = Input ( UInt (4. W ) )
    val out = Output ( UInt (2. W ) )
}
class Encoder4to2 extends Module {
    val io = IO (new EncoderIO )
    io.out:=0.U
    switch(io.in){
        is("b0001".U){io.out:="b00".U}
        is("b0010".U){io.out:="b01".U}
        is("b0100".U){io.out:= "b10".U}


package labs
import chisel3._
import org.scalatest._
import chiseltest._

class resettest  extends FreeSpec with ChiselScalatestTester {
    "Reset Test" in {

        test(new resetcounter(5)){c=>
        c.clock.step(20)
        c.io.result.expect(0.B)

        }


package labs
import chisel3._
import org.scalatest._
import chiseltest._

    "mux2 Test" in {
        test(new Mux_2to1()){c=>
        c.io.in_A.poke(10.U)
        c.io.in_B.poke(11.U)
        c.io.select.poke(0.B)
        c.clock.step(20)
        c.io.out.expect(10.B)

        }
    }
}

class mux2test  extends FreeSpec with ChiselScalatestTester {


package labs
import chisel3._
import org.scalatest._
import chiseltest._
class ALUtest extends FreeSpec with ChiselScalatestTester{

    "ALU Test" in {
        test(new ALU()){c=>
        c.io.in_A.poke(4.U)
        c.io.in_B.poke(5.U)
        c.io.alu_Op.poke(4.U)


package labs
import chisel3._
import org.scalatest._
import chiseltest._
class Adder5test extends FreeSpec with ChiselScalatestTester{
    "Adder5 Test" in {

        test(new Adder5(32)){c=>
        c.io.in0.poke(2.U)
        c.io.in1.poke(2.U)


package labs
import chisel3._
import org.scalatest._
import chiseltest._

class NANDtest  extends FreeSpec with ChiselScalatestTester {

    "NAND Gate Test" in {
        test(new NAND()){c=>
        c.io.a.poke(8.S)
        c.io.b.poke(15.S)


package labs
import chisel3._
import org.scalatest._
import chiseltest._

class fulladdertest  extends FreeSpec with ChiselScalatestTester {
    "fulladder Gate Test" in {
        test(new fulladder()){c=>
        c.io.a.poke(8.S)

        c.io.b.poke(-15.S)
        c.io.c.poke(2.S)
        c.clock.step(1)
        c.io.sum.expect(-5.S)
        c.io.cout.expect(0.S)


package labs
import chisel3._
import org.scalatest._
import chiseltest._

class halfaddertest  extends FreeSpec with ChiselScalatestTester {
    "halfadder Gate Test" in {

        c.clock.step(1)
        c.io.sum.expect(-7.S)
        c.io.cout.expect(0.S)

        }
    }
}

        test(new halfadder()){c=>
        c.io.a.poke(8.S)


package chipyard.clocking

import chisel3._

import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.prci._

trait CanHaveClockTap { this: BaseSubsystem =>
  require(!p(SubsystemDriveClockGroupsFromIO), "Subsystem must not drive clocks from IO")
  val clockTapNode = Option.when(p(ClockTapKey)) {
    val clockTap = ClockSinkNode(Seq(ClockSinkParameters(name=Some("clock_tap"))))
    clockTap := ClockGroup() := allClockGroupsNode
    clockTap
  }
  val clockTapIO = clockTapNode.map { node => InModuleBody {
    val clock_tap = IO(Output(Clock()))
    clock_tap := node.in.head._1.clock
    clock_tap
  }}
}

case object ClockTapKey extends Field[Boolean](true)