blob: 3046712e2e44ea471edd9537d060f41d88584b71 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package vta.shell
import chisel3._
import chisel3.util._
import vta.util.config._
import vta.util.genericbundle._
import vta.interface.axi._
/** VCR parameters.
*
* These parameters are used on VCR interfaces and modules.
*/
case class VCRParams() {
val nCtrl = 1
val nECnt = 1
val nVals = 1
val nPtrs = 6
val nUCnt = 1
val regBits = 32
}
/** VCRBase. Parametrize base class. */
abstract class VCRBase(implicit p: Parameters) extends GenericParameterizedBundle(p)
/** VCRMaster.
*
* This is the master interface used by VCR in the VTAShell to control
* the Core unit.
*/
class VCRMaster(implicit p: Parameters) extends VCRBase {
val vp = p(ShellKey).vcrParams
val mp = p(ShellKey).memParams
val launch = Output(Bool())
val finish = Input(Bool())
val ecnt = Vec(vp.nECnt, Flipped(ValidIO(UInt(vp.regBits.W))))
val vals = Output(Vec(vp.nVals, UInt(vp.regBits.W)))
val ptrs = Output(Vec(vp.nPtrs, UInt(mp.addrBits.W)))
val ucnt = Vec(vp.nUCnt, Flipped(ValidIO(UInt(vp.regBits.W))))
}
/** VCRClient.
*
* This is the client interface used by the Core module to communicate
* to the VCR in the VTAShell.
*/
class VCRClient(implicit p: Parameters) extends VCRBase {
val vp = p(ShellKey).vcrParams
val mp = p(ShellKey).memParams
val launch = Input(Bool())
val finish = Output(Bool())
val ecnt = Vec(vp.nECnt, ValidIO(UInt(vp.regBits.W)))
val vals = Input(Vec(vp.nVals, UInt(vp.regBits.W)))
val ptrs = Input(Vec(vp.nPtrs, UInt(mp.addrBits.W)))
val ucnt = Vec(vp.nUCnt, ValidIO(UInt(vp.regBits.W)))
}
/** VTA Control Registers (VCR).
*
* This unit provides control registers (32 and 64 bits) to be used by a control'
* unit, typically a host processor. These registers are read-only by the core
* at the moment but this will likely change once we add support to general purpose
* registers that could be used as event counters by the Core unit.
*/
class VCR(implicit p: Parameters) extends Module {
val io = IO(new Bundle {
val host = new AXILiteClient(p(ShellKey).hostParams)
val vcr = new VCRMaster
})
val vp = p(ShellKey).vcrParams
val mp = p(ShellKey).memParams
val hp = p(ShellKey).hostParams
// Write control (AW, W, B)
val waddr = RegInit("h_ffff".U(hp.addrBits.W)) // init with invalid address
val wdata = io.host.w.bits.data
val sWriteAddress :: sWriteData :: sWriteResponse :: Nil = Enum(3)
val wstate = RegInit(sWriteAddress)
// read control (AR, R)
val sReadAddress :: sReadData :: Nil = Enum(2)
val rstate = RegInit(sReadAddress)
val rdata = RegInit(0.U(vp.regBits.W))
// registers
val nPtrs = if (mp.addrBits == 32) vp.nPtrs else 2 * vp.nPtrs
val nTotal = vp.nCtrl + vp.nECnt + vp.nVals + nPtrs + vp.nUCnt
val reg = Seq.fill(nTotal)(RegInit(0.U(vp.regBits.W)))
val addr = Seq.tabulate(nTotal)(_ * 4)
val reg_map = (addr zip reg) map { case (a, r) => a.U -> r }
val eo = vp.nCtrl
val vo = eo + vp.nECnt
val po = vo + vp.nVals
val uo = po + nPtrs
switch(wstate) {
is(sWriteAddress) {
when(io.host.aw.valid) {
wstate := sWriteData
}
}
is(sWriteData) {
when(io.host.w.valid) {
wstate := sWriteResponse
}
}
is(sWriteResponse) {
when(io.host.b.ready) {
wstate := sWriteAddress
}
}
}
when(io.host.aw.fire) { waddr := io.host.aw.bits.addr }
io.host.aw.ready := wstate === sWriteAddress
io.host.w.ready := wstate === sWriteData
io.host.b.valid := wstate === sWriteResponse
io.host.b.bits.resp := 0.U
switch(rstate) {
is(sReadAddress) {
when(io.host.ar.valid) {
rstate := sReadData
}
}
is(sReadData) {
when(io.host.r.ready) {
rstate := sReadAddress
}
}
}
io.host.ar.ready := rstate === sReadAddress
io.host.r.valid := rstate === sReadData
io.host.r.bits.data := rdata
io.host.r.bits.resp := 0.U
when(io.vcr.finish) {
reg(0) := "b_10".U
}.elsewhen(io.host.w.fire && addr(0).U === waddr) {
reg(0) := wdata
}
for (i <- 0 until vp.nECnt) {
when(io.vcr.ecnt(i).valid) {
reg(eo + i) := io.vcr.ecnt(i).bits
}.elsewhen(io.host.w.fire && addr(eo + i).U === waddr) {
reg(eo + i) := wdata
}
}
for (i <- 0 until (vp.nVals + nPtrs)) {
when(io.host.w.fire && addr(vo + i).U === waddr) {
reg(vo + i) := wdata
}
}
when(io.host.ar.fire) {
rdata := MuxLookup(io.host.ar.bits.addr, 0.U, reg_map)
}
io.vcr.launch := reg(0)(0)
for (i <- 0 until vp.nVals) {
io.vcr.vals(i) := reg(vo + i)
}
if (mp.addrBits == 32) { // 32-bit pointers
for (i <- 0 until nPtrs) {
io.vcr.ptrs(i) := reg(po + i)
}
} else { // 64-bits pointers
for (i <- 0 until (nPtrs / 2)) {
io.vcr.ptrs(i) := Cat(reg(po + 2 * i + 1), reg(po + 2 * i))
}
}
for (i <- 0 until vp.nUCnt) {
when(io.vcr.ucnt(i).valid) {
reg(uo + i) := io.vcr.ucnt(i).bits
}.elsewhen(io.host.w.fire && addr(uo + i).U === waddr) {
reg(uo + i) := wdata
}
}
}