From 0f117abab44c8a8f3739f0e75f15c879c98220bf Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 24 Sep 2020 20:39:13 +0100 Subject: [PATCH] c4m iopad integration working --- src/soc/debug/jtag.py | 24 +++++++++-- src/soc/litex/florent/libresoc/core.py | 54 +++++++++++++++++++++++++ src/soc/litex/florent/libresoc/ls180.py | 30 +++++--------- src/soc/litex/florent/ls180soc.py | 39 +++++++++++++++--- 4 files changed, 117 insertions(+), 30 deletions(-) diff --git a/src/soc/debug/jtag.py b/src/soc/debug/jtag.py index b83f993e..b1091dac 100644 --- a/src/soc/debug/jtag.py +++ b/src/soc/debug/jtag.py @@ -14,10 +14,10 @@ iotypes = {'-': IOType.In, '+': IOType.Out, '*': IOType.InTriOut} +# TODO: move to suitable location +class Pins: -class JTAG(DMITAP): def __init__(self): - super().__init__(ir_width=4) # sigh this needs to come from pinmux. gpios = [] @@ -25,15 +25,31 @@ class JTAG(DMITAP): gpios.append("gpio%d*" % i) self.io_names = {'serial': ['tx+', 'rx-'], 'gpio': gpios} + def __iter__(self): # start parsing io_names and create IOConn Records - self.ios = [] for fn, pins in self.io_names.items(): for pin in pins: # decode the pin name and determine the c4m jtag io type name, pin_type = pin[:-1], pin[-1] iotype = iotypes[pin_type] pin_name = "%s_%s" % (fn, name) - self.ios.append(self.add_io(iotype=iotype, name=pin_name)) + yield (fn, name, iotype, pin_name) + +class JTAG(DMITAP, Pins): + def __init__(self): + DMITAP.__init__(self, ir_width=4) + Pins.__init__(self) + + # sigh this needs to come from pinmux. + gpios = [] + for i in range(16): + gpios.append("gpio%d*" % i) + self.io_names = {'serial': ['tx+', 'rx-'], 'gpio': gpios} + + # start parsing io_names and create IOConn Records + self.ios = [] + for fn, pin, iotype, pin_name in list(self): + self.ios.append(self.add_io(iotype=iotype, name=pin_name)) # this is redundant. or maybe part of testing, i don't know. self.sr = self.add_shiftreg(ircode=4, length=3) diff --git a/src/soc/litex/florent/libresoc/core.py b/src/soc/litex/florent/libresoc/core.py index a082f72b..c366961a 100644 --- a/src/soc/litex/florent/libresoc/core.py +++ b/src/soc/litex/florent/libresoc/core.py @@ -5,6 +5,13 @@ from migen import ClockSignal, ResetSignal, Signal, Instance, Cat from litex.soc.interconnect import wishbone as wb from litex.soc.cores.cpu import CPU +from soc.debug.jtag import Pins # TODO move to suitable location +from c4m.nmigen.jtag.tap import IOType + +from libresoc.ls180io import make_uart, make_gpio +from litex.build.generic_platform import ConstraintManager + + CPU_VARIANTS = ["standard", "standard32", "standardjtag", "ls180"] @@ -28,6 +35,35 @@ def make_wb_slave(prefix, obj): return res +def make_jtag_ioconn(res, pin, cpupads, iopads): + (fn, pin, iotype, pin_name) = pin + #serial_tx__core__o, serial_rx__pad__i, + print ("cpupads", cpupads) + print ("iopads", iopads) + print ("pin", fn, pin, iotype, pin_name) + cpu = cpupads[fn] + io = iopads[fn] + sigs = [] + + if iotype == IOType.Out: + # output from the pad is routed through C4M JTAG and so + # is an *INPUT* into core. ls180soc connects this to "real" peripheral + res['i_%s_%s_core__o' % (fn, pin)] = getattr(cpu, pin) + res['o_%s_%s_pad__o' % (fn, pin)] = getattr(io, pin) + + elif iotype == IOType.In: + # input to the pad is routed through C4M JTAG and so + # is an *OUTPUT* into core. ls180soc connects this to "real" peripheral + res['o_%s_%s_core__i' % (fn, pin)] = getattr(cpu, pin) + res['i_%s_%s_pad__i' % (fn, pin)] = getattr(io, pin) + + if iotype in (IOType.In, IOType.InTriOut): + sigs.append(("i", 1)) + if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut): + sigs.append(("o", 1)) + if iotype in (IOType.TriOut, IOType.InTriOut): + sigs.append(("oe", 1)) + class LibreSoC(CPU): name = "libre_soc" human_name = "Libre-SoC" @@ -148,6 +184,24 @@ class LibreSoC(CPU): if jtag_en: self.cpu_params.update(make_wb_bus("jtag_wb", jtag_wb, simple=True)) + # urr yuk. have to expose iopads / pins from core to litex + # then back again. cut _some_ of that out by connecting + self.cpuresources = (make_uart('serial', 0), + make_gpio('gpio', 0, 16)) + self.padresources = (make_uart('serial', 0), + make_gpio('gpio', 0, 16)) + self.cpu_cm = ConstraintManager(self.cpuresources, []) + self.pad_cm = ConstraintManager(self.cpuresources, []) + self.cpupads = {'serial': self.cpu_cm.request('serial', 0), + 'gpio': self.cpu_cm.request('gpio', 0)} + self.iopads = {'serial': self.pad_cm.request('serial', 0), + 'gpio': self.pad_cm.request('gpio', 0)} + + p = Pins() + for pin in list(p): + make_jtag_ioconn(self.cpu_params, pin, self.cpupads, + self.iopads) + # add verilog sources self.add_sources(platform) diff --git a/src/soc/litex/florent/libresoc/ls180.py b/src/soc/litex/florent/libresoc/ls180.py index 51d3654e..b7e01ccd 100644 --- a/src/soc/litex/florent/libresoc/ls180.py +++ b/src/soc/litex/florent/libresoc/ls180.py @@ -20,8 +20,10 @@ from migen.fhdl.structure import _Fragment from litex.build.generic_platform import (GenericPlatform, Pins, Subsignal, IOStandard, Misc, ) +from libresoc.ls180io import make_uart, make_gpio import os + # IOs ---------------------------------------------------------------------------------------------- _io = [ @@ -43,18 +45,6 @@ _io = [ Subsignal("sda", Pins("M1"), IOStandard("LVCMOS33")) ), - # UART0: 2 pins - ("serial", 0, - Subsignal("tx", Pins("L4"), IOStandard("LVCMOS33")), - Subsignal("rx", Pins("M1"), IOStandard("LVCMOS33")) - ), - - # UART1: 2 pins - ("serial", 1, - Subsignal("tx", Pins("L4"), IOStandard("LVCMOS33")), - Subsignal("rx", Pins("M1"), IOStandard("LVCMOS33")) - ), - # SPI0: 4 pins ("spi_master", 0, Subsignal("clk", Pins("J1")), @@ -119,22 +109,20 @@ _io = [ ("pwm", 1, Pins("P2"), IOStandard("LVCMOS33")), ] -pins = [] n_gpio = 16 -for i in range(n_gpio): - pins.append("X%d" % i) -pins = ' '.join(pins) # 16 GPIOs -_io.append( ("gpio", 0, - Subsignal("i", Pins(pins), Misc("PULLMODE=UP")), - Subsignal("o", Pins(pins), Misc("PULLMODE=UP")), - Subsignal("oe", Pins(pins), Misc("PULLMODE=UP")), - IOStandard("LVCMOS33")) ) +_io.append( make_gpio("gpio_litex", 0, n_gpio) ) # EINT: 3 pins _io.append( ("eint", 3, Pins("E0 E1 E2"), IOStandard("LVCMOS33")) ) +# UART0: 2 pins +_io.append(make_uart("uart_litex", 0)) +# UART1: 2 pins +_io.append(make_uart("uart_litex", 1)) + + # Platform ----------------------------------------------------------------------------------------- class LS180Platform(GenericPlatform): diff --git a/src/soc/litex/florent/ls180soc.py b/src/soc/litex/florent/ls180soc.py index 4ee35898..0ddea034 100755 --- a/src/soc/litex/florent/ls180soc.py +++ b/src/soc/litex/florent/ls180soc.py @@ -6,7 +6,7 @@ from functools import reduce from operator import or_ from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState, - Cat, Record, ClockSignal, wrap) + Cat, Record, ClockSignal, wrap, ResetInserter) from litex.build.generic_platform import Pins, Subsignal from litex.build.sim import SimPlatform @@ -27,6 +27,7 @@ from litedram.phy.dfi import Interface as DFIInterface from litex.soc.cores.spi import SPIMaster from litex.soc.cores.pwm import PWM from litex.soc.cores.bitbang import I2CMaster +from litex.soc.cores import uart from litex.tools.litex_sim import sdram_module_nphases, get_sdram_phy_settings @@ -250,7 +251,7 @@ class LibreSoCSim(SoCCore): uart_name = "sim" elif platform == 'ls180': platform = LS180Platform() - uart_name = "serial" + uart_name = "uart_litex" #cpu_data_width = 32 cpu_data_width = 64 @@ -291,7 +292,8 @@ class LibreSoCSim(SoCCore): cpu_variant = variant, csr_data_width = 8, l2_size = 0, - uart_name = uart_name, + with_uart = False, + uart_name = None, with_sdram = with_sdram, sdram_module = sdram_module, sdram_data_width = sdram_data_width, @@ -360,9 +362,36 @@ class LibreSoCSim(SoCCore): self.add_constant("MEMTEST_ADDR_DEBUG", 1) self.add_constant("MEMTEST_DATA_DEBUG", 1) + # UART + uart_core_pads = self.cpu.cpupads['serial'] + self.submodules.uart_phy = uart.UARTPHY( + pads = uart_core_pads, + clk_freq = self.sys_clk_freq, + baudrate = 115200) + self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy, + tx_fifo_depth = 16, + rx_fifo_depth = 16)) + # "real" pads connect to C4M JTAG iopad + uart_pads = platform.request(uart_name) # "real" (actual) pin + uart_io_pads = self.cpu.iopads['serial'] # C4M JTAG pads + self.comb += uart_pads.tx.eq(uart_io_pads.tx) + self.comb += uart_io_pads.rx.eq(uart_pads.rx) + + self.csr.add("uart_phy", use_loc_if_exists=True) + self.csr.add("uart", use_loc_if_exists=True) + self.irq.add("uart", use_loc_if_exists=True) + # GPIOs (bi-directional) - self.submodules.gpio = GPIOTristateASIC(platform.request("gpio")) - self.add_csr("gpio") + if False: + gpio_core_pads = self.cpu.cpupads['gpio'] + self.submodules.gpio = GPIOTristateASIC(gpio_core_pads) + self.add_csr("gpio") + + gpio_pads = platform.request("gpio_litex") + gpio_io_pads = self.cpu.iopads['gpio'] # C4M JTAG pads + self.comb += gpio_pads.i.eq(gpio_io_pads.i) + self.comb += gpio_io_pads.o.eq(gpio_pads.o) + self.comb += gpio_io_pads.oe.eq(gpio_pads.oe) # SPI Master self.submodules.spi_master = SPIMaster( -- 2.30.2