blob: 06ba4f123db9def37696ac70b1c1163324a3e9bc [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 kelvin
import chisel3._
import chisel3.util._
import bus.{AxiBurstType, AxiMasterIO}
import common._
class AxiSlave(p: Parameters) extends Module {
val io = IO(new Bundle{
val axi = Flipped(new AxiMasterIO(p.axi2AddrBits, p.axi2DataBits, p.axi2IdBits))
val fabric = new FabricIO(p)
// Output indicating that a transaction is in progress
val txnInProgress = Output(Bool())
// Input indicating that the peripheral is busy -- do not accept AXI transactions
val periBusy = Input(Bool())
})
val readAddr = RegInit(MakeValid(false.B, 0.U.asTypeOf(io.axi.read.addr.bits)))
val readBaseAddr = RegInit(0.U.asTypeOf(io.axi.read.addr.bits.addr))
io.axi.read.addr.ready := !readAddr.valid && !io.periBusy
val canRead = !readAddr.valid && io.axi.read.addr.valid && !io.periBusy
when (canRead) {
readAddr := MakeValid(true.B, io.axi.read.addr.bits)
val readMask = VecInit((0 until io.axi.read.addr.bits.addr.getWidth).map(x => !(x.U < io.axi.read.addr.bits.size)))
readBaseAddr := io.axi.read.addr.bits.addr & readMask.asUInt;
}
val readValid = RegInit(false.B)
val doRead = readAddr.valid && !readValid
readValid := doRead
io.axi.read.data.valid := readValid
when (io.axi.read.data.fire) {
when (io.axi.read.data.bits.last) {
readAddr := MakeValid(false.B, 0.U.asTypeOf(io.axi.read.addr.bits))
} .otherwise {
val (burst, burstValid) = AxiBurstType.safe(readAddr.bits.burst)
readAddr.bits.addr := MuxOR(burstValid, MuxLookup(burst, 0.U)(Seq(
AxiBurstType.FIXED -> readAddr.bits.addr,
AxiBurstType.INCR -> (readAddr.bits.addr + (1.U << readAddr.bits.size)),
AxiBurstType.WRAP -> {
val newAddr = readAddr.bits.addr + (1.U << readAddr.bits.size)
val newAddrWrapped = Mux(newAddr >= readBaseAddr + (p.axi2DataBits / 8).U, readBaseAddr, newAddr)
newAddrWrapped(31,0)
}
)))
readAddr.bits.len := MuxOR(burstValid, readAddr.bits.len - 1.U)
}
}
io.fabric.readDataAddr := MakeValid(readAddr.valid, readAddr.bits.addr)
val alignedAddrMask = VecInit((0 until io.axi.read.addr.bits.addr.getWidth).map(
x => !(x.U < io.axi.read.addr.bits.size)
))
val alignedAddr = io.axi.read.addr.bits.addr & alignedAddrMask.asUInt
val msb = log2Ceil(p.axi2DataBits) - 1
val readDataShift = ((io.axi.read.addr.bits.addr - alignedAddr) << 3.U)(msb,0)
io.axi.read.data.bits.data := io.fabric.readData << readDataShift
io.axi.read.data.bits.id := Mux(readAddr.valid, readAddr.bits.id, 0.U)
io.axi.read.data.bits.resp := 0.U
io.axi.read.data.bits.last := Mux(readAddr.valid, readAddr.bits.len === 0.U, false.B)
val writeAddr = RegInit(MakeValid(false.B, 0.U.asTypeOf(io.axi.write.addr.bits)))
val writeBaseAddr = RegInit(0.U.asTypeOf(io.axi.write.addr.bits.addr))
io.axi.write.addr.ready := !writeAddr.valid && !io.periBusy
val canWrite = !writeAddr.valid && io.axi.write.addr.valid
when (canWrite) {
writeAddr := MakeValid(true.B, io.axi.write.addr.bits)
val writeMask = VecInit((0 until io.axi.write.addr.bits.addr.getWidth).map(x => !(x.U < io.axi.write.addr.bits.size)))
writeBaseAddr := io.axi.write.addr.bits.addr & writeMask.asUInt
}
val writeData = RegInit(MakeValid(false.B, 0.U.asTypeOf(io.axi.write.data.bits)))
io.axi.write.data.ready := !writeData.valid && !io.periBusy
val canWriteData = !writeData.valid && io.axi.write.data.valid
when (canWriteData) {
writeData := MakeValid(true.B, io.axi.write.data.bits)
}
when (writeData.valid) {
writeData := MakeValid(false.B, 0.U.asTypeOf(io.axi.write.data.bits))
val (burst, burstValid) = AxiBurstType.safe(writeAddr.bits.burst)
writeAddr.bits.addr := MuxOR(burstValid, MuxLookup(burst, 0.U)(Seq(
AxiBurstType.FIXED -> writeAddr.bits.addr,
AxiBurstType.INCR -> (writeAddr.bits.addr + (1.U << writeAddr.bits.size)),
AxiBurstType.WRAP -> {
val newAddr = writeAddr.bits.addr + (1.U << writeAddr.bits.size)
val newAddrWrapped = Mux(newAddr >= writeBaseAddr + (p.axi2DataBits / 8).U, writeBaseAddr, newAddr)
newAddrWrapped(31,0)
},
)))
writeAddr.bits.len := MuxOR(burstValid, writeAddr.bits.len - 1.U)
}
io.fabric.writeDataAddr := MakeValid(writeData.valid, writeAddr.bits.addr)
io.fabric.writeDataBits := writeData.bits.data
io.fabric.writeDataStrb := writeData.bits.strb
val doWrite = writeData.valid && writeAddr.valid
val writeRespValid = RegInit(false.B)
writeRespValid := writeAddr.valid && writeData.valid && writeAddr.bits.len === 0.U && writeData.bits.last
io.axi.write.resp.valid := writeRespValid
when (io.axi.write.resp.fire) {
writeAddr := MakeValid(false.B, 0.U.asTypeOf(io.axi.write.addr.bits))
writeBaseAddr := 0.U.asTypeOf(io.axi.write.addr.bits.addr)
}
io.axi.write.resp.bits.resp := 0.U
io.axi.write.resp.bits.id := Mux(doWrite, writeAddr.bits.id, 0.U.asTypeOf(io.axi.write.resp.bits.id))
io.txnInProgress := readAddr.valid || writeAddr.valid
}