gateware: add UART to CSR
This commit is contained in:
parent
32fb8383d1
commit
96dabe013a
@ -41,7 +41,7 @@ class I2C(Elaboratable):
|
|||||||
# [3]: read - read a byte from the bus
|
# [3]: read - read a byte from the bus
|
||||||
# [4]: read_ack - ACK value that gets written out during a read operation
|
# [4]: read_ack - ACK value that gets written out during a read operation
|
||||||
# [5]: read_ack_en - Hacky solution to determine if we want to save read_ack
|
# [5]: read_ack_en - Hacky solution to determine if we want to save read_ack
|
||||||
self.CR = Element(6, Element.Access.W, name="CR")
|
self.CR = Element(6, Element.Access.W, name="I2C_CR")
|
||||||
|
|
||||||
# Status register
|
# Status register
|
||||||
#
|
#
|
||||||
@ -49,27 +49,28 @@ class I2C(Elaboratable):
|
|||||||
# [0]: busy - bus is busy operating
|
# [0]: busy - bus is busy operating
|
||||||
# [1]: ack - an ACK has been received from a bus slave
|
# [1]: ack - an ACK has been received from a bus slave
|
||||||
# [2]: read_ack - a convenience read field to see value of CR->read_ack
|
# [2]: read_ack - a convenience read field to see value of CR->read_ack
|
||||||
self.SR = Element(3, Element.Access.R, name="SR")
|
self.SR = Element(3, Element.Access.R, name="I2C_SR")
|
||||||
|
|
||||||
# Data write register
|
# Data write register
|
||||||
#
|
#
|
||||||
# Latches in data to be written when write signal is applied.
|
# Latches in data to be written when write signal is applied.
|
||||||
self.DWR = Element(8, Element.Access.W, name="DWR")
|
self.DWR = Element(8, Element.Access.W, name="I2C_DWR")
|
||||||
|
|
||||||
# Data read register
|
# Data read register
|
||||||
#
|
#
|
||||||
# Only presents valid data after 'read' has started, and once 'busy' is no longer asserted.
|
# Only presents valid data after 'read' has started, and once 'busy' is no longer asserted.
|
||||||
self.DRR = Element(8, Element.Access.R, name="DRR")
|
self.DRR = Element(8, Element.Access.R, name="I2C_DRR")
|
||||||
|
|
||||||
# Set up CSR bus
|
# Set up CSR bus
|
||||||
addr_width = ceil(log2(64)) # Support up to 64 registers just because
|
addr_width = ceil(log2(64)) # Support up to 64 registers just because
|
||||||
data_width = 8 # 32 bit bus
|
data_width = 8 # 32 bit bus
|
||||||
self._csr_mux = Multiplexer(addr_width=addr_width, data_width=data_width)
|
self._csr_mux = Multiplexer(addr_width=addr_width, data_width=data_width)
|
||||||
# TODO export the addresses of these somehow
|
# TODO export these addresses into some config file
|
||||||
self._csr_mux.add(self.CR)
|
cr_start, _stop = self._csr_mux.add(self.CR)
|
||||||
self._csr_mux.add(self.SR)
|
sr_start, _stop = self._csr_mux.add(self.SR)
|
||||||
self._csr_mux.add(self.DWR)
|
dwr_start, _stop = self._csr_mux.add(self.DWR)
|
||||||
self._csr_mux.add(self.DRR)
|
drr_start, _stop = self._csr_mux.add(self.DRR)
|
||||||
|
print(f"I2C added. CR 0x{cr_start:x}, SR 0x{sr_start:x}, DWR 0x{dwr_start:x}, DRR 0x{drr_start:x}")
|
||||||
self.bus = self._csr_mux.bus
|
self.bus = self._csr_mux.bus
|
||||||
|
|
||||||
# Set up I2C initiator submodule
|
# Set up I2C initiator submodule
|
||||||
|
@ -146,7 +146,6 @@ class Core(Elaboratable):
|
|||||||
print(f"CSR bus added at 0x{start:08x}")
|
print(f"CSR bus added at 0x{start:08x}")
|
||||||
|
|
||||||
# I2C (connected to DAC for VCO and ADC?)
|
# I2C (connected to DAC for VCO and ADC?)
|
||||||
Signal()
|
|
||||||
if platform is not None:
|
if platform is not None:
|
||||||
i2c_pads = platform.request("i2c")
|
i2c_pads = platform.request("i2c")
|
||||||
else:
|
else:
|
||||||
@ -158,7 +157,20 @@ class Core(Elaboratable):
|
|||||||
m.d.comb += i2c_pads.scl.i.eq(1)
|
m.d.comb += i2c_pads.scl.i.eq(1)
|
||||||
self.i2c = i2c.I2C(50e6, 100e3, i2c_pads)
|
self.i2c = i2c.I2C(50e6, 100e3, i2c_pads)
|
||||||
m.submodules.i2c = self.i2c
|
m.submodules.i2c = self.i2c
|
||||||
self.csr.add(self.i2c.bus)
|
i2c_start, _stop, _step = self.csr.add(self.i2c.bus)
|
||||||
|
print(f"LED added to CSR at 0x{i2c_start}")
|
||||||
|
|
||||||
|
if platform is not None:
|
||||||
|
uart_pads = platform.request("uart")
|
||||||
|
else:
|
||||||
|
uart_pads = type('UARTPads', (), {})
|
||||||
|
uart_pads.tx = Signal()
|
||||||
|
uart_pads.rx = Signal()
|
||||||
|
# TODO spread sysclk freq through design
|
||||||
|
self.uart = uart.UART(50e6, 1152_000)
|
||||||
|
m.submodules.uart = self.uart
|
||||||
|
uart_start, _stop, _step = self.csr.add(self.uart.bus)
|
||||||
|
print(f"UART added to CSR at 0x{uart_start:x}")
|
||||||
|
|
||||||
self.csr_bridge = WishboneCSRBridge(self.csr.bus, data_width=32, name="CSR")
|
self.csr_bridge = WishboneCSRBridge(self.csr.bus, data_width=32, name="CSR")
|
||||||
m.submodules.csr_bridge = self.csr_bridge
|
m.submodules.csr_bridge = self.csr_bridge
|
||||||
|
@ -1 +1 @@
|
|||||||
from colorlight_i9 import *
|
from .colorlight_i9 import *
|
||||||
|
@ -25,8 +25,18 @@ class Colorlight_i9_Platform(LatticeECP5Platform):
|
|||||||
# attrs=Attrs(IO_TYPE="LVCMOS33", PULLMODE="UP")),
|
# attrs=Attrs(IO_TYPE="LVCMOS33", PULLMODE="UP")),
|
||||||
|
|
||||||
UARTResource(0,
|
UARTResource(0,
|
||||||
tx="J17",
|
tx="E17",
|
||||||
rx="H18",
|
rx="D18",
|
||||||
|
attrs=Attrs(IO_TYPE="LVCMOS33")
|
||||||
|
),
|
||||||
|
UARTResource(1,
|
||||||
|
tx="P16",
|
||||||
|
rx="L5",
|
||||||
|
attrs=Attrs(IO_TYPE="LVCMOS33")
|
||||||
|
),
|
||||||
|
UARTResource(2,
|
||||||
|
tx="J18",
|
||||||
|
rx="J16",
|
||||||
attrs=Attrs(IO_TYPE="LVCMOS33")
|
attrs=Attrs(IO_TYPE="LVCMOS33")
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class UART(Elaboratable):
|
|||||||
#
|
#
|
||||||
# Sets input/output baudrate to system clock / divisor. Resets to value
|
# Sets input/output baudrate to system clock / divisor. Resets to value
|
||||||
# that provides 115200 baud rate. Writes to this register clear FIFOs.
|
# that provides 115200 baud rate. Writes to this register clear FIFOs.
|
||||||
self.DIVISOR = Element(16, Element.Access.RW, name="DIVISOR")
|
self.DIVISOR = Element(16, Element.Access.RW, name="UART_DIVISOR")
|
||||||
|
|
||||||
# Status register.
|
# Status register.
|
||||||
#
|
#
|
||||||
@ -47,22 +47,23 @@ class UART(Elaboratable):
|
|||||||
# [1]: txfifo_empty
|
# [1]: txfifo_empty
|
||||||
# [2]: rxfifo_full
|
# [2]: rxfifo_full
|
||||||
# [3]: rxfifo_empty
|
# [3]: rxfifo_empty
|
||||||
self.SR = Element(4, Element.Access.R, name="SR")
|
self.SR = Element(4, Element.Access.R, name="UART_SR")
|
||||||
|
|
||||||
# Data register.
|
# Data register.
|
||||||
#
|
#
|
||||||
# Writes push data into TX FIFO, and are discarded if full, reads pull
|
# Writes push data into TX FIFO, and are discarded if full, reads pull
|
||||||
# data from RX FIFO, and are invalid if it is empty. Incoming bytes are discarded
|
# data from RX FIFO, and are invalid if it is empty. Incoming bytes are discarded
|
||||||
# if the RX FIFO is full.
|
# if the RX FIFO is full.
|
||||||
self.DR = Element(8, Element.Access.RW, name="DR")
|
self.DR = Element(8, Element.Access.RW, name="UART_DR")
|
||||||
|
|
||||||
# Set up CSR bus
|
# Set up CSR bus
|
||||||
addr_width = ceil(log2(64))
|
addr_width = ceil(log2(64))
|
||||||
data_width = 32
|
data_width = 8
|
||||||
self._csr_mux = Multiplexer(addr_width=addr_width, data_width=data_width)
|
self._csr_mux = Multiplexer(addr_width=addr_width, data_width=data_width)
|
||||||
self._csr_mux.add(self.DIVISOR)
|
div_start, _stop = self._csr_mux.add(self.DIVISOR)
|
||||||
self._csr_mux.add(self.SR)
|
sr_start, _stop = self._csr_mux.add(self.SR)
|
||||||
self._csr_mux.add(self.DR)
|
dr_start, _stop = self._csr_mux.add(self.DR)
|
||||||
|
print(f"UART added. DIVISOR 0x{div_start:x}, SR 0x{sr_start:x}, DR 0x{dr_start:x}")
|
||||||
self.bus = self._csr_mux.bus
|
self.bus = self._csr_mux.bus
|
||||||
|
|
||||||
# Actual business logic
|
# Actual business logic
|
||||||
@ -94,6 +95,7 @@ class UART(Elaboratable):
|
|||||||
m.submodules.csr_mux = self._csr_mux
|
m.submodules.csr_mux = self._csr_mux
|
||||||
|
|
||||||
# Hook up divisor to register.
|
# Hook up divisor to register.
|
||||||
|
# TODO do some validation and write a known good value if a dumb value was provided
|
||||||
m.d.comb += self.DIVISOR.r_data.eq(self._serial.divisor)
|
m.d.comb += self.DIVISOR.r_data.eq(self._serial.divisor)
|
||||||
with m.If(self.DIVISOR.w_stb):
|
with m.If(self.DIVISOR.w_stb):
|
||||||
m.d.sync += self._serial.divisor.eq(self.DIVISOR.w_data)
|
m.d.sync += self._serial.divisor.eq(self.DIVISOR.w_data)
|
||||||
|
Loading…
Reference in New Issue
Block a user