blob: d53ad1c93561eb9eb60577981519a2895b0c95f5 [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.dpi
import chisel3._
import chisel3.util._
import chisel3.experimental.IntParam
import vta.util.config._
import vta.interface.axi._
import vta.shell._
/** Memory DPI parameters */
case class VTAMemDPIParams(
dpiDelay : Int,
dpiLenBits: Int,
dpiAddrBits: Int,
dpiDataBits: Int,
dpiTagBits: Int
) {}
case object DpiKey extends Field[VTAMemDPIParams]
/** Memory master interface.
*
* This interface is tipically used by the Accelerator
*/
class MemRequest(implicit val p: Parameters) extends Bundle {
val len = (UInt(p(ShellKey).memParams.dataBits.W))
val addr = (UInt(p(ShellKey).memParams.addrBits.W))
val id = (UInt(p(ShellKey).memParams.idBits.W))
}
class VTAMemDPIData(implicit val p: Parameters) extends Bundle {
val data = UInt(p(ShellKey).memParams.dataBits.W)
val id = UInt(p(ShellKey).memParams.idBits.W)
}
class VTAMemDPIWrData(implicit val p: Parameters) extends Bundle {
val data = UInt(p(ShellKey).memParams.dataBits.W)
val strb = UInt((p(ShellKey).memParams.dataBits/8).W)
}
class VTAMemDPIMaster(implicit val p: Parameters) extends Bundle {
val req = new Bundle {
val ar_valid = Output(Bool())
val ar_len = Output(UInt(p(ShellKey).memParams.lenBits.W))
val ar_addr = Output(UInt(p(ShellKey).memParams.addrBits.W))
val ar_id = Output(UInt(p(ShellKey).memParams.idBits.W))
val aw_valid = Output(Bool())
val aw_addr = Output(UInt(p(ShellKey).memParams.addrBits.W))
val aw_len = Output(UInt(p(ShellKey).memParams.lenBits.W))
}
val wr = ValidIO(new VTAMemDPIWrData)
val rd = Flipped(Decoupled(new VTAMemDPIData))
}
/** Memory client interface.
*
* This interface is tipically used by the Host
*/
class VTAMemDPIClient(implicit val p: Parameters) extends Bundle {
val req = new Bundle {
val ar_valid = Input(Bool())
val ar_len = Input(UInt(p(ShellKey).memParams.lenBits.W))
val ar_addr = Input(UInt(p(ShellKey).memParams.addrBits.W))
val ar_id = Input(UInt(p(ShellKey).memParams.idBits.W))
val aw_valid = Input(Bool())
val aw_addr = Input(UInt(p(ShellKey).memParams.addrBits.W))
val aw_len = Input(UInt(p(ShellKey).memParams.lenBits.W))
}
val wr = Flipped(ValidIO(new VTAMemDPIWrData))
val rd = (Decoupled(new VTAMemDPIData))
}
/** Memory DPI module.
*
* Wrapper for Memory Verilog DPI module.
*/
class VTAMemDPI(implicit val p: Parameters) extends BlackBox(
Map(
"LEN_BITS" -> IntParam(p(ShellKey).memParams.lenBits),
"ADDR_BITS" -> IntParam(p(ShellKey).memParams.addrBits),
"DATA_BITS" -> IntParam(p(ShellKey).memParams.dataBits))) with HasBlackBoxResource {
val io = IO(new Bundle {
val clock = Input(Clock())
val reset = Input(Reset())
val dpi = new VTAMemDPIClient
})
addResource("/verilog/VTAMemDPI.v")
}
class VTAMemDPIToAXI(debug: Boolean = true)(implicit val p: Parameters) extends Module {
val io = IO(new Bundle {
val dpi = new VTAMemDPIMaster
val axi = new AXIClient(p(ShellKey).memParams)
})
//Read request interface for sw memory manager
val ar_valid = RegInit(false.B)
val ar_len = RegInit(0.U.asTypeOf(chiselTypeOf(io.dpi.req.ar_len)))
val ar_addr = RegInit(0.U.asTypeOf(chiselTypeOf(io.dpi.req.ar_addr)))
val ar_id = RegInit(0.U.asTypeOf(chiselTypeOf(io.dpi.req.ar_len)))
val rd_data = RegInit(0.U.asTypeOf(chiselTypeOf(io.dpi.rd.bits.data)))
val rIdle :: readData :: Nil = Enum(2)
val rstate = RegInit(rIdle)
//Write request interface for sw memomry manager
val aw_valid = RegInit(false.B)
val aw_len = RegInit(0.U.asTypeOf(chiselTypeOf(io.dpi.req.aw_len)))
val aw_addr = RegInit(0.U.asTypeOf(chiselTypeOf(io.dpi.req.aw_addr)))
val wIdle :: writeAddress :: writeData :: writeResponse :: Nil = Enum(4)
val wstate = RegInit(wIdle)
//Read Interface to Memory Manager
val counter = RegInit(0.U(32.W))
val dpiDelay = 16.U
val dpiReqQueue = Module(new Queue(new MemRequest, 256))
dpiReqQueue.io.enq.valid := io.axi.ar.valid & dpiReqQueue.io.enq.ready
dpiReqQueue.io.enq.bits.addr := io.axi.ar.bits.addr
dpiReqQueue.io.enq.bits.len := io.axi.ar.bits.len
dpiReqQueue.io.enq.bits.id := io.axi.ar.bits.id
when(dpiReqQueue.io.deq.valid && counter < dpiDelay){
counter := counter + 1.U
}.elsewhen(dpiReqQueue.io.deq.valid && counter === dpiDelay){
counter := counter
}.otherwise{
counter := 0.U
}
switch(rstate){
is(rIdle){
when(dpiReqQueue.io.deq.valid && dpiReqQueue.io.deq.bits.len =/=0.U && counter === dpiDelay){
rstate := readData
}
}
is(readData) {
when(io.axi.r.ready && io.dpi.rd.valid && ar_len === 1.U) {
rstate := rIdle
}
}
}
when(rstate === rIdle) {
when(dpiReqQueue.io.deq.ready){
ar_len := dpiReqQueue.io.deq.bits.len
ar_addr := dpiReqQueue.io.deq.bits.addr
ar_id := dpiReqQueue.io.deq.bits.id
}
}
.elsewhen(rstate === readData){
when(io.axi.r.ready && io.dpi.rd.valid && ar_len =/= 0.U){
ar_len := ar_len - 1.U
}
}
dpiReqQueue.io.deq.ready := ((dpiReqQueue.io.deq.valid && (rstate === rIdle)) && (counter === dpiDelay))
when(rstate === rIdle && dpiReqQueue.io.deq.valid){
io.dpi.req.ar_len := dpiReqQueue.io.deq.bits.len
io.dpi.req.ar_addr := dpiReqQueue.io.deq.bits.addr
io.dpi.req.ar_id := dpiReqQueue.io.deq.bits.id
io.dpi.req.ar_valid := dpiReqQueue.io.deq.ready
}.otherwise{
io.dpi.req.ar_len := ar_len
io.dpi.req.ar_addr := ar_addr
io.dpi.req.ar_id := ar_id
io.dpi.req.ar_valid := (dpiReqQueue.io.deq.ready)
}
io.axi.ar.ready := dpiReqQueue.io.enq.ready
io.axi.r.valid := io.dpi.rd.valid
io.axi.r.bits.data := io.dpi.rd.bits.data
io.axi.r.bits.last := (ar_len === 0.U && io.dpi.rd.valid)
io.axi.r.bits.resp := 0.U
io.axi.r.bits.user := 0.U
io.axi.r.bits.id := io.dpi.rd.bits.id
io.dpi.rd.ready := io.axi.r.ready
//Write Request
switch(wstate){
is(wIdle){
when(io.axi.aw.valid){
wstate := writeAddress
}
}
is(writeAddress) {
when(io.axi.aw.valid) {
wstate := writeData
}
}
is(writeData) {
when(io.axi.w.valid && io.axi.w.bits.last) {
wstate := writeResponse
}
}
is(writeResponse) {
when(io.axi.b.ready) {
wstate := wIdle
}
}
}
when(wstate === wIdle){
when(io.axi.aw.valid){
aw_len := io.axi.aw.bits.len
aw_addr := io.axi.aw.bits.addr
}
}
io.dpi.req.aw_addr := aw_addr
io.dpi.req.aw_len := aw_len
io.dpi.req.aw_valid := RegNext(io.axi.aw.valid) & (wstate === writeAddress)
io.axi.aw.ready := wstate === writeAddress
io.dpi.wr.valid := wstate === writeData & io.axi.w.valid
io.dpi.wr.bits.data := io.axi.w.bits.data
io.dpi.wr.bits.strb := io.axi.w.bits.strb
io.axi.w.ready := wstate === writeData
io.axi.b.valid := wstate === writeResponse
io.axi.b.bits.resp := 0.U
io.axi.b.bits.user := 0.U
io.axi.b.bits.id := 0.U
}