/* * 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() }