blob: 448b9579cda426f69a7dbae8ea5a04412ed80a0b [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, Fill}
/**
TL-UL adapter for the register interface used by peripherals
*/
class TL_RegAdapter(regAw: Int = 8, regDw: Int = 32)(regBw: Int = regDw/8)(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()
// Register interface
val re_o = Output(Bool())
val we_o = Output(Bool())
val addr_o = Output(UInt(regAw.W))
val wdata_o = Output(UInt(regDw.W))
val be_o = Output(UInt(regBw.W))
val rdata_i = Input(UInt(regDw.W))
val error_i = Input(Bool())
})
val a_ack = Wire(Bool())
val d_ack = Wire(Bool())
val rdata_q = RegInit(0.U(regDw.W))
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
// Request signals coming from Host
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.re_o := rd_req && !err_internal
io.addr_o := Cat(io.tl_i.a_address(regAw-1, 2), 0.U(2.W)) // word aligned address
io.wdata_o := io.tl_i.a_data
io.be_o := io.tl_i.a_mask
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)
rdata_q := Mux(err_internal, Fill(regDw, 1.U), io.rdata_i) // return all 1111s if err_internal = true
error := io.error_i || err_internal
} .elsewhen(d_ack) {
outstanding := 0.U
}
io.tl_o.a_ready := !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 := rdata_q
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
}