1 # Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2 # Copyright (c) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Copyright (C) 2022 Raptor Engineering, LLC <support@raptorengineering.com>
5 # Based on code from LambaConcept, from the gram example which is BSD-2-License
6 # https://github.com/jeanthom/gram/tree/master/examples
8 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
9 # under EU Grants 871528 and 957073, under the LGPLv3+ License
11 from nmigen
import (Module
, Elaboratable
, DomainRenamer
, Record
,
12 Signal
, Cat
, Const
, ClockSignal
, ResetSignal
)
13 from nmigen
.build
.dsl
import Attrs
14 from nmigen
.cli
import verilog
15 from nmigen
.lib
.cdc
import ResetSynchronizer
16 from nmigen_soc
import wishbone
, memory
17 from nmigen_soc
.memory
import MemoryMap
18 from nmigen
.utils
import log2_int
20 from nmigen_stdio
.serial
import AsyncSerial
23 from nmigen_boards
.resources
.memory
import HyperRAMResource
24 from lambdasoc
.periph
.hyperram
import HyperRAM
, HyperRAMPads
, HyperRAMPHY
26 from lambdasoc
.periph
.intc
import GenericInterruptController
27 from lambdasoc
.periph
.sram
import SRAMPeripheral
28 from lambdasoc
.periph
.timer
import TimerPeripheral
29 from lambdasoc
.periph
import Peripheral
30 from lambdasoc
.soc
.base
import SoC
31 from soc
.bus
.uart_16550
import UART16550
# opencores 16550 uart
32 from soc
.bus
.tercel
import Tercel
# SPI XIP master
33 from soc
.bus
.external_core
import ExternalCore
# external libresoc/microwatt
34 from soc
.bus
.wb_downconvert
import WishboneDownConvert
35 from soc
.bus
.syscon
import MicrowattSYSCON
38 from gram
.common
import (PhySettings
, get_cl_cw
, get_sys_latency
,
40 from gram
.core
import gramCore
41 from gram
.phy
.ecp5ddrphy
import ECP5DDRPHY
42 from gram
.phy
.fakephy
import FakePHY
, SDRAM_VERBOSE_STD
, SDRAM_VERBOSE_DBG
43 from gram
.modules
import MT41K256M16
, MT41K64M16
44 from gram
.frontend
.wishbone
import gramWishbone
46 # Board (and simulation) platforms
47 from nmigen_boards
.versa_ecp5
import VersaECP5Platform
48 from nmigen_boards
.versa_ecp5
import VersaECP5Platform85
# custom board
49 from nmigen_boards
.ulx3s
import ULX3S_85F_Platform
50 from nmigen_boards
.arty_a7
import ArtyA7_100Platform
51 from nmigen_boards
.test
.blinky
import Blinky
52 from icarusversa
import IcarusVersaPlatform
53 # Clock-Reset Generator (works for all ECP5 platforms)
54 from ecp5_crg
import ECP5CRG
55 from arty_crg
import ArtyA7CRG
60 def sim_ddr3_settings(clk_freq
=100e6
):
61 tck
= 2/(2*2*clk_freq
)
67 cl
, cwl
= get_cl_cw("DDR3", tck
)
68 cl_sys_latency
= get_sys_latency(nphases
, cl
)
69 cwl_sys_latency
= get_sys_latency(nphases
, cwl
)
70 rdcmdphase
, rdphase
= get_sys_phases(nphases
, cl_sys_latency
, cl
)
71 wrcmdphase
, wrphase
= get_sys_phases(nphases
, cwl_sys_latency
, cwl
)
76 dfi_databits
=4*databits
,
81 rdcmdphase
=rdcmdphase
,
82 wrcmdphase
=wrcmdphase
,
85 read_latency
=2 + cl_sys_latency
+ 2 + log2_int(4//nphases
) + 4,
86 write_latency
=cwl_sys_latency
90 class WB64to32Convert(Elaboratable
):
91 """Microwatt IO wishbone slave 64->32 bits converter
93 For timing reasons, this adds a one cycle latch on the way both
94 in and out. This relaxes timing and routing pressure on the "main"
95 memory bus by moving all simple IOs to a slower 32-bit bus.
97 This implementation is rather dumb at the moment, no stash buffer,
98 so we stall whenever that latch is busy. This can be improved.
100 def __init__(self
, master
, slave
):
104 def elaborate(self
, platform
):
106 comb
, sync
= m
.d
.comb
, m
.d
.sync
107 master
, slave
= self
.master
, self
.slave
114 with m
.State("IDLE"):
115 # Clear ACK (and has_top_r) in case it was set
116 sync
+= master
.ack
.eq(0)
117 sync
+= has_top_r
.eq(0)
119 # Do we have a cycle ?
120 with m
.If(master
.cyc
& master
.stb
):
121 # Stall master until we are done, we are't (yet) pipelining
122 # this, it's all slow IOs.
123 sync
+= master
.stall
.eq(1)
125 # Start cycle downstream
126 sync
+= slave
.cyc
.eq(1)
127 sync
+= slave
.stb
.eq(1)
129 # Do we have a top word and/or a bottom word ?
130 comb
+= has_top
.eq(master
.sel
[4:].bool())
131 comb
+= has_bot
.eq(master
.sel
[:4].bool())
132 # record the has_top flag for the next FSM state
133 sync
+= has_top_r
.eq(has_top
)
135 # Copy write enable to IO out, copy address as well,
136 # LSB is set later based on HI/LO
137 sync
+= slave
.we
.eq(master
.we
)
138 sync
+= slave
.adr
.eq(Cat(0, master
.adr
))
140 # If we have a bottom word, handle it first, otherwise
141 # send the top word down. XXX Split the actual mux out
142 # and only generate a control signal.
144 with m
.If(master
.we
):
145 sync
+= slave
.dat_w
.eq(master
.dat_w
[:32])
146 sync
+= slave
.sel
.eq(master
.sel
[:4])
148 # Wait for ack on BOTTOM half
149 m
.next
= "WAIT_ACK_BOT"
152 with m
.If(master
.we
):
153 sync
+= slave
.dat_w
.eq(master
.dat_w
[32:])
154 sync
+= slave
.sel
.eq(master
.sel
[4:])
156 # Bump LSB of address
157 sync
+= slave
.adr
[0].eq(1)
159 # Wait for ack on TOP half
160 m
.next
= "WAIT_ACK_TOP"
163 with m
.State("WAIT_ACK_BOT"):
164 # If we aren't stalled by the device, clear stb
165 if hasattr(slave
, "stall"):
166 with m
.If(~slave
.stall
):
167 sync
+= slave
.stb
.eq(0)
170 with m
.If(slave
.ack
):
171 # If it's a read, latch the data
172 with m
.If(~slave
.we
):
173 sync
+= master
.dat_r
[:32].eq(slave
.dat_r
)
175 # Do we have a "top" part as well ?
176 with m
.If(has_top_r
):
178 with m
.If(master
.we
):
179 sync
+= slave
.dat_w
.eq(master
.dat_w
[32:])
180 sync
+= slave
.sel
.eq(master
.sel
[4:])
182 # Bump address and set STB
183 sync
+= slave
.adr
[0].eq(1)
184 sync
+= slave
.stb
.eq(1)
187 m
.next
= "WAIT_ACK_TOP"
190 # We are done, ack up, clear cyc downstram
191 sync
+= slave
.cyc
.eq(0)
192 sync
+= slave
.stb
.eq(0)
194 # And ack & unstall upstream
195 sync
+= master
.ack
.eq(1)
196 if hasattr(master
, "stall"):
197 sync
+= master
.stall
.eq(0)
202 with m
.State("WAIT_ACK_TOP"):
203 # If we aren't stalled by the device, clear stb
204 if hasattr(slave
, "stall"):
205 with m
.If(~slave
.stall
):
206 sync
+= slave
.stb
.eq(0)
209 with m
.If(slave
.ack
):
210 # If it's a read, latch the data
211 with m
.If(~slave
.we
):
212 sync
+= master
.dat_r
[32:].eq(slave
.dat_r
)
214 # We are done, ack up, clear cyc downstram
215 sync
+= slave
.cyc
.eq(0)
216 sync
+= slave
.stb
.eq(0)
218 # And ack & unstall upstream
219 sync
+= master
.ack
.eq(1)
220 if hasattr(master
, "stall"):
221 sync
+= master
.stall
.eq(0)
229 class DDR3SoC(SoC
, Elaboratable
):
230 def __init__(self
, *,
233 uart_pins
, spi_0_pins
,
234 ddr_pins
, ddrphy_addr
, dramcore_addr
, ddr_addr
,
237 spi0_addr
, spi0_cfg_addr
,
243 # wishbone routing is as follows:
256 # +---decoder----+--------+---------+-------+
258 # uart XICS CSRs DRAM XIP SPI HyperRAM
260 # set up wishbone bus arbiter and decoder. arbiter routes,
261 # decoder maps local-relative addressed satellites to global addresses
262 self
._arbiter
= wishbone
.Arbiter(addr_width
=30, data_width
=32,
264 features
={"cti", "bte", "stall"})
265 self
._decoder
= wishbone
.Decoder(addr_width
=30, data_width
=32,
267 features
={"cti", "bte", "stall"})
269 # default firmware name
271 firmware
= "firmware/main.bin"
273 # set up clock request generator
275 if fpga
in ['versa_ecp5', 'versa_ecp5_85', 'isim', 'ulx3s']:
278 self
.crg
= ECP5CRG(clk_freq
, pod_bits
)
279 if fpga
in ['arty_a7']:
280 self
.crg
= ArtyA7CRG(clk_freq
)
282 # set up CPU, with 64-to-32-bit downconverters
284 self
.cpu
= ExternalCore(name
="ext_core")
285 cvtdbus
= wishbone
.Interface(addr_width
=30, data_width
=32,
286 granularity
=8, features
={'stall'})
287 cvtibus
= wishbone
.Interface(addr_width
=30, data_width
=32,
288 granularity
=8, features
={'stall'})
289 self
.dbusdowncvt
= WB64to32Convert(self
.cpu
.dbus
, cvtdbus
)
290 self
.ibusdowncvt
= WB64to32Convert(self
.cpu
.ibus
, cvtibus
)
291 self
._arbiter
.add(cvtibus
) # I-Cache Master
292 self
._arbiter
.add(cvtdbus
) # D-Cache Master. TODO JTAG master
293 self
.cvtibus
= cvtibus
294 self
.cvtdbus
= cvtdbus
296 # CPU interrupt controller
297 self
.intc
= GenericInterruptController(width
=len(self
.cpu
.irq
))
299 # SRAM (but actually a ROM, for firmware), at address 0x0
300 if fw_addr
is not None:
302 self
.bootmem
= SRAMPeripheral(size
=0x8000, data_width
=sram_width
,
304 if firmware
is not None:
305 with
open(firmware
, "rb") as f
:
306 words
= iter(lambda: f
.read(sram_width
// 8), b
'')
307 bios
= [int.from_bytes(w
, "little") for w
in words
]
308 self
.bootmem
.init
= bios
309 self
._decoder
.add(self
.bootmem
.bus
, addr
=fw_addr
) # ROM at fw_addr
311 # System Configuration info
312 self
.syscon
= MicrowattSYSCON(sys_clk_freq
=clk_freq
,
313 has_uart
=(uart_pins
is not None))
314 self
._decoder
.add(self
.syscon
.bus
, addr
=0xc0000000) # at 0xc000_0000
317 # SRAM (read-writeable BRAM)
318 self
.ram
= SRAMPeripheral(size
=4096)
319 self
._decoder
.add(self
.ram
.bus
, addr
=0x8000000) # at 0x8000_0000
321 # UART at 0xC000_2000, convert 32-bit bus down to 8-bit in an odd way
322 if uart_pins
is not None:
323 # sigh actual UART in microwatt is 8-bit
324 self
.uart
= UART16550(data_width
=8, pins
=uart_pins
,
326 # but (see soc.vhdl) 8-bit regs are addressed at 32-bit locations
327 cvtuartbus
= wishbone
.Interface(addr_width
=5, data_width
=32,
330 umap
= MemoryMap(addr_width
=7, data_width
=8, name
="uart_map")
331 cvtuartbus
.memory_map
= umap
332 self
._decoder
.add(cvtuartbus
, addr
=0xc0002000) # 16550 UART addr
333 self
.cvtuartbus
= cvtuartbus
335 # SDRAM module using opencores sdr_ctrl
337 class MT48LC16M16(SDRModule):
343 technology_timings = _TechnologyTimings(tREFI=64e6/8192,
347 speedgrade_timings = {"default": _SpeedgradeTimings(tRP=20,
356 if ddr_pins
is not None or fpga
== 'sim':
357 ddrmodule
= dram_cls(clk_freq
, "1:2") # match DDR3 ASIC P/N
360 drs
= DomainRenamer("dramsync")
363 self
.ddrphy
= FakePHY(module
=ddrmodule
,
364 settings
=sim_ddr3_settings(clk_freq
),
365 verbosity
=SDRAM_VERBOSE_DBG
,
368 self
.ddrphy
= drs(ECP5DDRPHY(ddr_pins
, sys_clk_freq
=clk_freq
))
369 self
._decoder
.add(self
.ddrphy
.bus
, addr
=ddrphy_addr
)
371 dramcore
= gramCore(phy
=self
.ddrphy
,
372 geom_settings
=ddrmodule
.geom_settings
,
373 timing_settings
=ddrmodule
.timing_settings
,
376 self
.dramcore
= dramcore
378 self
.dramcore
= drs(dramcore
)
379 self
._decoder
.add(self
.dramcore
.bus
, addr
=dramcore_addr
)
381 # map the DRAM onto Wishbone, XXX use stall but set classic below
382 drambone
= gramWishbone(dramcore
, features
={'stall'})
384 self
.drambone
= drambone
386 self
.drambone
= drs(drambone
)
387 self
._decoder
.add(self
.drambone
.bus
, addr
=ddr_addr
)
390 if spi_0_pins
is not None and fpga
in ['sim',
391 'rcs_arctic_tern_bmc_card']:
392 # The Lattice ECP5 devices require special handling on the
393 # dedicated SPI clock line, which is shared with the internal
394 # SPI controller used for FPGA bitstream loading.
395 spi0_is_lattice_ecp5_clk
= False
396 if platform
is not None and fpga
in ['versa_ecp5',
397 'rcs_arctic_tern_bmc_card',
399 spi0_is_lattice_ecp5_clk
= True
401 # Tercel contains two independent Wishbone regions, a
402 # configuration region and the direct API access region,
403 # Set the SPI 0 access region to 16MB, as the FPGA
404 # bitstream Flash device is unlikely to be larger than this.
405 # The main SPI Flash (SPI 1) should be set to at
406 # least 28 bits (256MB) to allow the use of large 4BA devices.
407 self
.spi0
= Tercel(data_width
=32, spi_region_addr_width
=24,
410 lattice_ecp5_usrmclk
=spi0_is_lattice_ecp5_clk
)
411 self
._decoder
.add(self
.spi0
.bus
, addr
=spi0_addr
)
412 self
._decoder
.add(self
.spi0
.cfg_bus
, addr
=spi0_cfg_addr
)
414 # HyperRAM modules *plural*. Assumes using a Quad PMOD by Piotr
415 # Esden, sold by 1bitsquared, only doing one CS_N enable at the
417 if hyperram_pins
is not None:
418 self
.hyperram
= HyperRAM(io
=hyperram_pins
, phy_kls
=HyperRAMPHY
,
420 self
._decoder
.add(self
.hyperram
.bus
, addr
=hyperram_addr
)
422 self
.memory_map
= self
._decoder
.bus
.memory_map
424 self
.clk_freq
= clk_freq
426 def elaborate(self
, platform
):
430 # add the peripherals and clock-reset-generator
431 if platform
is not None and hasattr(self
, "crg"):
432 m
.submodules
.sysclk
= self
.crg
434 if hasattr(self
, "bootmem"):
435 m
.submodules
.bootmem
= self
.bootmem
436 m
.submodules
.syscon
= self
.syscon
437 if hasattr(self
, "ram"):
438 m
.submodules
.ram
= self
.ram
439 if hasattr(self
, "uart"):
440 m
.submodules
.uart
= self
.uart
441 comb
+= self
.uart
.cts_i
.eq(1)
442 comb
+= self
.uart
.dsr_i
.eq(1)
443 comb
+= self
.uart
.ri_i
.eq(0)
444 comb
+= self
.uart
.dcd_i
.eq(1)
445 # sigh connect up the wishbone bus manually to deal with
446 # the mis-match on the data
447 uartbus
= self
.uart
.bus
448 comb
+= uartbus
.adr
.eq(self
.cvtuartbus
.adr
)
449 comb
+= uartbus
.stb
.eq(self
.cvtuartbus
.stb
)
450 comb
+= uartbus
.cyc
.eq(self
.cvtuartbus
.cyc
)
451 comb
+= uartbus
.sel
.eq(self
.cvtuartbus
.sel
)
452 comb
+= uartbus
.we
.eq(self
.cvtuartbus
.we
)
453 comb
+= uartbus
.dat_w
.eq(self
.cvtuartbus
.dat_w
) # drops 8..31
454 comb
+= self
.cvtuartbus
.dat_r
.eq(uartbus
.dat_r
) # drops 8..31
455 comb
+= self
.cvtuartbus
.ack
.eq(uartbus
.ack
)
456 # aaand with the WB4-pipeline-to-WB3-classic mismatch, sigh
457 comb
+= uartbus
.stall
.eq(uartbus
.cyc
& ~uartbus
.ack
)
458 comb
+= self
.cvtuartbus
.stall
.eq(uartbus
.stall
)
459 if hasattr(self
, "cpu"):
460 m
.submodules
.intc
= self
.intc
461 m
.submodules
.extcore
= self
.cpu
462 m
.submodules
.dbuscvt
= self
.dbusdowncvt
463 m
.submodules
.ibuscvt
= self
.ibusdowncvt
464 # create stall sigs, assume wishbone classic
465 #ibus, dbus = self.cvtibus, self.cvtdbus
466 #comb += ibus.stall.eq(ibus.stb & ~ibus.ack)
467 #comb += dbus.stall.eq(dbus.stb & ~dbus.ack)
469 m
.submodules
.arbiter
= self
._arbiter
470 m
.submodules
.decoder
= self
._decoder
471 if hasattr(self
, "ddrphy"):
472 m
.submodules
.ddrphy
= self
.ddrphy
473 m
.submodules
.dramcore
= self
.dramcore
474 m
.submodules
.drambone
= drambone
= self
.drambone
475 # grrr, same problem with drambone: not WB4-pipe compliant
476 comb
+= drambone
.bus
.stall
.eq(drambone
.bus
.cyc
& ~drambone
.bus
.ack
)
478 # add hyperram module
479 if hasattr(self
, "hyperram"):
480 m
.submodules
.hyperram
= hyperram
= self
.hyperram
481 # grrr, same problem with hyperram: not WB4-pipe compliant
482 comb
+= hyperram
.bus
.stall
.eq(hyperram
.bus
.cyc
& ~hyperram
.bus
.ack
)
484 # add blinky lights so we know FPGA is alive
485 if platform
is not None:
486 m
.submodules
.blinky
= Blinky()
488 # connect the arbiter (of wishbone masters)
489 # to the decoder (addressing wishbone slaves)
490 comb
+= self
._arbiter
.bus
.connect(self
._decoder
.bus
)
492 if hasattr(self
, "cpu"):
493 # wire up the CPU interrupts
494 comb
+= self
.cpu
.irq
.eq(self
.intc
.ip
)
499 # add uart16550 verilog source. assumes a directory
500 # structure where ls2 has been checked out in a common
501 # subdirectory as https://github.com/freecores/uart16550
502 opencores_16550
= "../../uart16550/rtl/verilog"
503 pth
= os
.path
.split(__file__
)[0]
504 pth
= os
.path
.join(pth
, opencores_16550
)
505 fname
= os
.path
.abspath(pth
)
507 self
.uart
.add_verilog_source(fname
, platform
)
509 if hasattr(self
, "spi0"):
510 # add Tercel verilog source. assumes a directory
511 # structure where ls2 has been checked out in a common
512 # subdirectory as https://git.libre-soc.org/git/microwatt.git
513 raptor_tercel
= "../../microwatt/tercel"
514 pth
= os
.path
.split(__file__
)[0]
515 pth
= os
.path
.join(pth
, raptor_tercel
)
516 fname
= os
.path
.abspath(pth
)
518 self
.spi0
.add_verilog_source(fname
, platform
)
521 pth
= os
.path
.split(__file__
)[0]
522 pth
= os
.path
.join(pth
, '../external_core_top.v')
523 fname
= os
.path
.abspath(pth
)
524 with
open(fname
) as f
:
525 platform
.add_file(fname
, f
)
530 # puzzlingly the only IO ports needed are peripheral pins,
531 # and at the moment that's just UART tx/rx.
533 ports
+= [self
.uart
.tx_o
, self
.uart
.rx_i
]
534 if hasattr(self
, "hyperram"):
535 ports
+= list(self
.hyperram
.ports())
536 if hasattr(self
, "ddrphy"):
537 if hasattr(self
.ddrphy
, "pads"): # real PHY
538 ports
+= list(self
.ddrphy
.pads
.fields
.values())
539 else: # FakePHY, get at the dfii pads, stops deletion of nets
540 for phase
in self
.dramcore
.dfii
.master
.phases
:
541 print ("dfi master", phase
)
542 ports
+= list(phase
.fields
.values())
543 for phase
in self
.dramcore
.dfii
.slave
.phases
:
544 print ("dfi master", phase
)
545 ports
+= list(phase
.fields
.values())
546 for phase
in self
.dramcore
.dfii
._inti
.phases
:
547 print ("dfi master", phase
)
548 ports
+= list(phase
.fields
.values())
549 ports
+= [ClockSignal(), ResetSignal()]
552 def build_platform(fpga
, firmware
):
554 # create a platform selected from the toolchain.
555 platform_kls
= {'versa_ecp5': VersaECP5Platform
,
556 'versa_ecp5_85': VersaECP5Platform85
,
557 'ulx3s': ULX3S_85F_Platform
,
558 'arty_a7': ArtyA7_100Platform
,
559 'isim': IcarusVersaPlatform
,
562 toolchain
= {'arty_a7': "yosys_nextpnr",
563 'versa_ecp5': 'Trellis',
564 'versa_ecp5_85': 'Trellis',
569 dram_cls
= {'arty_a7': None,
570 'versa_ecp5': MT41K64M16
,
571 'versa_ecp5_85': MT41K64M16
,
572 #'versa_ecp5': MT41K256M16,
577 if platform_kls
is not None:
578 platform
= platform_kls(toolchain
=toolchain
)
579 if fpga
== 'versa_ecp5_85':
580 platform
.speed
= "7" # HACK. speed grade 7, sigh
584 print ("platform", fpga
, firmware
, platform
)
586 # set clock frequency
591 clk_freq
= 50e6
# below 50 mhz, stops DRAM being enabled
592 if fpga
== 'versa_ecp5':
593 clk_freq
= 50e6
# crank right down to test hyperram
594 if fpga
== 'versa_ecp5_85':
596 if fpga
== 'arty_a7':
601 # select a firmware address
603 if firmware
is not None:
604 fw_addr
= 0x0000_0000
606 print ("fpga", fpga
, "firmware", firmware
)
608 # get UART resource pins
609 if platform
is not None:
610 uart_pins
= platform
.request("uart", 0)
612 uart_pins
= Record([('tx', 1), ('rx', 1)], name
="uart_0")
614 # get DDR resource pins, disable if clock frequency is below 50 mhz for now
616 if (clk_freq
> 50e6
and platform
is not None and
617 fpga
in ['versa_ecp5', 'versa_ecp5_85', 'arty_a7', 'isim']):
618 ddr_pins
= platform
.request("ddr3", 0,
619 dir={"dq":"-", "dqs":"-"},
620 xdr
={"rst": 4, "clk":4, "a":4,
622 "odt":4, "ras":4, "cas":4, "we":4,
625 # Get SPI resource pins
627 if platform
is not None and fpga
in ['rcs_arctic_tern_bmc_card']:
628 if toolchain
== 'Trellis':
629 # The ECP5 series FPGAs handle the SPI clock directly on
630 # the FPGA configuration Flash device
631 spi_0_pins
= platform
.request("spi_0", 0,
632 dir={"dq":"io", "cs_n":"o"},
633 xdr
={"dq": 1, "cs_n": 1})
635 spi_0_pins
= platform
.request("spi_0", 0,
636 dir={"dq":"io", "cs_n":"o", "clk":"o"},
637 xdr
={"dq": 1, "cs_n": 1, "clk": 0})
642 hyperram_pins
= HyperRAMPads()
643 elif fpga
in ['isim']:
644 hyperram_ios
= HyperRAMResource(0, cs_n
="B11",
645 dq
="D4 D3 F4 F3 G2 H2 D2 E2",
646 rwds
="U13", rst_n
="T13", ck_p
="V10",
647 # ck_n="D12" - for later (DDR)
648 attrs
=Attrs(IOSTANDARD
="LVCMOS33"))
649 platform
.add_resources(hyperram_ios
)
650 hyperram_pins
= platform
.request("hyperram")
651 print ("isim a7 hyperram", hyperram_ios
)
652 # Digilent Arty A7-100t
653 elif platform
is not None and fpga
in ['arty_a7']:
654 hyperram_ios
= HyperRAMResource(0, cs_n
="B11",
655 dq
="D4 D3 F4 F3 G2 H2 D2 E2",
656 rwds
="U13", rst_n
="T13", ck_p
="V10",
657 # ck_n="D12" - for later (DDR)
658 attrs
=Attrs(IOSTANDARD
="LVCMOS33"))
659 platform
.add_resources(hyperram_ios
)
660 hyperram_pins
= platform
.request("hyperram")
661 print ("arty a7 hyperram", hyperram_ios
)
663 elif platform
is not None and fpga
in ['versa_ecp5', 'versa_ecp5_85']:
664 hyperram_ios
= HyperRAMResource(0, cs_n
="B13",
665 dq
="E14 C10 B10 E12 D12 A9 D11 D14",
666 rwds
="C14", rst_n
="E13", ck_p
="D13",
667 attrs
=Attrs(IO_TYPE
="LVCMOS33"))
668 platform
.add_resources(hyperram_ios
)
669 hyperram_pins
= platform
.request("hyperram")
670 print ("versa ecp5 hyperram", hyperram_ios
)
671 print ("hyperram pins", hyperram_pins
)
674 soc
= DDR3SoC(fpga
=fpga
, dram_cls
=dram_cls
,
675 # check microwatt_soc.h for these
676 ddrphy_addr
=0xff000000, # DRAM_INIT_BASE firmware base
677 dramcore_addr
=0xc8000000, # DRAM_CTRL_BASE
678 ddr_addr
=0x40000000, # DRAM_BASE
679 spi0_addr
=0x10000000, # SPI0_BASE
680 spi0_cfg_addr
=0xc0003000, # SPI0_CTRL_BASE
681 hyperram_addr
=0xa0000000, # HYPERRAM_BASE
686 spi_0_pins
=spi_0_pins
,
687 hyperram_pins
=hyperram_pins
,
692 if toolchain
== 'Trellis':
693 # add -abc9 option to yosys synth_ecp5
694 #os.environ['NMIGEN_synth_opts'] = '-abc9 -nowidelut'
695 #os.environ['NMIGEN_synth_opts'] = '-abc9'
696 os
.environ
['NMIGEN_synth_opts'] = '-nowidelut'
698 if platform
is not None:
699 # build and upload it
701 platform
.build(soc
, do_program
=False,
702 do_build
=True, build_dir
="build_simsoc")
704 platform
.build(soc
, do_program
=True)
706 # for now, generate verilog
707 vl
= verilog
.convert(soc
, ports
=soc
.ports())
708 with
open("ls2.v", "w") as f
:
712 # urrr this gets exec()d by the build process without arguments
713 # which screws up. use the arty_a7_ls2.py etc. with no arguments
714 if __name__
== '__main__':
717 if len(sys
.argv
) >= 2:
719 if len(sys
.argv
) >= 3:
720 firmware
= sys
.argv
[2]
721 build_platform(fpga
, firmware
)