blob: dd704d4ddf0dbc01eff06abbdaa72365d1414a2c [file] [log] [blame]
// SPDX-FileCopyrightText: 2020 Muhammad Hadir Khan
//
// Licensed 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.
// SPDX-License-Identifier: Apache-2.0
package merl.uit.tilelink
import chisel3._
import chisel3.util.{Cat, Enum, Fill, log2Ceil}
class TL_SramAdapter(sramAw: Int, sramDw: Int, forFetch: Bool = false.B)(implicit val conf: TLConfiguration) extends Module {
val io = IO(new Bundle {
// TL-UL interface
val tl_i = Flipped(new TL_H2D())
val tl_o = new TL_D2H()
// SRAM interface
val we_o = Output(Vec(conf.TL_DBW, Bool()))
val addr_o = Output(UInt(sramAw.W))
val wdata_o = Output(UInt(sramDw.W))
//val wmask_o = Output(Vec(conf.TL_DBW, Bool()))
val rdata_i = Input(UInt(sramDw.W))
//val rerror_i = Input(UInt(2.W))
})
val a_ack = Wire(Bool())
val d_ack = Wire(Bool())
// reading data received from DCCM
val rdata = Wire(UInt(sramDw.W))
// reading data received from ICCM
// separate wires because for fetch we cannot wait for valid
// and stall the pipeline so we directly receive the data and
// pass it to the tilelink response bus.
val rdata_fetch = Wire(UInt(sramDw.W))
rdata_fetch := io.rdata_i
val error = RegInit(0.U(1.W))
val err_internal = Wire(Bool())
val addr_align_err = Wire(Bool())
val tl_err = Wire(Bool())
val reqId = RegInit(0.U(conf.TL_AIW.W))
val reqSz = RegInit(0.U(conf.TL_SZW.W))
val respOp = RegInit(TL_D_Opcode.accessAck)
val rd_req = Wire(Bool())
val wr_req = Wire(Bool())
val outstanding = RegInit(0.U(1.W))
a_ack := io.tl_i.a_valid && io.tl_o.a_ready
d_ack := io.tl_o.d_valid && io.tl_i.d_ready
wr_req := a_ack && ((io.tl_i.a_opcode === TL_A_Opcode.putFullData) || (io.tl_i.a_opcode === TL_A_Opcode.putPartialData))
rd_req := a_ack && (io.tl_i.a_opcode === TL_A_Opcode.get)
// io.we_o := wr_req && !err_internal
// io.addr_o := Cat(io.tl_i.a_address(sramAw-1, 2), 0.U(2.W)) // word aligned address
io.addr_o := io.tl_i.a_address >> 2
io.wdata_o := io.tl_i.a_data
when(wr_req && !err_internal) {
for(i <- 0 until conf.TL_DBW) {
io.we_o(i) := io.tl_i.a_mask(i).asBool()
}
} .otherwise {
for(i <- 0 until conf.TL_DBW) {
io.we_o(i) := false.B
}
}
when(a_ack) {
outstanding := 1.U
reqId := io.tl_i.a_source
reqSz := io.tl_i.a_size
respOp := Mux(rd_req, TL_D_Opcode.accessAckData, TL_D_Opcode.accessAck)
error := err_internal
} .elsewhen(d_ack) {
outstanding := 0.U
}
when(outstanding.asBool()) {
rdata := Mux(error.asBool(), Fill(sramDw, 1.U), io.rdata_i) // return all 1111s if err_internal = true
} .otherwise {
rdata := 0.U
}
io.tl_o.a_ready := Mux(forFetch, true.B, !outstanding)
io.tl_o.d_valid := outstanding
io.tl_o.d_opcode := respOp
io.tl_o.d_param := 0.U
io.tl_o.d_size := reqSz
io.tl_o.d_source := reqId
io.tl_o.d_sink := 0.U
io.tl_o.d_data := Mux(forFetch, rdata_fetch, rdata)
io.tl_o.d_error := error
err_internal := addr_align_err | tl_err
when(wr_req) {
addr_align_err := io.tl_i.a_address(1,0).orR
} .otherwise {
addr_align_err := false.B
}
// separate tl_err checker which checks the address, size and mask correspondence according to the spec.
val tlErr = Module(new TL_Err)
tlErr.io.tl_i := io.tl_i
tl_err := tlErr.io.err_o
}