内存映射UART

简介

此示例将采用先前 示例 中实现的 UartCtrl 组件来创建内存映射UART控制器。

规范

该实现将基于带有RX FIFO的APB3总线。

这是寄存器映射表:

名称

类型

访问

地址

描述

clockDivider

UInt

RW

0

设置UartCtrl时钟分频器

frame

UartCtrlFrameConfig

RW

4

设置数据长度、奇偶校验和停止位配置

writeCmd

W

8

向UartCtrl发送写命令

writeBusy

Bool

R

8

当可以发送新的writeCmd时,位0 => 0

read

Bool / Bits

R

12

位7到0 => rx payload
位31 => rx payload valid

实现

此实现将使用Apb3SlaveFactory工具。它允许您使用良好的语法定义APB3从端。您可以在 这里 找到该工具的文档。

首先,我们只需要定义控制器要使用的 Apb3Config。它在Scala object中被定义为一个函数,以便能够从任何地方获取它。

object Apb3UartCtrl {
  def getApb3Config = Apb3Config(
    addressWidth = 4,
    dataWidth    = 32
  )
}

然后我们可以定义一个 Apb3UartCtrl 组件,该组件实例化了一个 UartCtrl 并在它和APB3总线之间创建内存映射逻辑:

../../../_images/memory_mapped_uart.svg
case class Apb3UartCtrl(uartCtrlConfig: UartCtrlGenerics, rxFifoDepth: Int) extends Component {
  val io = new Bundle {
    val bus =  slave(Apb3(Apb3UartCtrl.getApb3Config))
    val uart = master(Uart())
  }

  // Instantiate an simple uart controller
  val uartCtrl = new UartCtrl(uartCtrlConfig)
  io.uart <> uartCtrl.io.uart

  // Create an instance of the Apb3SlaveFactory that will then be used as a slave factory drived by io.bus
  val busCtrl = Apb3SlaveFactory(io.bus)

  // Ask the busCtrl to create a readable/writable register at the address 0
  // and drive uartCtrl.io.config.clockDivider with this register
  busCtrl.driveAndRead(uartCtrl.io.config.clockDivider,address = 0)

  // Do the same thing than above but for uartCtrl.io.config.frame at the address 4
  busCtrl.driveAndRead(uartCtrl.io.config.frame,address = 4)

  // Ask the busCtrl to create a writable Flow[Bits] (valid/payload) at the address 8.
  // Then convert it into a stream and connect it to the uartCtrl.io.write by using an register stage (>->)
  busCtrl.createAndDriveFlow(Bits(uartCtrlConfig.dataWidthMax bits),address = 8).toStream >-> uartCtrl.io.write

  // To avoid losing writes commands between the Flow to Stream transformation just above,
  // make the occupancy of the uartCtrl.io.write readable at address 8
  busCtrl.read(uartCtrl.io.write.valid,address = 8)

  // Take uartCtrl.io.read, convert it into a Stream, then connect it to the input of a FIFO of 64 elements
  // Then make the output of the FIFO readable at the address 12 by using a non blocking protocol
  // (Bit 7 downto 0 => read data <br> Bit 31 => read data valid )
  busCtrl.readStreamNonBlocking(uartCtrl.io.read.queue(rxFifoDepth),
                                address = 12, validBitOffset = 31, payloadBitOffset = 0)
}

重要

是的,仅此而已。它同样是可综合的。
Apb3SlaveFactory工具不是硬编码到SpinalHDL编译器中的东西。它是使用SpinalHDL常规的硬件描述语法实现的。