-
Notifications
You must be signed in to change notification settings - Fork 365
Expand file tree
/
Copy pathsipeed_tang_nano_9k.py
More file actions
executable file
·189 lines (158 loc) · 8.59 KB
/
Copy pathsipeed_tang_nano_9k.py
File metadata and controls
executable file
·189 lines (158 loc) · 8.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/usr/bin/env python3
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2022 Icenowy Zheng <icenowy@aosc.io>
# SPDX-License-Identifier: BSD-2-Clause
import os
from migen import *
from litex.gen import *
from litex_boards.platforms import sipeed_tang_nano_9k
from litex.soc.cores.clock.gowin_gw1n import GW1NPLL
from litex.soc.integration.soc import *
from litex.soc.integration.soc import SoCRegion
from litex.soc.integration.builder import *
from litex.soc.cores.led import LedChaser
from litex.soc.cores.video import *
from litex.soc.cores.hyperbus import HyperRAM
# CRG ----------------------------------------------------------------------------------------------
class _CRG(LiteXModule):
def __init__(self, platform, sys_clk_freq, with_video_pll=False):
self.rst = Signal()
self.cd_sys = ClockDomain()
# # #
# Clk / Rst
clk27 = platform.request("clk27")
rst_n = platform.request("user_btn_n", 0)
# PLL
self.pll = pll = GW1NPLL(devicename=platform.devicename, device=platform.device)
self.comb += pll.reset.eq(~rst_n)
pll.register_clkin(clk27, 27e6)
pll.create_clkout(self.cd_sys, sys_clk_freq)
# Video PLL
if with_video_pll:
self.video_pll = video_pll = GW1NPLL(devicename=platform.devicename, device=platform.device)
self.comb += video_pll.reset.eq(~rst_n)
video_pll.register_clkin(clk27, 27e6)
self.cd_hdmi = ClockDomain()
self.cd_hdmi5x = ClockDomain()
video_pll.create_clkout(self.cd_hdmi5x, 125e6)
self.specials += Instance("CLKDIV",
p_DIV_MODE= "5",
i_RESETN = rst_n,
i_HCLKIN = self.cd_hdmi5x.clk,
o_CLKOUT = self.cd_hdmi.clk
)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, toolchain="gowin", sys_clk_freq=27e6, bios_flash_offset=0x0,
with_led_chaser = True,
with_video_terminal = False,
with_integrated_rom = False,
**kwargs):
platform = sipeed_tang_nano_9k.Platform(toolchain=toolchain)
# This GW1NR-9 is tight on LUTs, so build Ibex (when selected) with its
# distributed-RAM register file instead of the default flip-flop one,
# which overflows the part. Ignored by every other CPU.
platform.ibex_regfile = "fpga"
# CRG --------------------------------------------------------------------------------------
self.crg = _CRG(platform, sys_clk_freq, with_video_pll=with_video_terminal)
# SoCCore ----------------------------------------------------------------------------------
# Keep the BIOS in external SPI Flash by default to save GW1N-9 resources.
# --with-integrated-rom is useful for SRAM-only loading/debug, at the cost of extra BRAMs.
if with_integrated_rom:
kwargs.setdefault("integrated_rom_size", 128 * KILOBYTE)
else:
kwargs["integrated_rom_size"] = 0
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Tang Nano 9K", **kwargs)
# SPI Flash --------------------------------------------------------------------------------
from litespi.modules import W25Q32
from litespi.opcodes import SpiNorFlashOpCodes as Codes
self.add_spi_flash(mode="1x", module=W25Q32(Codes.READ_1_1_1), with_master=False)
# Add ROM linker region --------------------------------------------------------------------
if not with_integrated_rom:
self.bus.add_region("rom", SoCRegion(
origin = self.bus.regions["spiflash"].origin + bios_flash_offset,
size = 64 * KILOBYTE,
linker = True)
)
self.cpu.set_reset_address(self.bus.regions["rom"].origin)
# HyperRAM ---------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
# TODO: Use second 32Mbit PSRAM chip.
dq = platform.request("IO_psram_dq")
rwds = platform.request("IO_psram_rwds")
reset_n = platform.request("O_psram_reset_n")
cs_n = platform.request("O_psram_cs_n")
ck = platform.request("O_psram_ck")
ck_n = platform.request("O_psram_ck_n")
class HyperRAMPads:
def __init__(self, n):
self.clk = Signal()
self.rst_n = reset_n[n]
self.dq = dq[8*n:8*(n+1)]
self.cs_n = cs_n[n]
self.rwds = rwds[n]
hyperram_pads = HyperRAMPads(0)
self.comb += ck[0].eq(hyperram_pads.clk)
self.comb += ck_n[0].eq(~hyperram_pads.clk)
# FIXME: Issue with upstream HyperRAM core, so use old one when available.
HyperRAMCore = HyperRAM
if not os.path.exists("hyperbus.py"):
os.system("wget https://github.com/litex-hub/litex-boards/files/8831568/hyperbus.py.txt")
if os.path.exists("hyperbus.py.txt"):
os.system("mv hyperbus.py.txt hyperbus.py")
if os.path.exists("hyperbus.py"):
try:
from hyperbus import HyperRAM as HyperRAMCore
except ImportError:
pass
self.hyperram = HyperRAMCore(hyperram_pads)
self.bus.add_slave("main_ram", slave=self.hyperram.bus, region=SoCRegion(origin=self.mem_map["main_ram"], size=4 * MEGABYTE, mode="rwx"))
# Video ------------------------------------------------------------------------------------
if with_video_terminal:
self.videophy = VideoGowinHDMIPHY(platform.request("hdmi"), clock_domain="hdmi")
self.add_video_colorbars(phy=self.videophy, timings="640x480@60Hz", clock_domain="hdmi")
#self.add_video_terminal(phy=self.videophy, timings="640x480@75Hz", clock_domain="hdmi") # FIXME: Free up BRAMs.
# Leds -------------------------------------------------------------------------------------
if with_led_chaser:
self.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
# Build --------------------------------------------------------------------------------------------
def main():
from litex.build.parser import LiteXArgumentParser
parser = LiteXArgumentParser(platform=sipeed_tang_nano_9k.Platform, description="LiteX SoC on Tang Nano 9K.")
parser.add_target_argument("--flash", action="store_true", help="Flash bitstream.")
parser.add_target_argument("--sys-clk-freq", default=27e6, type=float, help="System clock frequency.")
parser.add_target_argument("--bios-flash-offset", default="0x0", help="BIOS offset in SPI Flash.")
parser.add_target_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support.")
parser.add_target_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (HDMI).")
parser.add_target_argument("--with-integrated-rom", action="store_true", help="Build BIOS into FPGA bitstream for SRAM-only loading/debug.")
parser.add_target_argument("--prog-kit", default="openfpgaloader", help="Programmer select from Gowin/openFPGALoader.")
args = parser.parse_args()
soc = BaseSoC(
toolchain = args.toolchain,
sys_clk_freq = args.sys_clk_freq,
bios_flash_offset = int(args.bios_flash_offset, 0),
with_video_terminal = args.with_video_terminal,
with_integrated_rom = args.with_integrated_rom,
**parser.soc_argdict
)
if args.with_spi_sdcard:
soc.add_spi_sdcard()
builder = Builder(soc, **parser.builder_argdict)
if args.build:
builder.build(**parser.toolchain_argdict)
if args.load:
prog = soc.platform.create_programmer(kit=args.prog_kit)
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))
if args.flash:
prog = soc.platform.create_programmer(kit=args.prog_kit)
prog.flash(0, builder.get_bitstream_filename(mode="flash", ext=".fs")) # FIXME
# Axternal SPI programming not supported by gowin 'programmer_cli' now!
# if needed, use openFPGALoader or Gowin programmer GUI
if args.prog_kit == "openfpgaloader":
prog.flash(int(args.bios_flash_offset, 0), builder.get_bios_filename(), external=True)
if __name__ == "__main__":
main()