beginning to add hyperram module
[ls2.git] / src / ls2.py
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>
4 #
5 # Based on code from LambaConcept, from the gram example which is BSD-2-License
6 # https://github.com/jeanthom/gram/tree/master/examples
7 #
8 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
9 # under EU Grants 871528 and 957073, under the LGPLv3+ License
10
11 from nmigen import (Module, Elaboratable, DomainRenamer, Record,
12 Signal, Cat, Const, ClockSignal, ResetSignal)
13 from nmigen.cli import verilog
14 from nmigen.lib.cdc import ResetSynchronizer
15 from nmigen_soc import wishbone, memory
16 from nmigen_soc.memory import MemoryMap
17
18 from nmigen_stdio.serial import AsyncSerial
19 from nmigen_boards.resources.memory import HyperRAMResource
20
21 from lambdasoc.periph.intc import GenericInterruptController
22 from lambdasoc.periph.sram import SRAMPeripheral
23 from lambdasoc.periph.timer import TimerPeripheral
24 from lambdasoc.periph import Peripheral
25 from lambdasoc.soc.base import SoC
26 from soc.bus.uart_16550 import UART16550 # opencores 16550 uart
27 from soc.bus.tercel import Tercel # SPI XIP master
28 from soc.bus.external_core import ExternalCore # external libresoc/microwatt
29 from soc.bus.wb_downconvert import WishboneDownConvert
30 from soc.bus.syscon import MicrowattSYSCON
31
32 from gram.common import (PhySettings, get_cl_cw, get_sys_latency,
33 get_sys_phases,)
34 from nmigen.utils import log2_int
35 from gram.core import gramCore
36 from gram.phy.ecp5ddrphy import ECP5DDRPHY
37 from gram.phy.fakephy import FakePHY, SDRAM_VERBOSE_STD, SDRAM_VERBOSE_DBG
38 from gram.modules import MT41K256M16, MT41K64M16
39 from gram.frontend.wishbone import gramWishbone
40
41 from nmigen_boards.versa_ecp5 import VersaECP5Platform
42 from nmigen_boards.ulx3s import ULX3S_85F_Platform
43 from nmigen_boards.arty_a7 import ArtyA7_100Platform
44 from nmigen_boards.test.blinky import Blinky
45
46 from crg import ECPIX5CRG
47 from icarusversa import IcarusVersaPlatform
48
49 import sys
50 import os
51
52 def sim_ddr3_settings(clk_freq=100e6):
53 tck = 2/(2*2*clk_freq)
54 nphases = 2
55 databits = 16
56 nranks = 1
57 addressbits = 14
58 bankbits = 3
59 cl, cwl = get_cl_cw("DDR3", tck)
60 cl_sys_latency = get_sys_latency(nphases, cl)
61 cwl_sys_latency = get_sys_latency(nphases, cwl)
62 rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
63 wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
64 return PhySettings(
65 phytype="ECP5DDRPHY",
66 memtype="DDR3",
67 databits=databits,
68 dfi_databits=4*databits,
69 nranks=nranks,
70 nphases=nphases,
71 rdphase=rdphase,
72 wrphase=wrphase,
73 rdcmdphase=rdcmdphase,
74 wrcmdphase=wrcmdphase,
75 cl=cl,
76 cwl=cwl,
77 read_latency=2 + cl_sys_latency + 2 + log2_int(4//nphases) + 4,
78 write_latency=cwl_sys_latency
79 )
80
81
82 class WB64to32Convert(Elaboratable):
83 """Microwatt IO wishbone slave 64->32 bits converter
84
85 For timing reasons, this adds a one cycle latch on the way both
86 in and out. This relaxes timing and routing pressure on the "main"
87 memory bus by moving all simple IOs to a slower 32-bit bus.
88
89 This implementation is rather dumb at the moment, no stash buffer,
90 so we stall whenever that latch is busy. This can be improved.
91 """
92 def __init__(self, master, slave):
93 self.master = master
94 self.slave = slave
95
96 def elaborate(self, platform):
97 m = Module()
98 comb, sync = m.d.comb, m.d.sync
99 master, slave = self.master, self.slave
100
101 has_top = Signal()
102 has_top_r = Signal()
103 has_bot = Signal()
104
105 with m.FSM() as fsm:
106 with m.State("IDLE"):
107 # Clear ACK (and has_top_r) in case it was set
108 sync += master.ack.eq(0)
109 sync += has_top_r.eq(0)
110
111 # Do we have a cycle ?
112 with m.If(master.cyc & master.stb):
113 # Stall master until we are done, we are't (yet) pipelining
114 # this, it's all slow IOs.
115 sync += master.stall.eq(1)
116
117 # Start cycle downstream
118 sync += slave.cyc.eq(1)
119 sync += slave.stb.eq(1)
120
121 # Do we have a top word and/or a bottom word ?
122 comb += has_top.eq(master.sel[4:].bool())
123 comb += has_bot.eq(master.sel[:4].bool())
124 # record the has_top flag for the next FSM state
125 sync += has_top_r.eq(has_top)
126
127 # Copy write enable to IO out, copy address as well,
128 # LSB is set later based on HI/LO
129 sync += slave.we.eq(master.we)
130 sync += slave.adr.eq(Cat(0, master.adr))
131
132 # If we have a bottom word, handle it first, otherwise
133 # send the top word down. XXX Split the actual mux out
134 # and only generate a control signal.
135 with m.If(has_bot):
136 with m.If(master.we):
137 sync += slave.dat_w.eq(master.dat_w[:32])
138 sync += slave.sel.eq(master.sel[:4])
139
140 # Wait for ack on BOTTOM half
141 m.next = "WAIT_ACK_BOT"
142
143 with m.Else():
144 with m.If(master.we):
145 sync += slave.dat_w.eq(master.dat_w[32:])
146 sync += slave.sel.eq(master.sel[4:])
147
148 # Bump LSB of address
149 sync += slave.adr[0].eq(1)
150
151 # Wait for ack on TOP half
152 m.next = "WAIT_ACK_TOP"
153
154
155 with m.State("WAIT_ACK_BOT"):
156 # If we aren't stalled by the device, clear stb
157 if hasattr(slave, "stall"):
158 with m.If(~slave.stall):
159 sync += slave.stb.eq(0)
160
161 # Handle ack
162 with m.If(slave.ack):
163 # If it's a read, latch the data
164 with m.If(~slave.we):
165 sync += master.dat_r[:32].eq(slave.dat_r)
166
167 # Do we have a "top" part as well ?
168 with m.If(has_top_r):
169 # Latch data & sel
170 with m.If(master.we):
171 sync += slave.dat_w.eq(master.dat_w[32:])
172 sync += slave.sel.eq(master.sel[4:])
173
174 # Bump address and set STB
175 sync += slave.adr[0].eq(1)
176 sync += slave.stb.eq(1)
177
178 # Wait for new ack
179 m.next = "WAIT_ACK_TOP"
180
181 with m.Else():
182 # We are done, ack up, clear cyc downstram
183 sync += slave.cyc.eq(0)
184 sync += slave.stb.eq(0)
185
186 # And ack & unstall upstream
187 sync += master.ack.eq(1)
188 if hasattr(master , "stall"):
189 sync += master.stall.eq(0)
190
191 # Wait for next one
192 m.next = "IDLE"
193
194 with m.State("WAIT_ACK_TOP"):
195 # If we aren't stalled by the device, clear stb
196 if hasattr(slave, "stall"):
197 with m.If(~slave.stall):
198 sync += slave.stb.eq(0)
199
200 # Handle ack
201 with m.If(slave.ack):
202 # If it's a read, latch the data
203 with m.If(~slave.we):
204 sync += master.dat_r[32:].eq(slave.dat_r)
205
206 # We are done, ack up, clear cyc downstram
207 sync += slave.cyc.eq(0)
208 sync += slave.stb.eq(0)
209
210 # And ack & unstall upstream
211 sync += master.ack.eq(1)
212 if hasattr(master, "stall"):
213 sync += master.stall.eq(0)
214
215 # Wait for next one
216 m.next = "IDLE"
217
218 return m
219
220
221 class DDR3SoC(SoC, Elaboratable):
222 def __init__(self, *,
223 fpga,
224 dram_cls,
225 uart_pins, spi_0_pins,
226 ddr_pins, ddrphy_addr, dramcore_addr, ddr_addr,
227 fw_addr=0x0000_0000,
228 firmware=None,
229 spi0_addr, spi0_cfg_addr,
230 hyperram_addr=None,
231 hyperram_pinset=None,
232 clk_freq=50e6,
233 add_cpu=True):
234
235 # wishbone routing is as follows:
236 #
237 # SoC
238 # +--+--+
239 # | |
240 # ibus dbus
241 # | |
242 # +--+--+
243 # |
244 # 64to32DownCvt
245 # |
246 # arbiter
247 # |
248 # +---decoder----+--------+---------+
249 # | | | | |
250 # uart XICS CSRs DRAM XIP SPI
251
252 # set up wishbone bus arbiter and decoder. arbiter routes,
253 # decoder maps local-relative addressed satellites to global addresses
254 self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32,
255 granularity=8,
256 features={"cti", "bte", "stall"})
257 self._decoder = wishbone.Decoder(addr_width=30, data_width=32,
258 granularity=8,
259 features={"cti", "bte", "stall"})
260
261 # default firmware name
262 if firmware is None:
263 firmware = "firmware/main.bin"
264
265 # set up clock request generator
266 self.crg = ECPIX5CRG(clk_freq)
267
268 # set up CPU, with 64-to-32-bit downconverters
269 if add_cpu:
270 self.cpu = ExternalCore(name="ext_core")
271 cvtdbus = wishbone.Interface(addr_width=30, data_width=32,
272 granularity=8, features={'stall'})
273 cvtibus = wishbone.Interface(addr_width=30, data_width=32,
274 granularity=8, features={'stall'})
275 self.dbusdowncvt = WB64to32Convert(self.cpu.dbus, cvtdbus)
276 self.ibusdowncvt = WB64to32Convert(self.cpu.ibus, cvtibus)
277 self._arbiter.add(cvtibus) # I-Cache Master
278 self._arbiter.add(cvtdbus) # D-Cache Master. TODO JTAG master
279 self.cvtibus = cvtibus
280 self.cvtdbus = cvtdbus
281
282 # CPU interrupt controller
283 self.intc = GenericInterruptController(width=len(self.cpu.irq))
284
285 # SRAM (but actually a ROM, for firmware), at address 0x0
286 if fw_addr is not None:
287 sram_width = 32
288 self.bootmem = SRAMPeripheral(size=0x8000, data_width=sram_width,
289 writable=True)
290 if firmware is not None:
291 with open(firmware, "rb") as f:
292 words = iter(lambda: f.read(sram_width // 8), b'')
293 bios = [int.from_bytes(w, "little") for w in words]
294 self.bootmem.init = bios
295 self._decoder.add(self.bootmem.bus, addr=fw_addr) # ROM at fw_addr
296
297 # System Configuration info
298 self.syscon = MicrowattSYSCON(sys_clk_freq=clk_freq,
299 has_uart=(uart_pins is not None))
300 self._decoder.add(self.syscon.bus, addr=0xc0000000) # at 0xc000_0000
301
302 if False:
303 # SRAM (read-writeable BRAM)
304 self.ram = SRAMPeripheral(size=4096)
305 self._decoder.add(self.ram.bus, addr=0x8000000) # at 0x8000_0000
306
307 # UART at 0xC000_2000, convert 32-bit bus down to 8-bit in an odd way
308 if uart_pins is not None:
309 # sigh actual UART in microwatt is 8-bit
310 self.uart = UART16550(data_width=8, pins=uart_pins,
311 features={'stall'})
312 # but (see soc.vhdl) 8-bit regs are addressed at 32-bit locations
313 cvtuartbus = wishbone.Interface(addr_width=5, data_width=32,
314 granularity=8,
315 features={'stall'})
316 umap = MemoryMap(addr_width=7, data_width=8, name="uart_map")
317 cvtuartbus.memory_map = umap
318 self._decoder.add(cvtuartbus, addr=0xc0002000) # 16550 UART addr
319 self.cvtuartbus = cvtuartbus
320
321 # SDRAM module using opencores sdr_ctrl
322 """
323 class MT48LC16M16(SDRModule):
324 # geometry
325 nbanks = 4
326 nrows = 8192
327 ncols = 512
328 # timings
329 technology_timings = _TechnologyTimings(tREFI=64e6/8192,
330 tWTR=(2, None),
331 tCCD=(1, None),
332 tRRD=(None, 15))
333 speedgrade_timings = {"default": _SpeedgradeTimings(tRP=20,
334 tRCD=20,
335 tWR=15,
336 tRFC=(None, 66),
337 tFAW=None,
338 tRAS=44)}
339 """
340
341 # DRAM Module
342 if ddr_pins is not None or fpga == 'sim':
343 ddrmodule = dram_cls(clk_freq, "1:2") # match DDR3 ASIC P/N
344
345 #drs = lambda x: x
346 drs = DomainRenamer("dramsync")
347
348 if fpga == 'sim':
349 self.ddrphy = FakePHY(module=ddrmodule,
350 settings=sim_ddr3_settings(clk_freq),
351 verbosity=SDRAM_VERBOSE_DBG,
352 clk_freq=clk_freq)
353 else:
354 self.ddrphy = drs(ECP5DDRPHY(ddr_pins, sys_clk_freq=clk_freq))
355 self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
356
357 dramcore = gramCore(phy=self.ddrphy,
358 geom_settings=ddrmodule.geom_settings,
359 timing_settings=ddrmodule.timing_settings,
360 clk_freq=clk_freq)
361 if fpga == 'sim':
362 self.dramcore = dramcore
363 else:
364 self.dramcore = drs(dramcore)
365 self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
366
367 # map the DRAM onto Wishbone, XXX use stall but set classic below
368 drambone = gramWishbone(dramcore, features={'stall'})
369 if fpga == 'sim':
370 self.drambone = drambone
371 else:
372 self.drambone = drs(drambone)
373 self._decoder.add(self.drambone.bus, addr=ddr_addr)
374
375 # SPI controller
376 if spi_0_pins is not None and fpga in ['sim',
377 'rcs_arctic_tern_bmc_card']:
378 # The Lattice ECP5 devices require special handling on the
379 # dedicated SPI clock line, which is shared with the internal
380 # SPI controller used for FPGA bitstream loading.
381 spi0_is_lattice_ecp5_clk = False
382 if platform is not None and fpga in ['versa_ecp5',
383 'rcs_arctic_tern_bmc_card',
384 'isim']:
385 spi0_is_lattice_ecp5_clk = True
386
387 # Tercel contains two independent Wishbone regions, a
388 # configuration region and the direct API access region,
389 # Set the SPI 0 access region to 16MB, as the FPGA
390 # bitstream Flash device is unlikely to be larger than this.
391 # The main SPI Flash (SPI 1) should be set to at
392 # least 28 bits (256MB) to allow the use of large 4BA devices.
393 self.spi0 = Tercel(data_width=32, spi_region_addr_width=24,
394 clk_freq=clk_freq,
395 pins=spi_0_pins,
396 lattice_ecp5_usrmclk=spi0_is_lattice_ecp5_clk)
397 self._decoder.add(self.spi0.bus, addr=spi0_addr)
398 self._decoder.add(self.spi0.cfg_bus, addr=spi0_cfg_addr)
399
400 # HyperRAM modules *plural*. Assumes using a Quad PMOD by Piotr
401 # Esden, sold by 1bitsquared
402
403 self.memory_map = self._decoder.bus.memory_map
404
405 self.clk_freq = clk_freq
406
407 def elaborate(self, platform):
408 m = Module()
409 comb = m.d.comb
410
411 # add the peripherals and clock-reset-generator
412 if platform is not None:
413 m.submodules.sysclk = self.crg
414
415 if hasattr(self, "bootmem"):
416 m.submodules.bootmem = self.bootmem
417 m.submodules.syscon = self.syscon
418 if hasattr(self, "ram"):
419 m.submodules.ram = self.ram
420 if hasattr(self, "uart"):
421 m.submodules.uart = self.uart
422 comb += self.uart.cts_i.eq(1)
423 comb += self.uart.dsr_i.eq(1)
424 comb += self.uart.ri_i.eq(0)
425 comb += self.uart.dcd_i.eq(1)
426 # sigh connect up the wishbone bus manually to deal with
427 # the mis-match on the data
428 uartbus = self.uart.bus
429 comb += uartbus.adr.eq(self.cvtuartbus.adr)
430 comb += uartbus.stb.eq(self.cvtuartbus.stb)
431 comb += uartbus.cyc.eq(self.cvtuartbus.cyc)
432 comb += uartbus.sel.eq(self.cvtuartbus.sel)
433 comb += uartbus.we.eq(self.cvtuartbus.we)
434 comb += uartbus.dat_w.eq(self.cvtuartbus.dat_w) # drops 8..31
435 comb += self.cvtuartbus.dat_r.eq(uartbus.dat_r) # drops 8..31
436 comb += self.cvtuartbus.ack.eq(uartbus.ack)
437 # aaand with the WB4-pipeline-to-WB3-classic mismatch, sigh
438 comb += uartbus.stall.eq(uartbus.cyc & ~uartbus.ack)
439 comb += self.cvtuartbus.stall.eq(uartbus.stall)
440 if hasattr(self, "cpu"):
441 m.submodules.intc = self.intc
442 m.submodules.extcore = self.cpu
443 m.submodules.dbuscvt = self.dbusdowncvt
444 m.submodules.ibuscvt = self.ibusdowncvt
445 # create stall sigs, assume wishbone classic
446 #ibus, dbus = self.cvtibus, self.cvtdbus
447 #comb += ibus.stall.eq(ibus.stb & ~ibus.ack)
448 #comb += dbus.stall.eq(dbus.stb & ~dbus.ack)
449
450 m.submodules.arbiter = self._arbiter
451 m.submodules.decoder = self._decoder
452 if hasattr(self, "ddrphy"):
453 m.submodules.ddrphy = self.ddrphy
454 m.submodules.dramcore = self.dramcore
455 m.submodules.drambone = drambone = self.drambone
456 # grrr, same problem with drambone: not WB4-pipe compliant
457 comb += drambone.bus.stall.eq(drambone.bus.cyc & ~drambone.bus.ack)
458
459 # add blinky lights so we know FPGA is alive
460 if platform is not None:
461 m.submodules.blinky = Blinky()
462
463 # connect the arbiter (of wishbone masters)
464 # to the decoder (addressing wishbone slaves)
465 comb += self._arbiter.bus.connect(self._decoder.bus)
466
467 if hasattr(self, "cpu"):
468 # wire up the CPU interrupts
469 comb += self.cpu.irq.eq(self.intc.ip)
470
471 if platform is None:
472 return m
473
474 # add uart16550 verilog source. assumes a directory
475 # structure where ls2 has been checked out in a common
476 # subdirectory as https://github.com/freecores/uart16550
477 opencores_16550 = "../../uart16550/rtl/verilog"
478 pth = os.path.split(__file__)[0]
479 pth = os.path.join(pth, opencores_16550)
480 fname = os.path.abspath(pth)
481 print (fname)
482 self.uart.add_verilog_source(fname, platform)
483
484 # add Tercel verilog source. assumes a directory
485 # structure where ls2 has been checked out in a common
486 # subdirectory as https://git.libre-soc.org/git/microwatt.git
487 raptor_tercel = "../../microwatt/tercel"
488 pth = os.path.split(__file__)[0]
489 pth = os.path.join(pth, raptor_tercel)
490 fname = os.path.abspath(pth)
491 print (fname)
492 self.spi0.add_verilog_source(fname, platform)
493
494 # add the main core
495 pth = os.path.split(__file__)[0]
496 pth = os.path.join(pth, '../external_core_top.v')
497 fname = os.path.abspath(pth)
498 with open(fname) as f:
499 platform.add_file(fname, f)
500
501 return m
502
503 def ports(self):
504 # puzzlingly the only IO ports needed are peripheral pins,
505 # and at the moment that's just UART tx/rx.
506 ports = []
507 ports += [self.uart.tx_o, self.uart.rx_i]
508 if hasattr(self, "ddrphy"):
509 if hasattr(self.ddrphy, "pads"): # real PHY
510 ports += list(self.ddrphy.pads.fields.values())
511 else: # FakePHY, get at the dfii pads, stops deletion of nets
512 for phase in self.dramcore.dfii.master.phases:
513 print ("dfi master", phase)
514 ports += list(phase.fields.values())
515 for phase in self.dramcore.dfii.slave.phases:
516 print ("dfi master", phase)
517 ports += list(phase.fields.values())
518 for phase in self.dramcore.dfii._inti.phases:
519 print ("dfi master", phase)
520 ports += list(phase.fields.values())
521 ports += [ClockSignal(), ResetSignal()]
522 return ports
523
524 if __name__ == "__main__":
525
526 # create a platform selected from the toolchain. defaults to VERSA_ECP5
527 # only VERSA_ECP5 will work for now because of the DDR3 module
528 fpga = "versa_ecp5"
529 if len(sys.argv) >= 2:
530 fpga = sys.argv[1]
531 platform_kls = {'versa_ecp5': VersaECP5Platform,
532 'ulx3s': ULX3S_85F_Platform,
533 'arty_a7': ArtyA7_100Platform,
534 'isim': IcarusVersaPlatform,
535 'sim': None,
536 }[fpga]
537 toolchain = {'arty_a7': "yosys_nextpnr",
538 'versa_ecp5': 'Trellis',
539 'isim': 'Trellis',
540 'ulx3s': 'Trellis',
541 'sim': None,
542 }.get(fpga, None)
543 dram_cls = {'arty_a7': None,
544 'versa_ecp5': MT41K64M16,
545 #'versa_ecp5': MT41K256M16,
546 'ulx3s': None,
547 'sim': MT41K256M16,
548 'isim': MT41K64M16,
549 }.get(fpga, None)
550 if platform_kls is not None:
551 platform = platform_kls(toolchain=toolchain)
552 else:
553 platform = None
554
555 # set clock frequency
556 clk_freq = 70e6
557 if fpga == 'sim':
558 clk_freq = 100e6
559 if fpga == 'versa_ecp5':
560 clk_freq = 55e6
561
562 # select a firmware file
563 firmware = None
564 fw_addr = None
565 if len(sys.argv) >= 3:
566 firmware = sys.argv[2]
567 fw_addr = 0x0000_0000
568
569 # get UART resource pins
570 if platform is not None:
571 uart_pins = platform.request("uart", 0)
572 else:
573 uart_pins = Record([('tx', 1), ('rx', 1)], name="uart_0")
574
575 # get DDR resource pins
576 ddr_pins = None
577 if platform is not None and fpga in ['versa_ecp5', 'arty_a7', 'isim']:
578 ddr_pins = platform.request("ddr3", 0,
579 dir={"dq":"-", "dqs":"-"},
580 xdr={"rst": 4, "clk":4, "a":4,
581 "ba":4, "clk_en":4,
582 "odt":4, "ras":4, "cas":4, "we":4,
583 "cs": 4})
584
585 # Get SPI resource pins
586 spi_0_pins = None
587 if platform is not None and fpga in ['rcs_arctic_tern_bmc_card']:
588 if toolchain == 'Trellis':
589 # The ECP5 series FPGAs handle the SPI clock directly on
590 # the FPGA configuration Flash device
591 spi_0_pins = platform.request("spi_0", 0,
592 dir={"dq":"io", "cs_n":"o"},
593 xdr={"dq": 1, "cs_n": 1})
594 else:
595 spi_0_pins = platform.request("spi_0", 0,
596 dir={"dq":"io", "cs_n":"o", "clk":"o"},
597 xdr={"dq": 1, "cs_n": 1, "clk": 0})
598
599 # Get HyperRAM pinsets, there are multiple of these!
600 hyperram_pinset = None
601 if platform is not None and fpga in ['versa_ecp5']:
602 hyperram_ios = HyperRAMResources(cs_n="B1",
603 dq="D0 D1 D2 D3 D4 D7 D6 D7",
604 rwds="B2", rst_n="B3", clk_p="B4",
605 attrs=IOStandard("LVCMOS33"))
606 self.platform.add_extension(hyperram_ios)
607 hyperram_pinset = self.platform.request("hyperram")
608
609 # set up the SOC
610 soc = DDR3SoC(fpga=fpga, dram_cls=dram_cls,
611 # check microwatt_soc.h for these
612 ddrphy_addr=0xff000000, # DRAM_INIT_BASE firmware base
613 dramcore_addr=0xc8000000, # DRAM_CTRL_BASE
614 ddr_addr=0x40000000, # DRAM_BASE
615 spi0_addr=0x10000000, # SPI0_BASE
616 spi0_cfg_addr=0xc0003000, # SPI0_CTRL_BASE
617 hyperram_addr=0xa0000000, # HYPERRAM_BASE
618 fw_addr=fw_addr,
619 #fw_addr=None,
620 ddr_pins=ddr_pins,
621 uart_pins=uart_pins,
622 spi_0_pins=spi_0_pins,
623 hyperram_pinset=hyperram_pinset,
624 firmware=firmware,
625 clk_freq=clk_freq,
626 add_cpu=True)
627
628 if toolchain == 'Trellis':
629 # add -abc9 option to yosys synth_ecp5
630 #os.environ['NMIGEN_synth_opts'] = '-abc9 -nowidelut'
631 #os.environ['NMIGEN_synth_opts'] = '-abc9'
632 os.environ['NMIGEN_synth_opts'] = '-nowidelut'
633
634 if platform is not None:
635 # build and upload it
636 if fpga == 'isim':
637 platform.build(soc, do_program=False,
638 do_build=True, build_dir="build_simsoc")
639 else:
640 platform.build(soc, do_program=True)
641 else:
642 # for now, generate verilog
643 vl = verilog.convert(soc, ports=soc.ports())
644 with open("ls2.v", "w") as f:
645 f.write(vl)
646