Clean Murax toplevel by extracting integrated Area into dedicated components located in MuraxUtiles.scala
This commit is contained in:
parent
0cf278b04f
commit
a72c7fd0d1
|
@ -2,15 +2,15 @@ package vexriscv.demo
|
||||||
|
|
||||||
import spinal.core._
|
import spinal.core._
|
||||||
import spinal.lib._
|
import spinal.lib._
|
||||||
import spinal.lib.bus.amba3.apb.{Apb3SlaveFactory, Apb3Decoder, Apb3Gpio, Apb3}
|
import spinal.lib.bus.amba3.apb._
|
||||||
import spinal.lib.bus.misc.SizeMapping
|
import spinal.lib.bus.misc.SizeMapping
|
||||||
import spinal.lib.com.jtag.Jtag
|
import spinal.lib.com.jtag.Jtag
|
||||||
import spinal.lib.com.uart._
|
import spinal.lib.com.uart._
|
||||||
import spinal.lib.io.TriStateArray
|
import spinal.lib.io.TriStateArray
|
||||||
import spinal.lib.misc.{InterruptCtrl, Timer, Prescaler}
|
import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer}
|
||||||
import spinal.lib.soc.pinsec.{PinsecTimerCtrlExternal, PinsecTimerCtrl}
|
import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal}
|
||||||
import vexriscv.plugin._
|
import vexriscv.plugin._
|
||||||
import vexriscv.{plugin, VexRiscvConfig, VexRiscv}
|
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||||
|
|
||||||
import scala.collection.mutable.ArrayBuffer
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
@ -132,27 +132,6 @@ object MuraxConfig{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class SimpleBusCmd() extends Bundle{
|
|
||||||
val wr = Bool
|
|
||||||
val address = UInt(32 bits)
|
|
||||||
val data = Bits(32 bit)
|
|
||||||
val mask = Bits(4 bit)
|
|
||||||
}
|
|
||||||
|
|
||||||
case class SimpleBusRsp() extends Bundle{
|
|
||||||
val data = Bits(32 bit)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case class SimpleBus() extends Bundle with IMasterSlave {
|
|
||||||
val cmd = Stream(SimpleBusCmd())
|
|
||||||
val rsp = Flow(SimpleBusRsp())
|
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
|
||||||
master(cmd)
|
|
||||||
slave(rsp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class Murax(config : MuraxConfig) extends Component{
|
case class Murax(config : MuraxConfig) extends Component{
|
||||||
import config._
|
import config._
|
||||||
|
@ -211,6 +190,14 @@ case class Murax(config : MuraxConfig) extends Component{
|
||||||
)
|
)
|
||||||
|
|
||||||
val system = new ClockingArea(systemClockDomain) {
|
val system = new ClockingArea(systemClockDomain) {
|
||||||
|
val simpleBusConfig = SimpleBusConfig(
|
||||||
|
addressWidth = 32,
|
||||||
|
dataWidth = 32
|
||||||
|
)
|
||||||
|
|
||||||
|
//Arbiter of the cpu dBus/iBus to drive the mainBus
|
||||||
|
//Priority to dBus, !! cmd transactions can change on the fly !!
|
||||||
|
val mainBusArbiter = new MuraxMasterArbiter(simpleBusConfig)
|
||||||
|
|
||||||
//Instanciate the CPU
|
//Instanciate the CPU
|
||||||
val cpu = new VexRiscv(
|
val cpu = new VexRiscv(
|
||||||
|
@ -222,18 +209,14 @@ case class Murax(config : MuraxConfig) extends Component{
|
||||||
//Checkout plugins used to instanciate the CPU to connect them to the SoC
|
//Checkout plugins used to instanciate the CPU to connect them to the SoC
|
||||||
val timerInterrupt = False
|
val timerInterrupt = False
|
||||||
val externalInterrupt = False
|
val externalInterrupt = False
|
||||||
var iBus : IBusSimpleBus = null
|
|
||||||
var dBus : DBusSimpleBus = null
|
|
||||||
var debugBus : DebugExtensionBus = null
|
|
||||||
for(plugin <- cpu.plugins) plugin match{
|
for(plugin <- cpu.plugins) plugin match{
|
||||||
case plugin : IBusSimplePlugin => iBus = plugin.iBus
|
case plugin : IBusSimplePlugin => mainBusArbiter.io.iBus <> plugin.iBus
|
||||||
case plugin : DBusSimplePlugin => {
|
case plugin : DBusSimplePlugin => {
|
||||||
if(!pipelineDBus)
|
if(!pipelineDBus)
|
||||||
dBus = plugin.dBus
|
mainBusArbiter.io.dBus <> plugin.dBus
|
||||||
else {
|
else {
|
||||||
dBus = cloneOf(plugin.dBus)
|
mainBusArbiter.io.dBus.cmd << plugin.dBus.cmd.halfPipe()
|
||||||
dBus.cmd << plugin.dBus.cmd.halfPipe()
|
mainBusArbiter.io.dBus.rsp <> plugin.dBus.rsp
|
||||||
dBus.rsp <> plugin.dBus.rsp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case plugin : CsrPlugin => {
|
case plugin : CsrPlugin => {
|
||||||
|
@ -248,218 +231,58 @@ case class Murax(config : MuraxConfig) extends Component{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val mainBus = SimpleBus()
|
|
||||||
|
|
||||||
//Arbiter of the cpu dBus/iBus to drive the mainBus
|
//****** MainBus slaves ********
|
||||||
//Priority to dBus, !! cmd transactions can change on the fly !!
|
val ram = new MuraxSimpleBusRam(
|
||||||
val mainBusArbiter = new Area{
|
onChipRamSize = onChipRamSize,
|
||||||
mainBus.cmd.valid := iBus.cmd.valid || dBus.cmd.valid
|
onChipRamHexFile = onChipRamHexFile,
|
||||||
mainBus.cmd.wr := dBus.cmd.valid && dBus.cmd.wr
|
simpleBusConfig = simpleBusConfig
|
||||||
mainBus.cmd.address := dBus.cmd.valid ? dBus.cmd.address | iBus.cmd.pc
|
|
||||||
mainBus.cmd.data := dBus.cmd.data
|
|
||||||
mainBus.cmd.mask := dBus.cmd.size.mux(
|
|
||||||
0 -> B"0001",
|
|
||||||
1 -> B"0011",
|
|
||||||
default -> B"1111"
|
|
||||||
) |<< dBus.cmd.address(1 downto 0)
|
|
||||||
iBus.cmd.ready := mainBus.cmd.ready && !dBus.cmd.valid
|
|
||||||
dBus.cmd.ready := mainBus.cmd.ready
|
|
||||||
|
|
||||||
|
|
||||||
val rspPending = RegInit(False) clearWhen(mainBus.rsp.valid)
|
|
||||||
val rspTarget = RegInit(False)
|
|
||||||
when(mainBus.cmd.fire && !mainBus.cmd.wr){
|
|
||||||
rspTarget := dBus.cmd.valid
|
|
||||||
rspPending := True
|
|
||||||
}
|
|
||||||
|
|
||||||
when(rspPending && !mainBus.rsp.valid){
|
|
||||||
iBus.cmd.ready := False
|
|
||||||
dBus.cmd.ready := False
|
|
||||||
mainBus.cmd.valid := False
|
|
||||||
}
|
|
||||||
|
|
||||||
iBus.rsp.ready := mainBus.rsp.valid && !rspTarget
|
|
||||||
iBus.rsp.inst := mainBus.rsp.data
|
|
||||||
iBus.rsp.error := False
|
|
||||||
|
|
||||||
dBus.rsp.ready := mainBus.rsp.valid && rspTarget
|
|
||||||
dBus.rsp.data := mainBus.rsp.data
|
|
||||||
dBus.rsp.error := False
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create an SimpleBus mapped RAM
|
|
||||||
val ram = new Area{
|
|
||||||
val bus = SimpleBus()
|
|
||||||
val ram = Mem(Bits(32 bits), onChipRamSize / 4)
|
|
||||||
bus.rsp.valid := RegNext(bus.cmd.fire && !bus.cmd.wr) init(False)
|
|
||||||
bus.rsp.data := ram.readWriteSync(
|
|
||||||
address = (bus.cmd.address >> 2).resized,
|
|
||||||
data = bus.cmd.data,
|
|
||||||
enable = bus.cmd.valid,
|
|
||||||
write = bus.cmd.wr,
|
|
||||||
mask = bus.cmd.mask
|
|
||||||
)
|
)
|
||||||
bus.cmd.ready := True
|
|
||||||
|
|
||||||
if(onChipRamHexFile != null){
|
val apbBridge = new MuraxSimpleBusToApbBridge(
|
||||||
def readHexFile(path : String, callback : (Int, Int) => Unit): Unit ={
|
apb3Config = Apb3Config(
|
||||||
import scala.io.Source
|
|
||||||
def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16)
|
|
||||||
|
|
||||||
var offset = 0
|
|
||||||
for (line <- Source.fromFile(path).getLines) {
|
|
||||||
if (line.charAt(0) == ':'){
|
|
||||||
val byteCount = hToI(line, 1, 2)
|
|
||||||
val nextAddr = hToI(line, 3, 4) + offset
|
|
||||||
val key = hToI(line, 7, 2)
|
|
||||||
key match {
|
|
||||||
case 0 =>
|
|
||||||
for(i <- 0 until byteCount){
|
|
||||||
callback(nextAddr + i, hToI(line, 9 + i * 2, 2))
|
|
||||||
}
|
|
||||||
case 2 =>
|
|
||||||
offset = hToI(line, 9, 4) << 4
|
|
||||||
case 4 =>
|
|
||||||
offset = hToI(line, 9, 4) << 16
|
|
||||||
case 3 =>
|
|
||||||
case 1 =>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val initContent = Array.fill[BigInt](ram.wordCount)(0)
|
|
||||||
readHexFile(onChipRamHexFile,(address,data) => {
|
|
||||||
initContent(address >> 2) |= BigInt(data) << ((address & 3)*8)
|
|
||||||
})
|
|
||||||
ram.initBigInt(initContent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Bridge simpleBus to apb
|
|
||||||
val apbBridge = new Area{
|
|
||||||
val simpleBus = SimpleBus()
|
|
||||||
val apb = Apb3(
|
|
||||||
addressWidth = 20,
|
addressWidth = 20,
|
||||||
dataWidth = 32
|
dataWidth = 32
|
||||||
)
|
),
|
||||||
val simpleBusStage = SimpleBus()
|
pipelineBridge = pipelineApbBridge,
|
||||||
simpleBusStage.cmd << (if(pipelineApbBridge) simpleBus.cmd.halfPipe() else simpleBus.cmd)
|
simpleBusConfig = simpleBusConfig
|
||||||
simpleBusStage.rsp >-> simpleBus.rsp
|
|
||||||
|
|
||||||
val state = RegInit(False)
|
|
||||||
simpleBusStage.cmd.ready := False
|
|
||||||
|
|
||||||
apb.PSEL(0) := simpleBusStage.cmd.valid
|
|
||||||
apb.PENABLE := state
|
|
||||||
apb.PWRITE := simpleBusStage.cmd.wr
|
|
||||||
apb.PADDR := simpleBusStage.cmd.address.resized
|
|
||||||
apb.PWDATA := simpleBusStage.cmd.data
|
|
||||||
|
|
||||||
simpleBusStage.rsp.valid := False
|
|
||||||
simpleBusStage.rsp.data := apb.PRDATA
|
|
||||||
when(!state){
|
|
||||||
state := simpleBusStage.cmd.valid
|
|
||||||
} otherwise{
|
|
||||||
when(apb.PREADY){
|
|
||||||
state := False
|
|
||||||
simpleBusStage.rsp.valid := !simpleBusStage.cmd.wr
|
|
||||||
simpleBusStage.cmd.ready := True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Connect the mainBus to all slaves (ram, apbBridge)
|
|
||||||
val mainBusDecoder = new Area {
|
|
||||||
val masterBus = SimpleBus()
|
|
||||||
if(!pipelineMainBus) {
|
|
||||||
masterBus.cmd << mainBus.cmd
|
|
||||||
masterBus.rsp >> mainBus.rsp
|
|
||||||
} else {
|
|
||||||
masterBus.cmd <-< mainBus.cmd
|
|
||||||
masterBus.rsp >> mainBus.rsp
|
|
||||||
}
|
|
||||||
|
|
||||||
val specification = List[(SimpleBus,SizeMapping)](
|
|
||||||
ram.bus -> (0x00000000l, onChipRamSize kB),
|
|
||||||
apbBridge.simpleBus -> (0xF0000000l, 1 MB)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val slaveBuses = specification.map(_._1)
|
|
||||||
val memorySpaces = specification.map(_._2)
|
|
||||||
|
|
||||||
val hits = for((slaveBus, memorySpace) <- specification) yield {
|
|
||||||
val hit = memorySpace.hit(masterBus.cmd.address)
|
|
||||||
slaveBus.cmd.valid := masterBus.cmd.valid && hit
|
|
||||||
slaveBus.cmd.payload := masterBus.cmd.payload
|
|
||||||
hit
|
|
||||||
}
|
|
||||||
val noHit = !hits.orR
|
|
||||||
masterBus.cmd.ready := (hits,slaveBuses).zipped.map(_ && _.cmd.ready).orR || noHit
|
|
||||||
|
|
||||||
val rspPending = RegInit(False) clearWhen(masterBus.rsp.valid) setWhen(masterBus.cmd.fire && !masterBus.cmd.wr)
|
//******** APB peripherals *********
|
||||||
val rspNoHit = RegNext(False) init(False) setWhen(noHit)
|
val gpioACtrl = Apb3Gpio(gpioWidth = gpioWidth)
|
||||||
val rspSourceId = RegNextWhen(OHToUInt(hits), masterBus.cmd.fire)
|
|
||||||
masterBus.rsp.valid := slaveBuses.map(_.rsp.valid).orR || (rspPending && rspNoHit)
|
|
||||||
masterBus.rsp.payload := slaveBuses.map(_.rsp.payload).read(rspSourceId)
|
|
||||||
|
|
||||||
when(rspPending && !masterBus.rsp.valid) { //Only one pending read request is allowed
|
|
||||||
masterBus.cmd.ready := False
|
|
||||||
slaveBuses.foreach(_.cmd.valid := False)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val gpioACtrl = Apb3Gpio(
|
|
||||||
gpioWidth = gpioWidth
|
|
||||||
)
|
|
||||||
io.gpioA <> gpioACtrl.io.gpio
|
io.gpioA <> gpioACtrl.io.gpio
|
||||||
|
|
||||||
val uartCtrl = Apb3UartCtrl(uartCtrlConfig)
|
val uartCtrl = Apb3UartCtrl(uartCtrlConfig)
|
||||||
uartCtrl.io.uart <> io.uart
|
uartCtrl.io.uart <> io.uart
|
||||||
externalInterrupt setWhen(uartCtrl.io.interrupt)
|
externalInterrupt setWhen(uartCtrl.io.interrupt)
|
||||||
|
|
||||||
val timer = new Area{
|
val timer = new MuraxApb3Timer()
|
||||||
val apb = Apb3(
|
timerInterrupt setWhen(timer.io.interrupt)
|
||||||
addressWidth = 8,
|
|
||||||
dataWidth = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
val prescaler = Prescaler(16)
|
|
||||||
val timerA,timerB = Timer(16)
|
|
||||||
|
|
||||||
val busCtrl = Apb3SlaveFactory(apb)
|
|
||||||
val prescalerBridge = prescaler.driveFrom(busCtrl,0x00)
|
|
||||||
|
|
||||||
val timerABridge = timerA.driveFrom(busCtrl,0x40)(
|
|
||||||
ticks = List(True, prescaler.io.overflow),
|
|
||||||
clears = List(timerA.io.full)
|
|
||||||
)
|
|
||||||
|
|
||||||
val timerBBridge = timerB.driveFrom(busCtrl,0x50)(
|
|
||||||
ticks = List(True, prescaler.io.overflow),
|
|
||||||
clears = List(timerB.io.full)
|
|
||||||
)
|
|
||||||
|
|
||||||
val interruptCtrl = InterruptCtrl(2)
|
|
||||||
val interruptCtrlBridge = interruptCtrl.driveFrom(busCtrl,0x10)
|
|
||||||
interruptCtrl.io.inputs(0) := timerA.io.full
|
|
||||||
interruptCtrl.io.inputs(1) := timerB.io.full
|
|
||||||
timerInterrupt setWhen(interruptCtrl.io.pendings.orR)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//******** Memory mappings *********
|
||||||
val apbDecoder = Apb3Decoder(
|
val apbDecoder = Apb3Decoder(
|
||||||
master = apbBridge.apb,
|
master = apbBridge.io.apb,
|
||||||
slaves = List(
|
slaves = List(
|
||||||
gpioACtrl.io.apb -> (0x00000, 4 kB),
|
gpioACtrl.io.apb -> (0x00000, 4 kB),
|
||||||
uartCtrl.io.apb -> (0x10000, 4 kB),
|
uartCtrl.io.apb -> (0x10000, 4 kB),
|
||||||
timer.apb -> (0x20000, 4 kB)
|
timer.io.apb -> (0x20000, 4 kB)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val mainBusDecoder = new Area {
|
||||||
|
val logic = new MuraxSimpleBusDecoder(
|
||||||
|
master = mainBusArbiter.io.masterBus,
|
||||||
|
specification = List[(SimpleBus,SizeMapping)](
|
||||||
|
ram.io.bus -> (0x00000000l, onChipRamSize kB),
|
||||||
|
apbBridge.io.simpleBus -> (0xF0000000l, 1 MB)
|
||||||
|
),
|
||||||
|
pipelineMaster = pipelineMainBus
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
package vexriscv.demo
|
||||||
|
|
||||||
|
import spinal.core._
|
||||||
|
import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config, Apb3SlaveFactory}
|
||||||
|
import spinal.lib.bus.misc.SizeMapping
|
||||||
|
import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer}
|
||||||
|
import spinal.lib._
|
||||||
|
import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus}
|
||||||
|
|
||||||
|
case class SimpleBusConfig(addressWidth : Int, dataWidth : Int)
|
||||||
|
|
||||||
|
case class SimpleBusCmd(config : SimpleBusConfig) extends Bundle{
|
||||||
|
val wr = Bool
|
||||||
|
val address = UInt(config.addressWidth bits)
|
||||||
|
val data = Bits(config.dataWidth bits)
|
||||||
|
val mask = Bits(4 bit)
|
||||||
|
}
|
||||||
|
|
||||||
|
case class SimpleBusRsp(config : SimpleBusConfig) extends Bundle{
|
||||||
|
val data = Bits(config.dataWidth bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case class SimpleBus(config : SimpleBusConfig) extends Bundle with IMasterSlave {
|
||||||
|
val cmd = Stream(SimpleBusCmd(config))
|
||||||
|
val rsp = Flow(SimpleBusRsp(config))
|
||||||
|
|
||||||
|
override def asMaster(): Unit = {
|
||||||
|
master(cmd)
|
||||||
|
slave(rsp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{
|
||||||
|
val io = new Bundle{
|
||||||
|
val iBus = slave(IBusSimpleBus(false))
|
||||||
|
val dBus = slave(DBusSimpleBus())
|
||||||
|
val masterBus = master(SimpleBus(simpleBusConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
io.masterBus.cmd.valid := io.iBus.cmd.valid || io.dBus.cmd.valid
|
||||||
|
io.masterBus.cmd.wr := io.dBus.cmd.valid && io.dBus.cmd.wr
|
||||||
|
io.masterBus.cmd.address := io.dBus.cmd.valid ? io.dBus.cmd.address | io.iBus.cmd.pc
|
||||||
|
io.masterBus.cmd.data := io.dBus.cmd.data
|
||||||
|
io.masterBus.cmd.mask := io.dBus.cmd.size.mux(
|
||||||
|
0 -> B"0001",
|
||||||
|
1 -> B"0011",
|
||||||
|
default -> B"1111"
|
||||||
|
) |<< io.dBus.cmd.address(1 downto 0)
|
||||||
|
io.iBus.cmd.ready := io.masterBus.cmd.ready && !io.dBus.cmd.valid
|
||||||
|
io.dBus.cmd.ready := io.masterBus.cmd.ready
|
||||||
|
|
||||||
|
|
||||||
|
val rspPending = RegInit(False) clearWhen(io.masterBus.rsp.valid)
|
||||||
|
val rspTarget = RegInit(False)
|
||||||
|
when(io.masterBus.cmd.fire && !io.masterBus.cmd.wr){
|
||||||
|
rspTarget := io.dBus.cmd.valid
|
||||||
|
rspPending := True
|
||||||
|
}
|
||||||
|
|
||||||
|
when(rspPending && !io.masterBus.rsp.valid){
|
||||||
|
io.iBus.cmd.ready := False
|
||||||
|
io.dBus.cmd.ready := False
|
||||||
|
io.masterBus.cmd.valid := False
|
||||||
|
}
|
||||||
|
|
||||||
|
io.iBus.rsp.ready := io.masterBus.rsp.valid && !rspTarget
|
||||||
|
io.iBus.rsp.inst := io.masterBus.rsp.data
|
||||||
|
io.iBus.rsp.error := False
|
||||||
|
|
||||||
|
io.dBus.rsp.ready := io.masterBus.rsp.valid && rspTarget
|
||||||
|
io.dBus.rsp.data := io.masterBus.rsp.data
|
||||||
|
io.dBus.rsp.error := False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MuraxSimpleBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, simpleBusConfig : SimpleBusConfig) extends Component{
|
||||||
|
val io = new Bundle{
|
||||||
|
val bus = slave(SimpleBus(simpleBusConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
val ram = Mem(Bits(32 bits), onChipRamSize / 4)
|
||||||
|
io.bus.rsp.valid := RegNext(io.bus.cmd.fire && !io.bus.cmd.wr) init(False)
|
||||||
|
io.bus.rsp.data := ram.readWriteSync(
|
||||||
|
address = (io.bus.cmd.address >> 2).resized,
|
||||||
|
data = io.bus.cmd.data,
|
||||||
|
enable = io.bus.cmd.valid,
|
||||||
|
write = io.bus.cmd.wr,
|
||||||
|
mask = io.bus.cmd.mask
|
||||||
|
)
|
||||||
|
io.bus.cmd.ready := True
|
||||||
|
|
||||||
|
if(onChipRamHexFile != null){
|
||||||
|
def readHexFile(path : String, callback : (Int, Int) => Unit): Unit ={
|
||||||
|
import scala.io.Source
|
||||||
|
def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16)
|
||||||
|
|
||||||
|
var offset = 0
|
||||||
|
for (line <- Source.fromFile(path).getLines) {
|
||||||
|
if (line.charAt(0) == ':'){
|
||||||
|
val byteCount = hToI(line, 1, 2)
|
||||||
|
val nextAddr = hToI(line, 3, 4) + offset
|
||||||
|
val key = hToI(line, 7, 2)
|
||||||
|
key match {
|
||||||
|
case 0 =>
|
||||||
|
for(i <- 0 until byteCount){
|
||||||
|
callback(nextAddr + i, hToI(line, 9 + i * 2, 2))
|
||||||
|
}
|
||||||
|
case 2 =>
|
||||||
|
offset = hToI(line, 9, 4) << 4
|
||||||
|
case 4 =>
|
||||||
|
offset = hToI(line, 9, 4) << 16
|
||||||
|
case 3 =>
|
||||||
|
case 1 =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val initContent = Array.fill[BigInt](ram.wordCount)(0)
|
||||||
|
readHexFile(onChipRamHexFile,(address,data) => {
|
||||||
|
initContent(address >> 2) |= BigInt(data) << ((address & 3)*8)
|
||||||
|
})
|
||||||
|
ram.initBigInt(initContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MuraxSimpleBusToApbBridge(apb3Config: Apb3Config, pipelineBridge : Boolean, simpleBusConfig : SimpleBusConfig) extends Component{
|
||||||
|
assert(apb3Config.dataWidth == simpleBusConfig.dataWidth)
|
||||||
|
|
||||||
|
val io = new Bundle {
|
||||||
|
val simpleBus = slave(SimpleBus(simpleBusConfig))
|
||||||
|
val apb = master(Apb3(apb3Config))
|
||||||
|
}
|
||||||
|
|
||||||
|
val simpleBusStage = SimpleBus(simpleBusConfig)
|
||||||
|
simpleBusStage.cmd << (if(pipelineBridge) io.simpleBus.cmd.halfPipe() else io.simpleBus.cmd)
|
||||||
|
simpleBusStage.rsp >-> io.simpleBus.rsp
|
||||||
|
|
||||||
|
val state = RegInit(False)
|
||||||
|
simpleBusStage.cmd.ready := False
|
||||||
|
|
||||||
|
io.apb.PSEL(0) := simpleBusStage.cmd.valid
|
||||||
|
io.apb.PENABLE := state
|
||||||
|
io.apb.PWRITE := simpleBusStage.cmd.wr
|
||||||
|
io.apb.PADDR := simpleBusStage.cmd.address.resized
|
||||||
|
io.apb.PWDATA := simpleBusStage.cmd.data
|
||||||
|
|
||||||
|
simpleBusStage.rsp.valid := False
|
||||||
|
simpleBusStage.rsp.data := io.apb.PRDATA
|
||||||
|
when(!state) {
|
||||||
|
state := simpleBusStage.cmd.valid
|
||||||
|
} otherwise {
|
||||||
|
when(io.apb.PREADY){
|
||||||
|
state := False
|
||||||
|
simpleBusStage.rsp.valid := !simpleBusStage.cmd.wr
|
||||||
|
simpleBusStage.cmd.ready := True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MuraxSimpleBusDecoder(master : SimpleBus, specification : List[(SimpleBus,SizeMapping)], pipelineMaster : Boolean) extends Area{
|
||||||
|
val masterPipelined = SimpleBus(master.config)
|
||||||
|
if(!pipelineMaster) {
|
||||||
|
masterPipelined.cmd << master.cmd
|
||||||
|
masterPipelined.rsp >> master.rsp
|
||||||
|
} else {
|
||||||
|
masterPipelined.cmd <-< master.cmd
|
||||||
|
masterPipelined.rsp >> master.rsp
|
||||||
|
}
|
||||||
|
|
||||||
|
val slaveBuses = specification.map(_._1)
|
||||||
|
val memorySpaces = specification.map(_._2)
|
||||||
|
|
||||||
|
val hits = for((slaveBus, memorySpace) <- specification) yield {
|
||||||
|
val hit = memorySpace.hit(masterPipelined.cmd.address)
|
||||||
|
slaveBus.cmd.valid := masterPipelined.cmd.valid && hit
|
||||||
|
slaveBus.cmd.payload := masterPipelined.cmd.payload
|
||||||
|
hit
|
||||||
|
}
|
||||||
|
val noHit = !hits.orR
|
||||||
|
masterPipelined.cmd.ready := (hits,slaveBuses).zipped.map(_ && _.cmd.ready).orR || noHit
|
||||||
|
|
||||||
|
val rspPending = RegInit(False) clearWhen(masterPipelined.rsp.valid) setWhen(masterPipelined.cmd.fire && !masterPipelined.cmd.wr)
|
||||||
|
val rspNoHit = RegNext(False) init(False) setWhen(noHit)
|
||||||
|
val rspSourceId = RegNextWhen(OHToUInt(hits), masterPipelined.cmd.fire)
|
||||||
|
masterPipelined.rsp.valid := slaveBuses.map(_.rsp.valid).orR || (rspPending && rspNoHit)
|
||||||
|
masterPipelined.rsp.payload := slaveBuses.map(_.rsp.payload).read(rspSourceId)
|
||||||
|
|
||||||
|
when(rspPending && !masterPipelined.rsp.valid) { //Only one pending read request is allowed
|
||||||
|
masterPipelined.cmd.ready := False
|
||||||
|
slaveBuses.foreach(_.cmd.valid := False)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MuraxApb3Timer extends Component{
|
||||||
|
val io = new Bundle {
|
||||||
|
val apb = slave(Apb3(
|
||||||
|
addressWidth = 8,
|
||||||
|
dataWidth = 32
|
||||||
|
))
|
||||||
|
val interrupt = out Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
val prescaler = Prescaler(16)
|
||||||
|
val timerA,timerB = Timer(16)
|
||||||
|
|
||||||
|
val busCtrl = Apb3SlaveFactory(io.apb)
|
||||||
|
val prescalerBridge = prescaler.driveFrom(busCtrl,0x00)
|
||||||
|
|
||||||
|
val timerABridge = timerA.driveFrom(busCtrl,0x40)(
|
||||||
|
ticks = List(True, prescaler.io.overflow),
|
||||||
|
clears = List(timerA.io.full)
|
||||||
|
)
|
||||||
|
|
||||||
|
val timerBBridge = timerB.driveFrom(busCtrl,0x50)(
|
||||||
|
ticks = List(True, prescaler.io.overflow),
|
||||||
|
clears = List(timerB.io.full)
|
||||||
|
)
|
||||||
|
|
||||||
|
val interruptCtrl = InterruptCtrl(2)
|
||||||
|
val interruptCtrlBridge = interruptCtrl.driveFrom(busCtrl,0x10)
|
||||||
|
interruptCtrl.io.inputs(0) := timerA.io.full
|
||||||
|
interruptCtrl.io.inputs(1) := timerB.io.full
|
||||||
|
io.interrupt := interruptCtrl.io.pendings.orR
|
||||||
|
}
|
Loading…
Reference in New Issue