Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
R
rkx7-litex-boards
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Reform
rkx7-litex-boards
Commits
94ef096e
Commit
94ef096e
authored
4 years ago
by
Michael Betz
Browse files
Options
Downloads
Plain Diff
Merge branch 'master' of
https://github.com/litex-hub/litex-boards
into HEAD
parents
12aed445
fff20f75
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
litex_boards/targets/fomu.py
+116
-251
116 additions, 251 deletions
litex_boards/targets/fomu.py
with
116 additions
and
251 deletions
litex_boards/targets/fomu.py
+
116
−
251
View file @
94ef096e
...
...
@@ -5,295 +5,160 @@
#
# Copyright (c) 2019 Sean Cross <sean@xobs.io>
# Copyright (c) 2018 David Shah <dave@ds0.me>
# Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import
os
import
sys
import
argparse
from
migen
import
*
from
migen.genlib.resetsync
import
AsyncResetSynchronizer
from
litex.soc.cores
import
up5kspram
from
litex.soc.integration.soc_core
import
SoCCore
from
litex.soc.integration.builder
import
Builder
,
builder_argdict
,
builder_args
from
litex.soc.integration.soc_core
import
soc_core_argdict
,
soc_core_args
from
litex.soc.integration.doc
import
AutoDoc
from
litex_boards.platforms
import
fomu_pvt
from
valentyusb.usbcore
import
io
as
usbio
from
valentyusb.usbcore.cpu
import
dummyusb
,
epfifo
,
eptri
from
litex.soc.cores.up5kspram
import
Up5kSPRAM
from
litex.soc.cores.spi_flash
import
SpiFlash
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.led
import
LedChaser
import
os
,
shutil
,
subprocess
kB
=
1024
mB
=
1024
*
kB
# CRG ----------------------------------------------------------------------------------------------
class
_CRG
(
Module
,
AutoDoc
):
"""
Fomu Clock Resource Generator
Fomu is a USB device, which means it must have a 12 MHz clock. Valentyusb
oversamples the clock by 4x, which drives the requirement for a 48 MHz clock.
The ICE40UP5k is a relatively low speed grade of FPGA that is incapable of
running the entire design at 48 MHz, so the majority of the logic is placed
in the 12 MHz domain while only critical USB logic is placed in the fast
48 MHz domain.
Fomu has a 48 MHz crystal on it, which provides the raw clock input. This
signal is fed through the ICE40 PLL in order to divide it down into a 12 MHz
signal and keep the clocks within 1ns of phase. Earlier designs used a simple
flop, however this proved unreliable when the FPGA became very full.
The following clock domains are available on this design:
+---------+------------+---------------------------------+
| Name | Frequency | Description |
+=========+============+=================================+
| usb_48 | 48 MHz | Raw USB signals and pulse logic |
+---------+------------+---------------------------------+
| usb_12 | 12 MHz | USB control logic |
+---------+------------+---------------------------------+
| sys | 12 MHz | System CPU and wishbone bus |
+---------+------------+---------------------------------+
"""
def
__init__
(
self
,
platform
):
clk48_raw
=
platform
.
request
(
"
clk48
"
)
clk12
=
Signal
()
reset_delay
=
Signal
(
12
,
reset
=
4095
)
self
.
clock_domains
.
cd_por
=
ClockDomain
()
self
.
reset
=
Signal
()
self
.
clock_domains
.
cd_sys
=
ClockDomain
()
class
_CRG
(
Module
):
def
__init__
(
self
,
platform
,
sys_clk_freq
):
assert
sys_clk_freq
==
12e6
self
.
clock_domains
.
cd_sys
=
ClockDomain
()
self
.
clock_domains
.
cd_por
=
ClockDomain
(
reset_less
=
True
)
self
.
clock_domains
.
cd_usb_12
=
ClockDomain
()
self
.
clock_domains
.
cd_usb_48
=
ClockDomain
()
platform
.
add_period_constraint
(
self
.
cd_usb_48
.
clk
,
1e9
/
48e6
)
platform
.
add_period_constraint
(
self
.
cd_sys
.
clk
,
1e9
/
12e6
)
platform
.
add_period_constraint
(
self
.
cd_usb_12
.
clk
,
1e9
/
12e6
)
platform
.
add_period_constraint
(
clk48_raw
,
1e9
/
48e6
)
# POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset.
self
.
comb
+=
[
self
.
cd_por
.
clk
.
eq
(
self
.
cd_sys
.
clk
),
self
.
cd_sys
.
rst
.
eq
(
reset_delay
!=
0
),
self
.
cd_usb_12
.
rst
.
eq
(
reset_delay
!=
0
),
]
# POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset.
self
.
comb
+=
[
self
.
cd_usb_48
.
rst
.
eq
(
reset_delay
!=
0
),
]
# # #
self
.
comb
+=
self
.
cd_usb_48
.
clk
.
eq
(
clk48_raw
)
self
.
specials
+=
Instance
(
"
SB_PLL40_CORE
"
,
# Parameters
p_DIVR
=
0
,
p_DIVF
=
15
,
p_DIVQ
=
5
,
p_FILTER_RANGE
=
1
,
p_FEEDBACK_PATH
=
"
SIMPLE
"
,
p_DELAY_ADJUSTMENT_MODE_FEEDBACK
=
"
FIXED
"
,
p_FDA_FEEDBACK
=
15
,
p_DELAY_ADJUSTMENT_MODE_RELATIVE
=
"
FIXED
"
,
p_FDA_RELATIVE
=
0
,
p_SHIFTREG_DIV_MODE
=
1
,
p_PLLOUT_SELECT
=
"
GENCLK_HALF
"
,
p_ENABLE_ICEGATE
=
0
,
# IO
i_REFERENCECLK
=
clk48_raw
,
o_PLLOUTCORE
=
clk12
,
# o_PLLOUTGLOBAL = clk12,
#i_EXTFEEDBACK,
#i_DYNAMICDELAY,
#o_LOCK,
i_BYPASS
=
0
,
i_RESETB
=
1
,
#i_LATCHINPUTVALUE,
#o_SDO,
#i_SDI,
)
# Clk/Rst
clk48
=
platform
.
request
(
"
clk48
"
)
platform
.
add_period_constraint
(
clk48
,
1e9
/
48e6
)
self
.
comb
+=
self
.
cd_sys
.
clk
.
eq
(
clk12
)
self
.
comb
+=
self
.
cd_usb_12
.
clk
.
eq
(
clk12
)
# 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
))
self
.
sync
.
por
+=
\
If
(
reset_delay
!=
0
,
reset_delay
.
eq
(
reset_delay
-
1
)
)
self
.
specials
+=
AsyncResetSynchronizer
(
self
.
cd_por
,
self
.
reset
)
# USB PLL
self
.
submodules
.
pll
=
pll
=
iCE40PLL
()
pll
.
clko_freq_range
=
(
12e6
,
275e9
)
# FIXME: improve iCE40PLL to avoid lowering clko_freq_min.
pll
.
register_clkin
(
clk48
,
48e6
)
pll
.
create_clkout
(
self
.
cd_usb_12
,
12e6
,
with_reset
=
False
)
self
.
comb
+=
self
.
cd_usb_48
.
clk
.
eq
(
clk48
)
self
.
specials
+=
AsyncResetSynchronizer
(
self
.
cd_usb_12
,
~
por_done
|
~
pll
.
locked
)
self
.
specials
+=
AsyncResetSynchronizer
(
self
.
cd_usb_48
,
~
por_done
|
~
pll
.
locked
)
# Sys Clk
self
.
comb
+=
self
.
cd_sys
.
clk
.
eq
(
self
.
cd_usb_12
.
clk
)
self
.
specials
+=
AsyncResetSynchronizer
(
self
.
cd_sys
,
~
por_done
|
~
pll
.
locked
)
# BaseSoC ------------------------------------------------------------------------------------------
class
BaseSoC
(
SoCCore
):
"""
A SoC on Fomu, optionally with a softcore CPU
"""
# Create a default CSR map to prevent values from getting reassigned.
# This increases consistency across litex versions.
SoCCore
.
csr_map
=
{
"
ctrl
"
:
0
,
# provided by default (optional)
"
crg
"
:
1
,
# user
"
uart_phy
"
:
2
,
# provided by default (optional)
"
uart
"
:
3
,
# provided by default (optional)
"
identifier_mem
"
:
4
,
# provided by default (optional)
"
timer0
"
:
5
,
# provided by default (optional)
"
cpu_or_bridge
"
:
8
,
"
usb
"
:
9
,
"
picorvspi
"
:
10
,
"
touch
"
:
11
,
"
reboot
"
:
12
,
"
rgb
"
:
13
,
"
version
"
:
14
,
}
# Statically-define the memory map, to prevent it from shifting across
# various litex versions.
SoCCore
.
mem_map
=
{
"
rom
"
:
0x00000000
,
# (default shadow @0x80000000)
"
sram
"
:
0x10000000
,
# (default shadow @0xa0000000)
"
spiflash
"
:
0x20000000
,
# (default shadow @0xa0000000)
"
main_ram
"
:
0x40000000
,
# (default shadow @0xc0000000)
"
csr
"
:
0xe0000000
,
# (default shadow @0x60000000)
}
def
__init__
(
self
,
board
,
pnr_placer
=
"
heap
"
,
pnr_seed
=
0
,
usb_core
=
"
dummyusb
"
,
usb_bridge
=
False
,
use_dsp
=
True
,
**
kwargs
):
"""
Create a basic SoC for Fomu.
Create a basic SoC for Fomu, including a 48 MHz and 12 MHz clock
domain called `usb_48` and `usb_12`. The `sys` frequency will
run at 12 MHz.
The USB core will optionally have a bridge to the Wishbone bus.
Args:
board (str): Which Fomu board to build for: pvt, evt, or hacker
pnr_placer (str): Which placer to use in nextpnr
pnr_seed (int): Which seed to use in nextpnr
usb_core (str): The name of the USB core to use, if any: dummyusb, epfifo, eptri
usb_bridge (bool): Whether to include a USB-to-Wishbone bridge
Raises:
ValueError: If either the `usb_core` or `board` are unrecognized
Returns:
Newly-constructed SoC
"""
if
board
==
"
pvt
"
:
from
litex_boards.platforms.fomu_pvt
import
Platform
elif
board
==
"
hacker
"
:
from
litex_boards.platforms.fomu_hacker
import
Platform
elif
board
==
"
evt
"
:
from
litex_boards.platforms.fomu_evt
import
Platform
else
:
raise
ValueError
(
"
unrecognized fomu board: {}
"
.
format
(
board
))
platform
=
Platform
()
if
"
cpu_type
"
not
in
kwargs
:
kwargs
[
"
cpu_type
"
]
=
None
kwargs
[
"
cpu_variant
"
]
=
None
clk_freq
=
int
(
12e6
)
if
"
with_uart
"
not
in
kwargs
:
kwargs
[
"
with_uart
"
]
=
False
if
"
with_ctrl
"
not
in
kwargs
:
kwargs
[
"
with_ctrl
"
]
=
False
mem_map
=
{
**
SoCCore
.
mem_map
,
**
{
"
spiflash
"
:
0x80000000
}}
def
__init__
(
self
,
bios_flash_offset
,
**
kwargs
):
kwargs
[
"
uart_name
"
]
=
"
usb_acm
"
# Enforce UART to USB-ACM
sys_clk_freq
=
int
(
12e6
)
platform
=
fomu_pvt
.
Platform
()
# Disable Integrated ROM/SRAM since too large for iCE40 and UP5K has specific SPRAM.
kwargs
[
"
integrated_sram_size
"
]
=
0
SoCCore
.
__init__
(
self
,
platform
,
clk_freq
,
**
kwargs
)
self
.
submodules
.
crg
=
_CRG
(
platform
)
# UP5K has single port RAM, which is a dedicated 128 kilobyte block.
# Use this as CPU RAM.
spram_size
=
128
*
1024
self
.
submodules
.
spram
=
up5kspram
.
Up5kSPRAM
(
size
=
spram_size
)
self
.
register_mem
(
"
sram
"
,
self
.
mem_map
[
"
sram
"
],
self
.
spram
.
bus
,
spram_size
)
if
usb_core
is
not
None
:
# Add USB pads. We use DummyUsb, which simply enumerates as a USB
# device. Then all interaction is done via the wishbone bridge.
usb_pads
=
platform
.
request
(
"
usb
"
)
usb_iobuf
=
usbio
.
IoBuf
(
usb_pads
.
d_p
,
usb_pads
.
d_n
,
usb_pads
.
pullup
)
if
usb_core
==
"
dummyusb
"
:
self
.
submodules
.
usb
=
dummyusb
.
DummyUsb
(
usb_iobuf
,
debug
=
usb_bridge
)
elif
usb_core
==
"
epfifo
"
:
self
.
submodules
.
usb
=
epfifo
.
PerEndpointFifo
(
usb_iobuf
,
debug
=
usb_bridge
)
elif
usb_core
==
"
eptri
"
:
self
.
submodules
.
usb
=
eptri
.
TriEndpointInterface
(
usb_iobuf
,
debug
=
usb_bridge
)
else
:
raise
ValueError
(
"
unrecognized usb_core: {}
"
.
format
(
usb_core
))
if
usb_bridge
:
self
.
add_wb_master
(
self
.
usb
.
debug_bridge
.
wishbone
)
# Override default LiteX's yosys/build templates
assert
hasattr
(
platform
.
toolchain
,
"
yosys_template
"
)
assert
hasattr
(
platform
.
toolchain
,
"
build_template
"
)
platform
.
toolchain
.
yosys_template
=
[
"
{read_files}
"
,
"
attrmap -tocase keep -imap keep=
\"
true
\"
keep=1 -imap keep=
\"
false
\"
keep=0 -remove keep=0
"
,
"
synth_ice40 -json {build_name}.json -top {build_name}
"
,
]
platform
.
toolchain
.
build_template
=
[
"
yosys -q -l {build_name}.rpt {build_name}.ys
"
,
"
nextpnr-ice40 --json {build_name}.json --pcf {build_name}.pcf --asc {build_name}.txt
\
--pre-pack {build_name}_pre_pack.py --{architecture} --package {package}
"
,
"
icepack {build_name}.txt {build_name}.bin
"
]
# Add "-relut -dffe_min_ce_use 4" to the synth_ice40 command.
# The "-reult" adds an additional LUT pass to pack more stuff in,
# and the "-dffe_min_ce_use 4" flag prevents Yosys from generating a
# Clock Enable signal for a LUT that has fewer than 4 flip-flops.
# This increases density, and lets us use the FPGA more efficiently.
platform
.
toolchain
.
yosys_template
[
2
]
+=
"
-relut -abc2 -dffe_min_ce_use 4 -relut
"
if
use_dsp
:
platform
.
toolchain
.
yosys_template
[
2
]
+=
"
-dsp
"
# Disable final deep-sleep power down so firmware words are loaded
# onto softcore's address bus.
platform
.
toolchain
.
build_template
[
2
]
=
"
icepack -s {build_name}.txt {build_name}.bin
"
# Allow us to set the nextpnr seed
platform
.
toolchain
.
build_template
[
1
]
+=
"
--seed
"
+
str
(
pnr_seed
)
if
pnr_placer
is
not
None
:
platform
.
toolchain
.
build_template
[
1
]
+=
"
--placer {}
"
.
format
(
pnr_placer
)
class
USBSoC
(
BaseSoC
):
"""
A SoC for Fomu with interrupts for a softcore CPU
"""
interrupt_map
=
{
"
usb
"
:
3
,
}
interrupt_map
.
update
(
SoCCore
.
interrupt_map
)
kwargs
[
"
integrated_rom_size
"
]
=
0
# Set CPU variant / reset address
kwargs
[
"
cpu_reset_address
"
]
=
self
.
mem_map
[
"
spiflash
"
]
+
bios_flash_offset
# Serial -----------------------------------------------------------------------------------
# FIXME: do proper install of ValentyUSB.
# FIXME: replace IoBuf with https://github.com/im-tomu/valentyusb/blob/master/valentyusb/usbcore/io.py#L13-L61.
os
.
system
(
"
git clone https://github.com/gregdavill/valentyusb -b hw_cdc_eptri
"
)
sys
.
path
.
append
(
"
valentyusb
"
)
# SoCCore ----------------------------------------------------------------------------------
SoCCore
.
__init__
(
self
,
platform
,
sys_clk_freq
,
ident
=
"
LiteX SoC on Fomu
"
,
ident_version
=
True
,
**
kwargs
)
# CRG --------------------------------------------------------------------------------------
self
.
submodules
.
crg
=
_CRG
(
platform
,
sys_clk_freq
)
# 128KB SPRAM (used as SRAM) ---------------------------------------------------------------
self
.
submodules
.
spram
=
Up5kSPRAM
(
size
=
128
*
kB
)
self
.
bus
.
add_slave
(
"
sram
"
,
self
.
spram
.
bus
,
SoCRegion
(
size
=
128
*
kB
))
# SPI Flash --------------------------------------------------------------------------------
self
.
add_spi_flash
(
mode
=
"
1x
"
,
dummy_cycles
=
8
)
# Add ROM linker region --------------------------------------------------------------------
self
.
bus
.
add_region
(
"
rom
"
,
SoCRegion
(
origin
=
self
.
mem_map
[
"
spiflash
"
]
+
bios_flash_offset
,
size
=
32
*
kB
,
linker
=
True
)
)
# Leds -------------------------------------------------------------------------------------
self
.
submodules
.
leds
=
LedChaser
(
pads
=
platform
.
request_all
(
"
user_led_n
"
),
sys_clk_freq
=
sys_clk_freq
)
self
.
add_csr
(
"
leds
"
)
# Flash --------------------------------------------------------------------------------------------
def
flash
(
bios_flash_offset
):
from
litex.build.dfu
import
DFUProg
prog
=
DFUProg
(
vid
=
"
1209
"
,
pid
=
"
5bf0
"
)
bitstream
=
open
(
"
build/fomu_pvt/gateware/fomu_pvt.bin
"
,
"
rb
"
)
bios
=
open
(
"
build/fomu_pvt/software/bios/bios.bin
"
,
"
rb
"
)
image
=
open
(
"
build/fomu_pvt/image.bin
"
,
"
wb
"
)
# Copy bitstream at 0x00000000
for
i
in
range
(
0x00000000
,
0x0020000
):
b
=
bitstream
.
read
(
1
)
if
not
b
:
image
.
write
(
0xff
.
to_bytes
(
1
,
"
big
"
))
else
:
image
.
write
(
b
)
# Copy bios at 0x00020000
for
i
in
range
(
0x00000000
,
0x00010000
):
b
=
bios
.
read
(
1
)
if
not
b
:
image
.
write
(
0xff
.
to_bytes
(
1
,
"
big
"
))
else
:
image
.
write
(
b
)
bitstream
.
close
()
bios
.
close
()
image
.
close
()
prog
.
load_bitstream
(
"
build/fomu_pvt/image.bin
"
)
# Build --------------------------------------------------------------------------------------------
def
add_dfu_suffix
(
fn
):
fn_base
,
_ext
=
os
.
path
.
splitext
(
fn
)
fn_dfu
=
fn_base
+
'
.dfu
'
shutil
.
copyfile
(
fn
,
fn_dfu
)
subprocess
.
check_call
([
'
dfu-suffix
'
,
'
--pid
'
,
'
1209
'
,
'
--vid
'
,
'
5bf0
'
,
'
--add
'
,
fn_dfu
])
def
main
():
parser
=
argparse
.
ArgumentParser
(
description
=
"
LiteX SoC on Fomu
"
)
parser
.
add_argument
(
"
--build
"
,
action
=
"
store_true
"
,
help
=
"
Build bitstream
"
)
parser
.
add_argument
(
"
--board
"
,
choices
=
[
"
evt
"
,
"
pvt
"
,
"
hacker
"
],
required
=
True
,
help
=
"
Build for a particular hardware board
"
)
parser
.
add_argument
(
"
--seed
"
,
default
=
0
,
help
=
"
Seed to use in Nextpnr
"
)
parser
.
add_argument
(
"
--placer
"
,
default
=
"
heap
"
,
choices
=
[
"
sa
"
,
"
heap
"
],
help
=
"
Which placer to use in Nextpnr
"
)
parser
.
add_argument
(
"
--build
"
,
action
=
"
store_true
"
,
help
=
"
Build bitstream
"
)
parser
.
add_argument
(
"
--bios-flash-offset
"
,
default
=
0x60000
,
help
=
"
BIOS offset in SPI Flash
"
)
parser
.
add_argument
(
"
--flash
"
,
action
=
"
store_true
"
,
help
=
"
Flash Bitstream
"
)
builder_args
(
parser
)
soc_core_args
(
parser
)
args
=
parser
.
parse_args
()
soc
=
BaseSoC
(
board
=
args
.
board
,
pnr_placer
=
args
.
placer
,
pnr_seed
=
args
.
seed
,
debug
=
True
,
**
soc_core_argdict
(
args
))
soc
=
BaseSoC
(
args
.
bios_flash_offset
,
**
soc_core_argdict
(
args
))
builder
=
Builder
(
soc
,
**
builder_argdict
(
args
))
builder
.
build
(
run
=
args
.
build
)
if
args
.
flash
:
flash
(
args
.
bios_flash_offset
)
if
__name__
==
"
__main__
"
:
main
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment