blob: c28013de36bf1131caf643079cef36200337710f [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 chisel3.util.experimental.decode._
import bus._
import common._
import _root_.circt.stage.ChiselStage
class CoreAxi(p: Parameters, coreModuleName: String) extends RawModule {
override val desiredName = coreModuleName + "Axi"
val memoryRegions = Seq(
new MemoryRegion(0x0000, 0x2000, MemoryRegionType.IMEM), // ITCM
new MemoryRegion(0x10000, 0x8000, MemoryRegionType.DMEM), // DTCM
new MemoryRegion(0x30000, 0x2000, MemoryRegionType.Peripheral), // CSR
)
p.m = memoryRegions
val io = IO(new Bundle {
// AXI
val aclk = Input(Clock())
val aresetn = Input(AsyncReset())
// ITCM, DTCM, CSR
val axi_slave = Flipped(new AxiMasterIO(p.axi2AddrBits, p.axi2DataBits, p.axi2IdBits))
val axi_master = new AxiMasterIO(p.axi2AddrBits, p.axi2DataBits, p.axi2IdBits)
// Core status interrupts
val halted = Output(Bool())
val fault = Output(Bool())
val wfi = Output(Bool())
val irq = Input(Bool())
// Debug data interface
val debug = new DebugIO(p)
// String logging interface
val slog = new SLogIO(p)
})
dontTouch(io)
val rst_sync = Module(new RstSync())
rst_sync.io.clk_i := io.aclk
rst_sync.io.rstn_i := io.aresetn
rst_sync.io.clk_en := true.B
withClockAndReset(rst_sync.io.clk_o, (!rst_sync.io.rstn_o.asBool).asAsyncReset) {
val itcmSizeBytes = 8 * 1024 // 8 kB
val itcmSubEntryWidth = 8
val itcmWidth = p.axi2DataBits
val itcmEntries = itcmSizeBytes / (itcmWidth / 8)
val itcmSubEntries = itcmWidth / itcmSubEntryWidth
//TODO(stefanhall@): add support for HexMemoryFile
val itcm = Module(new TCM128(itcmSizeBytes, itcmSubEntryWidth))
dontTouch(itcm.io)
val itcmArbiter =
Module(new Arbiter(
new SRAMInterface(itcmEntries, Vec(itcmSubEntries, UInt(itcmSubEntryWidth.W)), 0, 0, 1, true),
2))
val dtcmSizeBytes = 32 * 1024 // 32 kB
val dtcmWidth = p.axi2DataBits
val dtcmEntries = dtcmSizeBytes / (dtcmWidth / 8)
val dtcmSubEntryWidth = 8
val dtcmSubEntries = dtcmWidth / dtcmSubEntryWidth
val dtcm = Module(new TCM128(dtcmSizeBytes, dtcmSubEntryWidth))
val dtcmArbiter =
Module(new Arbiter(
new SRAMInterface(dtcmEntries, Vec(dtcmSubEntries, UInt(dtcmSubEntryWidth.W)), 0, 0, 1, true),
2))
val csr = Module(new CoreAxiCSR(p))
val cg = Module(new ClockGate())
cg.io.clk_i := rst_sync.io.clk_o
val core = withClockAndReset(cg.io.clk_o, csr.io.reset.asAsyncReset) { Core(p, coreModuleName) }
cg.io.enable := io.irq || (!csr.io.cg && !core.io.wfi)
csr.io.kelvin_csr := core.io.csr.out
val itcmBridge = Module(new AxiSlave2SRAM(p, log2Ceil(itcmEntries)))
itcmArbiter.io.in(0).bits.readwritePorts(0).address := itcmBridge.io.sram.address
itcmArbiter.io.in(0).bits.readwritePorts(0).enable := itcmBridge.io.sram.enable
itcmArbiter.io.in(0).bits.readwritePorts(0).isWrite := itcmBridge.io.sram.isWrite
itcmArbiter.io.in(0).bits.readwritePorts(0).writeData := itcmBridge.io.sram.writeData
itcmArbiter.io.in(0).bits.readwritePorts(0).mask.get := itcmBridge.io.sram.mask
itcmArbiter.io.in(0).bits.readwritePorts(0).readData := itcm.io.rdata
itcmBridge.io.sram.readData := itcmArbiter.io.in(0).bits.readwritePorts(0).readData
val lsb = log2Ceil(p.axi2DataBits / 8)
itcmArbiter.io.in(1).bits.readwritePorts(0).address := core.io.ibus.addr(log2Ceil(itcmEntries) + lsb - 1, lsb)
itcmArbiter.io.in(1).bits.readwritePorts(0).enable := core.io.ibus.ready
itcmArbiter.io.in(1).bits.readwritePorts(0).isWrite := false.B
itcmArbiter.io.in(1).bits.readwritePorts(0).writeData := 0.U.asTypeOf(itcmArbiter.io.in(1).bits.readwritePorts(0).writeData)
itcmArbiter.io.in(1).bits.readwritePorts(0).mask.get := -1.S.asTypeOf(itcmArbiter.io.in(1).bits.readwritePorts(0).mask.get)
itcmArbiter.io.in(1).bits.readwritePorts(0).readData := itcm.io.rdata
core.io.ibus.rdata := Cat(itcmArbiter.io.in(1).bits.readwritePorts(0).readData)
itcm.io.addr := itcmArbiter.io.out.bits.readwritePorts(0).address
itcm.io.enable := itcmArbiter.io.out.bits.readwritePorts(0).enable
itcm.io.write := itcmArbiter.io.out.bits.readwritePorts(0).isWrite
itcm.io.wdata := itcmArbiter.io.out.bits.readwritePorts(0).writeData
itcm.io.wmask := itcmArbiter.io.out.bits.readwritePorts(0).mask.get
itcmArbiter.io.in(0).valid := itcmBridge.io.txnInProgress
itcmArbiter.io.in(1).valid := core.io.ibus.valid
itcmArbiter.io.out.ready := true.B
core.io.ibus.ready := core.io.ibus.valid && itcmArbiter.io.chosen === 1.U
itcmBridge.io.periBusy := core.io.ibus.valid
io.halted := core.io.halted
io.fault := core.io.fault
io.wfi := core.io.wfi
core.io.irq := io.irq
csr.io.halted := core.io.halted
csr.io.fault := core.io.fault
core.io.debug_req := true.B
val dtcmBridge = Module(new AxiSlave2SRAM(p, log2Ceil(dtcmEntries)))
dtcmBridge.io.periBusy := core.io.dbus.valid
dtcmArbiter.io.in(0).bits.readwritePorts(0).address := dtcmBridge.io.sram.address
dtcmArbiter.io.in(0).bits.readwritePorts(0).enable := dtcmBridge.io.sram.enable
dtcmArbiter.io.in(0).bits.readwritePorts(0).isWrite := dtcmBridge.io.sram.isWrite
dtcmArbiter.io.in(0).bits.readwritePorts(0).writeData := dtcmBridge.io.sram.writeData
dtcmArbiter.io.in(0).bits.readwritePorts(0).mask.get := dtcmBridge.io.sram.mask
dtcmArbiter.io.in(0).bits.readwritePorts(0).readData := dtcm.io.rdata
dtcmBridge.io.sram.readData := dtcmArbiter.io.in(0).bits.readwritePorts(0).readData
dtcmArbiter.io.in(1).bits.readwritePorts(0).address := core.io.dbus.addr(log2Ceil(dtcmEntries) + lsb - 1, lsb)
dtcmArbiter.io.in(1).bits.readwritePorts(0).enable := core.io.dbus.ready
dtcmArbiter.io.in(1).bits.readwritePorts(0).isWrite := core.io.dbus.write
dtcmArbiter.io.in(1).bits.readwritePorts(0).writeData := UIntToVec(core.io.dbus.wdata, 8)
dtcmArbiter.io.in(1).bits.readwritePorts(0).mask.get := core.io.dbus.wmask.asBools
dtcmArbiter.io.in(1).bits.readwritePorts(0).readData := dtcm.io.rdata
dtcm.io.addr := dtcmArbiter.io.out.bits.readwritePorts(0).address
dtcm.io.enable := dtcmArbiter.io.out.bits.readwritePorts(0).enable
dtcm.io.write := dtcmArbiter.io.out.bits.readwritePorts(0).isWrite
dtcm.io.wdata := dtcmArbiter.io.out.bits.readwritePorts(0).writeData
dtcm.io.wmask := dtcmArbiter.io.out.bits.readwritePorts(0).mask.get
core.io.dbus.rdata := Cat(dtcmArbiter.io.out.bits.readwritePorts(0).readData)
core.io.dbus.ready := core.io.dbus.valid && dtcmArbiter.io.chosen === 1.U
dtcmArbiter.io.in(0).valid := dtcmBridge.io.txnInProgress
dtcmArbiter.io.in(1).valid := core.io.dbus.valid
dtcmArbiter.io.out.ready := true.B
val ebus2axi = DBus2Axi(p)
ebus2axi.io.dbus <> core.io.ebus.dbus
ebus2axi.io.axi <> 0.U.asTypeOf(ebus2axi.io.axi)
val axi_mux = Module(new CoreAxiSlaveMux(p, memoryRegions, 2))
axi_mux.io.axi_slave(0) <> io.axi_slave
axi_mux.io.axi_slave(1) <> 0.U.asTypeOf(axi_mux.io.axi_slave(1))
io.axi_master <> 0.U.asTypeOf(io.axi_master)
// If an internal transaction is issued on the EBUS,
// connect the AXI master interface to the internal
// peripheral mux.
when (core.io.ebus.internal) {
axi_mux.io.axi_slave(1) <> ebus2axi.io.axi
io.axi_master <> 0.U.asTypeOf(io.axi_master)
} .otherwise {
axi_mux.io.axi_slave(1) <> 0.U.asTypeOf(axi_mux.io.axi_slave(1))
io.axi_master <> ebus2axi.io.axi
}
axi_mux.io.ports(0) <> itcmBridge.io.axi
axi_mux.io.ports(1) <> dtcmBridge.io.axi
axi_mux.io.ports(2) <> csr.io.axi
core.io.csr <> 0.U.asTypeOf(core.io.csr)
core.io.csr.in.value(0) := csr.io.pcStart
io.slog <> core.io.slog
io.debug <> core.io.debug
// Tie-offs
core.io.dflush.ready := true.B
core.io.iflush.ready := true.B
}
}