blob: c8573c20d81a9875d6e5c1e93780c9d2a5ff443a [file] [log] [blame]
// Copyright 2024 Google LLC
//
// 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.
package chai
import chisel3._
import chisel3.util._
object KelvinToTlul {
object State extends ChiselEnum {
val sIdle, sWaitForReady, sWaitForResponse = Value
}
def apply(tlul_p: kelvin.TLULParameters, kelvin_p: kelvin.Parameters): KelvinToTlul = {
return Module(new KelvinToTlul(tlul_p, kelvin_p))
}
}
class KelvinToTlul(tlul_p: kelvin.TLULParameters, kelvin_p: kelvin.Parameters) extends Module {
import KelvinToTlul.State
import KelvinToTlul.State._
val io = IO(new Bundle {
val tl_i = Input(new _root_.kelvin.TileLinkULIO_D2H(tlul_p))
val tl_o = Output(new _root_.kelvin.TileLinkULIO_H2D(tlul_p))
val kelvin = Flipped(new matcha.KelvinMemIO(kelvin_p))
})
val state = RegInit(sIdle)
val wmask_width = io.kelvin.wmask.getWidth
val wmask_bits = (0 until wmask_width)
.map(x => Mux(io.kelvin.wmask(x), 0xff.U(wmask_width.W) << (x * 8).U, 0.U(wmask_width.W)))
.reduce(_ | _)
io.tl_o := 0.U.asTypeOf(new kelvin.TileLinkULIO_H2D(tlul_p))
io.tl_o.a_user.instr_type := 9.U
io.tl_o.a_source := 0.U
io.tl_o.d_ready := true.B
io.kelvin.rid := 0.U
io.kelvin.cready := true.B
io.kelvin.rvalid := false.B
io.kelvin.rdata := 0.U
io.tl_o.a_mask := -1.S(io.tl_o.a_mask.getWidth.W).asUInt
io.tl_o.a_param := 0.U
io.tl_o.a_size := 5.U
// state | transition | next state
// sIdle | valid & a_ready | sWaitForResponse
// sIdle | valid & !a_ready | sWaitForReady
// sWaitForReady | a_ready | sWaitForResponse
// sWaitForResponse | d_valid | sIdle
switch(state) {
is(sIdle) {
io.kelvin.cready := true.B
when(io.kelvin.cvalid) {
io.kelvin.cready := false.B
io.tl_o.a_valid := true.B
io.tl_o.a_address := io.kelvin.caddr
val cwrite = io.kelvin.cwrite
io.tl_o.a_opcode := Mux(cwrite, kelvin.TLULOpcodesA.PutFullData.asUInt, kelvin.TLULOpcodesA.Get.asUInt)
io.tl_o.a_data := Mux(cwrite, io.kelvin.wdata & wmask_bits, 0.U)
state := Mux(io.tl_i.a_ready, sWaitForResponse, sWaitForReady)
}
}
is(sWaitForReady) {
when(io.tl_i.a_ready) {
state := sWaitForResponse
}
}
is(sWaitForResponse) {
io.tl_o.a_valid := false.B
when(io.tl_i.d_valid) {
val (value, valid) = kelvin.TLULOpcodesD.safe(io.tl_i.d_opcode)
val valid2 = valid && (value =/= kelvin.TLULOpcodesD.End)
assert(valid2, "Received invalid TLUL-D opcode\n")
val rdata = chisel3.util.MuxLookup(value, 0.U(32.W))(
Array(
kelvin.TLULOpcodesD.AccessAck -> 0.U,
kelvin.TLULOpcodesD.AccessAckData -> io.tl_i.d_data
)
)
val rvalid = chisel3.util.MuxLookup(value, false.B)(
Array(
kelvin.TLULOpcodesD.AccessAck -> false.B,
kelvin.TLULOpcodesD.AccessAckData -> true.B
)
)
val rid = chisel3.util.MuxLookup(value, 0.U)(
Array(
kelvin.TLULOpcodesD.AccessAck -> 0.U,
kelvin.TLULOpcodesD.AccessAckData -> io.kelvin.cid
)
)
io.kelvin.rvalid := rvalid
io.kelvin.rdata := rdata
io.kelvin.cready := true.B
io.kelvin.rid := rid
state := sIdle
}
}
}
}