-
Notifications
You must be signed in to change notification settings - Fork 311
/
Copy pathicebreaker.py
executable file
·160 lines (130 loc) · 7.06 KB
/
icebreaker.py
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
#!/usr/bin/env python3
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2019 Sean Cross <[email protected]>
# Copyright (c) 2018 David Shah <[email protected]>
# Copyright (c) 2020 Piotr Esden-Tempski <[email protected]>
# Copyright (c) 2020 Florent Kermarrec <[email protected]>
# SPDX-License-Identifier: BSD-2-Clause
# The iCEBreaker is the first open source iCE40 FPGA development board designed for teachers and
# students: https://www.crowdsupply.com/1bitsquared/icebreaker-fpga
# This target file provides a minimal LiteX SoC for the iCEBreaker with a CPU, its ROM (in SPI Flash),
# its SRAM, close to the others LiteX targets. A more complete example of LiteX SoC for the iCEBreaker
# with more features, examples to run C/Rust code on the RISC-V CPU and documentation can be found
# at: https://github.com/icebreaker-fpga/icebreaker-litex-examples
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from litex.gen import *
from litex_boards.platforms import icebreaker
from litex.soc.cores.ram import Up5kSPRAM
from litex.soc.cores.clock import iCE40PLL
from litex.soc.integration.soc_core import *
from litex.soc.integration.soc import SoCRegion
from litex.soc.integration.builder import *
from litex.soc.cores.video import VideoDVIPHY
from litex.soc.cores.led import LedChaser
# CRG ----------------------------------------------------------------------------------------------
class _CRG(LiteXModule):
def __init__(self, platform, sys_clk_freq):
self.rst = Signal()
self.cd_sys = ClockDomain()
self.cd_por = ClockDomain()
# # #
# Clk/Rst
clk12 = platform.request("clk12")
rst_n = platform.request("user_btn_n")
# Power On Reset
por_count = Signal(16, reset=2**16-1)
por_done = Signal()
self.comb += self.cd_por.clk.eq(ClockSignal())
self.comb += por_done.eq(por_count == 0)
self.sync.por += If(~por_done, por_count.eq(por_count - 1))
# PLL
self.pll = pll = iCE40PLL(primitive="SB_PLL40_PAD")
self.comb += pll.reset.eq(~rst_n) # FIXME: Add proper iCE40PLL reset support and add back | self.rst.
pll.register_clkin(clk12, 12e6)
pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False)
self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked)
platform.add_period_constraint(self.cd_sys.clk, 1e9/sys_clk_freq)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, bios_flash_offset, sys_clk_freq=24e6,
with_led_chaser = True,
with_video_terminal = False,
**kwargs):
platform = icebreaker.Platform()
platform.add_extension(icebreaker.break_off_pmod)
# CRG --------------------------------------------------------------------------------------
self.crg = _CRG(platform, sys_clk_freq)
# SoCCore ----------------------------------------------------------------------------------
# Disable Integrated ROM/SRAM since too large for iCE40 and UP5K has specific SPRAM.
kwargs["integrated_sram_size"] = 0
kwargs["integrated_rom_size"] = 0
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on iCEBreaker", **kwargs)
# 128KB SPRAM (used as 64kB SRAM / 64kB RAM) -----------------------------------------------
self.spram = Up5kSPRAM(size=128 * KILOBYTE)
self.bus.add_slave("psram", self.spram.bus, SoCRegion(origin=self.mem_map["sram"], size=128 * KILOBYTE))
self.bus.add_region("sram", SoCRegion(
origin = self.bus.regions["psram"].origin + 0 * KILOBYTE,
size = 64 * KILOBYTE,
linker = True)
)
if not self.integrated_main_ram_size:
self.bus.add_region("main_ram", SoCRegion(
origin = self.bus.regions["psram"].origin + 64 * KILOBYTE,
size = 64 * KILOBYTE,
linker = True)
)
# SPI Flash --------------------------------------------------------------------------------
from litespi.modules import W25Q128JV
from litespi.opcodes import SpiNorFlashOpCodes as Codes
self.add_spi_flash(mode="4x", module=W25Q128JV(Codes.READ_1_1_4), with_master=False)
# Add ROM linker region --------------------------------------------------------------------
self.bus.add_region("rom", SoCRegion(
origin = self.bus.regions["spiflash"].origin + bios_flash_offset,
size = 32 * KILOBYTE,
linker = True)
)
self.cpu.set_reset_address(self.bus.regions["rom"].origin)
# Video ------------------------------------------------------------------------------------
if with_video_terminal:
platform.add_extension(icebreaker.dvi_pmod)
self.videophy = VideoDVIPHY(platform.request("dvi"), clock_domain="sys")
self.add_video_terminal(phy=self.videophy, timings="640x480@75Hz", clock_domain="sys")
# Leds -------------------------------------------------------------------------------------
if with_led_chaser:
self.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
# Flash --------------------------------------------------------------------------------------------
def flash(build_dir, build_name, bios_flash_offset):
from litex.build.lattice.programmer import IceStormProgrammer
prog = IceStormProgrammer()
prog.flash(bios_flash_offset, f"{build_dir}/software/bios/bios.bin")
prog.flash(0x00000000, f"{build_dir}/gateware/{build_name}.bin")
# Build --------------------------------------------------------------------------------------------
def main():
from litex.build.parser import LiteXArgumentParser
parser = LiteXArgumentParser(platform=icebreaker.Platform, description="LiteX SoC on iCEBreaker.")
parser.add_target_argument("--flash", action="store_true", help="Flash Bitstream and BIOS.")
parser.add_target_argument("--sys-clk-freq", default=24e6, type=float, help="System clock frequency.")
parser.add_target_argument("--bios-flash-offset", default="0x40000", help="BIOS offset in SPI Flash.")
parser.add_target_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (with DVI PMOD).")
args = parser.parse_args()
soc = BaseSoC(
bios_flash_offset = int(args.bios_flash_offset, 0),
sys_clk_freq = args.sys_clk_freq,
with_video_terminal = args.with_video_terminal,
**parser.soc_argdict
)
builder = Builder(soc, **parser.builder_argdict)
if args.build:
builder.build(**parser.toolchain_argdict)
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(builder.get_bitstream_filename(mode="sram", ext=".bin")) # FIXME
if args.flash:
flash(builder.output_dir, soc.build_name, args.bios_flash_offset)
if __name__ == "__main__":
main()