sw: first software commit
The software is untested, but it builds. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
14
hw/bin/litex_read_verilog
Executable file
14
hw/bin/litex_read_verilog
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
from litex.tools.litex_read_verilog import main
|
||||
main()
|
14
hw/bin/litex_server
Executable file
14
hw/bin/litex_server
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
from litex.tools.litex_server import main
|
||||
main()
|
14
hw/bin/litex_sim
Executable file
14
hw/bin/litex_sim
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
from litex.tools.litex_sim import main
|
||||
main()
|
14
hw/bin/litex_simple
Executable file
14
hw/bin/litex_simple
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
from litex.boards.targets.simple import main
|
||||
main()
|
14
hw/bin/litex_term
Executable file
14
hw/bin/litex_term
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
from litex.tools.litex_term import main
|
||||
main()
|
14
hw/bin/mkmscimg
Executable file
14
hw/bin/mkmscimg
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
from litex.soc.software.mkmscimg import main
|
||||
main()
|
1
hw/deps/litedram
Submodule
1
hw/deps/litedram
Submodule
Submodule hw/deps/litedram added at da68e21bad
1
hw/deps/litescope
Submodule
1
hw/deps/litescope
Submodule
Submodule hw/deps/litescope added at 7f20aa477f
1
hw/deps/litex
Submodule
1
hw/deps/litex
Submodule
Submodule hw/deps/litex added at 3a72688b28
1
hw/deps/lxsocsupport
Submodule
1
hw/deps/lxsocsupport
Submodule
Submodule hw/deps/lxsocsupport added at 74f1333401
1
hw/deps/migen
Submodule
1
hw/deps/migen
Submodule
Submodule hw/deps/migen added at bc903441a5
1
hw/deps/pyserial
Submodule
1
hw/deps/pyserial
Submodule
Submodule hw/deps/pyserial added at acab9d2c0e
1
hw/deps/valentyusb
Submodule
1
hw/deps/valentyusb
Submodule
Submodule hw/deps/valentyusb added at 3052a16d9f
883
hw/factory-bitstream.py
Normal file
883
hw/factory-bitstream.py
Normal file
@ -0,0 +1,883 @@
|
||||
#!/usr/bin/env python3
|
||||
# This variable defines all the external programs that this module
|
||||
# relies on. lxbuildenv reads this variable in order to ensure
|
||||
# the build will finish without exiting due to missing third-party
|
||||
# programs.
|
||||
LX_DEPENDENCIES = ["riscv", "icestorm", "yosys"]
|
||||
|
||||
# Import lxbuildenv to integrate the deps/ directory
|
||||
import lxbuildenv
|
||||
|
||||
# Disable pylint's E1101, which breaks completely on migen
|
||||
#pylint:disable=E1101
|
||||
|
||||
#from migen import *
|
||||
from migen import Module, Signal, Instance, ClockDomain, If
|
||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||
from migen.fhdl.specials import TSTriple
|
||||
from migen.fhdl.bitcontainer import bits_for
|
||||
from migen.fhdl.structure import ClockSignal, ResetSignal, Replicate, Cat
|
||||
|
||||
from litex.build.lattice.platform import LatticePlatform
|
||||
from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal
|
||||
from litex.soc.integration import SoCCore
|
||||
from litex.soc.integration.builder import Builder
|
||||
from litex.soc.integration.soc_core import csr_map_update
|
||||
from litex.soc.interconnect import wishbone
|
||||
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
|
||||
|
||||
from valentyusb import usbcore
|
||||
from valentyusb.usbcore import io as usbio
|
||||
from valentyusb.usbcore.cpu import epmem, unififo, epfifo
|
||||
from valentyusb.usbcore.endpoint import EndpointType
|
||||
|
||||
from lxsocsupport import up5kspram, spi_flash
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
_io_evt = [
|
||||
("serial", 0,
|
||||
Subsignal("rx", Pins("21")),
|
||||
Subsignal("tx", Pins("13"), Misc("PULLUP")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
("usb", 0,
|
||||
Subsignal("d_p", Pins("34")),
|
||||
Subsignal("d_n", Pins("37")),
|
||||
Subsignal("pullup", Pins("35")),
|
||||
Subsignal("pulldown", Pins("36")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
("touch", 0,
|
||||
Subsignal("t1", Pins("48"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t2", Pins("47"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t3", Pins("46"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t4", Pins("45"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("pmoda", 0,
|
||||
Subsignal("p1", Pins("28"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p2", Pins("27"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p3", Pins("26"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p4", Pins("23"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("pmodb", 0,
|
||||
Subsignal("p1", Pins("48"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p2", Pins("47"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p3", Pins("46"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p4", Pins("45"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("led", 0,
|
||||
Subsignal("rgb0", Pins("39"), IOStandard("LVCMOS33")),
|
||||
Subsignal("rgb1", Pins("40"), IOStandard("LVCMOS33")),
|
||||
Subsignal("rgb2", Pins("41"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("spiflash", 0,
|
||||
Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")),
|
||||
Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")),
|
||||
Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")),
|
||||
Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")),
|
||||
Subsignal("wp", Pins("18"), IOStandard("LVCMOS33")),
|
||||
Subsignal("hold", Pins("19"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("spiflash4x", 0,
|
||||
Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")),
|
||||
Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")),
|
||||
Subsignal("dq", Pins("14 17 19 18"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("clk48", 0, Pins("44"), IOStandard("LVCMOS33"))
|
||||
]
|
||||
|
||||
_io_pvt = [
|
||||
("serial", 0,
|
||||
Subsignal("rx", Pins("C3")),
|
||||
Subsignal("tx", Pins("B3"), Misc("PULLUP")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
("usb", 0,
|
||||
Subsignal("d_p", Pins("A1")),
|
||||
Subsignal("d_n", Pins("A2")),
|
||||
Subsignal("pullup", Pins("A4")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
("touch", 0,
|
||||
Subsignal("t1", Pins("E4"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t2", Pins("D5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t3", Pins("E5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t4", Pins("F5"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("led", 0,
|
||||
Subsignal("rgb0", Pins("A5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("rgb1", Pins("B5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("rgb2", Pins("C5"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("spiflash", 0,
|
||||
Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("miso", Pins("E1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("mosi", Pins("F1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("wp", Pins("F2"), IOStandard("LVCMOS33")),
|
||||
Subsignal("hold", Pins("B1"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("spiflash4x", 0,
|
||||
Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("dq", Pins("E1 F1 F2 B1"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("clk48", 0, Pins("F4"), IOStandard("LVCMOS33"))
|
||||
]
|
||||
|
||||
_io_hacker = [
|
||||
("serial", 0,
|
||||
Subsignal("rx", Pins("C3")),
|
||||
Subsignal("tx", Pins("B3"), Misc("PULLUP")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
("usb", 0,
|
||||
Subsignal("d_p", Pins("A4")),
|
||||
Subsignal("d_n", Pins("A2")),
|
||||
Subsignal("pullup", Pins("D5")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
("touch", 0,
|
||||
Subsignal("t1", Pins("F4"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t2", Pins("E5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t3", Pins("E4"), IOStandard("LVCMOS33")),
|
||||
Subsignal("t4", Pins("F2"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("led", 0,
|
||||
Subsignal("rgb0", Pins("A5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("rgb1", Pins("B5"), IOStandard("LVCMOS33")),
|
||||
Subsignal("rgb2", Pins("C5"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("spiflash", 0,
|
||||
Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("miso", Pins("E1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("mosi", Pins("F1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("wp", Pins("A1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("hold", Pins("B1"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("spiflash4x", 0,
|
||||
Subsignal("cs_n", Pins("C1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("clk", Pins("D1"), IOStandard("LVCMOS33")),
|
||||
Subsignal("dq", Pins("E1 F1 A1 B1"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
("clk48", 0, Pins("F5"), IOStandard("LVCMOS33"))
|
||||
]
|
||||
|
||||
_connectors = []
|
||||
|
||||
class _CRG(Module):
|
||||
def __init__(self, platform, use_pll):
|
||||
clk48_raw = platform.request("clk48")
|
||||
clk12_raw = Signal()
|
||||
clk48 = Signal()
|
||||
clk12 = Signal()
|
||||
|
||||
reset_delay = Signal(13, reset=4095)
|
||||
self.clock_domains.cd_por = ClockDomain()
|
||||
self.reset = Signal()
|
||||
|
||||
self.clock_domains.cd_sys = ClockDomain()
|
||||
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, 1e9/48e6)
|
||||
platform.add_period_constraint(clk48_raw, 1e9/48e6)
|
||||
platform.add_period_constraint(clk12_raw, 1e9/12e6)
|
||||
|
||||
# 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),
|
||||
]
|
||||
|
||||
if use_pll:
|
||||
# Divide clk48 down to clk12, to ensure they're synchronized.
|
||||
# By doing this, we avoid needing clock-domain crossing.
|
||||
clk12_counter = Signal(2)
|
||||
|
||||
self.clock_domains.cd_usb_48_raw = ClockDomain()
|
||||
|
||||
platform.add_period_constraint(self.cd_usb_48_raw.clk, 1e9/48e6)
|
||||
|
||||
# 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_raw.clk.eq(clk48_raw)
|
||||
self.comb += self.cd_usb_48.clk.eq(clk48)
|
||||
|
||||
self.sync.usb_48_raw += clk12_counter.eq(clk12_counter + 1)
|
||||
|
||||
self.comb += clk12_raw.eq(clk12_counter[1])
|
||||
self.specials += Instance(
|
||||
"SB_GB",
|
||||
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw,
|
||||
o_GLOBAL_BUFFER_OUTPUT=clk12,
|
||||
)
|
||||
|
||||
self.specials += Instance(
|
||||
"SB_PLL40_CORE",
|
||||
# Parameters
|
||||
p_DIVR = 0,
|
||||
p_DIVF = 3,
|
||||
p_DIVQ = 2,
|
||||
p_FILTER_RANGE = 1,
|
||||
p_FEEDBACK_PATH = "PHASE_AND_DELAY",
|
||||
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 = "SHIFTREG_0deg",
|
||||
p_ENABLE_ICEGATE = 0,
|
||||
# IO
|
||||
i_REFERENCECLK = clk12,
|
||||
# o_PLLOUTCORE = clk12,
|
||||
o_PLLOUTGLOBAL = clk48,
|
||||
#i_EXTFEEDBACK,
|
||||
#i_DYNAMICDELAY,
|
||||
#o_LOCK,
|
||||
i_BYPASS = 0,
|
||||
i_RESETB = 1,
|
||||
#i_LATCHINPUTVALUE,
|
||||
#o_SDO,
|
||||
#i_SDI,
|
||||
)
|
||||
else:
|
||||
self.specials += Instance(
|
||||
"SB_GB",
|
||||
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk48_raw,
|
||||
o_GLOBAL_BUFFER_OUTPUT=clk48,
|
||||
)
|
||||
self.comb += self.cd_usb_48.clk.eq(clk48)
|
||||
|
||||
clk12_counter = Signal(2)
|
||||
self.sync.usb_48 += clk12_counter.eq(clk12_counter + 1)
|
||||
|
||||
self.comb += clk12_raw.eq(clk12_counter[1])
|
||||
self.specials += Instance(
|
||||
"SB_GB",
|
||||
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw,
|
||||
o_GLOBAL_BUFFER_OUTPUT=clk12,
|
||||
)
|
||||
|
||||
self.comb += self.cd_sys.clk.eq(clk12)
|
||||
self.comb += self.cd_usb_12.clk.eq(clk12)
|
||||
|
||||
self.sync.por += \
|
||||
If(reset_delay != 0,
|
||||
reset_delay.eq(reset_delay - 1)
|
||||
)
|
||||
self.specials += AsyncResetSynchronizer(self.cd_por, self.reset)
|
||||
|
||||
class RandomFirmwareROM(wishbone.SRAM):
|
||||
"""
|
||||
Seed the random data with a fixed number, so different bitstreams
|
||||
can all share firmware.
|
||||
"""
|
||||
def __init__(self, size, seed=2373):
|
||||
def xorshift32(x):
|
||||
x = x ^ (x << 13) & 0xffffffff
|
||||
x = x ^ (x >> 17) & 0xffffffff
|
||||
x = x ^ (x << 5) & 0xffffffff
|
||||
return x & 0xffffffff
|
||||
|
||||
def get_rand(x):
|
||||
out = 0
|
||||
for i in range(32):
|
||||
x = xorshift32(x)
|
||||
if (x & 1) == 1:
|
||||
out = out | (1 << i)
|
||||
return out & 0xffffffff
|
||||
data = []
|
||||
seed = 1
|
||||
for d in range(int(size / 4)):
|
||||
seed = get_rand(seed)
|
||||
data.append(seed)
|
||||
wishbone.SRAM.__init__(self, size, read_only=True, init=data)
|
||||
|
||||
class FirmwareROM(wishbone.SRAM):
|
||||
def __init__(self, size, filename):
|
||||
data = []
|
||||
with open(filename, 'rb') as inp:
|
||||
data = inp.read()
|
||||
wishbone.SRAM.__init__(self, size, read_only=True, init=data)
|
||||
|
||||
class Platform(LatticePlatform):
|
||||
def __init__(self, revision=None, toolchain="icestorm"):
|
||||
if revision == "evt":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-sg48", _io_evt, _connectors, toolchain="icestorm")
|
||||
elif revision == "pvt" or revision == "dvt":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_pvt, _connectors, toolchain="icestorm")
|
||||
elif revision == "hacker":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_hacker, _connectors, toolchain="icestorm")
|
||||
else:
|
||||
raise ValueError("Unrecognized reivsion: {}. Known values: evt, dvt, pvt, hacker".format(revision))
|
||||
|
||||
def create_programmer(self):
|
||||
raise ValueError("programming is not supported")
|
||||
|
||||
class SBLED(Module, AutoCSR):
|
||||
def __init__(self, pads):
|
||||
rgba_pwm = Signal(3)
|
||||
|
||||
self.dat = CSRStorage(8)
|
||||
self.addr = CSRStorage(4)
|
||||
self.ctrl = CSRStorage(4)
|
||||
|
||||
self.specials += Instance("SB_RGBA_DRV",
|
||||
i_CURREN = self.ctrl.storage[1],
|
||||
i_RGBLEDEN = self.ctrl.storage[2],
|
||||
i_RGB0PWM = rgba_pwm[0],
|
||||
i_RGB1PWM = rgba_pwm[1],
|
||||
i_RGB2PWM = rgba_pwm[2],
|
||||
o_RGB0 = pads.rgb0,
|
||||
o_RGB1 = pads.rgb1,
|
||||
o_RGB2 = pads.rgb2,
|
||||
p_CURRENT_MODE = "0b1",
|
||||
p_RGB0_CURRENT = "0b000011",
|
||||
p_RGB1_CURRENT = "0b000001",
|
||||
p_RGB2_CURRENT = "0b000011",
|
||||
)
|
||||
|
||||
self.specials += Instance("SB_LEDDA_IP",
|
||||
i_LEDDCS = self.dat.re,
|
||||
i_LEDDCLK = ClockSignal(),
|
||||
i_LEDDDAT7 = self.dat.storage[7],
|
||||
i_LEDDDAT6 = self.dat.storage[6],
|
||||
i_LEDDDAT5 = self.dat.storage[5],
|
||||
i_LEDDDAT4 = self.dat.storage[4],
|
||||
i_LEDDDAT3 = self.dat.storage[3],
|
||||
i_LEDDDAT2 = self.dat.storage[2],
|
||||
i_LEDDDAT1 = self.dat.storage[1],
|
||||
i_LEDDDAT0 = self.dat.storage[0],
|
||||
i_LEDDADDR3 = self.addr.storage[3],
|
||||
i_LEDDADDR2 = self.addr.storage[2],
|
||||
i_LEDDADDR1 = self.addr.storage[1],
|
||||
i_LEDDADDR0 = self.addr.storage[0],
|
||||
i_LEDDDEN = self.dat.re,
|
||||
i_LEDDEXE = self.ctrl.storage[0],
|
||||
# o_LEDDON = led_is_on, # Indicates whether LED is on or not
|
||||
# i_LEDDRST = ResetSignal(), # This port doesn't actually exist
|
||||
o_PWMOUT0 = rgba_pwm[0],
|
||||
o_PWMOUT1 = rgba_pwm[1],
|
||||
o_PWMOUT2 = rgba_pwm[2],
|
||||
o_LEDDON = Signal(),
|
||||
)
|
||||
|
||||
|
||||
class SBWarmBoot(Module, AutoCSR):
|
||||
def __init__(self):
|
||||
self.ctrl = CSRStorage(size=8)
|
||||
self.addr = CSRStorage(size=32)
|
||||
do_reset = Signal()
|
||||
self.comb += [
|
||||
# "Reset Key" is 0xac (0b101011xx)
|
||||
do_reset.eq(self.ctrl.storage[2] & self.ctrl.storage[3] & ~self.ctrl.storage[4]
|
||||
& self.ctrl.storage[5] & ~self.ctrl.storage[6] & self.ctrl.storage[7])
|
||||
]
|
||||
self.specials += Instance("SB_WARMBOOT",
|
||||
i_S0 = self.ctrl.storage[0],
|
||||
i_S1 = self.ctrl.storage[1],
|
||||
i_BOOT = do_reset,
|
||||
)
|
||||
|
||||
class TouchPads(Module, AutoCSR):
|
||||
def __init__(self, pads):
|
||||
touch1 = TSTriple()
|
||||
touch2 = TSTriple()
|
||||
touch3 = TSTriple()
|
||||
touch4 = TSTriple()
|
||||
self.specials += touch1.get_tristate(pads.t1)
|
||||
self.specials += touch2.get_tristate(pads.t2)
|
||||
self.specials += touch3.get_tristate(pads.t3)
|
||||
self.specials += touch4.get_tristate(pads.t4)
|
||||
|
||||
self.o = CSRStorage(size=4)
|
||||
self.oe = CSRStorage(size=4)
|
||||
self.i = CSRStatus(size=4)
|
||||
|
||||
self.comb += [
|
||||
touch1.o.eq(self.o.storage[0]),
|
||||
touch2.o.eq(self.o.storage[1]),
|
||||
touch3.o.eq(self.o.storage[2]),
|
||||
touch4.o.eq(self.o.storage[3]),
|
||||
|
||||
touch1.oe.eq(self.oe.storage[0]),
|
||||
touch2.oe.eq(self.oe.storage[1]),
|
||||
touch3.oe.eq(self.oe.storage[2]),
|
||||
touch4.oe.eq(self.oe.storage[3]),
|
||||
|
||||
self.i.status.eq(Cat(touch1.i, touch2.i, touch3.i, touch4.i))
|
||||
]
|
||||
|
||||
|
||||
class PicoRVSpi(Module, AutoCSR):
|
||||
def __init__(self, platform, pads, size=2*1024*1024):
|
||||
self.size = size
|
||||
|
||||
self.bus = bus = wishbone.Interface()
|
||||
|
||||
self.reset = Signal()
|
||||
|
||||
self.cfg1 = CSRStorage(size=8)
|
||||
self.cfg2 = CSRStorage(size=8)
|
||||
self.cfg3 = CSRStorage(size=8)
|
||||
self.cfg4 = CSRStorage(size=8)
|
||||
|
||||
self.stat1 = CSRStatus(size=8)
|
||||
self.stat2 = CSRStatus(size=8)
|
||||
self.stat3 = CSRStatus(size=8)
|
||||
self.stat4 = CSRStatus(size=8)
|
||||
|
||||
cfg = Signal(32)
|
||||
cfg_we = Signal(4)
|
||||
cfg_out = Signal(32)
|
||||
self.comb += [
|
||||
cfg.eq(Cat(self.cfg1.storage, self.cfg2.storage, self.cfg3.storage, self.cfg4.storage)),
|
||||
cfg_we.eq(Cat(self.cfg1.re, self.cfg2.re, self.cfg3.re, self.cfg4.re)),
|
||||
self.stat1.status.eq(cfg_out[0:8]),
|
||||
self.stat2.status.eq(cfg_out[8:16]),
|
||||
self.stat3.status.eq(cfg_out[16:24]),
|
||||
self.stat4.status.eq(cfg_out[24:32]),
|
||||
]
|
||||
|
||||
mosi_pad = TSTriple()
|
||||
miso_pad = TSTriple()
|
||||
cs_n_pad = TSTriple()
|
||||
clk_pad = TSTriple()
|
||||
wp_pad = TSTriple()
|
||||
hold_pad = TSTriple()
|
||||
self.specials += mosi_pad.get_tristate(pads.mosi)
|
||||
self.specials += miso_pad.get_tristate(pads.miso)
|
||||
self.specials += cs_n_pad.get_tristate(pads.cs_n)
|
||||
self.specials += clk_pad.get_tristate(pads.clk)
|
||||
self.specials += wp_pad.get_tristate(pads.wp)
|
||||
self.specials += hold_pad.get_tristate(pads.hold)
|
||||
|
||||
reset = Signal()
|
||||
self.comb += [
|
||||
reset.eq(ResetSignal() | self.reset),
|
||||
cs_n_pad.oe.eq(~reset),
|
||||
clk_pad.oe.eq(~reset),
|
||||
]
|
||||
|
||||
flash_addr = Signal(24)
|
||||
mem_bits = bits_for(size)
|
||||
self.comb += flash_addr.eq(bus.adr[0:mem_bits-2] << 2),
|
||||
|
||||
read_active = Signal()
|
||||
spi_ready = Signal()
|
||||
self.sync += [
|
||||
If(bus.stb & bus.cyc & ~read_active,
|
||||
read_active.eq(1),
|
||||
bus.ack.eq(0),
|
||||
)
|
||||
.Elif(read_active & spi_ready,
|
||||
read_active.eq(0),
|
||||
bus.ack.eq(1),
|
||||
)
|
||||
.Else(
|
||||
bus.ack.eq(0),
|
||||
read_active.eq(0),
|
||||
)
|
||||
]
|
||||
|
||||
o_rdata = Signal(32)
|
||||
self.comb += bus.dat_r.eq(o_rdata)
|
||||
|
||||
self.specials += Instance("spimemio",
|
||||
o_flash_io0_oe = mosi_pad.oe,
|
||||
o_flash_io1_oe = miso_pad.oe,
|
||||
o_flash_io2_oe = wp_pad.oe,
|
||||
o_flash_io3_oe = hold_pad.oe,
|
||||
|
||||
o_flash_io0_do = mosi_pad.o,
|
||||
o_flash_io1_do = miso_pad.o,
|
||||
o_flash_io2_do = wp_pad.o,
|
||||
o_flash_io3_do = hold_pad.o,
|
||||
o_flash_csb = cs_n_pad.o,
|
||||
o_flash_clk = clk_pad.o,
|
||||
|
||||
i_flash_io0_di = mosi_pad.i,
|
||||
i_flash_io1_di = miso_pad.i,
|
||||
i_flash_io2_di = wp_pad.i,
|
||||
i_flash_io3_di = hold_pad.i,
|
||||
|
||||
i_resetn = ~reset,
|
||||
i_clk = ClockSignal(),
|
||||
|
||||
i_valid = bus.stb & bus.cyc,
|
||||
o_ready = spi_ready,
|
||||
i_addr = flash_addr,
|
||||
o_rdata = o_rdata,
|
||||
|
||||
i_cfgreg_we = cfg_we,
|
||||
i_cfgreg_di = cfg,
|
||||
o_cfgreg_do = cfg_out,
|
||||
)
|
||||
platform.add_source("rtl/spimemio.v")
|
||||
|
||||
class BBSpi(Module, AutoCSR):
|
||||
def __init__(self, platform, pads):
|
||||
self.reset = Signal()
|
||||
|
||||
mosi_pad = TSTriple()
|
||||
miso_pad = TSTriple()
|
||||
cs_n_pad = TSTriple()
|
||||
clk_pad = TSTriple()
|
||||
wp_pad = TSTriple()
|
||||
hold_pad = TSTriple()
|
||||
|
||||
self.do = CSRStorage(size=6)
|
||||
self.oe = CSRStorage(size=6)
|
||||
self.di = CSRStatus(size=6)
|
||||
|
||||
self.specials += mosi_pad.get_tristate(pads.mosi)
|
||||
self.specials += miso_pad.get_tristate(pads.miso)
|
||||
self.specials += cs_n_pad.get_tristate(pads.cs_n)
|
||||
self.specials += clk_pad.get_tristate(pads.clk)
|
||||
self.specials += wp_pad.get_tristate(pads.wp)
|
||||
self.specials += hold_pad.get_tristate(pads.hold)
|
||||
|
||||
self.comb += [
|
||||
mosi_pad.oe.eq(self.oe.storage[0]),
|
||||
miso_pad.oe.eq(self.oe.storage[1]),
|
||||
wp_pad.oe.eq(self.oe.storage[2]),
|
||||
hold_pad.oe.eq(self.oe.storage[3]),
|
||||
clk_pad.oe.eq(self.oe.storage[4]),
|
||||
cs_n_pad.oe.eq(self.oe.storage[5]),
|
||||
|
||||
mosi_pad.o.eq(self.do.storage[0]),
|
||||
miso_pad.o.eq(self.do.storage[1]),
|
||||
wp_pad.o.eq(self.do.storage[2]),
|
||||
hold_pad.o.eq(self.do.storage[3]),
|
||||
clk_pad.o.eq(self.do.storage[4]),
|
||||
cs_n_pad.o.eq(self.do.storage[5]),
|
||||
|
||||
self.di.status.eq(Cat(mosi_pad.i, miso_pad.i, wp_pad.i, hold_pad.i, clk_pad.i, cs_n_pad.i)),
|
||||
]
|
||||
|
||||
class Version(Module, AutoCSR):
|
||||
def __init__(self):
|
||||
def makeint(i, base=10):
|
||||
try:
|
||||
return int(i, base=base)
|
||||
except:
|
||||
return 0
|
||||
def get_gitver():
|
||||
import subprocess
|
||||
def decode_version(v):
|
||||
version = v.split(".")
|
||||
major = 0
|
||||
minor = 0
|
||||
rev = 0
|
||||
if len(version) >= 3:
|
||||
rev = makeint(version[2])
|
||||
if len(version) >= 2:
|
||||
minor = makeint(version[1])
|
||||
if len(version) >= 1:
|
||||
major = makeint(version[0])
|
||||
return (major, minor, rev)
|
||||
git_rev_cmd = subprocess.Popen(["git", "describe", "--tags", "--dirty=+"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(git_stdout, _) = git_rev_cmd.communicate()
|
||||
if git_rev_cmd.wait() != 0:
|
||||
git_rev_cmd = subprocess.Popen(["git", "rev-parse", "HEAD"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(git_stdout, _) = git_rev_cmd.communicate()
|
||||
if git_rev_cmd.wait() != 0:
|
||||
print('WARNING: unable to get git version')
|
||||
return (0, 0, 0, 0, 0, False)
|
||||
return (0, 0, 0, makeint(git_stdout[0:8], 16), 0, False)
|
||||
raw_git_rev = git_stdout.decode().strip()
|
||||
|
||||
dirty = False
|
||||
if raw_git_rev[-1] == "+":
|
||||
raw_git_rev = raw_git_rev[:-1]
|
||||
dirty = True
|
||||
|
||||
parts = raw_git_rev.split("-")
|
||||
major = 0
|
||||
minor = 0
|
||||
rev = 0
|
||||
gitrev = 0
|
||||
gitextra = 0
|
||||
|
||||
if len(parts) >= 3:
|
||||
if parts[0].startswith("v"):
|
||||
version = parts[0]
|
||||
if version.startswith("v"):
|
||||
version = parts[0][1:]
|
||||
(major, minor, rev) = decode_version(version)
|
||||
gitextra = makeint(parts[1])
|
||||
if parts[2].startswith("g"):
|
||||
gitrev = makeint(parts[2][1:], base=16)
|
||||
elif len(parts) >= 2:
|
||||
if parts[1].startswith("g"):
|
||||
gitrev = makeint(parts[1][1:], base=16)
|
||||
version = parts[0]
|
||||
if version.startswith("v"):
|
||||
version = parts[0][1:]
|
||||
(major, minor, rev) = decode_version(version)
|
||||
elif len(parts) >= 1:
|
||||
version = parts[0]
|
||||
if version.startswith("v"):
|
||||
version = parts[0][1:]
|
||||
(major, minor, rev) = decode_version(version)
|
||||
|
||||
return (major, minor, rev, gitrev, gitextra, dirty)
|
||||
|
||||
self.major = CSRStatus(8)
|
||||
self.minor = CSRStatus(8)
|
||||
self.revision = CSRStatus(8)
|
||||
self.gitrev = CSRStatus(32)
|
||||
self.gitextra = CSRStatus(10)
|
||||
self.dirty = CSRStatus(1)
|
||||
|
||||
(major, minor, rev, gitrev, gitextra, dirty) = get_gitver()
|
||||
self.comb += [
|
||||
self.major.status.eq(major),
|
||||
self.minor.status.eq(minor),
|
||||
self.revision.status.eq(rev),
|
||||
self.gitrev.status.eq(gitrev),
|
||||
self.gitextra.status.eq(gitextra),
|
||||
self.dirty.status.eq(dirty),
|
||||
]
|
||||
|
||||
|
||||
class BaseSoC(SoCCore):
|
||||
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,
|
||||
}
|
||||
|
||||
mem_map = {
|
||||
"spiflash": 0x20000000, # (default shadow @0xa0000000)
|
||||
}
|
||||
mem_map.update(SoCCore.mem_map)
|
||||
|
||||
interrupt_map = {
|
||||
"usb": 3,
|
||||
}
|
||||
interrupt_map.update(SoCCore.interrupt_map)
|
||||
|
||||
def __init__(self, platform, boot_source="rand",
|
||||
debug=None, bios_file=None, use_pll=True,
|
||||
use_dsp=False, placer=None, output_dir="build",
|
||||
**kwargs):
|
||||
# Disable integrated RAM as we'll add it later
|
||||
self.integrated_sram_size = 0
|
||||
|
||||
self.output_dir = output_dir
|
||||
|
||||
clk_freq = int(12e6)
|
||||
self.submodules.crg = _CRG(platform, use_pll=use_pll)
|
||||
|
||||
SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, with_uart=False, **kwargs)
|
||||
|
||||
usb_debug = False
|
||||
if debug is not None:
|
||||
if debug == "uart":
|
||||
from litex.soc.cores.uart import UARTWishboneBridge
|
||||
self.submodules.uart_bridge = UARTWishboneBridge(platform.request("serial"), clk_freq, baudrate=115200)
|
||||
self.add_wb_master(self.uart_bridge.wishbone)
|
||||
elif debug == "usb":
|
||||
usb_debug = True
|
||||
if hasattr(self, "cpu"):
|
||||
self.cpu.use_external_variant("rtl/2-stage-1024-cache-debug.v")
|
||||
self.copy_memory_file("2-stage-1024-cache-debug.v_toplevel_RegFilePlugin_regFile.bin")
|
||||
os.path.join(output_dir, "gateware")
|
||||
self.register_mem("vexriscv_debug", 0xf00f0000, self.cpu.debug_bus, 0x10)
|
||||
else:
|
||||
if hasattr(self, "cpu"):
|
||||
self.cpu.use_external_variant("rtl/2-stage-1024-cache.v")
|
||||
self.copy_memory_file("2-stage-1024-cache.v_toplevel_RegFilePlugin_regFile.bin")
|
||||
|
||||
# SPRAM- UP5K has single port RAM, might as well use it as SRAM to
|
||||
# free up scarce block RAM.
|
||||
spram_size = 128*1024
|
||||
self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size)
|
||||
self.register_mem("sram", 0x10000000, self.spram.bus, spram_size)
|
||||
|
||||
if boot_source == "rand":
|
||||
kwargs['cpu_reset_address']=0
|
||||
bios_size = 0x2000
|
||||
self.submodules.random_rom = RandomFirmwareROM(bios_size)
|
||||
self.add_constant("ROM_DISABLE", 1)
|
||||
self.register_rom(self.random_rom.bus, bios_size)
|
||||
elif boot_source == "bios":
|
||||
kwargs['cpu_reset_address'] = 0
|
||||
if bios_file is None:
|
||||
self.integrated_rom_size = bios_size = 0x2000
|
||||
self.submodules.rom = wishbone.SRAM(bios_size, read_only=True, init=[])
|
||||
self.register_rom(self.rom.bus, bios_size)
|
||||
else:
|
||||
bios_size = 0x2000
|
||||
self.submodules.firmware_rom = FirmwareROM(bios_size, bios_file)
|
||||
self.add_constant("ROM_DISABLE", 1)
|
||||
self.register_rom(self.firmware_rom.bus, bios_size)
|
||||
|
||||
elif boot_source == "spi":
|
||||
bios_size = 0x8000
|
||||
kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size
|
||||
self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size)
|
||||
self.add_constant("ROM_DISABLE", 1)
|
||||
self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size
|
||||
self.add_memory_region("user_flash",
|
||||
self.flash_boot_address,
|
||||
# Leave a grace area- possible one-by-off bug in add_memory_region?
|
||||
# Possible fix: addr < origin + length - 1
|
||||
platform.spiflash_total_size - (self.flash_boot_address - self.mem_map["spiflash"]) - 0x100)
|
||||
else:
|
||||
raise ValueError("unrecognized boot_source: {}".format(boot_source))
|
||||
|
||||
# Add a simple bit-banged SPI Flash module
|
||||
spi_pads = platform.request("spiflash")
|
||||
self.submodules.picorvspi = PicoRVSpi(platform, spi_pads)
|
||||
self.register_mem("spiflash", self.mem_map["spiflash"],
|
||||
self.picorvspi.bus, size=self.picorvspi.size)
|
||||
|
||||
self.submodules.reboot = SBWarmBoot()
|
||||
self.cpu.cpu_params.update(
|
||||
i_externalResetVector=self.reboot.addr.storage,
|
||||
)
|
||||
|
||||
self.submodules.rgb = SBLED(platform.request("led"))
|
||||
self.submodules.version = Version()
|
||||
|
||||
# Add USB pads
|
||||
usb_pads = platform.request("usb")
|
||||
usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup)
|
||||
self.submodules.usb = epfifo.PerEndpointFifoInterface(usb_iobuf, debug=usb_debug)
|
||||
if usb_debug:
|
||||
self.add_wb_master(self.usb.debug_bridge.wishbone)
|
||||
# For the EVT board, ensure the pulldown pin is tristated as an input
|
||||
if hasattr(usb_pads, "pulldown"):
|
||||
pulldown = TSTriple()
|
||||
self.specials += pulldown.get_tristate(usb_pads.pulldown)
|
||||
self.comb += pulldown.oe.eq(0)
|
||||
|
||||
# Add GPIO pads for the touch buttons
|
||||
self.submodules.touch = TouchPads(platform.request("touch"))
|
||||
|
||||
# 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.nextpnr_yosys_template[2] += " -relut -dffe_min_ce_use 4"
|
||||
if use_dsp:
|
||||
platform.toolchain.nextpnr_yosys_template[2] += " -dsp"
|
||||
|
||||
# Disable final deep-sleep power down so firmware words are loaded
|
||||
# onto softcore's address bus.
|
||||
platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin"
|
||||
platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin"
|
||||
|
||||
if placer is not None:
|
||||
platform.toolchain.nextpnr_build_template[1] += " --placer {}".format(placer)
|
||||
|
||||
def copy_memory_file(self, src):
|
||||
import os
|
||||
from shutil import copyfile
|
||||
if not os.path.exists(self.output_dir):
|
||||
os.mkdir(self.output_dir)
|
||||
if not os.path.exists(os.path.join(self.output_dir, "gateware")):
|
||||
os.mkdir(os.path.join(self.output_dir, "gateware"))
|
||||
copyfile(os.path.join("rtl", src), os.path.join(self.output_dir, "gateware", src))
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Build Fomu Main Gateware")
|
||||
parser.add_argument(
|
||||
"--boot-source", choices=["spi", "rand", "bios"], default="bios",
|
||||
help="where to have the CPU obtain its executable code from"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--revision", choices=["pvt", "dvt", "evt", "hacker"], required=True,
|
||||
help="build foboot for a particular hardware revision"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bios", help="use specified file as a BIOS, rather than building one"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--with-debug", help="enable debug support", choices=["usb", "uart", None]
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-pll", help="disable pll -- this is easier to route, but may not work", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--with-dsp", help="use dsp inference in yosys (not all yosys builds have -dsp)", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-cpu", help="disable cpu generation for debugging purposes", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--placer", choices=["sa", "heap"], help="which placer to use in nextpnr"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = 'build'
|
||||
|
||||
compile_software = False
|
||||
if args.boot_source == "bios" and args.bios is None:
|
||||
compile_software = True
|
||||
|
||||
cpu_type = "vexriscv"
|
||||
cpu_variant = "min"
|
||||
if args.with_debug:
|
||||
cpu_variant = "debug"
|
||||
|
||||
if args.no_cpu:
|
||||
cpu_type = None
|
||||
cpu_variant = None
|
||||
|
||||
os.environ["LITEX"] = "1" # Give our Makefile something to look for
|
||||
platform = Platform(revision=args.revision)
|
||||
soc = BaseSoC(platform, cpu_type=cpu_type, cpu_variant=cpu_variant,
|
||||
debug=args.with_debug, boot_source=args.boot_source,
|
||||
bios_file=args.bios, use_pll=not args.no_pll,
|
||||
use_dsp=args.with_dsp, placer=args.placer,
|
||||
output_dir=output_dir)
|
||||
builder = Builder(soc, output_dir=output_dir, csr_csv="test/csr.csv", compile_software=compile_software)
|
||||
if compile_software:
|
||||
builder.software_packages = [
|
||||
("bios", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "sw")))
|
||||
]
|
||||
vns = builder.build()
|
||||
soc.do_exit(vns)
|
||||
|
||||
print(
|
||||
"""Foboot build complete. Output files:
|
||||
{}/gateware/top.bin Bitstream file. Load this onto the FPGA for testing.
|
||||
{}/gateware/top.v Source Verilog file. Useful for debugging issues.
|
||||
{}/software/include/generated/ Directory with header files for API access.
|
||||
{}/software/bios/bios.elf ELF file for debugging bios.
|
||||
""".format(output_dir, output_dir, output_dir, output_dir))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
553
hw/lxbuildenv.py
Normal file
553
hw/lxbuildenv.py
Normal file
@ -0,0 +1,553 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script enables easy, cross-platform building without the need
|
||||
# to install third-party Python modules.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
|
||||
DEPS_DIR = "deps"
|
||||
|
||||
DEFAULT_DEPS = {
|
||||
'migen': 'https://github.com/m-labs/migen.git',
|
||||
'litex': 'https://github.com/enjoy-digital/litex.git',
|
||||
'litedram': 'https://github.com/enjoy-digital/litedram.git',
|
||||
'litescope': 'https://github.com/enjoy-digital/litescope.git',
|
||||
'pyserial': 'https://github.com/pyserial/pyserial.git',
|
||||
}
|
||||
|
||||
OPTIONAL_DEPS = {
|
||||
'liteeth': 'https://github.com/enjoy-digital/liteeth.git',
|
||||
'liteusb': 'https://github.com/enjoy-digital/liteusb.git',
|
||||
'litepcie': 'https://github.com/enjoy-digital/litepcie.git',
|
||||
'litesdcard': 'https://github.com/enjoy-digital/litesdcard.git',
|
||||
'liteiclink': 'https://github.com/enjoy-digital/liteiclink.git',
|
||||
'litevideo': 'https://github.com/enjoy-digital/litevideo.git',
|
||||
'usb': 'https://github.com/pyusb/pyusb.git',
|
||||
}
|
||||
|
||||
# Obtain the path to this script, plus a trailing separator. This will
|
||||
# be used later on to construct various environment variables for paths
|
||||
# to a variety of support directories.
|
||||
script_path = os.path.dirname(os.path.realpath(__file__)) + os.path.sep
|
||||
|
||||
# Look through the specified file for known variables to get the dependency list
|
||||
def get_required_dependencies(filename):
|
||||
import ast
|
||||
|
||||
# Always check the Python version
|
||||
dependencies = {
|
||||
'python': 1
|
||||
}
|
||||
main_src = ""
|
||||
|
||||
try:
|
||||
with open(sys.argv[0], 'r') as f:
|
||||
main_src = f.read()
|
||||
main_ast = ast.parse(main_src, filename=filename)
|
||||
except:
|
||||
return list(dependencies.keys())
|
||||
|
||||
# Iterate through the top-level nodes looking for variables named
|
||||
# LX_DEPENDENCIES or LX_DEPENDENCY and get the values that are
|
||||
# assigned to them.
|
||||
for node in ast.iter_child_nodes(main_ast):
|
||||
if isinstance(node, ast.Assign):
|
||||
value = node.value
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
if target.id == "LX_DEPENDENCIES" or target.id == "LX_DEPENDENCY":
|
||||
if isinstance(value, (ast.List, ast.Tuple)):
|
||||
for elt in value.elts:
|
||||
if isinstance(elt, ast.Str):
|
||||
dependencies[elt.s] = 1
|
||||
elif isinstance(value, ast.Str):
|
||||
dependencies[value.s] = 1
|
||||
|
||||
# Set up sub-dependencies
|
||||
if 'riscv' in dependencies:
|
||||
dependencies['make'] = 1
|
||||
return list(dependencies.keys())
|
||||
|
||||
def get_python_path(script_path, args):
|
||||
# Python has no concept of a local dependency path, such as the C `-I``
|
||||
# switch, or the nodejs `node_modules` path, or the rust cargo registry.
|
||||
# Instead, it relies on an environment variable to append to the search
|
||||
# path.
|
||||
# Construct this variable by adding each subdirectory under the `deps/`
|
||||
# directory to the PYTHONPATH environment variable.
|
||||
python_path = []
|
||||
if os.path.isdir(script_path + DEPS_DIR):
|
||||
for dep in os.listdir(script_path + DEPS_DIR):
|
||||
dep = script_path + DEPS_DIR + os.path.sep + dep
|
||||
if os.path.isdir(dep):
|
||||
python_path.append(dep)
|
||||
return python_path
|
||||
|
||||
def fixup_env(script_path, args):
|
||||
os.environ["PYTHONPATH"] = os.pathsep.join(get_python_path(script_path, 0))
|
||||
|
||||
# Set the "LXBUILDENV_REEXEC" variable to prevent the script from continuously
|
||||
# reinvoking itself.
|
||||
os.environ["LXBUILDENV_REEXEC"] = "1"
|
||||
|
||||
# Python randomizes the order in which it traverses hashes, and Migen uses
|
||||
# hashes an awful lot when bringing together modules. As such, the order
|
||||
# in which Migen generates its output Verilog will change with every run,
|
||||
# and the addresses for various modules will change.
|
||||
# Make builds deterministic so that the generated Verilog code won't change
|
||||
# across runs.
|
||||
os.environ["PYTHONHASHSEED"] = "1"
|
||||
|
||||
# Some Makefiles are invoked as part of the build process, and those Makefiles
|
||||
# occasionally have calls to Python. Ensure those Makefiles use the same
|
||||
# interpreter that this script is using.
|
||||
os.environ["PYTHON"] = sys.executable
|
||||
|
||||
# Set the environment variable "V" to 1. This causes Makefiles to print
|
||||
# the commands they run, which makes them easier to debug.
|
||||
if "lx_verbose" in args and args.lx_verbose:
|
||||
os.environ["V"] = "1"
|
||||
|
||||
# If the user just wanted to print the environment variables, do that and quit.
|
||||
if args.lx_print_env:
|
||||
print("PYTHONPATH={}".format(os.environ["PYTHONPATH"]))
|
||||
print("PYTHONHASHSEED={}".format(os.environ["PYTHONHASHSEED"]))
|
||||
print("PYTHON={}".format(sys.executable))
|
||||
print("LXBUILDENV_REEXEC={}".format(os.environ["LXBUILDENV_REEXEC"]))
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
# Equivalent to the powershell Get-Command, and kinda like `which`
|
||||
def get_command(cmd):
|
||||
if os.name == 'nt':
|
||||
path_ext = os.environ["PATHEXT"].split(os.pathsep)
|
||||
else:
|
||||
path_ext = [""]
|
||||
for ext in path_ext:
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
|
||||
if os.path.exists(path + os.path.sep + cmd + ext):
|
||||
return path + os.path.sep + cmd + ext
|
||||
return None
|
||||
|
||||
def check_python_version(args):
|
||||
import platform
|
||||
# Litex / Migen require Python 3.5 or newer. Ensure we're running
|
||||
# under a compatible version of Python.
|
||||
if sys.version_info[:3] < (3, 5):
|
||||
return (False,
|
||||
"python: You need Python 3.5+ (version {} found)".format(sys.version_info[:3]))
|
||||
return (True, "python 3.5+: ok (Python {} found)".format(platform.python_version()))
|
||||
|
||||
def check_vivado(args):
|
||||
vivado_path = get_command("vivado")
|
||||
if vivado_path == None:
|
||||
# Look for the default Vivado install directory
|
||||
if os.name == 'nt':
|
||||
base_dir = r"C:\Xilinx\Vivado"
|
||||
else:
|
||||
base_dir = "/opt/Xilinx/Vivado"
|
||||
if os.path.exists(base_dir):
|
||||
for file in os.listdir(base_dir):
|
||||
bin_dir = base_dir + os.path.sep + file + os.path.sep + "bin"
|
||||
if os.path.exists(bin_dir + os.path.sep + "vivado"):
|
||||
os.environ["PATH"] += os.pathsep + bin_dir
|
||||
vivado_path = bin_dir
|
||||
break
|
||||
if vivado_path == None:
|
||||
return (False, "toolchain not found in your PATH", "download it from https://www.xilinx.com/support/download.html")
|
||||
return (True, "found at {}".format(vivado_path))
|
||||
|
||||
def check_cmd(args, cmd, name=None, fix=None):
|
||||
if name is None:
|
||||
name = cmd
|
||||
path = get_command(cmd)
|
||||
if path == None:
|
||||
return (False, name + " not found in your PATH", fix)
|
||||
return (True, "found at {}".format(path))
|
||||
|
||||
def check_make(args):
|
||||
return check_cmd(args, "make", "GNU Make")
|
||||
|
||||
def check_riscv(args):
|
||||
riscv64 = check_cmd(args, "riscv64-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/boards/")
|
||||
if riscv64[0] == True:
|
||||
return riscv64
|
||||
|
||||
riscv32 = check_cmd(args, "riscv32-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/boards/")
|
||||
if riscv32[0] == True:
|
||||
return riscv32
|
||||
|
||||
return riscv64
|
||||
|
||||
def check_yosys(args):
|
||||
return check_cmd(args, "yosys")
|
||||
|
||||
def check_arachne(args):
|
||||
return check_cmd(args, "arachne-pnr")
|
||||
|
||||
def check_icestorm(args):
|
||||
return check_cmd(args, "icepack") and check_cmd(args, "nextpnr-ice40")
|
||||
|
||||
dependency_checkers = {
|
||||
'python': check_python_version,
|
||||
'vivado': check_vivado,
|
||||
'make': check_make,
|
||||
'riscv': check_riscv,
|
||||
'yosys': check_yosys,
|
||||
'arachne-pnr': check_arachne,
|
||||
'icestorm': check_icestorm,
|
||||
}
|
||||
|
||||
# Validate that the required dependencies (Vivado, compilers, etc.)
|
||||
# have been installed.
|
||||
def check_dependencies(args, dependency_list):
|
||||
|
||||
dependency_errors = 0
|
||||
for dependency_name in dependency_list:
|
||||
if not dependency_name in dependency_checkers:
|
||||
print('WARNING: Unrecognized dependency "{}"'.format(dependency_name))
|
||||
continue
|
||||
result = dependency_checkers[dependency_name](args)
|
||||
if result[0] == False:
|
||||
if len(result) > 2:
|
||||
print('{}: {} -- {}'.format(dependency_name, result[1], result[2]))
|
||||
else:
|
||||
print('{}: {}'.format(dependency_name, result[1]))
|
||||
dependency_errors = dependency_errors + 1
|
||||
|
||||
elif args.lx_check_deps or args.lx_verbose:
|
||||
print('dependency: {}: {}'.format(dependency_name, result[1]))
|
||||
if dependency_errors > 0:
|
||||
if args.lx_ignore_deps:
|
||||
print('{} missing dependencies were found but continuing anyway'.format(dependency_errors))
|
||||
else:
|
||||
raise SystemExit(str(dependency_errors) +
|
||||
" missing dependencies were found")
|
||||
|
||||
if args.lx_check_deps:
|
||||
sys.exit(0)
|
||||
|
||||
# Return True if the given tree needs to be initialized
|
||||
def check_module_recursive(root_path, depth, verbose=False, breadcrumbs=[]):
|
||||
if verbose:
|
||||
print('git-dep: checking if "{}" requires updating (depth: {})...'.format(root_path, depth))
|
||||
|
||||
# If the directory isn't a valid git repo, initialization is required
|
||||
git_dir_cmd = subprocess.Popen(["git", "rev-parse", "--show-toplevel"],
|
||||
cwd=root_path,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(git_stdout, _) = git_dir_cmd.communicate()
|
||||
if git_dir_cmd.wait() != 0:
|
||||
if verbose:
|
||||
print('git-dep: missing git directory, starting update...')
|
||||
return True
|
||||
git_dir = git_stdout.decode().strip()
|
||||
|
||||
if git_dir in breadcrumbs:
|
||||
if verbose:
|
||||
print('git-dep: root path {} is not in git path'.format(root_path))
|
||||
return True
|
||||
breadcrumbs.append(git_dir)
|
||||
|
||||
if not os.path.exists(git_dir + os.path.sep + '.git'):
|
||||
if verbose:
|
||||
print('git-dep: .git not found in "{}"'.format(git_dir))
|
||||
return True
|
||||
|
||||
# If there are no submodules, no initialization needs to be done
|
||||
if not os.path.isfile(git_dir + os.path.sep + '.gitmodules'):
|
||||
if verbose:
|
||||
print('git-dep: .gitmodules not found in "{}", so not updating'.format(git_dir))
|
||||
return False
|
||||
|
||||
# Loop through the gitmodules to check all submodules
|
||||
gitmodules = open(git_dir + os.path.sep + '.gitmodules', 'r')
|
||||
for line in gitmodules:
|
||||
parts = line.split("=", 2)
|
||||
if parts[0].strip() == "path":
|
||||
path = parts[1].strip()
|
||||
if check_module_recursive(git_dir + os.path.sep + path, depth + 1, verbose=verbose, breadcrumbs=breadcrumbs):
|
||||
return True
|
||||
return False
|
||||
|
||||
# Determine whether we need to invoke "git submodules init --recurse"
|
||||
def check_submodules(script_path, args):
|
||||
if check_module_recursive(script_path, 0, verbose=args.lx_verbose):
|
||||
print("Missing submodules -- updating")
|
||||
subprocess.Popen(["git", "submodule", "update",
|
||||
"--init", "--recursive"], cwd=script_path).wait()
|
||||
elif args.lx_verbose:
|
||||
print("Submodule check: Submodules found")
|
||||
|
||||
|
||||
def lx_git(cmd, *args):
|
||||
import subprocess
|
||||
git_cmd = ["git", cmd]
|
||||
if args is not None:
|
||||
for arg in args:
|
||||
git_cmd = git_cmd + [arg]
|
||||
subprocess.call(git_cmd)
|
||||
|
||||
def lx_print_deps():
|
||||
print('Known dependencies:')
|
||||
for dep in dependency_checkers.keys():
|
||||
print(' {}'.format(dep))
|
||||
print('To define a dependency, add a variable inside {} at the top level called LX_DEPENDENCIES and assign it a list or tuple.'.format(sys.argv[0]))
|
||||
print('For example:')
|
||||
print('LX_DEPENDENCIES = ("riscv", "vivado")')
|
||||
|
||||
|
||||
def lx_main(args):
|
||||
if args.lx_print_env:
|
||||
fixup_env(script_path, args)
|
||||
|
||||
elif args.lx_print_deps:
|
||||
lx_print_deps()
|
||||
|
||||
elif args.lx_run is not None:
|
||||
script_name=args.lx_run[0]
|
||||
get_required_dependencies(script_name)
|
||||
|
||||
fixup_env(script_path, args)
|
||||
check_submodules(script_path, args)
|
||||
|
||||
try:
|
||||
sys.exit(subprocess.Popen(
|
||||
[sys.executable] + [script_name] + args.lx_run[1:]).wait())
|
||||
except:
|
||||
sys.exit(1)
|
||||
elif args.init:
|
||||
if args.main is None:
|
||||
main_name = os.getcwd().split(os.path.sep)[-1] + '.py'
|
||||
new_main_name = input('What would you like your main program to be called? [' + main_name + '] ')
|
||||
if new_main_name is not None and new_main_name != "":
|
||||
main_name = new_main_name
|
||||
else:
|
||||
main_name = args.main
|
||||
if not main_name.endswith('.py'):
|
||||
main_name = main_name + '.py'
|
||||
|
||||
if args.no_git:
|
||||
print("skipping git initialization")
|
||||
else:
|
||||
if not os.path.exists(DEPS_DIR):
|
||||
os.mkdir(DEPS_DIR)
|
||||
|
||||
if not os.path.exists(".git"):
|
||||
print("initializing git repository")
|
||||
lx_git('init')
|
||||
else:
|
||||
print("using existing git repository")
|
||||
lx_git('add', str(__file__))
|
||||
|
||||
for dep_name, dep_url in DEFAULT_DEPS.items():
|
||||
dest_path = '{}{}{}'.format(DEPS_DIR, '/', dep_name)
|
||||
if not os.path.exists(dest_path):
|
||||
lx_git('submodule', 'add', dep_url, dest_path)
|
||||
lx_git('add', dest_path)
|
||||
|
||||
lx_git('submodule', 'update', '--init', '--recursive')
|
||||
|
||||
if args.no_bin:
|
||||
print("skipping bin/ initialization")
|
||||
elif os.path.exists("bin"):
|
||||
print("bin/ directory exists -- remove bin/ directory to re-initialize")
|
||||
else:
|
||||
bin_tools = {
|
||||
'mkmscimg': 'litex.soc.software.mkmscimg',
|
||||
'litex_term': 'litex.tools.litex_term',
|
||||
'litex_server': 'litex.tools.litex_server',
|
||||
'litex_sim': 'litex.tools.litex_sim',
|
||||
'litex_read_verilog': 'litex.tools.litex_read_verilog',
|
||||
'litex_simple': 'litex.boards.targets.simple',
|
||||
}
|
||||
bin_template = """#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# This script lives in the "bin" directory, but uses a helper script in the parent
|
||||
# directory. Obtain the current path so we can get the absolute parent path.
|
||||
script_path = os.path.dirname(os.path.realpath(
|
||||
__file__)) + os.path.sep + os.path.pardir + os.path.sep
|
||||
sys.path.insert(0, script_path)
|
||||
import lxbuildenv
|
||||
|
||||
"""
|
||||
print("Creating binaries")
|
||||
os.mkdir("bin")
|
||||
for bin_name, python_module in bin_tools.items():
|
||||
with open('bin' + os.path.sep + bin_name, 'w', newline='\n') as new_bin:
|
||||
new_bin.write(bin_template)
|
||||
new_bin.write('from ' + python_module + ' import main\n')
|
||||
new_bin.write('main()\n')
|
||||
import stat
|
||||
os.chmod('bin' + os.path.sep + bin_name, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
if not args.no_git:
|
||||
lx_git('add', '--chmod=+x', 'bin' + os.path.sep + bin_name)
|
||||
|
||||
if os.path.exists(main_name):
|
||||
print("skipping creation of {}: file exists".format(main_name))
|
||||
else:
|
||||
print("creating main program {}".format(main_name))
|
||||
with open(main_name, 'w') as m:
|
||||
program_template = """#!/usr/bin/env python3
|
||||
# This variable defines all the external programs that this module
|
||||
# relies on. lxbuildenv reads this variable in order to ensure
|
||||
# the build will finish without exiting due to missing third-party
|
||||
# programs.
|
||||
LX_DEPENDENCIES = ["riscv", "vivado"]
|
||||
|
||||
# Import lxbuildenv to integrate the deps/ directory
|
||||
import lxbuildenv
|
||||
|
||||
# Disable pylint's E1101, which breaks completely on migen
|
||||
#pylint:disable=E1101
|
||||
|
||||
from migen import *
|
||||
from litex.build.xilinx import VivadoProgrammer, XilinxPlatform
|
||||
from litex.build.generic_platform import Pins, IOStandard
|
||||
from litex.soc.integration import SoCSDRAM
|
||||
from litex.soc.integration.builder import Builder
|
||||
from litex.soc.integration.soc_core import csr_map_update
|
||||
|
||||
_io = [
|
||||
("clk50", 0, Pins("J19"), IOStandard("LVCMOS33")),
|
||||
]
|
||||
|
||||
class Platform(XilinxPlatform):
|
||||
def __init__(self, toolchain="vivado", programmer="vivado", part="35"):
|
||||
part = "xc7a" + part + "t-fgg484-2"
|
||||
def create_programmer(self):
|
||||
if self.programmer == "vivado":
|
||||
return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4")
|
||||
else:
|
||||
raise ValueError("{} programmer is not supported"
|
||||
.format(self.programmer))
|
||||
|
||||
def do_finalize(self, fragment):
|
||||
XilinxPlatform.do_finalize(self, fragment)
|
||||
|
||||
class BaseSoC(SoCSDRAM):
|
||||
csr_peripherals = [
|
||||
"ddrphy",
|
||||
# "dna",
|
||||
"xadc",
|
||||
"cpu_or_bridge",
|
||||
]
|
||||
csr_map_update(SoCSDRAM.csr_map, csr_peripherals)
|
||||
|
||||
def __init__(self, platform, **kwargs):
|
||||
clk_freq = int(100e6)
|
||||
|
||||
def main():
|
||||
platform = Platform()
|
||||
soc = BaseSoC(platform)
|
||||
builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv")
|
||||
vns = builder.build()
|
||||
soc.do_exit(vns)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
"""
|
||||
m.write(program_template)
|
||||
if not args.no_git:
|
||||
lx_git("add", main_name)
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
# For the main command, parse args and hand it off to main()
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Wrap Python code to enable quickstart",
|
||||
add_help=False)
|
||||
parser.add_argument(
|
||||
"-h", "--help", '--lx-help', help="show this help message and exit", action="help"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-i', '--init', '--lx-init', help='initialize a new project', action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-m', '--main', '--lx-main', help='name of main project'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-bin', '--lx-no-bin', help="don't create a bin/ directory"
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-git', '--lx-no-git', help="Don't create a git repository"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-e', '--print-env', '--lx-print-env', dest="lx_print_env", help="print environment variable listing for pycharm, vscode, or bash", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-d', '--print-deps', '--lx-print-deps', dest="lx_print_deps", help="print all possible dependencies and then exit", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lx-verbose", help="increase verboseness of some processes", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-r', '--run', '--lx-run', dest='lx_run', help="run the given script under lxbuildenv", nargs=argparse.REMAINDER
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if not lx_main(args):
|
||||
parser.print_help()
|
||||
|
||||
elif not os.path.isfile(sys.argv[0]):
|
||||
print("lxbuildenv doesn't operate while in interactive mode")
|
||||
|
||||
elif "LXBUILDENV_REEXEC" not in os.environ:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Wrap Python code to enable quickstart",
|
||||
add_help=False)
|
||||
parser.add_argument(
|
||||
"--lx-verbose", help="increase verboseness of some processes", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lx-print-env", help="print environment variable listing for pycharm, vscode, or bash", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lx-check-deps", help="check build environment for dependencies such as compiler and fpga tools and then exit", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lx-print-deps", help="print all possible dependencies and then exit", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lx-help", action="help"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--lx-ignore-deps", help="try building even if dependencies are missing", action="store_true"
|
||||
)
|
||||
(args, rest) = parser.parse_known_args()
|
||||
|
||||
if args.lx_print_deps:
|
||||
lx_print_deps()
|
||||
sys.exit(0)
|
||||
|
||||
deps = get_required_dependencies(sys.argv[0])
|
||||
|
||||
fixup_env(script_path, args)
|
||||
check_dependencies(args, deps)
|
||||
check_submodules(script_path, args)
|
||||
|
||||
try:
|
||||
sys.exit(subprocess.Popen(
|
||||
[sys.executable] + [sys.argv[0]] + rest).wait())
|
||||
except:
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Overwrite the deps directory.
|
||||
# Because we're running with a predefined PYTHONPATH, you'd think that
|
||||
# the DEPS_DIR would be first.
|
||||
# Unfortunately, setuptools causes the sitewide packages to take precedence
|
||||
# over the PYTHONPATH variable.
|
||||
# Work around this bug by inserting paths into the first index.
|
||||
for path in get_python_path(script_path, None):
|
||||
sys.path.insert(0, path)
|
3578
hw/rtl/2-stage-1024-cache-debug.v
Normal file
3578
hw/rtl/2-stage-1024-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/2-stage-1024-cache-debug.yaml
Normal file
5
hw/rtl/2-stage-1024-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
|
||||
kind: cached
|
3289
hw/rtl/2-stage-1024-cache.v
Normal file
3289
hw/rtl/2-stage-1024-cache.v
Normal file
File diff suppressed because it is too large
Load Diff
4
hw/rtl/2-stage-1024-cache.yaml
Normal file
4
hw/rtl/2-stage-1024-cache.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
|
||||
kind: cached
|
3578
hw/rtl/2-stage-2048-cache-debug.v
Normal file
3578
hw/rtl/2-stage-2048-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/2-stage-2048-cache-debug.yaml
Normal file
5
hw/rtl/2-stage-2048-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 2048}
|
||||
kind: cached
|
3297
hw/rtl/2-stage-2048-cache.v
Normal file
3297
hw/rtl/2-stage-2048-cache.v
Normal file
File diff suppressed because it is too large
Load Diff
4
hw/rtl/2-stage-2048-cache.yaml
Normal file
4
hw/rtl/2-stage-2048-cache.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 2048}
|
||||
kind: cached
|
3769
hw/rtl/2-stage-512-cache-debug.v
Normal file
3769
hw/rtl/2-stage-512-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/2-stage-512-cache-debug.yaml
Normal file
5
hw/rtl/2-stage-512-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [16399, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 512}
|
||||
kind: cached
|
3499
hw/rtl/2-stage-no-cache-debug.v
Normal file
3499
hw/rtl/2-stage-no-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
1
hw/rtl/2-stage-no-cache-debug.yaml
Normal file
1
hw/rtl/2-stage-no-cache-debug.yaml
Normal file
@ -0,0 +1 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
3965
hw/rtl/4-stage-1024-cache-debug.v
Normal file
3965
hw/rtl/4-stage-1024-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/4-stage-1024-cache-debug.yaml
Normal file
5
hw/rtl/4-stage-1024-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
|
||||
kind: cached
|
3865
hw/rtl/4-stage-no-cache-debug.v
Normal file
3865
hw/rtl/4-stage-no-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
1
hw/rtl/4-stage-no-cache-debug.yaml
Normal file
1
hw/rtl/4-stage-no-cache-debug.yaml
Normal file
@ -0,0 +1 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
3902
hw/rtl/5-stage-pipelined-no-cache-debug.v
Normal file
3902
hw/rtl/5-stage-pipelined-no-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
1
hw/rtl/5-stage-pipelined-no-cache-debug.yaml
Normal file
1
hw/rtl/5-stage-pipelined-no-cache-debug.yaml
Normal file
@ -0,0 +1 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
579
hw/rtl/spimemio.v
Normal file
579
hw/rtl/spimemio.v
Normal file
@ -0,0 +1,579 @@
|
||||
/*
|
||||
* PicoSoC - A simple example SoC using PicoRV32
|
||||
*
|
||||
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
module spimemio (
|
||||
input clk, resetn,
|
||||
|
||||
input valid,
|
||||
output ready,
|
||||
input [23:0] addr,
|
||||
output reg [31:0] rdata,
|
||||
|
||||
output flash_csb,
|
||||
output flash_clk,
|
||||
|
||||
output flash_io0_oe,
|
||||
output flash_io1_oe,
|
||||
output flash_io2_oe,
|
||||
output flash_io3_oe,
|
||||
|
||||
output flash_io0_do,
|
||||
output flash_io1_do,
|
||||
output flash_io2_do,
|
||||
output flash_io3_do,
|
||||
|
||||
input flash_io0_di,
|
||||
input flash_io1_di,
|
||||
input flash_io2_di,
|
||||
input flash_io3_di,
|
||||
|
||||
input [3:0] cfgreg_we,
|
||||
input [31:0] cfgreg_di,
|
||||
output [31:0] cfgreg_do
|
||||
);
|
||||
reg xfer_resetn;
|
||||
reg din_valid;
|
||||
wire din_ready;
|
||||
reg [7:0] din_data;
|
||||
reg [3:0] din_tag;
|
||||
reg din_cont;
|
||||
reg din_qspi;
|
||||
reg din_ddr;
|
||||
reg din_rd;
|
||||
|
||||
wire dout_valid;
|
||||
wire [7:0] dout_data;
|
||||
wire [3:0] dout_tag;
|
||||
|
||||
reg [23:0] buffer;
|
||||
|
||||
reg [23:0] rd_addr;
|
||||
reg rd_valid;
|
||||
reg rd_wait;
|
||||
reg rd_inc;
|
||||
|
||||
assign ready = valid && (addr == rd_addr) && rd_valid;
|
||||
wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
|
||||
|
||||
reg softreset;
|
||||
|
||||
reg config_en; // cfgreg[31]
|
||||
reg config_ddr; // cfgreg[22]
|
||||
reg config_qspi; // cfgreg[21]
|
||||
reg config_cont; // cfgreg[20]
|
||||
reg [3:0] config_dummy; // cfgreg[19:16]
|
||||
reg [3:0] config_oe; // cfgreg[11:8]
|
||||
reg config_csb; // cfgreg[5]
|
||||
reg config_clk; // cfgref[4]
|
||||
reg [3:0] config_do; // cfgreg[3:0]
|
||||
|
||||
assign cfgreg_do[31] = config_en;
|
||||
assign cfgreg_do[30:23] = 0;
|
||||
assign cfgreg_do[22] = config_ddr;
|
||||
assign cfgreg_do[21] = config_qspi;
|
||||
assign cfgreg_do[20] = config_cont;
|
||||
assign cfgreg_do[19:16] = config_dummy;
|
||||
assign cfgreg_do[15:12] = 0;
|
||||
assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe};
|
||||
assign cfgreg_do[7:6] = 0;
|
||||
assign cfgreg_do[5] = flash_csb;
|
||||
assign cfgreg_do[4] = flash_clk;
|
||||
assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
|
||||
|
||||
always @(posedge clk) begin
|
||||
softreset <= !config_en || cfgreg_we;
|
||||
if (!resetn) begin
|
||||
softreset <= 1;
|
||||
config_en <= 1;
|
||||
config_csb <= 0;
|
||||
config_clk <= 0;
|
||||
config_oe <= 0;
|
||||
config_do <= 0;
|
||||
config_ddr <= 0;
|
||||
config_qspi <= 0;
|
||||
config_cont <= 0;
|
||||
config_dummy <= 8;
|
||||
end else begin
|
||||
if (cfgreg_we[0]) begin
|
||||
config_csb <= cfgreg_di[5];
|
||||
config_clk <= cfgreg_di[4];
|
||||
config_do <= cfgreg_di[3:0];
|
||||
end
|
||||
if (cfgreg_we[1]) begin
|
||||
config_oe <= cfgreg_di[11:8];
|
||||
end
|
||||
if (cfgreg_we[2]) begin
|
||||
config_ddr <= cfgreg_di[22];
|
||||
config_qspi <= cfgreg_di[21];
|
||||
config_cont <= cfgreg_di[20];
|
||||
config_dummy <= cfgreg_di[19:16];
|
||||
end
|
||||
if (cfgreg_we[3]) begin
|
||||
config_en <= cfgreg_di[31];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire xfer_csb;
|
||||
wire xfer_clk;
|
||||
|
||||
wire xfer_io0_oe;
|
||||
wire xfer_io1_oe;
|
||||
wire xfer_io2_oe;
|
||||
wire xfer_io3_oe;
|
||||
|
||||
wire xfer_io0_do;
|
||||
wire xfer_io1_do;
|
||||
wire xfer_io2_do;
|
||||
wire xfer_io3_do;
|
||||
|
||||
reg xfer_io0_90;
|
||||
reg xfer_io1_90;
|
||||
reg xfer_io2_90;
|
||||
reg xfer_io3_90;
|
||||
|
||||
always @(negedge clk) begin
|
||||
xfer_io0_90 <= xfer_io0_do;
|
||||
xfer_io1_90 <= xfer_io1_do;
|
||||
xfer_io2_90 <= xfer_io2_do;
|
||||
xfer_io3_90 <= xfer_io3_do;
|
||||
end
|
||||
|
||||
assign flash_csb = config_en ? xfer_csb : config_csb;
|
||||
assign flash_clk = config_en ? xfer_clk : config_clk;
|
||||
|
||||
assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0];
|
||||
assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1];
|
||||
assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2];
|
||||
assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3];
|
||||
|
||||
assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0];
|
||||
assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1];
|
||||
assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2];
|
||||
assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3];
|
||||
|
||||
wire xfer_dspi = din_ddr && !din_qspi;
|
||||
wire xfer_ddr = din_ddr && din_qspi;
|
||||
|
||||
spimemio_xfer xfer (
|
||||
.clk (clk ),
|
||||
.resetn (xfer_resetn ),
|
||||
.din_valid (din_valid ),
|
||||
.din_ready (din_ready ),
|
||||
.din_data (din_data ),
|
||||
.din_tag (din_tag ),
|
||||
.din_cont (din_cont ),
|
||||
.din_dspi (xfer_dspi ),
|
||||
.din_qspi (din_qspi ),
|
||||
.din_ddr (xfer_ddr ),
|
||||
.din_rd (din_rd ),
|
||||
.dout_valid (dout_valid ),
|
||||
.dout_data (dout_data ),
|
||||
.dout_tag (dout_tag ),
|
||||
.flash_csb (xfer_csb ),
|
||||
.flash_clk (xfer_clk ),
|
||||
.flash_io0_oe (xfer_io0_oe ),
|
||||
.flash_io1_oe (xfer_io1_oe ),
|
||||
.flash_io2_oe (xfer_io2_oe ),
|
||||
.flash_io3_oe (xfer_io3_oe ),
|
||||
.flash_io0_do (xfer_io0_do ),
|
||||
.flash_io1_do (xfer_io1_do ),
|
||||
.flash_io2_do (xfer_io2_do ),
|
||||
.flash_io3_do (xfer_io3_do ),
|
||||
.flash_io0_di (flash_io0_di),
|
||||
.flash_io1_di (flash_io1_di),
|
||||
.flash_io2_di (flash_io2_di),
|
||||
.flash_io3_di (flash_io3_di)
|
||||
);
|
||||
|
||||
reg [3:0] state;
|
||||
|
||||
always @(posedge clk) begin
|
||||
xfer_resetn <= 1;
|
||||
din_valid <= 0;
|
||||
|
||||
if (!resetn || softreset) begin
|
||||
state <= 0;
|
||||
xfer_resetn <= 0;
|
||||
rd_valid <= 0;
|
||||
din_tag <= 0;
|
||||
din_cont <= 0;
|
||||
din_qspi <= 0;
|
||||
din_ddr <= 0;
|
||||
din_rd <= 0;
|
||||
end else begin
|
||||
if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data;
|
||||
if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data;
|
||||
if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data;
|
||||
if (dout_valid && dout_tag == 4) begin
|
||||
rdata <= {dout_data, buffer};
|
||||
rd_addr <= rd_inc ? rd_addr + 4 : addr;
|
||||
rd_valid <= 1;
|
||||
rd_wait <= rd_inc;
|
||||
rd_inc <= 1;
|
||||
end
|
||||
|
||||
if (valid)
|
||||
rd_wait <= 0;
|
||||
|
||||
case (state)
|
||||
0: begin
|
||||
din_valid <= 1;
|
||||
din_data <= 8'h ff;
|
||||
din_tag <= 0;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 1;
|
||||
end
|
||||
end
|
||||
1: begin
|
||||
if (dout_valid) begin
|
||||
xfer_resetn <= 0;
|
||||
state <= 2;
|
||||
end
|
||||
end
|
||||
2: begin
|
||||
din_valid <= 1;
|
||||
din_data <= 8'h ab;
|
||||
din_tag <= 0;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 3;
|
||||
end
|
||||
end
|
||||
3: begin
|
||||
if (dout_valid) begin
|
||||
xfer_resetn <= 0;
|
||||
state <= 4;
|
||||
end
|
||||
end
|
||||
4: begin
|
||||
rd_inc <= 0;
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
case ({config_ddr, config_qspi})
|
||||
2'b11: din_data <= 8'h ED;
|
||||
2'b01: din_data <= 8'h EB;
|
||||
2'b10: din_data <= 8'h BB;
|
||||
2'b00: din_data <= 8'h 03;
|
||||
endcase
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 5;
|
||||
end
|
||||
end
|
||||
5: begin
|
||||
if (valid && !ready) begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= addr[23:16];
|
||||
din_qspi <= config_qspi;
|
||||
din_ddr <= config_ddr;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 6;
|
||||
end
|
||||
end
|
||||
end
|
||||
6: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= addr[15:8];
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 7;
|
||||
end
|
||||
end
|
||||
7: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= addr[7:0];
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
din_data <= 0;
|
||||
state <= config_qspi || config_ddr ? 8 : 9;
|
||||
end
|
||||
end
|
||||
8: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= config_cont ? 8'h A5 : 8'h FF;
|
||||
if (din_ready) begin
|
||||
din_rd <= 1;
|
||||
din_data <= config_dummy;
|
||||
din_valid <= 0;
|
||||
state <= 9;
|
||||
end
|
||||
end
|
||||
9: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 1;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 10;
|
||||
end
|
||||
end
|
||||
10: begin
|
||||
din_valid <= 1;
|
||||
din_data <= 8'h 00;
|
||||
din_tag <= 2;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 11;
|
||||
end
|
||||
end
|
||||
11: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 3;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 12;
|
||||
end
|
||||
end
|
||||
12: begin
|
||||
if (!rd_wait || valid) begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 4;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 9;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
if (jump) begin
|
||||
rd_inc <= 0;
|
||||
rd_valid <= 0;
|
||||
xfer_resetn <= 0;
|
||||
if (config_cont) begin
|
||||
state <= 5;
|
||||
end else begin
|
||||
state <= 4;
|
||||
din_qspi <= 0;
|
||||
din_ddr <= 0;
|
||||
end
|
||||
din_rd <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module spimemio_xfer (
|
||||
input clk, resetn,
|
||||
|
||||
input din_valid,
|
||||
output din_ready,
|
||||
input [7:0] din_data,
|
||||
input [3:0] din_tag,
|
||||
input din_cont,
|
||||
input din_dspi,
|
||||
input din_qspi,
|
||||
input din_ddr,
|
||||
input din_rd,
|
||||
|
||||
output dout_valid,
|
||||
output [7:0] dout_data,
|
||||
output [3:0] dout_tag,
|
||||
|
||||
output reg flash_csb,
|
||||
output reg flash_clk,
|
||||
|
||||
output reg flash_io0_oe,
|
||||
output reg flash_io1_oe,
|
||||
output reg flash_io2_oe,
|
||||
output reg flash_io3_oe,
|
||||
|
||||
output reg flash_io0_do,
|
||||
output reg flash_io1_do,
|
||||
output reg flash_io2_do,
|
||||
output reg flash_io3_do,
|
||||
|
||||
input flash_io0_di,
|
||||
input flash_io1_di,
|
||||
input flash_io2_di,
|
||||
input flash_io3_di
|
||||
);
|
||||
reg [7:0] obuffer;
|
||||
reg [7:0] ibuffer;
|
||||
|
||||
reg [3:0] count;
|
||||
reg [3:0] dummy_count;
|
||||
|
||||
reg xfer_cont;
|
||||
reg xfer_dspi;
|
||||
reg xfer_qspi;
|
||||
reg xfer_ddr;
|
||||
reg xfer_ddr_q;
|
||||
reg xfer_rd;
|
||||
reg [3:0] xfer_tag;
|
||||
reg [3:0] xfer_tag_q;
|
||||
|
||||
reg [7:0] next_obuffer;
|
||||
reg [7:0] next_ibuffer;
|
||||
reg [3:0] next_count;
|
||||
|
||||
reg fetch;
|
||||
reg next_fetch;
|
||||
reg last_fetch;
|
||||
|
||||
always @(posedge clk) begin
|
||||
xfer_ddr_q <= xfer_ddr;
|
||||
xfer_tag_q <= xfer_tag;
|
||||
end
|
||||
|
||||
assign din_ready = din_valid && resetn && next_fetch;
|
||||
|
||||
assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn;
|
||||
assign dout_data = ibuffer;
|
||||
assign dout_tag = xfer_tag_q;
|
||||
|
||||
always @* begin
|
||||
flash_io0_oe = 0;
|
||||
flash_io1_oe = 0;
|
||||
flash_io2_oe = 0;
|
||||
flash_io3_oe = 0;
|
||||
|
||||
flash_io0_do = 0;
|
||||
flash_io1_do = 0;
|
||||
flash_io2_do = 0;
|
||||
flash_io3_do = 0;
|
||||
|
||||
next_obuffer = obuffer;
|
||||
next_ibuffer = ibuffer;
|
||||
next_count = count;
|
||||
next_fetch = 0;
|
||||
|
||||
if (dummy_count == 0) begin
|
||||
casez ({xfer_ddr, xfer_qspi, xfer_dspi})
|
||||
3'b 000: begin
|
||||
flash_io0_oe = 1;
|
||||
flash_io0_do = obuffer[7];
|
||||
|
||||
if (flash_clk) begin
|
||||
next_obuffer = {obuffer[6:0], 1'b 0};
|
||||
next_count = count - |count;
|
||||
end else begin
|
||||
next_ibuffer = {ibuffer[6:0], flash_io1_di};
|
||||
end
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
3'b 01?: begin
|
||||
flash_io0_oe = !xfer_rd;
|
||||
flash_io1_oe = !xfer_rd;
|
||||
flash_io2_oe = !xfer_rd;
|
||||
flash_io3_oe = !xfer_rd;
|
||||
|
||||
flash_io0_do = obuffer[4];
|
||||
flash_io1_do = obuffer[5];
|
||||
flash_io2_do = obuffer[6];
|
||||
flash_io3_do = obuffer[7];
|
||||
|
||||
if (flash_clk) begin
|
||||
next_obuffer = {obuffer[3:0], 4'b 0000};
|
||||
next_count = count - {|count, 2'b00};
|
||||
end else begin
|
||||
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
|
||||
end
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
3'b 11?: begin
|
||||
flash_io0_oe = !xfer_rd;
|
||||
flash_io1_oe = !xfer_rd;
|
||||
flash_io2_oe = !xfer_rd;
|
||||
flash_io3_oe = !xfer_rd;
|
||||
|
||||
flash_io0_do = obuffer[4];
|
||||
flash_io1_do = obuffer[5];
|
||||
flash_io2_do = obuffer[6];
|
||||
flash_io3_do = obuffer[7];
|
||||
|
||||
next_obuffer = {obuffer[3:0], 4'b 0000};
|
||||
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
|
||||
next_count = count - {|count, 2'b00};
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
3'b ??1: begin
|
||||
flash_io0_oe = !xfer_rd;
|
||||
flash_io1_oe = !xfer_rd;
|
||||
|
||||
flash_io0_do = obuffer[6];
|
||||
flash_io1_do = obuffer[7];
|
||||
|
||||
if (flash_clk) begin
|
||||
next_obuffer = {obuffer[5:0], 2'b 00};
|
||||
next_count = count - {|count, 1'b0};
|
||||
end else begin
|
||||
next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di};
|
||||
end
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!resetn) begin
|
||||
fetch <= 1;
|
||||
last_fetch <= 1;
|
||||
flash_csb <= 1;
|
||||
flash_clk <= 0;
|
||||
count <= 0;
|
||||
dummy_count <= 0;
|
||||
xfer_tag <= 0;
|
||||
xfer_cont <= 0;
|
||||
xfer_dspi <= 0;
|
||||
xfer_qspi <= 0;
|
||||
xfer_ddr <= 0;
|
||||
xfer_rd <= 0;
|
||||
end else begin
|
||||
fetch <= next_fetch;
|
||||
last_fetch <= xfer_ddr ? fetch : 1;
|
||||
if (dummy_count) begin
|
||||
flash_clk <= !flash_clk && !flash_csb;
|
||||
dummy_count <= dummy_count - flash_clk;
|
||||
end else
|
||||
if (count) begin
|
||||
flash_clk <= !flash_clk && !flash_csb;
|
||||
obuffer <= next_obuffer;
|
||||
ibuffer <= next_ibuffer;
|
||||
count <= next_count;
|
||||
end
|
||||
if (din_valid && din_ready) begin
|
||||
flash_csb <= 0;
|
||||
flash_clk <= 0;
|
||||
|
||||
count <= 8;
|
||||
dummy_count <= din_rd ? din_data : 0;
|
||||
obuffer <= din_data;
|
||||
|
||||
xfer_tag <= din_tag;
|
||||
xfer_cont <= din_cont;
|
||||
xfer_dspi <= din_dspi;
|
||||
xfer_qspi <= din_qspi;
|
||||
xfer_ddr <= din_ddr;
|
||||
xfer_rd <= din_rd;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
Reference in New Issue
Block a user