blob: 41b24d1ba7aa4775995610b5149bf2e9d751ac82 [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._
/** VME parameters.
*
* These parameters are used on VME interfaces and modules.
*/
case class VMEParams() {
val nReadClients: Int = 5
val nWriteClients: Int = 1
require(nReadClients > 0,
s"\n\n[VTA] [VMEParams] nReadClients must be larger than 0\n\n")
require(
nWriteClients == 1,
s"\n\n[VTA] [VMEParams] nWriteClients must be 1, only one-write-client support atm\n\n")
}
/** VMEBase. Parametrize base class. */
abstract class VMEBase(implicit p: Parameters) extends GenericParameterizedBundle(p)
/** VMECmd.
*
* This interface is used for creating write and read requests to memory.
*/
class VMECmd(implicit p: Parameters) extends VMEBase {
val addrBits = p(ShellKey).memParams.addrBits
val lenBits = p(ShellKey).memParams.lenBits
val addr = UInt(addrBits.W)
val len = UInt(lenBits.W)
}
/** VMEReadMaster.
*
* This interface is used by modules inside the core to generate read requests
* and receive responses from VME.
*/
class VMEReadMaster(implicit p: Parameters) extends Bundle {
val dataBits = p(ShellKey).memParams.dataBits
val cmd = Decoupled(new VMECmd)
val data = Flipped(Decoupled(UInt(dataBits.W)))
override def cloneType =
new VMEReadMaster().asInstanceOf[this.type]
}
/** VMEReadClient.
*
* This interface is used by the VME to receive read requests and generate
* responses to modules inside the core.
*/
class VMEReadClient(implicit p: Parameters) extends Bundle {
val dataBits = p(ShellKey).memParams.dataBits
val cmd = Flipped(Decoupled(new VMECmd))
val data = Decoupled(UInt(dataBits.W))
override def cloneType =
new VMEReadClient().asInstanceOf[this.type]
}
/** VMEWriteMaster.
*
* This interface is used by modules inside the core to generate write requests
* to the VME.
*/
class VMEWriteMaster(implicit p: Parameters) extends Bundle {
val dataBits = p(ShellKey).memParams.dataBits
val cmd = Decoupled(new VMECmd)
val data = Decoupled(UInt(dataBits.W))
val ack = Input(Bool())
override def cloneType =
new VMEWriteMaster().asInstanceOf[this.type]
}
/** VMEWriteClient.
*
* This interface is used by the VME to handle write requests from modules inside
* the core.
*/
class VMEWriteClient(implicit p: Parameters) extends Bundle {
val dataBits = p(ShellKey).memParams.dataBits
val cmd = Flipped(Decoupled(new VMECmd))
val data = Flipped(Decoupled(UInt(dataBits.W)))
val ack = Output(Bool())
override def cloneType =
new VMEWriteClient().asInstanceOf[this.type]
}
/** VMEMaster.
*
* Pack nRd number of VMEReadMaster interfaces and nWr number of VMEWriteMaster
* interfaces.
*/
class VMEMaster(implicit p: Parameters) extends Bundle {
val nRd = p(ShellKey).vmeParams.nReadClients
val nWr = p(ShellKey).vmeParams.nWriteClients
val rd = Vec(nRd, new VMEReadMaster)
val wr = Vec(nWr, new VMEWriteMaster)
}
/** VMEClient.
*
* Pack nRd number of VMEReadClient interfaces and nWr number of VMEWriteClient
* interfaces.
*/
class VMEClient(implicit p: Parameters) extends Bundle {
val nRd = p(ShellKey).vmeParams.nReadClients
val nWr = p(ShellKey).vmeParams.nWriteClients
val rd = Vec(nRd, new VMEReadClient)
val wr = Vec(nWr, new VMEWriteClient)
}
/** VTA Memory Engine (VME).
*
* This unit multiplexes the memory controller interface for the Core. Currently,
* it supports single-writer and multiple-reader mode and it is also based on AXI.
*/
class VME(implicit p: Parameters) extends Module {
val io = IO(new Bundle {
val mem = new AXIMaster(p(ShellKey).memParams)
val vme = new VMEClient
})
val nReadClients = p(ShellKey).vmeParams.nReadClients
val rd_arb = Module(new Arbiter(new VMECmd, nReadClients))
val rd_arb_chosen = RegEnable(rd_arb.io.chosen, rd_arb.io.out.fire())
for (i <- 0 until nReadClients) { rd_arb.io.in(i) <> io.vme.rd(i).cmd }
val sReadIdle :: sReadAddr :: sReadData :: Nil = Enum(3)
val rstate = RegInit(sReadIdle)
switch(rstate) {
is(sReadIdle) {
when(rd_arb.io.out.valid) {
rstate := sReadAddr
}
}
is(sReadAddr) {
when(io.mem.ar.ready) {
rstate := sReadData
}
}
is(sReadData) {
when(io.mem.r.fire() && io.mem.r.bits.last) {
rstate := sReadIdle
}
}
}
val sWriteIdle :: sWriteAddr :: sWriteData :: sWriteResp :: Nil = Enum(4)
val wstate = RegInit(sWriteIdle)
val addrBits = p(ShellKey).memParams.addrBits
val lenBits = p(ShellKey).memParams.lenBits
val wr_cnt = RegInit(0.U(lenBits.W))
when(wstate === sWriteIdle) {
wr_cnt := 0.U
}.elsewhen(io.mem.w.fire()) {
wr_cnt := wr_cnt + 1.U
}
switch(wstate) {
is(sWriteIdle) {
when(io.vme.wr(0).cmd.valid) {
wstate := sWriteAddr
}
}
is(sWriteAddr) {
when(io.mem.aw.ready) {
wstate := sWriteData
}
}
is(sWriteData) {
when(
io.vme
.wr(0)
.data
.valid && io.mem.w.ready && wr_cnt === io.vme.wr(0).cmd.bits.len) {
wstate := sWriteResp
}
}
is(sWriteResp) {
when(io.mem.b.valid) {
wstate := sWriteIdle
}
}
}
// registers storing read/write cmds
val rd_len = RegInit(0.U(lenBits.W))
val wr_len = RegInit(0.U(lenBits.W))
val rd_addr = RegInit(0.U(addrBits.W))
val wr_addr = RegInit(0.U(addrBits.W))
when(rd_arb.io.out.fire()) {
rd_len := rd_arb.io.out.bits.len
rd_addr := rd_arb.io.out.bits.addr
}
when(io.vme.wr(0).cmd.fire()) {
wr_len := io.vme.wr(0).cmd.bits.len
wr_addr := io.vme.wr(0).cmd.bits.addr
}
// rd arb
rd_arb.io.out.ready := rstate === sReadIdle
// vme
for (i <- 0 until nReadClients) {
io.vme.rd(i).data.valid := rd_arb_chosen === i.asUInt & io.mem.r.valid
io.vme.rd(i).data.bits := io.mem.r.bits.data
}
io.vme.wr(0).cmd.ready := wstate === sWriteIdle
io.vme.wr(0).ack := io.mem.b.fire()
io.vme.wr(0).data.ready := wstate === sWriteData & io.mem.w.ready
// mem
io.mem.aw.valid := wstate === sWriteAddr
io.mem.aw.bits.addr := wr_addr
io.mem.aw.bits.len := wr_len
io.mem.w.valid := wstate === sWriteData & io.vme.wr(0).data.valid
io.mem.w.bits.data := io.vme.wr(0).data.bits
io.mem.w.bits.last := wr_cnt === io.vme.wr(0).cmd.bits.len
io.mem.b.ready := wstate === sWriteResp
io.mem.ar.valid := rstate === sReadAddr
io.mem.ar.bits.addr := rd_addr
io.mem.ar.bits.len := rd_len
io.mem.r.ready := rstate === sReadData & io.vme.rd(rd_arb_chosen).data.ready
// AXI constants - statically defined
io.mem.setConst()
}