Litex: * SPI master * SPI sdcard * UART (tx/rx) * SDRAM (SDR) * GPIO (16) * EINT (2) * PWM (3) * I2C master * SDMMC * JTAG
ok i cranked the priority down just a leeetle bit :) i also just committed some preliminary changes, cut out the pins not needed, put in that verilog stuff we talked about commit 093ddebb6ba44f3edd291d699d775c6821b8d620 (HEAD -> master, origin/master) Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net> Date: Wed Sep 16 22:54:15 2020 +0100 make a start on LS180 platform
next bit is to hook up chips4makers jtag which has a wishbone bus master on it, and investigate ways to test it.
Current way of testing for JTAG implemented in Chips4Makers JTAG is use of cocotb and .svf files. .svf files are standardized text format for running tests through JTAG. In the Chips4Makers repo is a cocotb infrastructure for playing back these .svf files in a RTL simulation. I used cocotb as in the Retro-uC some nmigen modules are used which are wrapper around VHDL and Verilog code and pysim can't handle those. In theory now cxxsim should be able to handle anything yosys can synthesize. For pure nmigen code maybe the JTAG simulation infrastructure could be ported from cocotb to pysim/cxxsim. But I guess due to the use of litex the libre-SOC won't be a pure nmigen design either. Nice thing is that the tested .svf files in simulation could also be used later to test the chips. For Retro-uC I actually did both test .svf file in cocotb and later on FPGA using openOCD to play the .svf file.
(In reply to Staf Verhaegen from comment #3) > For pure nmigen code maybe the JTAG simulation infrastructure could be ported > from cocotb to pysim/cxxsim. But I guess due to the use of litex the > libre-SOC > won't be a pure nmigen design either. no, however i can at least do a basic unit test in nmigen, checking that JTAG creates WB requests correctly. > > Nice thing is that the tested .svf files in simulation could also be used > later to test the chips. For Retro-uC I actually did both test .svf file in > cocotb and later on FPGA using openOCD to play the .svf file. i like it! i would really like to work out how to use coriolis2 simulation of the netlist / transistors, at some point.
ok so you scan/parse the svf file and then can send jtag commands through cocotb to the hardware? https://gitlab.com/Chips4Makers/c4m-jtag/-/blob/master/c4m/cocotb/jtag/c4m_jtag_svfcocotb.py that should be pretty easy to adapt to nmigen.
//-------------------------------------------------------------------------------- // Auto-generated by Migen (731c192) & LiteX (35929c0f) on 2020-09-18 23:11:06 //-------------------------------------------------------------------------------- module sim( output reg serial_tx, input wire serial_rx, input wire sys_clk, output reg [12:0] sdram_a, inout wire [15:0] sdram_dq, output reg sdram_we_n, output reg sdram_ras_n, output reg sdram_cas_n, output reg sdram_cs_n, output reg sdram_cke, output reg [1:0] sdram_ba, output reg [1:0] sdram_dm, input wire [7:0] gpio_in, input wire [7:0] gpio_out, output reg spi_master_clk, output reg spi_master_mosi, output reg spi_master_cs_n, input wire spi_master_miso, output reg sdcard_clk, inout wire sdcard_cmd, inout wire [3:0] sdcard_data, output reg spisdcard_clk, output reg spisdcard_mosi, output reg spisdcard_cs_n, input wire spisdcard_miso ); ha! this is progressing much faster than i expected. Staf: for GPIO what is the definition of the IO pads? should we do very simple 8x GPIO-in and 8x GPIO-out, and not try to mix the two? i am tempted to go this route because i means not having to write any Litex code. if we try a GPIO bi-directional IOpad it would mean having to write some Litex code to add the CSRs for switching the direction, and to output verilog code-fragments maybe actually adding that to migen (!) i really do not want to do that.
It's up to you to decide, I do have preference to have the bidirectional possibility for GPIO. For bidirectional IO you should get have three signal ending op _i, _o and _oe. If I remember correctly I think TriState from migen should give these signals. How the value of the oe signal is best handled in Litex I leave that up to you.
(In reply to Staf Verhaegen from comment #7) > It's up to you to decide, I do have preference to have the bidirectional > possibility for GPIO. > For bidirectional IO you should get have three signal ending op _i, _o and > _oe. If I remember correctly I think TriState from migen should give these > signals. How the value of the oe signal is best handled in Litex I leave > that up to you. ah excellent, so as long as migen supports that and you're happy with it then i am too. the last thing i wanted was to be writing migen code.
hm. litex is generating the following verilog: module ls180( input wire [15:0] gpio, ); wire [15:0] main_pads; wire main_tstriple0_o; wire main_tstriple0_oe; assign main_pads[0] = main_tstriple0_oe ? main_tstriple0_o : 1'bz; assign main_tstriple0_i = main_pads[0]; all of which looks dodgy to me. gpio is an input only, for a start. plus, i would kinda expect that those 3 _o, _oe and _i would be "externally exposed" so you could connect them up manually. don't know. am putting it back to 8-in 8-out for now.
running into yosys massive amounts of memory issues (12GB) <daveshah> The solution will either to have LiteX use memory compiler primitives instead; or remove all calls to memory_map in your Yosys script so you are left with $mem cells (less ideal but maybe you can use memory_bram to map them to your ASIC primitives)
Removing $memory\mem[6227]$68502 ($dff) from module ls180. Removing $memory\mem[6226]$68500 ($dff) from module ls180. Removing $memory\mem[6225]$68498 ($dff) from module ls180. Removing $memory\mem[6224]$68496 ($dff) from module ls180. Removing $memory\mem[6223]$68494 ($dff) from module ls180. Removing $memory\mem[6222]$68492 ($dff) from module ls180. Removing $memory\mem[6221]$68490 ($dff) from module ls180. Removing $memory\mem[6220]$68488 ($dff) from module ls180. Removing $memory\mem[6219]$68486 ($dff) from module ls180. Removing $memory\mem[6218]$68484 ($dff) from module ls180.
New connections: $memory\mem$rdmux[0][7][48]$b$89345 [13] = $memory\mem$rdmux[0][7][48]$b$89345 [11] Consolidated identical input bits for $mux cell $memory\mem$rdmux[0][8][98]$89877: Old ports: A=$memory\mem$rdmux[0][8][98]$a$89878, B=$memory\mem$rdmux[0][8][98]$b$89879, Y=$memory\mem$rdmux[0][7][49]$a$89347 New ports: A={ $memory\mem$rdmux[0][8][98]$a$89878 [31:26] $memory\mem$rdmux[0][8][98]$a$89878 [24:21] $memory\mem$rdmux[0][8][98]$a$89878
(In reply to Staf Verhaegen from comment #3) > For pure nmigen code maybe the JTAG simulation infrastructure could be ported > from cocotb to pysim/cxxsim. But I guess due to the use of litex the i have a *very* basic unit test now with DMI2JTAG operational and reading IDCODE https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/debug/dmi2jtag.py;h=119aaf9860ff0f52e93f8fd2945cd7333c1a9962;hb=fd902da6f694e68a4c664786fd02857866d90d3e#l239 staf looking at the VCD files it seems that the addresses are stored in reverse-bit-order which is quite interesting but has no impact on functionality i may add one more unit test (JTAG wishbone read/write) and then i am going to add this to ls180. staf it would be nice to have DMI2TAG added to c4m jtag tap.py
https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/debug/dmi2jtag.py;h=24aa9d7956a75e590791730f6c593f2da2370b5d;hb=HEAD#l289 that works.
currently investigating JTAGREMOTE module in litex https://github.com/enjoy-digital/litex/blob/master/litex/build/sim/core/modules/jtagremote/jtagremote.c this *should* make it possible to speak "openocd bitbang" remotely, by linking jtag simulated pins to a TCP port. also to investigate: https://github.com/lowRISC/opentitan/tree/master/hw/dv/dpi/jtagdpi https://github.com/lowRISC/opentitan/blob/master/util/openocd/target/lowrisc-earlgrey.cfg https://github.com/lowRISC/opentitan/blob/master/util/openocd/interface/sim-jtagdpi.cfg
Staf: i just managed to (successfully) get openocd connected to litex "jtagremote" module under simulation. Info : JTAG tap: libresoc.tap tap/device found: 0x000018ff (mfg: 0x47f (<invalid>), part: 0x0001, ver: 0x0) however i had to add this to the openocd.cfg file: jtag newtap libresoc tap -irlen 1 -expected-id 0x000018ff that should be "irlen 4" because i set ir_width=4. the only reason i can think of why that would happen is if the bit-order for IR is inverted in c4m JTAG.
Would be strange if such a bug would be there as I successfully tested JTAG interface with openocd on FPGA. See for example this video: https://chips4makers.io/blog/blink-demo.html#blink-demo I don't know though if this was still using the VHDL version of the JTAG interface or the nmigen one. Anyway won't have time in near future to look deeper into this.
(In reply to Staf Verhaegen from comment #17) > Would be strange if such a bug would be there as I successfully tested JTAG > interface with openocd on FPGA. > See for example this video: > https://chips4makers.io/blog/blink-demo.html#blink-demo > I don't know though if this was still using the VHDL version of the JTAG > interface or the nmigen one. this is pure nmigen (c4m). i got it to "work" with this in openocd: jtag newtap libresoc tap -irlen 4 -irmask 0xf -ircapture 0xf -expected-id 0x000018ff > Anyway won't have time in near future to look deeper into this. ok. i will investigate more in-depth tomorrow after sorting out some alternative to openocd.
idk if we will have time, but it might be useful to implement gdb's remote protocol over a serial port.
(In reply to Jacob Lifshay from comment #19) > idk if we will have time, but it might be useful to implement gdb's remote > protocol over a serial port. in RTL? very unlikely. turns out that openocd (which is "working" for a given definition of "work") can talk gdb on one side and remote-network protocol on the other.
i've redesigned litex GPIO and SD/MMC Card to have signals that comprise "gpio_i", "gpio_o", "gpio_oe" and the same for sdcard cmd and data. this involves literally cut/pasting verbatim the entire litex GPIO and SDCard classes, duplicating the code, and replacing the pinout class with a suitable replacement. it's a mess, and the same mess will extend to SDRAM. FORTNUATELY, for SDRAM, the concept of alternative PHYs is an established practice, so i "only" have to create a replacement that munges the names of dq into triple-functions dq_i, dq_o, dq_en
(In reply to Luke Kenneth Casson Leighton from comment #21) > FORTNUATELY, for SDRAM, the concept of alternative PHYs is an > established practice, so i "only" have to create a replacement > that munges the names of dq into triple-functions dq_i, dq_o, dq_en done. commit 28638852cc74861c4fb5095aa1e712f26b3f364a (HEAD -> master, origin/master) Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net> Date: Wed Sep 23 22:44:56 2020 +0100 change litex sdram pinouts to ASIC type
sfaf should i be calling c4m_jtag TAP.add_io for *all* pins? that seems somewhat excessive, and now that i think about it it's a *lot* of work: * call add_ios in nmigen * expose both the pad wires *and* the the jtag-io wires (IOConn Record) * add all IOConn records to the litex libresoc core.py code * get litex to generate the ls180.v * join up the libresoc core (in verilog) to ls180.v * re-import ls180.v into nmigen * *finally* wire up the connections between jtag-io and pads i might actually do that last step in litex (ls180soc.py) to save some messing about, and reduce the number of wires routed between different compilers. so if it's ok with you i'm going to do the 16 GPIO, and the 2nd UART. this will cover: * IOType.In (uart1 rx) * IOType.Out (uart1 rx) * IOType.InTriOut (gpios 0-15 yes i worked out how to do o/i/oe) also: do you have a template for re-building the actual SoC with the c4m IO cells? i can throw something together if not but i will need some guidance / pointer-to-some-code.
(In reply to Luke Kenneth Casson Leighton from comment #23) > sfaf should i be calling c4m_jtag TAP.add_io for *all* pins? that > seems somewhat excessive, Currently only the low-level implementation of the JTAG interface is finished where you create for each IO cell a corresponding IOConn. For higher level implementation is to integrate JTAG interface inside the nmigen platform. Just like you now have XilinxPlatform you would also have ASICPlatform or C4MPlatform. If possible I would like it to implement so that using .add_resources() you could define the type of the cells (e.g. pin 2,3 are UART). The platform would then automatically instantiate the right IO cell and add it to the JTAG boundary scan. Unfortunately this is still TODO. > and now that i think about it it's a *lot* of work: > > * call add_ios in nmigen > * expose both the pad wires *and* the the jtag-io wires (IOConn Record) > * add all IOConn records to the litex libresoc core.py code > * get litex to generate the ls180.v > * join up the libresoc core (in verilog) to ls180.v > * re-import ls180.v into nmigen > * *finally* wire up the connections between jtag-io and pads Why do you need to bring IOConn into litex ? * You define peripherals in litex * You get a verilog file out of litex with the IO signals as inputs and outputs of the top verilog module. * You bring this top verilog cell in nmigen using Instance() * For each IO you do an add_io() on the TAP and connect the corresponding signals from the litex top in nmigen to the core part of the IOConn. The pad part of the IOConn you bring out as the new top signal in a generated verilog file. * This new top goes then to synthesis and P&R > > i might actually do that last step in litex (ls180soc.py) to save some > messing about, and reduce the number of wires routed between different > compilers. > > so if it's ok with you i'm going to do the 16 GPIO, and the 2nd UART. > this will cover: > > * IOType.In (uart1 rx) > * IOType.Out (uart1 rx) > * IOType.InTriOut (gpios 0-15 yes i worked out how to do o/i/oe) > > also: do you have a template for re-building the actual SoC with the > c4m IO cells? i can throw something together if not but i will need > some guidance / pointer-to-some-code. As said above, for the moment bring out the pad part of the IOConns as input/outputs of the top verilog file together with clk and rst. I will see with Jean-Paul how we add the IO cells to it. Later on also the nmigen platform should take care of this and instantiate the right IO cells but as said this is currently not implemented.
ok i have just finished (not tested yet), it will need review and testing. (In reply to Staf Verhaegen from comment #24) > (In reply to Luke Kenneth Casson Leighton from comment #23) > > sfaf should i be calling c4m_jtag TAP.add_io for *all* pins? that > > seems somewhat excessive, > > Currently only the low-level implementation of the JTAG interface is > finished where you create for each IO cell a corresponding IOConn. yes. i do that here at line 47: https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/debug/jtag.py;hb=HEAD#l47 > For > higher level implementation is to integrate JTAG interface inside the nmigen > platform. yes, that's > Just like you now have XilinxPlatform you would also have > ASICPlatform or C4MPlatform. yes, this is here (ls180.py) which derives from GenericPlatform, it would form the basis of an ASICPlatform https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/litex/florent/libresoc/ls180.py;hb=HEAD > If possible I would like it to implement so > that using .add_resources() you could define the type of the cells (e.g. pin > 2,3 are UART). at some point i want to completely replace litex with something similar to OpenTITAN except written in nmigen. > The platform would then automatically instantiate the right > IO cell and add it to the JTAG boundary scan. > Unfortunately this is still TODO. i have some partial infrastructure done, today, it is not fully automatic because that would need a lot more work in litex and i am not prepared to commit huge resources to something that's based on an unstable base (migen). however.... i import the same "Pins" structure from soc.debug.jtag and use exactly that in the litex core.py to create the "map" from the (now verilog) core to litex: https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/litex/florent/libresoc/core.py;hb=HEAD that is done at line 220 (declare another instance of Pins, similar to back in soc/debug/jtag.py line 47, and enumerate them) > Why do you need to bring IOConn into litex ? because something has to connect up the IOConn to the actual litex peripheral pads. there are two ways to do it: 1) get litex to do it 2) get nmigen to do it. this 2nd way requires passing the peripheral signals *in* to the verilog instantiation of the core (test_issuer.v): litex still therefore needs to know what they are, in some fashion. i decided to go (2) because it greatly simplifies the "third stage" - the nmigen "instantiation" of the combined litex-core verilog file. all that the final phase needs to do now is: connect to the IO pads. and i *think*... that actually might be a "null operation". less work for you! > * You define peripherals in litex > * You get a verilog file out of litex with the IO signals as inputs and > outputs of the top verilog module. > * You bring this top verilog cell in nmigen using Instance() ah, unfortunately, the litex sim code assumes that the nmigen test_issuer is a verilog instance. > * For each IO you do an add_io() on the TAP and connect the corresponding > signals from the litex top in nmigen to the core part of the IOConn. this is the bit that i have already done *before* it goes into litex. why? well... how can you call add_io on the tap *after* the TAP was created in the *first* one? and: how can we run a nmigen simulation of the TAP.add_io() calls if it is brought in as a verilog instance? we can't. it would have to be done through verilator (which has to be written) or cocotb (which has to be written) both of which are time-consuming > The pad > part of the IOConn you bring out as the new top signal in a generated > verilog file. i have implemented it slightly differently, but making exactly the same connections. instead of nmigen (3rd phase) instantiating the TAP and calling TAP.add_io it is done in the FIRST phase (because it is one JTAG class instance, the same one used for Wishbone and DMI) > As said above, for the moment bring out the pad part of the IOConns as > input/outputs of the top verilog file together with clk and rst. already done, connected up, the pad parts of the IOConns are connected in litex [1] for GPIO, [2] for UART so the phase (3) $Instance is, i have a feeling, basically not needed. > I will see > with Jean-Paul how we add the IO cells to it. > Later on also the nmigen platform should take care of this and instantiate > the right IO cells but as said this is currently not implemented. ok. well, aside from unit tests which i will look at tomorrow, that is currently the blocker for this because it's done. [1] GPIO ls180soc IOconn pad connections https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/litex/florent/ls180soc.py;h=9c7547f7078522cedccb5cc38f2beed6e58b7f6b;hb=HEAD#l389 [2] UART ls180soc IOconn pad connections https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/litex/florent/ls180soc.py;h=9c7547f7078522cedccb5cc38f2beed6e58b7f6b;hb=HEAD#l374
(In reply to Luke Kenneth Casson Leighton from comment #25) > > For > > higher level implementation is to integrate JTAG interface inside the nmigen > > platform. > > yes, that's an unfinished sentence :) that's what i've done. everything is declared back in nmigen: * TAP.add_ios * TAP.add_wishbone * TAP.add_dmi otherwise we cannot run nmigen simulation unit tests of the IOConns.
these are now defined by pinmux ls180 spec https://git.libre-soc.org/?p=pinmux.git;a=blob;f=src/spec/ls180.py;hb=HEAD the nmigen JTAG module sets up IOconn instances and also takes a pinset. https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/debug/jtag.py;hb=HEAD the pinset dictionary currently hardcoded as dummy_pinset() is now autogenerated by the pinmux Issuer creates one of these JTAG modules and through the pinset creates a suite of ports (JTAG core and io pads) which end up in the public interface in the verilog module. https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/simple/issuer.py;hb=HEAD#l83 using the EXACT same pinmux Pin definitions, Litex LS180Platform creates two sets of IO resources, one for JTAG pads one for JTAG core and connects up the core ones to the test_issuer verilog with make_jtag_conn https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/litex/florent/libresoc/core.py;hb=HEAD#l236 where a "normal" litex core would connect direct to the *platform* IO resource, because JTAG has been connected to that litex instead connects to the *CPU* IO resource(s) which were routed via the JTAG IOconn MUXes and back out again through test_issuer https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/litex/florent/ls180soc.py;hb=HEAD#l431 in the coriolis2 layout the ioring is created by using once again the EXACT same pinmux spec to create a JSON file with the mappings between LITEX peripheral names and coriolis2 IO pin names https://git.libre-soc.org/?p=soclayout.git;a=blob;f=experiments9/coriolis2/ioring.py;hb=HEAD in this way we get automated centrally specified IO without getting into a manual duplication mess.
declaring this one done, moving to coriolis2 project as it was needed for the layout to complete. staf EUR 250 for the help with JTAG TAP