Compare commits

..

No commits in common. "master" and "client-work" have entirely different histories.

38 changed files with 859 additions and 25448 deletions

View File

@ -1,35 +0,0 @@
# Foboot: The Bootloader for Fomu
Foboot is a failsafe bootloader for Fomu. It exposes a DFU interface to the host. Foboot comes in two halves: A Software half and a Hardware half.
## Building the Hardware
The hardware half is written in LiteX, and uses `lxbuildenv` to handle Python dependencies. Hardware is contained within the `hw/` directory. You must install software dependencies yourself:
* Python 3.5+
* Nextpnr
* Icestorm
* Yosys
* Git
Subproject dependencies will be taken care of with `lxbuildenv`.
### Usage
To build, run `foboot-bitstream.py`:
`python3 .\foboot-bitstream.py`
There are multiple build options available. Use `--help` to list them.
Build files will be generated in the `build/` directory. You will probably be most interested in `build/gateware/top.bin` and `build/software/include/generated/`.
## Tests
You can run tests by using the `unittest` command:
`python .\lxbuildenv.py -r -m unittest -v valentyusb.usbcore.cpu.epfifo_test.TestPerEndpointFifoInterface`
## Building the Software
Software is contained in the `sw/` directory.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
iBus: !!vexriscv.BusReport
flushInstructions: [16399, 19, 19, 19]
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
kind: cached

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
iBus: !!vexriscv.BusReport
flushInstructions: [16399, 19, 19, 19]
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
kind: cached

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
iBus: !!vexriscv.BusReport
flushInstructions: [16399, 19, 19, 19]
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
kind: cached

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
iBus: !!vexriscv.BusReport
flushInstructions: [16399, 19, 19, 19]
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
kind: cached

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
iBus: !!vexriscv.BusReport
flushInstructions: [16399, 19, 19, 19]
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
kind: cached

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}

15
hw/README.md Normal file
View File

@ -0,0 +1,15 @@
# Foboot Firmware Component
## Usage
To build:
`python3 .\foboot-bitstream.py`
This will ensure you have the required dependencies, and check out all submodules.
## Tests
You can run tests by using the `unittest` command:
`python .\lxbuildenv.py -r -m unittest -v valentyusb.usbcore.cpu.epfifo_test.TestPerEndpointFifoInterface`

@ -1 +1 @@
Subproject commit fd7ed6c1ec24ffbdbebb465bc8cc4713b6d40181 Subproject commit ff155a474d12b62fb84db0ca07d2577687c5c141

@ -1 +1 @@
Subproject commit 65292f0adbe688bda27f0b202cba9bea28de0d14 Subproject commit 8151e2b34e74ebd20c435c637340293dadcc52c1

View File

@ -14,16 +14,12 @@ import lxbuildenv
#from migen import * #from migen import *
from migen import Module, Signal, Instance, ClockDomain, If from migen import Module, Signal, Instance, ClockDomain, If
from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.fhdl.specials import TSTriple
from migen.fhdl.structure import ClockSignal, ResetSignal, Replicate, Cat
from litex.build.lattice.platform import LatticePlatform from litex.build.lattice.platform import LatticePlatform
from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal
from litex.soc.integration import SoCCore from litex.soc.integration import SoCCore
from litex.soc.integration.builder import Builder from litex.soc.integration.builder import Builder
from litex.soc.integration.soc_core import csr_map_update from litex.soc.integration.soc_core import csr_map_update
from litex.soc.interconnect import wishbone from litex.soc.interconnect import wishbone
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
from valentyusb import usbcore from valentyusb import usbcore
from valentyusb.usbcore import io as usbio from valentyusb.usbcore import io as usbio
@ -33,9 +29,8 @@ from valentyusb.usbcore.endpoint import EndpointType
from lxsocsupport import up5kspram, spi_flash from lxsocsupport import up5kspram, spi_flash
import argparse import argparse
import os
_io_evt = [ _io = [
("serial", 0, ("serial", 0,
Subsignal("rx", Pins("21")), Subsignal("rx", Pins("21")),
Subsignal("tx", Pins("13"), Misc("PULLUP")), Subsignal("tx", Pins("13"), Misc("PULLUP")),
@ -59,11 +54,6 @@ _io_evt = [
Subsignal("p3", Pins("46"), IOStandard("LVCMOS33")), Subsignal("p3", Pins("46"), IOStandard("LVCMOS33")),
Subsignal("p4", Pins("45"), 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, ("spiflash", 0,
Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")),
Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")),
@ -79,76 +69,11 @@ _io_evt = [
), ),
("clk48", 0, Pins("44"), IOStandard("LVCMOS33")) ("clk48", 0, Pins("44"), IOStandard("LVCMOS33"))
] ]
_io_dvt = [
("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")
),
("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")
),
("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("F5"), IOStandard("LVCMOS33"))
]
_connectors = [] _connectors = []
class _CRG(Module): class _CRG(Module):
def __init__(self, platform, use_pll): def __init__(self, platform):
if use_pll:
clk48_raw = platform.request("clk48") clk48_raw = platform.request("clk48")
clk12_raw = Signal() clk12_raw = Signal()
clk48 = Signal() clk48 = Signal()
@ -158,6 +83,17 @@ class _CRG(Module):
# By doing this, we avoid needing clock-domain crossing. # By doing this, we avoid needing clock-domain crossing.
clk12_counter = Signal(2) clk12_counter = Signal(2)
# # "0b00" Sets 48MHz HFOSC output
# # "0b01" Sets 24MHz HFOSC output.
# # "0b10" Sets 12MHz HFOSC output.
# # "0b11" Sets 6MHz HFOSC output
# self.specials += Instance(
# "SB_HFOSC",
# i_CLKHFEN=1,
# i_CLKHFPU=1,
# o_CLKHF=clk12,
# p_CLKHF_DIV="0b10", # 12MHz
# )
self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_usb_12 = ClockDomain() self.clock_domains.cd_usb_12 = ClockDomain()
@ -168,24 +104,28 @@ class _CRG(Module):
platform.add_period_constraint(self.cd_usb_48_raw.clk, 1e9/48e6) platform.add_period_constraint(self.cd_usb_48_raw.clk, 1e9/48e6)
platform.add_period_constraint(self.cd_sys.clk, 1e9/12e6) 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(self.cd_usb_12.clk, 1e9/12e6)
platform.add_period_constraint(clk48, 1e9/48e6)
platform.add_period_constraint(clk48_raw, 1e9/48e6)
self.reset = Signal() self.reset = Signal()
# POR reset logic- POR generated from sys clk, POR logic feeds sys clk # POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset. # reset.
self.clock_domains.cd_por = ClockDomain() self.clock_domains.cd_por = ClockDomain()
reset_delay = Signal(14, reset=4095) reset_delay = Signal(12, reset=4095)
self.comb += [ self.comb += [
self.cd_por.clk.eq(self.cd_sys.clk), self.cd_por.clk.eq(self.cd_sys.clk),
self.cd_sys.rst.eq(reset_delay != 0), self.cd_sys.rst.eq(reset_delay != 0),
self.cd_usb_12.rst.eq(reset_delay != 0), self.cd_usb_12.rst.eq(reset_delay != 0),
self.cd_usb_48.rst.eq(reset_delay != 0), # self.cd_usb_48.rst.eq(reset_delay != 0),
# self.cd_usb_48_raw.rst.eq(reset_delay != 0), # self.cd_usb_48_raw.rst.eq(reset_delay != 0),
] ]
clk48_in = Signal()
self.comb += self.cd_usb_48_raw.clk.eq(clk48_raw) self.comb += self.cd_usb_48_raw.clk.eq(clk48_raw)
self.specials += Instance(
"SB_GB",
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk48_raw,
o_GLOBAL_BUFFER_OUTPUT=clk48_in,
)
self.comb += self.cd_usb_48.clk.eq(clk48) self.comb += self.cd_usb_48.clk.eq(clk48)
self.sync.usb_48_raw += clk12_counter.eq(clk12_counter + 1) self.sync.usb_48_raw += clk12_counter.eq(clk12_counter + 1)
@ -196,7 +136,6 @@ class _CRG(Module):
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw, i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw,
o_GLOBAL_BUFFER_OUTPUT=clk12, o_GLOBAL_BUFFER_OUTPUT=clk12,
) )
platform.add_period_constraint(clk12_raw, 1e9/12e6)
self.specials += Instance( self.specials += Instance(
"SB_PLL40_CORE", "SB_PLL40_CORE",
@ -226,51 +165,6 @@ class _CRG(Module):
#o_SDO, #o_SDO,
#i_SDI, #i_SDI,
) )
else:
clk48_raw = platform.request("clk48")
clk12_raw = Signal()
clk48 = Signal()
clk12 = 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)
self.reset = Signal()
# POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset.
self.clock_domains.cd_por = ClockDomain()
reset_delay = Signal(13, reset=4095)
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),
# self.cd_usb_48.rst.eq(reset_delay != 0),
]
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])
platform.add_period_constraint(clk12_raw, 1e9/12e6)
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_sys.clk.eq(clk12)
self.comb += self.cd_usb_12.clk.eq(clk12) self.comb += self.cd_usb_12.clk.eq(clk12)
@ -305,13 +199,7 @@ class RandomFirmwareROM(wishbone.SRAM):
for d in range(int(size / 4)): for d in range(int(size / 4)):
seed = get_rand(seed) seed = get_rand(seed)
data.append(seed) data.append(seed)
wishbone.SRAM.__init__(self, size, read_only=True, init=data) print("Firmware {} bytes of random data".format(size))
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) wishbone.SRAM.__init__(self, size, read_only=True, init=data)
class Platform(LatticePlatform): class Platform(LatticePlatform):
@ -320,187 +208,20 @@ class Platform(LatticePlatform):
gateware_size = 0x20000 gateware_size = 0x20000
def __init__(self, revision=None, toolchain="icestorm"): def __init__(self, toolchain="icestorm"):
if revision == "evt": LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, toolchain="icestorm")
LatticePlatform.__init__(self, "ice40-up5k-sg48", _io_evt, _connectors, toolchain="icestorm")
elif revision == "dvt":
LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_dvt, _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".format(revision))
def create_programmer(self): def create_programmer(self):
raise ValueError("programming is not supported") raise ValueError("programming is not supported")
class SBLED(Module, AutoCSR): # def do_finalize(self, fragment):
def __init__(self, pads): # LatticePlatform.do_finalize(self, fragment)
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)
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 BBSpi(Module, AutoCSR):
def __init__(self, platform, pads):
self.reset = Signal()
# self.rdata = Signal(32)
# self.addr = Signal(24)
# self.ready = Signal()
# self.valid = Signal()
# self.flash_csb = Signal()
# self.flash_clk = Signal()
# cfgreg_we = Signal(4)
# cfgreg_di = Signal(32)
# cfgreg_do = Signal(32)
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.cfg = CSRStorage(size=8)
# cfg_remapped = Cat(self.cfg.storage[0:7], Signal(7), self.cfg.storage[7])
# self.comb += self.reset.eq(0)
# self.comb += [
# cfgreg_di.eq(Cat(self.do.storage, Replicate(2, 0), # Attach "DO" to lower 6 bits
# self.oe.storage, Replicate(4, 0), # Attach "OE" to bits 8-11
# cfg_remapped)),
# cfgreg_we.eq(Cat(self.do.re, self.oe.re, self.cfg.re, self.cfg.re)),
# self.di.status.eq(cfgreg_do),
# clk_pad.oe.eq(~self.reset),
# cs_n_pad.oe.eq(~self.reset),
# ]
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)),
]
# 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,
# 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 = ResetSignal() | self.reset,
# i_clk = ClockSignal(),
# i_valid = self.valid,
# o_ready = self.ready,
# i_addr = self.addr,
# o_rdata = self.rdata,
# i_cfgreg_we = cfgreg_we,
# i_cfgreg_di = cfgreg_di,
# o_cfgreg_do = cfgreg_do,
# o_flash_csb = self.flash_csb,
# o_flash_clk = self.flash_clk,
# )
# platform.add_source("spimemio.v")
class BaseSoC(SoCCore): class BaseSoC(SoCCore):
csr_peripherals = [ csr_peripherals = [
"cpu_or_bridge", "cpu_or_bridge",
"usb", "usb",
"bbspi", "usb_obuf",
"reboot", "usb_ibuf",
"rgb",
] ]
csr_map_update(SoCCore.csr_map, csr_peripherals) csr_map_update(SoCCore.csr_map, csr_peripherals)
@ -514,23 +235,14 @@ class BaseSoC(SoCCore):
} }
interrupt_map.update(SoCCore.interrupt_map) interrupt_map.update(SoCCore.interrupt_map)
def __init__(self, platform, boot_source="rand", debug=False, bios_file=None, use_pll=True, **kwargs): def __init__(self, platform, boot_source="random_rom", **kwargs):
# Disable integrated RAM as we'll add it later # Disable integrated RAM as we'll add it later
self.integrated_sram_size = 0 self.integrated_sram_size = 0
clk_freq = int(12e6) clk_freq = int(12e6)
self.submodules.crg = _CRG(platform, use_pll=use_pll) self.submodules.crg = _CRG(platform)
SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, with_uart=False, **kwargs) SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, **kwargs)
if debug:
self.cpu.use_external_variant("2-stage-1024-cache-debug.v")
from litex.soc.cores.uart import UARTWishboneBridge
self.register_mem("vexriscv_debug", 0xf00f0000, self.cpu.debug_bus, 0x10)
self.submodules.uart_bridge = UARTWishboneBridge(platform.request("serial"), clk_freq, baudrate=115200)
self.add_wb_master(self.uart_bridge.wishbone)
else:
self.cpu.use_external_variant("2-stage-1024-cache.v")
# SPRAM- UP5K has single port RAM, might as well use it as SRAM to # SPRAM- UP5K has single port RAM, might as well use it as SRAM to
# free up scarce block RAM. # free up scarce block RAM.
@ -538,25 +250,17 @@ class BaseSoC(SoCCore):
self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size) self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size)
self.register_mem("sram", 0x10000000, self.spram.bus, spram_size) self.register_mem("sram", 0x10000000, self.spram.bus, spram_size)
if boot_source == "rand": if boot_source == "random_rom":
kwargs['cpu_reset_address']=0 kwargs['cpu_reset_address']=0
bios_size = 0x2000 bios_size = 0x2000
self.submodules.random_rom = RandomFirmwareROM(bios_size) self.submodules.random_rom = RandomFirmwareROM(bios_size)
self.add_constant("ROM_DISABLE", 1) self.add_constant("ROM_DISABLE", 1)
self.register_rom(self.random_rom.bus, bios_size) self.register_rom(self.random_rom.bus, bios_size)
elif boot_source == "bios": elif boot_source == "bios_rom":
kwargs['cpu_reset_address']=0 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 bios_size = 0x2000
self.submodules.firmware_rom = FirmwareROM(bios_size, bios_file) self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size)
self.add_constant("ROM_DISABLE", 1) elif boot_source == "spi_rom":
self.register_rom(self.firmware_rom.bus, bios_size)
elif boot_source == "spi":
bios_size = 0x8000 bios_size = 0x8000
kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size
self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size)
@ -570,175 +274,60 @@ class BaseSoC(SoCCore):
else: else:
raise ValueError("unrecognized boot_source: {}".format(boot_source)) raise ValueError("unrecognized boot_source: {}".format(boot_source))
# Add a simple bit-banged SPI Flash module pmoda = platform.request("pmoda")
spi_pads = platform.request("spiflash") pmodb = platform.request("pmodb")
self.submodules.bbspi = BBSpi(platform, spi_pads)
self.submodules.reboot = SBWarmBoot()
self.submodules.rgb = SBLED(platform.request("led"))
# Add USB pads # Add USB pads
usb_pads = platform.request("usb") usb_pads = platform.request("usb")
usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup) usb_iobuf = usbio.IoBuf(pmoda.p4, pmodb.p4, usb_pads.pullup)
self.submodules.usb = epfifo.PerEndpointFifoInterface(usb_iobuf, endpoints=[EndpointType.BIDIR]) # self.submodules.usb = epfifo.PerEndpointFifoInterface(usb_iobuf, endpoints=[EndpointType.BIDIR])
# self.submodules.usb = epmem.MemInterface(usb_iobuf) # self.submodules.usb = epmem.MemInterface(usb_iobuf)
# self.submodules.usb = unififo.UsbUniFifo(usb_iobuf) self.submodules.usb = unififo.UsbUniFifo(usb_iobuf)
# Add "-relut -dffe_min_ce_use 4" to the synth_ice40 command. self.comb += [
# The "-reult" adds an additional LUT pass to pack more stuff in, pmoda.p1.eq(self.crg.cd_usb_48.clk),
# and the "-dffe_min_ce_use 4" flag prevents Yosys from generating a pmodb.p1.eq(self.crg.cd_usb_12.clk),
# Clock Enable signal for a LUT that has fewer than 4 flip-flops. pmodb.p2.eq(self.usb.tx.i_bit_strobe),
# This increases density, and lets us use the FPGA more efficiently. pmoda.p2.eq(self.usb.tx.fit_dat),
platform.toolchain.nextpnr_yosys_template[2] += " -dsp -relut -dffe_min_ce_use 5" pmodb.p3.eq(self.usb.tx.fit_oe),
]
# Disable final deep-sleep power down so firmware words are loaded # Disable final deep-sleep power down so firmware words are loaded
# onto softcore's address bus. # onto softcore's address bus.
platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin" 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" platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin"
# # Add a "Multiboot" variant
# platform.toolchain.nextpnr_build_template[3] = "icepack -s {build_name}.txt {build_name}-multi.bin"
def make_multiboot_header(filename, boot_offsets=[160]):
"""
ICE40 allows you to program the SB_WARMBOOT state machine by adding the following
values to the bitstream, before any given image:
[7e aa 99 7e] Sync Header
[92 00 k0] Boot mode (k = 1 for cold boot, 0 for warmboot)
[44 03 o1 o2 o3] Boot address
[82 00 00] Bank offset
[01 08] Reboot
[...] Padding (up to 32 bytes)
Note that in ICE40, the second nybble indicates the number of remaining bytes
(with the exception of the sync header).
The above construct is repeated five times:
INITIAL_BOOT The image loaded at first boot
BOOT_S00 The first image for SB_WARMBOOT
BOOT_S01 The second image for SB_WARMBOOT
BOOT_S10 The third image for SB_WARMBOOT
BOOT_S11 The fourth image for SB_WARMBOOT
"""
while len(boot_offsets) < 5:
boot_offsets.append(boot_offsets[0])
with open(filename, 'wb') as output:
for offset in boot_offsets:
# Sync Header
output.write(bytes([0x7e, 0xaa, 0x99, 0x7e]))
# Boot mode
output.write(bytes([0x92, 0x00, 0x00]))
# Boot address
output.write(bytes([0x44, 0x03,
(offset >> 16) & 0xff,
(offset >> 8) & 0xff,
(offset >> 0) & 0xff]))
# Bank offset
output.write(bytes([0x82, 0x00, 0x00]))
# Reboot command
output.write(bytes([0x01, 0x08]))
for x in range(17, 32):
output.write(bytes([0]))
def main(): def main():
platform = Platform()
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Build Fomu Main Gateware") description="Build Fomu Main Gateware",
add_help=False)
parser.add_argument( parser.add_argument(
"--boot-source", choices=["spi", "rand", "bios"], default="bios", "--bios", help="use bios as boot source", action="store_true"
help="where to have the CPU obtain its executable code from"
) )
parser.add_argument( parser.add_argument(
"--revision", choices=["dvt", "evt", "hacker"], required=True, "--rand", help="use random data as boot source", action="store_false"
help="build foboot for a particular hardware revision"
) )
parser.add_argument( parser.add_argument(
"--bios", help="use specified file as a BIOS, rather than building one" "--spi", help="boot from spi", action="store_true"
) )
parser.add_argument( (args, rest) = parser.parse_known_args()
"--with-debug", help="enable debug support", action="store_true"
)
parser.add_argument(
"--no-pll", help="disable pll (possibly improving timing)", action="store_false"
)
parser.add_argument(
"--export-random-rom-file", help="Generate a random ROM file and save it to a file"
)
args = parser.parse_args()
output_dir = 'build'
if args.export_random_rom_file is not None:
size = 0x2000
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
seed = 1
with open(args.export_random_rom_file, "w", newline="\n") as output:
for d in range(int(size / 4)):
seed = get_rand(seed)
print("{:08x}".format(seed), file=output)
return 0
if args.rand:
boot_source="random_rom"
compile_software=False compile_software=False
if args.boot_source == "bios" and args.bios is None: elif args.bios:
boot_source="bios_rom"
compile_software=True compile_software=True
elif args.spi:
boot_source = "spi_rom"
compile_software = False
cpu_variant = "min" soc = BaseSoC(platform, cpu_type="vexriscv", cpu_variant="min", boot_source=boot_source)
debug = False builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv", compile_software=compile_software)
if args.with_debug:
cpu_variant = "debug"
debug = True
os.environ["LITEX"] = "1" # Give our Makefile something to look for
platform = Platform(revision=args.revision)
soc = BaseSoC(platform, cpu_type="vexriscv", cpu_variant=cpu_variant,
debug=debug, boot_source=args.boot_source,
bios_file=args.bios, use_pll=args.no_pll)
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() vns = builder.build()
soc.do_exit(vns) soc.do_exit(vns)
make_multiboot_header(os.path.join(output_dir, "gateware", "multiboot-header.bin"), [160, 262144])
with open(os.path.join(output_dir, 'gateware', 'multiboot-header.bin'), 'rb') as multiboot_header_file:
multiboot_header = multiboot_header_file.read()
with open(os.path.join(output_dir, 'gateware', 'top.bin'), 'rb') as top_file:
top = top_file.read()
with open(os.path.join(output_dir, 'gateware', 'top-multiboot.bin'), 'wb') as top_multiboot_file:
top_multiboot_file.write(multiboot_header)
top_multiboot_file.write(top)
print(
"""Foboot build complete. Output files:
{}/gateware/top.bin Bitstream file. Load this onto the FPGA for testing.
{}/gateware/top-multiboot.bin Multiboot-enabled bitstream file. Flash this onto FPGA ROM.
{}/gateware/top.v Source Verilog file. Useful for debugging issues.
{}/software/include/generated Header files for API access.
{}/software/bios/bios.elf ELF file for debugging bios.
""".format(output_dir, output_dir, output_dir, output_dir, output_dir))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,48 +1,36 @@
PACKAGE = foboot
FOMU_SDK ?= .
ADD_CFLAGS = -I$(FOMU_SDK)/include -D__vexriscv__ -march=rv32im -mabi=ilp32
ADD_LFLAGS =
SRC_DIR = src
GIT_VERSION := $(shell git describe --tags) GIT_VERSION := $(shell git describe --tags)
TRGT ?= riscv64-unknown-elf- TRGT ?= riscv64-unknown-elf-
CC := $(TRGT)gcc CC = $(TRGT)gcc
CXX := $(TRGT)g++ CXX = $(TRGT)g++
OBJCOPY := $(TRGT)objcopy OBJCOPY = $(TRGT)objcopy
RM := rm -rf RM = rm -rf
COPY := cp -a COPY = cp -a
PATH_SEP := / PATH_SEP = /
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
COPY := copy COPY = copy
RM := del RM = del
PATH_SEP := \\ PATH_SEP = \\
endif endif
ifeq ($(LITEX),1) LDSCRIPT = $(FOMU_SDK)/ld/linker.ld
BASE_DIR := ../../../../sw LDSCRIPTS = $(LDSCRIPT) $(FOMU_SDK)/ld/output_format.ld $(FOMU_SDK)/ld/regions.ld
LDSCRIPT := $(BASE_DIR)/ld/linker.ld DBG_CFLAGS = -ggdb -g -DDEBUG -Wall
LD_DIR := ../include/generated DBG_LFLAGS = -ggdb -g -Wall
ADD_CFLAGS := -I../include -I$(BASE_DIR)/include -D__vexriscv__ -march=rv32im -mabi=ilp32 CFLAGS = $(ADD_CFLAGS) \
ADD_LFLAGS :=
PACKAGE := bios
else
BASE_DIR := .
LD_DIR := $(BASE_DIR)/ld
LDSCRIPT := $(BASE_DIR)/ld/linker.ld
ADD_CFLAGS := -I$(BASE_DIR)/include -D__vexriscv__ -march=rv32im -mabi=ilp32
ADD_LFLAGS :=
PACKAGE := foboot
endif
LDSCRIPTS := $(LDSCRIPT) $(LD_DIR)/output_format.ld $(LD_DIR)/regions.ld
SRC_DIR := $(BASE_DIR)/src
THIRD_PARTY := $(BASE_DIR)/third_party
DBG_CFLAGS := -ggdb -g -DDEBUG -Wall
DBG_LFLAGS := -ggdb -g -Wall
CFLAGS := $(ADD_CFLAGS) \
-Wall -Wextra \ -Wall -Wextra \
-ffunction-sections -fdata-sections -fno-common \ -ffunction-sections -fdata-sections -fno-common \
-fomit-frame-pointer -Os \ -fomit-frame-pointer -Os \
-march=rv32i \
-DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11 -DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11
CXXFLAGS := $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions CXXFLAGS = $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
LFLAGS := $(CFLAGS) $(ADD_LFLAGS) -L$(LD_DIR) \ LFLAGS = $(CFLAGS) $(ADD_LFLAGS) \
-nostartfiles \ -nostartfiles \
-nostdlib \ -nostdlib \
-Wl,--gc-sections \ -Wl,--gc-sections \
@ -50,22 +38,22 @@ LFLAGS := $(CFLAGS) $(ADD_LFLAGS) -L$(LD_DIR) \
-Wl,--script=$(LDSCRIPT) \ -Wl,--script=$(LDSCRIPT) \
-Wl,--build-id=none -Wl,--build-id=none
OBJ_DIR := .obj OBJ_DIR = .obj
CSOURCES := $(wildcard $(SRC_DIR)/*.c) $(wildcard $(THIRD_PARTY)/libbase/*.c) $(wildcard $(THIRD_PARTY)/*.c) CSOURCES = $(wildcard $(SRC_DIR)/*.c) $(wildcard third_party/libbase/*.c) $(wildcard third_party/*.c)
CPPSOURCES := $(wildcard $(SRC_DIR)/*.cpp) $(wildcard $(THIRD_PARTY)/libbase/*.cpp) $(wildcard $(THIRD_PARTY)/*.cpp) CPPSOURCES = $(wildcard $(SRC_DIR)/*.cpp) $(wildcard third_party/libbase/*.cpp) $(wildcard third_party/*.cpp)
ASOURCES := $(wildcard $(SRC_DIR)/*.S) $(wildcard $(THIRD_PARTY)/libbase/*.S) $(wildcard $(THIRD_PARTY)/*.S) ASOURCES = $(wildcard $(SRC_DIR)/*.S) $(wildcard third_party/libbase/*.S) $(wildcard third_party/*.S)
COBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o))) COBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o)))
CXXOBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o))) CXXOBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o)))
AOBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o))) AOBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o)))
OBJECTS := $(COBJS) $(CXXOBJS) $(AOBJS) OBJECTS = $(COBJS) $(CXXOBJS) $(AOBJS)
VPATH := $(SRC_DIR) $(THIRD_PARTY) $(THIRD_PARTY)/libbase VPATH = $(SRC_DIR) third_party/libbase third_party
QUIET := @ QUIET = @
ALL := all ALL = all
TARGET := $(PACKAGE).elf TARGET = $(PACKAGE).elf
CLEAN := clean CLEAN = clean
$(ALL): $(TARGET) $(PACKAGE).bin $(PACKAGE).ihex $(ALL): $(TARGET) $(PACKAGE).bin $(PACKAGE).ihex
@ -84,6 +72,10 @@ $(PACKAGE).dfu: $(TARGET)
$(QUIET) $(COPY) $(PACKAGE).bin $@ $(QUIET) $(COPY) $(PACKAGE).bin $@
$(QUIET) dfu-suffix -v 1209 -p 70b1 -a $@ $(QUIET) dfu-suffix -v 1209 -p 70b1 -a $@
#$(PACKAGE).bit: $(TARGET)
# $(QUIET) echo " BIT $@"
# # $(QUIET) ice40-repack input/top.bin input/mem_1.init ./foboot.bin ./foboot.bit
$(PACKAGE).ihex: $(TARGET) $(PACKAGE).ihex: $(TARGET)
$(QUIET) echo " IHEX $(PACKAGE).ihex" $(QUIET) echo " IHEX $(PACKAGE).ihex"
$(QUIET) $(OBJCOPY) -O ihex $(TARGET) $@ $(QUIET) $(OBJCOPY) -O ihex $(TARGET) $@
@ -97,7 +89,7 @@ $(DEBUG): $(TARGET)
$(OBJ_DIR): $(OBJ_DIR):
$(QUIET) mkdir $(OBJ_DIR) $(QUIET) mkdir $(OBJ_DIR)
$(COBJS) : $(OBJ_DIR)/%.o : %.c $(BASE_DIR)/Makefile $(COBJS) : $(OBJ_DIR)/%.o : %.c Makefile
$(QUIET) echo " CC $< $(notdir $@)" $(QUIET) echo " CC $< $(notdir $@)"
$(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD $(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD

View File

@ -63,13 +63,11 @@ typedef enum {
#define DFU_INTERFACE 0 #define DFU_INTERFACE 0
#define DFU_DETACH_TIMEOUT 10000 // 10 second timer #define DFU_DETACH_TIMEOUT 10000 // 10 second timer
#define DFU_TRANSFER_SIZE 256 // Flash sector size #define DFU_TRANSFER_SIZE 1024 // Flash sector size
// Main thread // Main thread
void dfu_init(); void dfu_init();
void dfu_poll(void);
// USB entry points. Always successful. // USB entry points. Always successful.
uint8_t dfu_getstate(); uint8_t dfu_getstate();

View File

@ -12,33 +12,6 @@ extern uint32_t csr_readl(uint32_t addr);
#include <hw/common.h> #include <hw/common.h>
#endif /* ! CSR_ACCESSORS_DEFINED */ #endif /* ! CSR_ACCESSORS_DEFINED */
/* bbspi */
#define CSR_BBSPI_BASE 0xe0005000
#define CSR_BBSPI_DO_ADDR 0xe0005000
#define CSR_BBSPI_DO_SIZE 1
static inline unsigned char bbspi_do_read(void) {
unsigned char r = csr_readl(0xe0005000);
return r;
}
static inline void bbspi_do_write(unsigned char value) {
csr_writel(value, 0xe0005000);
}
#define CSR_BBSPI_OE_ADDR 0xe0005004
#define CSR_BBSPI_OE_SIZE 1
static inline unsigned char bbspi_oe_read(void) {
unsigned char r = csr_readl(0xe0005004);
return r;
}
static inline void bbspi_oe_write(unsigned char value) {
csr_writel(value, 0xe0005004);
}
#define CSR_BBSPI_DI_ADDR 0xe0005008
#define CSR_BBSPI_DI_SIZE 1
static inline unsigned char bbspi_di_read(void) {
unsigned char r = csr_readl(0xe0005008);
return r;
}
/* ctrl */ /* ctrl */
#define CSR_CTRL_BASE 0xe0000000 #define CSR_CTRL_BASE 0xe0000000
#define CSR_CTRL_RESET_ADDR 0xe0000000 #define CSR_CTRL_RESET_ADDR 0xe0000000
@ -81,48 +54,6 @@ static inline unsigned int ctrl_bus_errors_read(void) {
return r; return r;
} }
/* reboot */
#define CSR_REBOOT_BASE 0xe0005800
#define CSR_REBOOT_CTRL_ADDR 0xe0005800
#define CSR_REBOOT_CTRL_SIZE 1
static inline unsigned char reboot_ctrl_read(void) {
unsigned char r = csr_readl(0xe0005800);
return r;
}
static inline void reboot_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0005800);
}
/* rgb */
#define CSR_RGB_BASE 0xe0006000
#define CSR_RGB_DAT_ADDR 0xe0006000
#define CSR_RGB_DAT_SIZE 1
static inline unsigned char rgb_dat_read(void) {
unsigned char r = csr_readl(0xe0006000);
return r;
}
static inline void rgb_dat_write(unsigned char value) {
csr_writel(value, 0xe0006000);
}
#define CSR_RGB_ADDR_ADDR 0xe0006004
#define CSR_RGB_ADDR_SIZE 1
static inline unsigned char rgb_addr_read(void) {
unsigned char r = csr_readl(0xe0006004);
return r;
}
static inline void rgb_addr_write(unsigned char value) {
csr_writel(value, 0xe0006004);
}
#define CSR_RGB_CTRL_ADDR 0xe0006008
#define CSR_RGB_CTRL_SIZE 1
static inline unsigned char rgb_ctrl_read(void) {
unsigned char r = csr_readl(0xe0006008);
return r;
}
static inline void rgb_ctrl_write(unsigned char value) {
csr_writel(value, 0xe0006008);
}
/* timer0 */ /* timer0 */
#define CSR_TIMER0_BASE 0xe0002800 #define CSR_TIMER0_BASE 0xe0002800
#define CSR_TIMER0_LOAD_ADDR 0xe0002800 #define CSR_TIMER0_LOAD_ADDR 0xe0002800
@ -219,6 +150,78 @@ static inline void timer0_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0002840); csr_writel(value, 0xe0002840);
} }
/* uart */
#define CSR_UART_BASE 0xe0001800
#define CSR_UART_RXTX_ADDR 0xe0001800
#define CSR_UART_RXTX_SIZE 1
static inline unsigned char uart_rxtx_read(void) {
unsigned char r = csr_readl(0xe0001800);
return r;
}
static inline void uart_rxtx_write(unsigned char value) {
csr_writel(value, 0xe0001800);
}
#define CSR_UART_TXFULL_ADDR 0xe0001804
#define CSR_UART_TXFULL_SIZE 1
static inline unsigned char uart_txfull_read(void) {
unsigned char r = csr_readl(0xe0001804);
return r;
}
#define CSR_UART_RXEMPTY_ADDR 0xe0001808
#define CSR_UART_RXEMPTY_SIZE 1
static inline unsigned char uart_rxempty_read(void) {
unsigned char r = csr_readl(0xe0001808);
return r;
}
#define CSR_UART_EV_STATUS_ADDR 0xe000180c
#define CSR_UART_EV_STATUS_SIZE 1
static inline unsigned char uart_ev_status_read(void) {
unsigned char r = csr_readl(0xe000180c);
return r;
}
static inline void uart_ev_status_write(unsigned char value) {
csr_writel(value, 0xe000180c);
}
#define CSR_UART_EV_PENDING_ADDR 0xe0001810
#define CSR_UART_EV_PENDING_SIZE 1
static inline unsigned char uart_ev_pending_read(void) {
unsigned char r = csr_readl(0xe0001810);
return r;
}
static inline void uart_ev_pending_write(unsigned char value) {
csr_writel(value, 0xe0001810);
}
#define CSR_UART_EV_ENABLE_ADDR 0xe0001814
#define CSR_UART_EV_ENABLE_SIZE 1
static inline unsigned char uart_ev_enable_read(void) {
unsigned char r = csr_readl(0xe0001814);
return r;
}
static inline void uart_ev_enable_write(unsigned char value) {
csr_writel(value, 0xe0001814);
}
/* uart_phy */
#define CSR_UART_PHY_BASE 0xe0001000
#define CSR_UART_PHY_TUNING_WORD_ADDR 0xe0001000
#define CSR_UART_PHY_TUNING_WORD_SIZE 4
static inline unsigned int uart_phy_tuning_word_read(void) {
unsigned int r = csr_readl(0xe0001000);
r <<= 8;
r |= csr_readl(0xe0001004);
r <<= 8;
r |= csr_readl(0xe0001008);
r <<= 8;
r |= csr_readl(0xe000100c);
return r;
}
static inline void uart_phy_tuning_word_write(unsigned int value) {
csr_writel(value >> 24, 0xe0001000);
csr_writel(value >> 16, 0xe0001004);
csr_writel(value >> 8, 0xe0001008);
csr_writel(value, 0xe000100c);
}
/* usb */ /* usb */
#define CSR_USB_BASE 0xe0004800 #define CSR_USB_BASE 0xe0004800
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800 #define CSR_USB_PULLUP_OUT_ADDR 0xe0004800
@ -362,6 +365,42 @@ static inline unsigned char usb_ep_0_in_ibuf_empty_read(void) {
unsigned char r = csr_readl(0xe0004840); unsigned char r = csr_readl(0xe0004840);
return r; return r;
} }
#define CSR_USB_USB_TRANSFER_O_PID_ADDR 0xe0004844
#define CSR_USB_USB_TRANSFER_O_PID_SIZE 1
static inline unsigned char usb_usb_transfer_o_pid_read(void) {
unsigned char r = csr_readl(0xe0004844);
return r;
}
#define CSR_USB_USB_TRANSFER_ERROR_STATE_ADDR 0xe0004848
#define CSR_USB_USB_TRANSFER_ERROR_STATE_SIZE 1
static inline unsigned char usb_usb_transfer_error_state_read(void) {
unsigned char r = csr_readl(0xe0004848);
return r;
}
#define CSR_USB_USB_TRANSFER_ERROR_PID_ADDR 0xe000484c
#define CSR_USB_USB_TRANSFER_ERROR_PID_SIZE 1
static inline unsigned char usb_usb_transfer_error_pid_read(void) {
unsigned char r = csr_readl(0xe000484c);
return r;
}
#define CSR_USB_DBG_LWH_ADDR 0xe0004850
#define CSR_USB_DBG_LWH_SIZE 1
static inline unsigned char usb_dbg_lwh_read(void) {
unsigned char r = csr_readl(0xe0004850);
return r;
}
#define CSR_USB_DBG_LWD_ADDR 0xe0004854
#define CSR_USB_DBG_LWD_SIZE 1
static inline unsigned char usb_dbg_lwd_read(void) {
unsigned char r = csr_readl(0xe0004854);
return r;
}
#define CSR_USB_DBG_LFP_ADDR 0xe0004858
#define CSR_USB_DBG_LFP_SIZE 1
static inline unsigned char usb_dbg_lfp_read(void) {
unsigned char r = csr_readl(0xe0004858);
return r;
}
/* constants */ /* constants */
#define NMI_INTERRUPT 0 #define NMI_INTERRUPT 0

View File

@ -1,10 +0,0 @@
#ifndef _RGB_H_
#define _RGB_H_
void rgb_init(void);
void rgb_mode_idle(void);
void rgb_mode_done(void);
void rgb_mode_writing(void);
void rgb_mode_error(void);
#endif /* _RGB_H_ */

View File

@ -1,93 +0,0 @@
#ifndef BB_SPI_H_
#define BB_SPI_H_
#include <stdint.h>
enum spi_state {
SS_UNCONFIGURED = 0,
SS_SINGLE,
SS_DUAL_RX,
SS_DUAL_TX,
SS_QUAD_RX,
SS_QUAD_TX,
SS_HARDWARE,
};
enum spi_type {
ST_UNCONFIGURED,
ST_SINGLE,
ST_DUAL,
ST_QUAD,
ST_QPI,
};
enum spi_pin {
SP_MOSI,
SP_MISO,
SP_HOLD,
SP_WP,
SP_CS,
SP_CLK,
SP_D0,
SP_D1,
SP_D2,
SP_D3,
};
struct spi_id {
uint8_t manufacturer_id; // Result from 0x90
uint8_t device_id; // Result from 0x90
uint8_t _manufacturer_id; // Result from 0x9f
uint8_t memory_type; // Result from 0x9f
uint8_t memory_size; // Result from 0x9f
uint8_t signature; // Result from 0xab
uint8_t serial[4]; // Result from 0x4b
int bytes; // -1 if unknown
const char *manufacturer;
const char *model;
const char *capacity;
};
struct ff_spi;
void spiPause(struct ff_spi *spi);
void spiBegin(struct ff_spi *spi);
void spiEnd(struct ff_spi *spi);
//void spiSingleTx(struct ff_spi *spi, uint8_t out);
//uint8_t spiSingleRx(struct ff_spi *spi);
//void spiDualTx(struct ff_spi *spi, uint8_t out);
//void spiQuadTx(struct ff_spi *spi, uint8_t out);
void spiCommand(struct ff_spi *spi, uint8_t cmd);
//uint8_t spiDualRx(struct ff_spi *spi);
//uint8_t spiQuadRx(struct ff_spi *spi);
int spiTx(struct ff_spi *spi, uint8_t word);
uint8_t spiRx(struct ff_spi *spi);
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr);
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val);
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
int spiSetType(struct ff_spi *spi, enum spi_type type);
int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count);
int spiIsBusy(struct ff_spi *spi);
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr);
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr);
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *data, unsigned int count);
struct spi_id spiId(struct ff_spi *spi);
void spiOverrideSize(struct ff_spi *spi, uint32_t new_size);
//int spi_wait_for_not_busy(struct ff_spi *spi);
int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count);
uint8_t spiReset(struct ff_spi *spi);
int spiInit(struct ff_spi *spi);
void spiHold(struct ff_spi *spi);
void spiUnhold(struct ff_spi *spi);
void spiSwapTxRx(struct ff_spi *spi);
struct ff_spi *spiAlloc(void);
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val);
void spiFree(struct ff_spi **spi);
#endif /* BB_SPI_H_ */

View File

@ -56,15 +56,4 @@ static inline void mtspr(unsigned long add, unsigned long val)
} }
#endif #endif
#include <generated/csr.h>
__attribute__((noreturn)) static inline void reboot(void) {
reboot_ctrl_write(0xac);
while (1);
}
__attribute__((noreturn)) static inline void reboot_to_image(uint8_t image_index) {
reboot_ctrl_write(0xac | (image_index & 3) << 0);
while (1);
}
#endif /* __SYSTEM_H */ #endif /* __SYSTEM_H */

View File

@ -61,7 +61,7 @@ struct usb_string_descriptor_struct {
#define DEVICE_VER 0x0101 // Bootloader version #define DEVICE_VER 0x0101 // Bootloader version
#define MANUFACTURER_NAME u"Kosagi" #define MANUFACTURER_NAME u"Kosagi"
#define MANUFACTURER_NAME_LEN sizeof(MANUFACTURER_NAME) #define MANUFACTURER_NAME_LEN sizeof(MANUFACTURER_NAME)
#define PRODUCT_NAME u"Fomu Bootloader (0) " GIT_VERSION #define PRODUCT_NAME u"Tomu Bootloader (0) " GIT_VERSION
#define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME) #define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME)
#define EP0_SIZE 64 #define EP0_SIZE 64
#define NUM_INTERFACE 1 #define NUM_INTERFACE 1

View File

@ -11,16 +11,14 @@ struct usb_setup_request;
void usb_isr(void); void usb_isr(void);
void usb_init(void); void usb_init(void);
void usb_connect(void); void usb_connect(void);
void usb_disconnect(void);
void usb_poll(void);
int usb_irq_happened(void); int usb_irq_happened(void);
void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup); void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup);
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count); int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count);
int usb_ack(struct usb_device *dev, int epnum); int usb_ack(struct usb_device *dev, int epnum);
int usb_err(struct usb_device *dev, int epnum); int usb_err(struct usb_device *dev, int epnum);
int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len); int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len);
void usb_poll(struct usb_device *dev);
int usb_wait_for_send_done(struct usb_device *dev);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,9 +1,9 @@
INCLUDE output_format.ld INCLUDE ld/output_format.ld
ENTRY(_start) ENTRY(_start)
__DYNAMIC = 0; __DYNAMIC = 0;
INCLUDE regions.ld INCLUDE ld/regions.ld
SECTIONS SECTIONS
{ {

View File

@ -27,15 +27,6 @@
#include <toboot-api.h> #include <toboot-api.h>
#include <toboot-internal.h> #include <toboot-internal.h>
#include <dfu.h> #include <dfu.h>
#include <rgb.h>
#define RESCUE_IMAGE_OFFSET 262144
#define ERASE_SIZE 65536 // Erase block size (in bytes)
#define WRITE_SIZE 256 // Number of bytes we can write
#include <spi.h>
extern struct ff_spi *spi; // Defined in main.c
// Internal flash-programming state machine // Internal flash-programming state machine
static unsigned fl_current_addr = 0; static unsigned fl_current_addr = 0;
@ -45,34 +36,72 @@ static enum {
flsPROGRAMMING flsPROGRAMMING
} fl_state; } fl_state;
static struct toboot_state {
// Version number of the program being loaded:
// 0 (legacy)
// 1 (toboot v1)
// 2 (toboot v2)
uint8_t version;
// When clearing, first ensure these sectors are cleared prior to updating
uint32_t clear_lo;
uint32_t clear_hi;
// The current block we're clearing
uint32_t clear_current;
// This is the address we'll start programming/erasing from after clearing
uint32_t next_addr;
enum {
/// Toboot has just started
tbsIDLE,
/// Secure erase memory is being cleared
tbsCLEARING,
/// New image is being loaded
tbsLOADING,
} state;
} tb_state;
static dfu_state_t dfu_state = dfuIDLE; static dfu_state_t dfu_state = dfuIDLE;
static dfu_status_t dfu_status = OK; static dfu_status_t dfu_status = OK;
static unsigned dfu_poll_timeout_ms = 1; static unsigned dfu_poll_timeout = 1;
static uint32_t dfu_buffer[DFU_TRANSFER_SIZE/4]; static uint32_t dfu_buffer[DFU_TRANSFER_SIZE/4];
static uint32_t dfu_buffer_offset; static uint32_t dfu_buffer_offset;
static uint32_t dfu_bytes_remaining; static uint32_t fl_num_words;
// Memory offset we're uploading to. // Memory offset we're uploading to.
static uint32_t dfu_target_address; static uint32_t dfu_target_address;
static void set_state(dfu_state_t new_state, dfu_status_t new_status) { static void set_state(dfu_state_t new_state, dfu_status_t new_status) {
if (new_state == dfuIDLE)
rgb_mode_idle();
else if (new_status != OK)
rgb_mode_error();
else if (new_state == dfuMANIFEST_WAIT_RESET)
rgb_mode_done();
else
rgb_mode_writing();
dfu_state = new_state; dfu_state = new_state;
dfu_status = new_status; dfu_status = new_status;
} }
bool fl_is_idle(void) {
return fl_state == flsIDLE;
}
/*
void *memcpy(void *dst, const void *src, size_t cnt) {
uint8_t *dst8 = dst;
const uint8_t *src8 = src;
while (cnt > 0) {
cnt--;
*(dst8++) = *(src8++);
}
return dst;
}
*/
static bool ftfl_busy() static bool ftfl_busy()
{ {
// Is the flash memory controller busy? // Is the flash memory controller busy?
return spiIsBusy(spi); // return (MSC->STATUS & MSC_STATUS_BUSY);
return 0;
} }
static void ftfl_busy_wait() static void ftfl_busy_wait()
@ -84,24 +113,13 @@ static void ftfl_busy_wait()
static void ftfl_begin_erase_sector(uint32_t address) static void ftfl_begin_erase_sector(uint32_t address)
{ {
ftfl_busy_wait(); // Erase the page at the specified address.
// Only erase if it's on the page boundry. //MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
if ((address & ~(ERASE_SIZE - 1) ) == address)
spiBeginErase64(spi, address);
fl_state = flsERASING;
}
static void ftfl_write_more_bytes(void)
{
uint32_t bytes_to_write = WRITE_SIZE;
if (dfu_bytes_remaining < bytes_to_write)
bytes_to_write = dfu_bytes_remaining;
ftfl_busy_wait(); ftfl_busy_wait();
spiBeginWrite(spi, dfu_target_address, &dfu_buffer[dfu_buffer_offset], bytes_to_write); //MSC->ADDRB = address;
//MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
dfu_bytes_remaining -= bytes_to_write; //MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE;
dfu_target_address += bytes_to_write;
dfu_buffer_offset += bytes_to_write;
} }
static void ftfl_begin_program_section(uint32_t address) static void ftfl_begin_program_section(uint32_t address)
@ -110,18 +128,90 @@ static void ftfl_begin_program_section(uint32_t address)
// Note that after this is done, the address is incremented by 4. // Note that after this is done, the address is incremented by 4.
dfu_buffer_offset = 0; dfu_buffer_offset = 0;
dfu_target_address = address; dfu_target_address = address;
ftfl_write_more_bytes(); fl_num_words--;
ftfl_busy_wait();
//MSC->ADDRB = address;
ftfl_busy_wait();
//MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
//MSC->WDATA = dfu_buffer[dfu_buffer_offset++];
//MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
} }
static uint32_t address_for_block(unsigned blockNum) static uint32_t address_for_block(unsigned blockNum)
{ {
static const uint32_t starting_offset = RESCUE_IMAGE_OFFSET; static uint32_t starting_offset;
return starting_offset + (blockNum * WRITE_SIZE); if (blockNum == 0) {
// Determine Toboot version.
if ((dfu_buffer[0x94 / 4] & TOBOOT_V2_MAGIC_MASK) == TOBOOT_V2_MAGIC) {
tb_state.version = 2;
starting_offset = ((struct toboot_configuration *)&dfu_buffer[0x94 / 4])->start;
}
// V1 used a different offset.
else if ((dfu_buffer[0x98 / 4] & TOBOOT_V1_MAGIC_MASK) == TOBOOT_V1_MAGIC) {
// Applications that know about Toboot will indicate their block
// offset by placing a magic byte at offset 0x98.
// Ordinarily this would be the address offset for IRQ 22,
// but since there are only 20 IRQs on the EFM32HG, there are three
// 32-bit values that are unused starting at offset 0x94.
// We already use offset 0x94 for "disable boot", so use offset 0x98
// in the incoming stream to indicate flags for Toboot.
tb_state.version = 1;
starting_offset = (dfu_buffer[0x98 / 4] & TOBOOT_V1_APP_PAGE_MASK) >> TOBOOT_V1_APP_PAGE_SHIFT;
}
// Legacy programs default to offset 0x4000.
else {
tb_state.version = 0;
starting_offset = 16;
}
// Set the state to "CLEARING", since we're just starting the programming process.
tb_state.state = tbsCLEARING;
starting_offset *= 0x400;
}
return starting_offset + (blockNum << 10);
}
// If requested, erase sectors before loading new code.
static void pre_clear_next_block(void) {
// If there is another sector to clear, do that.
while (++tb_state.clear_current < 64) {
if (tb_state.clear_current < 32) {
if ((tb_state.clear_lo & (1 << tb_state.clear_current))) {
ftfl_begin_erase_sector(tb_state.clear_current * 1024);
return;
}
}
else if (tb_state.clear_current < 64) {
if ((tb_state.clear_hi & (1 << (tb_state.clear_current & 31)))) {
ftfl_begin_erase_sector(tb_state.clear_current * 1024);
return;
}
}
}
// No more sectors to clear, continue with programming
tb_state.state = tbsLOADING;
ftfl_begin_erase_sector(tb_state.next_addr);
} }
void dfu_init(void) void dfu_init(void)
{ {
return; tb_state.state = tbsIDLE;
/*
// Ensure the clocks for the memory are enabled
CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
while (!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY))
;
// Unlock the MSC
MSC->LOCK = MSC_UNLOCK_CODE;
// Enable writing to flash
MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
MSC->IEN |= MSC_IEN_WRITE | MSC_IEN_ERASE;
NVIC_EnableIRQ(MSC_IRQn);
*/
} }
uint8_t dfu_getstate(void) uint8_t dfu_getstate(void)
@ -132,6 +222,8 @@ uint8_t dfu_getstate(void)
bool dfu_download(unsigned blockNum, unsigned blockLength, bool dfu_download(unsigned blockNum, unsigned blockLength,
unsigned packetOffset, unsigned packetLength, const uint8_t *data) unsigned packetOffset, unsigned packetLength, const uint8_t *data)
{ {
uint32_t i;
if (packetOffset + packetLength > DFU_TRANSFER_SIZE || if (packetOffset + packetLength > DFU_TRANSFER_SIZE ||
packetOffset + packetLength > blockLength) { packetOffset + packetLength > blockLength) {
@ -154,9 +246,9 @@ bool dfu_download(unsigned blockNum, unsigned blockLength,
return false; return false;
} }
if (ftfl_busy() || (fl_state != flsIDLE)) { if (ftfl_busy() || fl_state != flsIDLE) {
// Flash controller shouldn't be busy now! // Flash controller shouldn't be busy now!
set_state(dfuERROR, errWRITE); set_state(dfuERROR, errUNKNOWN);
return false; return false;
} }
@ -169,20 +261,122 @@ bool dfu_download(unsigned blockNum, unsigned blockLength,
// Start programming a block by erasing the corresponding flash sector // Start programming a block by erasing the corresponding flash sector
fl_state = flsERASING; fl_state = flsERASING;
fl_current_addr = address_for_block(blockNum); fl_current_addr = address_for_block(blockNum);
dfu_bytes_remaining = blockLength; fl_num_words = blockLength / 4;
// If it's the first block, figure out what we need to do in terms of erasing
// data and programming the new file.
if (blockNum == 0) {
const struct toboot_configuration *old_config = tb_get_config();
// Don't allow overwriting Toboot itself.
if (fl_current_addr < tb_first_free_address()) {
set_state(dfuERROR, errADDRESS);
return false;
}
// Calculate generation number and hash
if (tb_state.version == 2) {
struct toboot_configuration *new_config = (struct toboot_configuration *)&dfu_buffer[0x94 / 4];
// Update generation number
new_config->reserved_gen = old_config->reserved_gen + 1;
// Ensure we know this header is not fake
new_config->config &= ~TOBOOT_CONFIG_FAKE;
// Generate a valid signature
tb_sign_config(new_config);
}
// If the old configuration requires that certain blocks be erased, do that.
tb_state.clear_hi = old_config->erase_mask_hi;
tb_state.clear_lo = old_config->erase_mask_lo;
tb_state.clear_current = 0;
// Ensure we don't erase Toboot itself
for (i = 0; i < tb_first_free_sector(); i++) {
if (i < 32)
tb_state.clear_lo &= ~(1 << i);
else
tb_state.clear_hi &= ~(1 << i);
}
// If the newly-loaded program does not conform to Toboot V2.0, then look
// for any existing programs on the flash and delete those sectors.
// Because of boot priority, we need to ensure that no V2.0 applications
// exist on flash.
if (tb_state.version < 2) {
for (i = tb_first_free_sector(); i < 64; i++) {
if (tb_valid_signature_at_page(i) < 0)
continue;
if (i < 32)
tb_state.clear_lo |= (1 << i);
else
tb_state.clear_hi |= (1 << (i - 32));
}
}
// If we still have sectors to clear, do that. Otherwise,
// go straight into loading the program.
if (tb_state.clear_lo || tb_state.clear_hi) {
tb_state.state = tbsCLEARING;
tb_state.next_addr = fl_current_addr;
pre_clear_next_block();
}
else {
tb_state.state = tbsLOADING;
ftfl_begin_erase_sector(fl_current_addr);
}
}
else
ftfl_begin_erase_sector(fl_current_addr); ftfl_begin_erase_sector(fl_current_addr);
set_state(dfuDNLOAD_SYNC, OK); set_state(dfuDNLOAD_SYNC, OK);
return true; return true;
} }
static bool fl_handle_status(uint8_t fstat)
{
/*
* Handle common errors from an FSTAT register value.
* The indicated "specificError" is used for reporting a command-specific
* error from MGSTAT0.
*
* Returns true if handled, false if not.
*/
#if 0
if (fstat & MSC_STATUS_BUSY) {
// Still working...
return true;
}
if (fstat & (MSC_STATUS_ERASEABORTED | MSC_STATUS_WORDTIMEOUT)) {
// Bus collision. We did something wrong internally.
set_state(dfuERROR, errUNKNOWN);
fl_state = flsIDLE;
return true;
}
if (fstat & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) {
// Address or protection error
set_state(dfuERROR, errADDRESS);
fl_state = flsIDLE;
return true;
}
if (fl_state == flsPROGRAMMING) {
// Still programming...
return true;
}
#endif
return false;
}
static void fl_state_poll(void) static void fl_state_poll(void)
{ {
// Try to advance the state of our own flash programming state machine. // Try to advance the state of our own flash programming state machine.
if (spiIsBusy(spi)) uint32_t fstat = 0;//MSC->STATUS;
return;
switch (fl_state) { switch (fl_state) {
@ -190,53 +384,57 @@ static void fl_state_poll(void)
break; break;
case flsERASING: case flsERASING:
if (!fl_handle_status(fstat)) {
// ?If we're still pre-clearing, continue with that.
if (tb_state.state == tbsCLEARING) {
pre_clear_next_block();
}
// Done! Move on to programming the sector.
else {
fl_state = flsPROGRAMMING; fl_state = flsPROGRAMMING;
ftfl_begin_program_section(fl_current_addr); ftfl_begin_program_section(fl_current_addr);
}
}
break; break;
case flsPROGRAMMING: case flsPROGRAMMING:
// Program more blocks, if applicable if (!fl_handle_status(fstat)) {
if (dfu_bytes_remaining) // Done!
ftfl_write_more_bytes();
else
fl_state = flsIDLE; fl_state = flsIDLE;
}
break; break;
} }
} }
void dfu_poll(void)
{
if ((dfu_state == dfuDNLOAD_SYNC) || (dfu_state == dfuDNBUSY))
fl_state_poll();
}
bool dfu_getstatus(uint8_t status[8]) bool dfu_getstatus(uint8_t status[8])
{ {
switch (dfu_state) { switch (dfu_state) {
case dfuDNLOAD_SYNC: case dfuDNLOAD_SYNC:
case dfuDNBUSY: case dfuDNBUSY:
// Programming operation in progress. Advance our private flash state machine.
fl_state_poll();
if (dfu_state == dfuERROR) { if (dfu_state == dfuERROR) {
// An error occurred inside fl_state_poll(); // An error occurred inside fl_state_poll();
} else if (fl_state == flsIDLE) { } else if (fl_state == flsIDLE) {
set_state(dfuDNLOAD_IDLE, OK); dfu_state = dfuDNLOAD_IDLE;
} else { } else {
set_state(dfuDNBUSY, OK); dfu_state = dfuDNBUSY;
} }
break; break;
case dfuMANIFEST_SYNC: case dfuMANIFEST_SYNC:
// Ready to reboot. The main thread will take care of this. Also let the DFU tool // Ready to reboot. The main thread will take care of this. Also let the DFU tool
// know to leave us alone until this happens. // know to leave us alone until this happens.
set_state(dfuMANIFEST, OK); dfu_state = dfuMANIFEST;
dfu_poll_timeout_ms = 10; dfu_poll_timeout = 10;
break; break;
case dfuMANIFEST: case dfuMANIFEST:
// Perform the reboot // Perform the reboot
set_state(dfuMANIFEST_WAIT_RESET, OK); dfu_state = dfuMANIFEST_WAIT_RESET;
dfu_poll_timeout_ms = 1000; dfu_poll_timeout = 1000;
break; break;
default: default:
@ -244,9 +442,9 @@ bool dfu_getstatus(uint8_t status[8])
} }
status[0] = dfu_status; status[0] = dfu_status;
status[1] = dfu_poll_timeout_ms; status[1] = dfu_poll_timeout;
status[2] = dfu_poll_timeout_ms >> 8; status[2] = dfu_poll_timeout >> 8;
status[3] = dfu_poll_timeout_ms >> 16; status[3] = dfu_poll_timeout >> 16;
status[4] = dfu_state; status[4] = dfu_state;
status[5] = 0; // iString status[5] = 0; // iString
@ -258,8 +456,6 @@ bool dfu_clrstatus(void)
switch (dfu_state) { switch (dfu_state) {
case dfuERROR: case dfuERROR:
case dfuIDLE:
case dfuMANIFEST_WAIT_RESET:
// Clear an error // Clear an error
set_state(dfuIDLE, OK); set_state(dfuIDLE, OK);
return true; return true;
@ -276,3 +472,29 @@ bool dfu_abort(void)
set_state(dfuIDLE, OK); set_state(dfuIDLE, OK);
return true; return true;
} }
/*
void MSC_Handler(void) {
uint32_t msc_irq_reason = MSC->IF;
if (msc_irq_reason & MSC_IF_WRITE) {
// Write the buffer word to the currently selected address.
// Note that after this is done, the address is incremented by 4.
if (fl_num_words > 0) {
fl_num_words--;
dfu_target_address += 4;
MSC->ADDRB = dfu_target_address;
ftfl_busy_wait();
MSC->WDATA = dfu_buffer[dfu_buffer_offset++];
MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
}
else {
// Move to the IDLE state only if we're out of data to write.
fl_state = flsIDLE;
}
}
// Clear iterrupts so we don't fire again.
MSC->IFC = MSC_IFC_ERASE | MSC_IFC_WRITE;
}
*/

View File

@ -4,12 +4,8 @@
#include <uart.h> #include <uart.h>
#include <usb.h> #include <usb.h>
#include <time.h> #include <time.h>
#include <dfu.h>
#include <rgb.h>
#include <spi.h>
#include <generated/csr.h>
struct ff_spi *spi; #include <generated/csr.h>
void isr(void) void isr(void)
{ {
@ -20,13 +16,10 @@ void isr(void)
if (irqs & (1 << USB_INTERRUPT)) if (irqs & (1 << USB_INTERRUPT))
usb_isr(); usb_isr();
#ifdef CSR_UART_BASE
if (irqs & (1 << UART_INTERRUPT)) if (irqs & (1 << UART_INTERRUPT))
uart_isr(); uart_isr();
#endif
} }
#ifdef CSR_UART_BASE
static void rv_putchar(void *ignored, char c) static void rv_putchar(void *ignored, char c)
{ {
(void)ignored; (void)ignored;
@ -36,36 +29,17 @@ static void rv_putchar(void *ignored, char c)
return; return;
uart_write(c); uart_write(c);
} }
#endif
static void init(void) static void init(void)
{ {
#ifdef CSR_UART_BASE
init_printf(NULL, rv_putchar); init_printf(NULL, rv_putchar);
#endif
irq_setmask(0); irq_setmask(0);
irq_setie(1); irq_setie(1);
uart_init(); uart_init();
usb_init(); usb_init();
dfu_init();
time_init(); time_init();
rgb_init();
spi = spiAlloc();
spiSetPin(spi, SP_MOSI, 0);
spiSetPin(spi, SP_MISO, 1);
spiSetPin(spi, SP_WP, 2);
spiSetPin(spi, SP_HOLD, 3);
spiSetPin(spi, SP_CLK, 4);
spiSetPin(spi, SP_CS, 5);
spiSetPin(spi, SP_D0, 0);
spiSetPin(spi, SP_D1, 1);
spiSetPin(spi, SP_D2, 2);
spiSetPin(spi, SP_D3, 3);
spiInit(spi);
} }
#if 0
static const char *usb_hw_api(void) { static const char *usb_hw_api(void) {
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR #ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
return "epfifo"; return "epfifo";
@ -81,7 +55,6 @@ static const char *usb_hw_api(void) {
#endif /* CSR_USB_OBUF_EMPTY_ADDR */ #endif /* CSR_USB_OBUF_EMPTY_ADDR */
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */ #endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
} }
#endif
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -90,13 +63,34 @@ int main(int argc, char **argv)
init(); init();
printf("\n\nUSB API: %s\n", usb_hw_api());
// printf("Press any key to enable USB...\n");
// usb_print_status();
// uart_read();
printf("Enabling USB\n");
usb_connect(); usb_connect();
printf("USB enabled.\n");
// usb_print_status();
int last = 0;
static uint8_t bfr[12];
while (1) while (1)
{ {
usb_poll(NULL); if (usb_irq_happened() != last) {
dfu_poll(); last = usb_irq_happened();
// if (i > 200) printf("USB %d IRQ happened\n", last);
// reboot_ctrl_write(0xac); }
usb_poll();
/*
printf("Press any key to send... ");
uart_read();
printf("Sending... ");
bfr[0] = 0;
bfr[1] = ~0;
bfr[2] = 0;
usb_send(NULL, 0, bfr, 1);
printf("Sent\n");
*/
} }
return 0; return 0;
} }

View File

@ -1,113 +0,0 @@
#include <rgb.h>
#include <generated/csr.h>
enum led_registers {
LEDDCR0 = 8,
LEDDBR = 9,
LEDDONR = 10,
LEDDOFR = 11,
LEDDBCRR = 5,
LEDDBCFR = 6,
LEDDPWRR = 1,
LEDDPWRG = 2,
LEDDPWRB = 3,
};
#define BREATHE_ENABLE (1 << 7)
#define BREATHE_EDGE_ON (0 << 6)
#define BREATHE_EDGE_BOTH (1 << 6)
#define BREATHE_MODE_MODULATE (1 << 5)
#define BREATHE_RATE(x) ((x & 7) << 0)
#define RGB_SWITCH_MODE(x) do { \
if (rgb_mode == x) \
return; \
rgb_mode = x; \
/* Toggle LEDD_EXE to force the mode to switch */ \
rgb_ctrl_write( (1 << 1) | (1 << 2)); \
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
} while(0)
static enum {
INVALID = 0,
IDLE,
WRITING,
ERROR,
DONE,
} rgb_mode;
static void rgb_write(uint8_t value, uint8_t addr) {
rgb_addr_write(addr);
rgb_dat_write(value);
}
void rgb_init(void) {
// Turn on the RGB block and current enable, as well as enabling led control
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
// Enable the LED driver, and set 250 Hz mode.
// Also set quick stop, which we'll use to switch patterns quickly.
rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
// Set clock register to 12 MHz / 64 kHz - 1
rgb_write((12000000/64000)-1, LEDDBR);
rgb_mode_idle();
}
void rgb_mode_idle(void) {
RGB_SWITCH_MODE(IDLE);
// rgb_mode_writing(); return;
rgb_write(12, LEDDONR);
rgb_write(24, LEDDOFR);
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
rgb_write(0x00/4, LEDDPWRG); // Red
rgb_write(0x4a/4, LEDDPWRB); // Green
rgb_write(0xe1/4, LEDDPWRR); // Blue
}
void rgb_mode_writing(void) {
RGB_SWITCH_MODE(WRITING);
rgb_write(1, LEDDONR);
rgb_write(2, LEDDOFR);
rgb_write(BREATHE_ENABLE | 0
| BREATHE_MODE_MODULATE | BREATHE_RATE(1), LEDDBCRR);
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
rgb_write(0x00/4, LEDDPWRG); // Red
rgb_write(0x7a/4, LEDDPWRB); // Green
rgb_write(0x51/4, LEDDPWRR); // Blue
}
void rgb_mode_error(void) {
RGB_SWITCH_MODE(ERROR);
rgb_write(3, LEDDONR);
rgb_write(3, LEDDOFR);
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
rgb_write(0xf0/4, LEDDPWRG); // Red
rgb_write(0x0a/4, LEDDPWRB); // Green
rgb_write(0x01/4, LEDDPWRR); // Blue
}
void rgb_mode_done(void) {
RGB_SWITCH_MODE(DONE);
rgb_write(8, LEDDONR);
rgb_write(8, LEDDOFR);
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
| BREATHE_MODE_MODULATE | BREATHE_RATE(2), LEDDBCRR);
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(3), LEDDBCFR);
rgb_write(0x14/4, LEDDPWRG); // Red
rgb_write(0xff/4, LEDDPWRB); // Green
rgb_write(0x44/4, LEDDPWRR); // Blue
}

View File

@ -1,948 +0,0 @@
#include <stdint.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <printf.h>
#include <generated/csr.h>
#include "spi.h"
#define fprintf(...) do {} while(0)
static uint8_t do_mirror;
static uint8_t oe_mirror;
#define PI_OUTPUT 1
#define PI_INPUT 0
#define PI_ALT0 PI_INPUT
static void gpioSetMode(int pin, int mode) {
if (mode)
oe_mirror |= 1 << pin;
else
oe_mirror &= ~(1 << pin);
bbspi_oe_write(oe_mirror);
}
static void gpioWrite(int pin, int val) {
if (val)
do_mirror |= 1 << pin;
else
do_mirror &= ~(1 << pin);
bbspi_do_write(do_mirror);
}
static int gpioRead(int pin) {
return !!(bbspi_di_read() & (1 << pin));
}
static void gpioSync(void) {
// bbspi_do_write(do_mirror);
}
#define SPI_ONLY_SINGLE
enum ff_spi_quirks {
// There is no separate "Write SR 2" command. Instead,
// you must write SR2 after writing SR1
SQ_SR2_FROM_SR1 = (1 << 0),
// Don't issue a "Write Enable" command prior to writing
// a status register
SQ_SKIP_SR_WEL = (1 << 1),
// Security registers are shifted up by 4 bits
SQ_SECURITY_NYBBLE_SHIFT = (1 << 2),
};
struct ff_spi {
enum spi_state state;
enum spi_type type;
enum spi_type desired_type;
struct spi_id id;
enum ff_spi_quirks quirks;
int size_override;
struct {
int clk;
int d0;
int d1;
int d2;
int d3;
int wp;
int hold;
int cs;
int miso;
int mosi;
} pins;
};
static void spi_get_id(struct ff_spi *spi);
static void spi_set_state(struct ff_spi *spi, enum spi_state state) {
return;
if (spi->state == state)
return;
#ifndef SPI_ONLY_SINGLE
switch (state) {
case SS_SINGLE:
#endif
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
gpioSetMode(spi->pins.hold, PI_OUTPUT);
gpioSetMode(spi->pins.wp, PI_OUTPUT);
#ifndef SPI_ONLY_SINGLE
break;
case SS_DUAL_RX:
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
gpioSetMode(spi->pins.hold, PI_OUTPUT);
gpioSetMode(spi->pins.wp, PI_OUTPUT);
break;
case SS_DUAL_TX:
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
gpioSetMode(spi->pins.hold, PI_OUTPUT);
gpioSetMode(spi->pins.wp, PI_OUTPUT);
break;
case SS_QUAD_RX:
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
gpioSetMode(spi->pins.hold, PI_INPUT);
gpioSetMode(spi->pins.wp, PI_INPUT);
break;
case SS_QUAD_TX:
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
gpioSetMode(spi->pins.hold, PI_OUTPUT);
gpioSetMode(spi->pins.wp, PI_OUTPUT);
break;
case SS_HARDWARE:
gpioSetMode(spi->pins.clk, PI_ALT0); // CLK
gpioSetMode(spi->pins.cs, PI_ALT0); // CE0#
gpioSetMode(spi->pins.mosi, PI_ALT0); // MOSI
gpioSetMode(spi->pins.miso, PI_ALT0); // MISO
gpioSetMode(spi->pins.hold, PI_OUTPUT);
gpioSetMode(spi->pins.wp, PI_OUTPUT);
break;
default:
fprintf(stderr, "Unrecognized spi state\n");
return;
}
#endif
spi->state = state;
}
void spiPause(struct ff_spi *spi) {
(void)spi;
gpioSync();
// usleep(1);
return;
}
void spiBegin(struct ff_spi *spi) {
spi_set_state(spi, SS_SINGLE);
if ((spi->type == ST_SINGLE) || (spi->type == ST_DUAL)) {
gpioWrite(spi->pins.wp, 1);
gpioWrite(spi->pins.hold, 1);
}
gpioWrite(spi->pins.cs, 0);
}
void spiEnd(struct ff_spi *spi) {
(void)spi;
gpioWrite(spi->pins.cs, 1);
}
static uint8_t spiXfer(struct ff_spi *spi, uint8_t out) {
int bit;
uint8_t in = 0;
for (bit = 7; bit >= 0; bit--) {
if (out & (1 << bit)) {
gpioWrite(spi->pins.mosi, 1);
}
else {
gpioWrite(spi->pins.mosi, 0);
}
gpioWrite(spi->pins.clk, 1);
spiPause(spi);
in |= ((!!gpioRead(spi->pins.miso)) << bit);
gpioWrite(spi->pins.clk, 0);
spiPause(spi);
}
return in;
}
static void spiSingleTx(struct ff_spi *spi, uint8_t out) {
spi_set_state(spi, SS_SINGLE);
spiXfer(spi, out);
}
static uint8_t spiSingleRx(struct ff_spi *spi) {
spi_set_state(spi, SS_SINGLE);
return spiXfer(spi, 0xff);
}
static void spiDualTx(struct ff_spi *spi, uint8_t out) {
int bit;
spi_set_state(spi, SS_DUAL_TX);
for (bit = 7; bit >= 0; bit -= 2) {
if (out & (1 << (bit - 1))) {
gpioWrite(spi->pins.d0, 1);
}
else {
gpioWrite(spi->pins.d0, 0);
}
if (out & (1 << (bit - 0))) {
gpioWrite(spi->pins.d1, 1);
}
else {
gpioWrite(spi->pins.d1, 0);
}
gpioWrite(spi->pins.clk, 1);
spiPause(spi);
gpioWrite(spi->pins.clk, 0);
spiPause(spi);
}
}
static void spiQuadTx(struct ff_spi *spi, uint8_t out) {
int bit;
spi_set_state(spi, SS_QUAD_TX);
for (bit = 7; bit >= 0; bit -= 4) {
if (out & (1 << (bit - 3))) {
gpioWrite(spi->pins.d0, 1);
}
else {
gpioWrite(spi->pins.d0, 0);
}
if (out & (1 << (bit - 2))) {
gpioWrite(spi->pins.d1, 1);
}
else {
gpioWrite(spi->pins.d1, 0);
}
if (out & (1 << (bit - 1))) {
gpioWrite(spi->pins.d2, 1);
}
else {
gpioWrite(spi->pins.d2, 0);
}
if (out & (1 << (bit - 0))) {
gpioWrite(spi->pins.d3, 1);
}
else {
gpioWrite(spi->pins.d3, 0);
}
gpioWrite(spi->pins.clk, 1);
spiPause(spi);
gpioWrite(spi->pins.clk, 0);
spiPause(spi);
}
}
static uint8_t spiDualRx(struct ff_spi *spi) {
int bit;
uint8_t in = 0;
spi_set_state(spi, SS_QUAD_RX);
for (bit = 7; bit >= 0; bit -= 2) {
gpioWrite(spi->pins.clk, 1);
spiPause(spi);
in |= ((!!gpioRead(spi->pins.d0)) << (bit - 1));
in |= ((!!gpioRead(spi->pins.d1)) << (bit - 0));
gpioWrite(spi->pins.clk, 0);
spiPause(spi);
}
return in;
}
static uint8_t spiQuadRx(struct ff_spi *spi) {
int bit;
uint8_t in = 0;
spi_set_state(spi, SS_QUAD_RX);
for (bit = 7; bit >= 0; bit -= 4) {
gpioWrite(spi->pins.clk, 1);
spiPause(spi);
in |= ((!!gpioRead(spi->pins.d0)) << (bit - 3));
in |= ((!!gpioRead(spi->pins.d1)) << (bit - 2));
in |= ((!!gpioRead(spi->pins.d2)) << (bit - 1));
in |= ((!!gpioRead(spi->pins.d3)) << (bit - 0));
gpioWrite(spi->pins.clk, 0);
spiPause(spi);
}
return in;
}
int spiTx(struct ff_spi *spi, uint8_t word) {
switch (spi->type) {
case ST_SINGLE:
spiSingleTx(spi, word);
break;
case ST_DUAL:
spiDualTx(spi, word);
break;
case ST_QUAD:
case ST_QPI:
spiQuadTx(spi, word);
break;
default:
return -1;
}
return 0;
}
uint8_t spiRx(struct ff_spi *spi) {
switch (spi->type) {
case ST_SINGLE:
return spiSingleRx(spi);
case ST_DUAL:
return spiDualRx(spi);
case ST_QUAD:
case ST_QPI:
return spiQuadRx(spi);
default:
return 0xff;
}
}
void spiCommand(struct ff_spi *spi, uint8_t cmd) {
if (spi->type == ST_QPI)
spiQuadTx(spi, cmd);
else
spiSingleTx(spi, cmd);
}
uint8_t spiCommandRx(struct ff_spi *spi) {
if (spi->type == ST_QPI)
return spiQuadRx(spi);
else
return spiSingleRx(spi);
}
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
uint8_t val = 0xff;
(void)sr;
#if 0
switch (sr) {
case 1:
#endif
spiBegin(spi);
spiCommand(spi, 0x05);
val = spiCommandRx(spi);
spiEnd(spi);
#if 0
break;
case 2:
spiBegin(spi);
spiCommand(spi, 0x35);
val = spiCommandRx(spi);
spiEnd(spi);
break;
case 3:
spiBegin(spi);
spiCommand(spi, 0x15);
val = spiCommandRx(spi);
spiEnd(spi);
break;
default:
fprintf(stderr, "unrecognized status register: %d\n", sr);
break;
}
#endif
return val;
}
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
sr <<= 4;
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
// erase the register
spiBegin(spi);
spiCommand(spi, 0x44);
spiCommand(spi, 0x00); // A23-16
spiCommand(spi, sr); // A15-8
spiCommand(spi, 0x00); // A0-7
spiEnd(spi);
spi_get_id(spi);
sleep(1);
// write enable
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x42);
spiCommand(spi, 0x00); // A23-16
spiCommand(spi, sr); // A15-8
spiCommand(spi, 0x00); // A0-7
int i;
for (i = 0; i < 256; i++)
spiCommand(spi, security[i]);
spiEnd(spi);
spi_get_id(spi);
}
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
sr <<= 4;
spiBegin(spi);
spiCommand(spi, 0x48); // Read security registers
spiCommand(spi, 0x00); // A23-16
spiCommand(spi, sr); // A15-8
spiCommand(spi, 0x00); // A0-7
int i;
for (i = 0; i < 256; i++)
security[i] = spiCommandRx(spi);
spiEnd(spi);
}
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val) {
switch (sr) {
case 1:
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
}
spiBegin(spi);
spiCommand(spi, 0x50);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x01);
spiCommand(spi, val);
spiEnd(spi);
break;
case 2: {
uint8_t sr1 = 0x00;
if (spi->quirks & SQ_SR2_FROM_SR1)
sr1 = spiReadStatus(spi, 1);
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
}
spiBegin(spi);
spiCommand(spi, 0x50);
spiEnd(spi);
spiBegin(spi);
if (spi->quirks & SQ_SR2_FROM_SR1) {
spiCommand(spi, 0x01);
spiCommand(spi, sr1);
spiCommand(spi, val);
}
else {
spiCommand(spi, 0x31);
spiCommand(spi, val);
}
spiEnd(spi);
break;
}
case 3:
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
}
spiBegin(spi);
spiCommand(spi, 0x50);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x11);
spiCommand(spi, val);
spiEnd(spi);
break;
default:
fprintf(stderr, "unrecognized status register: %d\n", sr);
break;
}
}
struct spi_id spiId(struct ff_spi *spi) {
return spi->id;
}
static void spi_decode_id(struct ff_spi *spi) {
spi->id.bytes = -1; // unknown
if (spi->id.manufacturer_id == 0xef) {
// spi->id.manufacturer = "Winbond";
if ((spi->id.memory_type == 0x70)
&& (spi->id.memory_size == 0x18)) {
// spi->id.model = "W25Q128JV";
// spi->id.capacity = "128 Mbit";
spi->id.bytes = 16 * 1024 * 1024;
}
}
if (spi->id.manufacturer_id == 0x1f) {
// spi->id.manufacturer = "Adesto";
if ((spi->id.memory_type == 0x86)
&& (spi->id.memory_size == 0x01)) {
// spi->id.model = "AT25SF161";
// spi->id.capacity = "16 Mbit";
spi->id.bytes = 1 * 1024 * 1024;
}
}
return;
}
static void spi_get_id(struct ff_spi *spi) {
spiBegin(spi);
spiCommand(spi, 0x90); // Read manufacturer ID
spiCommand(spi, 0x00); // Dummy byte 1
spiCommand(spi, 0x00); // Dummy byte 2
spiCommand(spi, 0x00); // Dummy byte 3
spi->id.manufacturer_id = spiCommandRx(spi);
spi->id.device_id = spiCommandRx(spi);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x9f); // Read device id
spi->id._manufacturer_id = spiCommandRx(spi);
spi->id.memory_type = spiCommandRx(spi);
spi->id.memory_size = spiCommandRx(spi);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0xab); // Read electronic signature
spiCommand(spi, 0x00); // Dummy byte 1
spiCommand(spi, 0x00); // Dummy byte 2
spiCommand(spi, 0x00); // Dummy byte 3
spi->id.signature = spiCommandRx(spi);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x4b); // Read unique ID
spiCommand(spi, 0x00); // Dummy byte 1
spiCommand(spi, 0x00); // Dummy byte 2
spiCommand(spi, 0x00); // Dummy byte 3
spiCommand(spi, 0x00); // Dummy byte 4
spi->id.serial[0] = spiCommandRx(spi);
spi->id.serial[1] = spiCommandRx(spi);
spi->id.serial[2] = spiCommandRx(spi);
spi->id.serial[3] = spiCommandRx(spi);
spiEnd(spi);
spi_decode_id(spi);
return;
}
void spiOverrideSize(struct ff_spi *spi, uint32_t size) {
spi->size_override = size;
// If size is 0, re-read the capacity
if (!size)
spi_decode_id(spi);
else
spi->id.bytes = size;
}
int spiSetType(struct ff_spi *spi, enum spi_type type) {
if (spi->type == type)
return 0;
#ifndef SPI_ONLY_SINGLE
switch (type) {
case ST_SINGLE:
#endif
if (spi->type == ST_QPI) {
spiBegin(spi);
spiCommand(spi, 0xff); // Exit QPI Mode
spiEnd(spi);
}
spi->type = type;
spi_set_state(spi, SS_SINGLE);
#ifndef SPI_ONLY_SINGLE
break;
case ST_DUAL:
if (spi->type == ST_QPI) {
spiBegin(spi);
spiCommand(spi, 0xff); // Exit QPI Mode
spiEnd(spi);
}
spi->type = type;
spi_set_state(spi, SS_DUAL_TX);
break;
case ST_QUAD:
if (spi->type == ST_QPI) {
spiBegin(spi);
spiCommand(spi, 0xff); // Exit QPI Mode
spiEnd(spi);
}
// Enable QE bit
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
spi->type = type;
spi_set_state(spi, SS_QUAD_TX);
break;
case ST_QPI:
// Enable QE bit
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
spiBegin(spi);
spiCommand(spi, 0x38); // Enter QPI Mode
spiEnd(spi);
spi->type = type;
spi_set_state(spi, SS_QUAD_TX);
break;
default:
fprintf(stderr, "Unrecognized SPI type: %d\n", type);
return 1;
}
#endif
return 0;
}
int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count) {
unsigned int i;
spiBegin(spi);
switch (spi->type) {
case ST_SINGLE:
case ST_QPI:
spiCommand(spi, 0x0b);
break;
case ST_DUAL:
spiCommand(spi, 0x3b);
break;
case ST_QUAD:
spiCommand(spi, 0x6b);
break;
default:
fprintf(stderr, "unrecognized spi mode\n");
spiEnd(spi);
return 1;
}
spiCommand(spi, addr >> 16);
spiCommand(spi, addr >> 8);
spiCommand(spi, addr >> 0);
spiCommand(spi, 0x00);
for (i = 0; i < count; i++) {
if ((i & 0x3fff) == 0) {
// printf("\rReading @ %06x / %06x", i, count);
fflush(stdout);
}
data[i] = spiRx(spi);
}
// printf("\rReading @ %06x / %06x Done\n", i, count);
spiEnd(spi);
return 0;
}
static int spi_wait_for_not_busy(struct ff_spi *spi) {
uint8_t sr1;
sr1 = spiReadStatus(spi, 1);
do {
sr1 = spiReadStatus(spi, 1);
} while (sr1 & (1 << 0));
return 0;
}
int spiIsBusy(struct ff_spi *spi) {
return spiReadStatus(spi, 1) & (1 << 0);
}
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x52);
spiCommand(spi, erase_addr >> 16);
spiCommand(spi, erase_addr >> 8);
spiCommand(spi, erase_addr >> 0);
spiEnd(spi);
return 0;
}
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr) {
// Enable Write-Enable Latch (WEL)
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0xD8);
spiCommand(spi, erase_addr >> 16);
spiCommand(spi, erase_addr >> 8);
spiCommand(spi, erase_addr >> 0);
spiEnd(spi);
return 0;
}
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigned int count) {
uint8_t write_cmd = 0x02;
const uint8_t *data = v_data;
unsigned int i;
// Enable Write-Enable Latch (WEL)
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
// uint8_t sr1 = spiReadStatus(spi, 1);
// if (!(sr1 & (1 << 1)))
// fprintf(stderr, "error: write-enable latch (WEL) not set, write will probably fail\n");
spiBegin(spi);
spiCommand(spi, write_cmd);
spiCommand(spi, addr >> 16);
spiCommand(spi, addr >> 8);
spiCommand(spi, addr >> 0);
for (i = 0; (i < count) && (i < 256); i++)
spiTx(spi, *data++);
spiEnd(spi);
return 0;
}
void spiSwapTxRx(struct ff_spi *spi) {
int tmp = spi->pins.mosi;
spi->pins.mosi = spi->pins.miso;
spi->pins.miso = tmp;
spiSetType(spi, ST_SINGLE);
spi->state = SS_UNCONFIGURED;
spi_set_state(spi, SS_SINGLE);
}
int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count) {
unsigned int i;
if (addr & 0xff) {
fprintf(stderr, "Error: Target address is not page-aligned to 256 bytes\n");
return 1;
}
// Erase all applicable blocks
uint32_t erase_addr;
for (erase_addr = 0; erase_addr < count; erase_addr += 32768) {
// printf("\rErasing @ %06x / %06x", erase_addr, count);
fflush(stdout);
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x52);
spiCommand(spi, erase_addr >> 16);
spiCommand(spi, erase_addr >> 8);
spiCommand(spi, erase_addr >> 0);
spiEnd(spi);
spi_wait_for_not_busy(spi);
}
printf(" Done\n");
uint8_t write_cmd;
switch (spi->type) {
case ST_DUAL:
fprintf(stderr, "dual writes are broken -- need to temporarily set SINGLE mode\n");
return 1;
case ST_SINGLE:
case ST_QPI:
write_cmd = 0x02;
break;
case ST_QUAD:
write_cmd = 0x32;
break;
default:
fprintf(stderr, "unrecognized spi mode\n");
return 1;
}
while (count) {
fflush(stdout);
spiBegin(spi);
spiCommand(spi, 0x06);
spiEnd(spi);
uint8_t sr1 = spiReadStatus(spi, 1);
if (!(sr1 & (1 << 1)))
fprintf(stderr, "error: write-enable latch (WEL) not set, write will probably fail\n");
spiBegin(spi);
spiCommand(spi, write_cmd);
spiCommand(spi, addr >> 16);
spiCommand(spi, addr >> 8);
spiCommand(spi, addr >> 0);
for (i = 0; (i < count) && (i < 256); i++)
spiTx(spi, *data++);
spiEnd(spi);
count -= i;
addr += i;
spi_wait_for_not_busy(spi);
}
return 0;
}
uint8_t spiReset(struct ff_spi *spi) {
// XXX You should check the "Ready" bit before doing this!
// Shift to QPI mode, then back to Single mode, to ensure
// we're actually in Single mode.
spiSetType(spi, ST_QPI);
spiSetType(spi, ST_SINGLE);
spiBegin(spi);
spiCommand(spi, 0x66); // "Enable Reset" command
spiEnd(spi);
spiBegin(spi);
spiCommand(spi, 0x99); // "Reset Device" command
spiEnd(spi);
#pragma warn "Sleep for 30 ms here"
// usleep(30);
spiBegin(spi);
spiCommand(spi, 0xab); // "Resume from Deep Power-Down" command
spiEnd(spi);
return 0;
}
int spiInit(struct ff_spi *spi) {
spi->state = SS_UNCONFIGURED;
spi->type = ST_UNCONFIGURED;
// Reset the SPI flash, which will return it to SPI mode even
// if it's in QPI mode.
spiReset(spi);
spiSetType(spi, ST_SINGLE);
// Have the SPI flash pay attention to us
gpioWrite(spi->pins.hold, 1);
// Disable WP
gpioWrite(spi->pins.wp, 1);
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
gpioSetMode(spi->pins.hold, PI_OUTPUT);
gpioSetMode(spi->pins.wp, PI_OUTPUT);
spi_get_id(spi);
spi->quirks |= SQ_SR2_FROM_SR1;
// if (spi->id.manufacturer_id == 0x1f)
if (spi->id.manufacturer_id == 0xef)
spi->quirks |= SQ_SKIP_SR_WEL | SQ_SECURITY_NYBBLE_SHIFT;
return 0;
}
struct ff_spi *spiAlloc(void) {
static struct ff_spi spi;
// struct ff_spi *spi = (struct ff_spi *)malloc(sizeof(struct ff_spi));
// memset(&spi, 0, sizeof(spi));
return &spi;
}
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val) {
switch (pin) {
case SP_MOSI: spi->pins.mosi = val; break;
case SP_MISO: spi->pins.miso = val; break;
case SP_HOLD: spi->pins.hold = val; break;
case SP_WP: spi->pins.wp = val; break;
case SP_CS: spi->pins.cs = val; break;
case SP_CLK: spi->pins.clk = val; break;
case SP_D0: spi->pins.d0 = val; break;
case SP_D1: spi->pins.d1 = val; break;
case SP_D2: spi->pins.d2 = val; break;
case SP_D3: spi->pins.d3 = val; break;
default: fprintf(stderr, "unrecognized pin: %d\n", pin); break;
}
}
void spiHold(struct ff_spi *spi) {
spiBegin(spi);
spiCommand(spi, 0xb9);
spiEnd(spi);
}
void spiUnhold(struct ff_spi *spi) {
spiBegin(spi);
spiCommand(spi, 0xab);
spiEnd(spi);
}
void spiFree(struct ff_spi **spi) {
if (!spi)
return;
if (!*spi)
return;
spi_set_state(*spi, SS_HARDWARE);
// free(*spi);
// *spi = NULL;
}

View File

@ -1,12 +1,11 @@
#include <unistd.h>
#include "toboot-api.h" #include "toboot-api.h"
#include "toboot-internal.h" #include "toboot-internal.h"
// #define XXH_NO_LONG_LONG #define XXH_NO_LONG_LONG
// #define XXH_FORCE_ALIGN_CHECK 0 #define XXH_FORCE_ALIGN_CHECK 0
// #define XXH_FORCE_NATIVE_FORMAT 0 #define XXH_FORCE_NATIVE_FORMAT 0
// #define XXH_PRIVATE_API #define XXH_PRIVATE_API
// #include "xxhash.h" #include "xxhash.h"
static const struct toboot_configuration *current_config = NULL; static const struct toboot_configuration *current_config = NULL;
@ -27,7 +26,7 @@ uint32_t tb_first_free_address(void) {
} }
uint32_t tb_config_hash(const struct toboot_configuration *cfg) { uint32_t tb_config_hash(const struct toboot_configuration *cfg) {
return 0;//XXH32(cfg, sizeof(*cfg) - 4, TOBOOT_HASH_SEED); return XXH32(cfg, sizeof(*cfg) - 4, TOBOOT_HASH_SEED);
} }
void tb_sign_config(struct toboot_configuration *cfg) { void tb_sign_config(struct toboot_configuration *cfg) {
@ -120,7 +119,7 @@ uint32_t tb_generation(const struct toboot_configuration *cfg) {
return 0; return 0;
return cfg->reserved_gen; return cfg->reserved_gen;
} }
/*
__attribute__ ((used, section(".toboot_configuration"))) struct toboot_configuration toboot_configuration = { __attribute__ ((used, section(".toboot_configuration"))) struct toboot_configuration toboot_configuration = {
.magic = TOBOOT_V2_MAGIC, .magic = TOBOOT_V2_MAGIC,
@ -137,4 +136,3 @@ __attribute__ ((used, section(".toboot_configuration"))) struct toboot_configura
.erase_mask_hi = 0, .erase_mask_hi = 0,
.reserved_hash = 0, .reserved_hash = 0,
}; };
*/

View File

@ -104,7 +104,7 @@ static const uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
MSB(CONFIG_DESC_SIZE), MSB(CONFIG_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue 1, // bConfigurationValue
1, // iConfiguration 2, // iConfiguration
0x80, // bmAttributes 0x80, // bmAttributes
50, // bMaxPower 50, // bMaxPower
@ -119,7 +119,7 @@ static const uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
0x02, // bInterfaceProtocol 0x02, // bInterfaceProtocol
2, // iInterface 2, // iInterface
// DFU Functional Descriptor (DFU spec Table 4.2) // DFU Functional Descriptor (DFU spec TAble 4.2)
9, // bLength 9, // bLength
0x21, // bDescriptorType 0x21, // bDescriptorType
0x0D, // bmAttributes 0x0D, // bmAttributes

View File

@ -2,15 +2,15 @@
#include <unistd.h> #include <unistd.h>
#include <usb.h> #include <usb.h>
#include <dfu.h> #include <dfu.h>
#include <system.h>
#include <printf.h> #include <printf.h>
#include <usb-desc.h> #include <usb-desc.h>
static uint8_t reply_buffer[8]; static uint8_t reply_buffer[8];
static uint8_t usb_configuration = 0; static uint8_t usb_configuration = 0;
#define USB_MAX_PACKET_SIZE 64 #define USB_MAX_PACKET_SIZE 64 /* For FS device */
static uint32_t rx_buffer[USB_MAX_PACKET_SIZE/4]; static uint8_t rx_buffer[USB_MAX_PACKET_SIZE];
void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup) void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
{ {
@ -18,33 +18,32 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
uint32_t datalen = 0; uint32_t datalen = 0;
const usb_descriptor_list_t *list; const usb_descriptor_list_t *list;
// printf("%s:%d SETUP packet (%04x) value: %02x index: %02x\n", __FILE__, __LINE__, setup->wRequestAndType, setup->wIndex, setup->wValue);
switch (setup->wRequestAndType) switch (setup->wRequestAndType)
{ {
case 0x0500: // SET_ADDRESS case 0x0500: // SET_ADDRESS
case 0x0b01: // SET_INTERFACE // TODO: Handle set_daddr
dfu_clrstatus(); // efm32hg_set_daddr(setup->wValue);
break; break;
case 0x0900: // SET_CONFIGURATION case 0x0900: // SET_CONFIGURATION
usb_configuration = setup->wValue; usb_configuration = setup->wValue;
break; break;
case 0x0880: // GET_CONFIGURATION case 0x0880: // GET_CONFIGURATION
reply_buffer[0] = usb_configuration; reply_buffer[0] = usb_configuration;
datalen = 1; datalen = 1;
data = reply_buffer; data = reply_buffer;
break; break;
case 0x0080: // GET_STATUS (device) case 0x0080: // GET_STATUS (device)
reply_buffer[0] = 0; reply_buffer[0] = 0;
reply_buffer[1] = 0; reply_buffer[1] = 0;
datalen = 2; datalen = 2;
data = reply_buffer; data = reply_buffer;
break; break;
case 0x0082: // GET_STATUS (endpoint) case 0x0082: // GET_STATUS (endpoint)
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
printf("get_status (setup->wIndex: %d)\n", setup->wIndex);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -57,11 +56,11 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
data = reply_buffer; data = reply_buffer;
datalen = 2; datalen = 2;
break; break;
case 0x0102: // CLEAR_FEATURE (endpoint) case 0x0102: // CLEAR_FEATURE (endpoint)
if (setup->wIndex > 0 || setup->wValue != 0) if (setup->wIndex > 0 || setup->wValue != 0)
{ {
// TODO: do we need to handle IN vs OUT here? // TODO: do we need to handle IN vs OUT here?
printf("%s:%d clear feature (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -69,11 +68,11 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL; // USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
// TODO: do we need to clear the data toggle here? // TODO: do we need to clear the data toggle here?
break; break;
case 0x0302: // SET_FEATURE (endpoint) case 0x0302: // SET_FEATURE (endpoint)
if (setup->wIndex > 0 || setup->wValue != 0) if (setup->wIndex > 0 || setup->wValue != 0)
{ {
// TODO: do we need to handle IN vs OUT here? // TODO: do we need to handle IN vs OUT here?
printf("%s:%d clear feature (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -81,7 +80,6 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL; // USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
// TODO: do we need to clear the data toggle here? // TODO: do we need to clear the data toggle here?
break; break;
case 0x0680: // GET_DESCRIPTOR case 0x0680: // GET_DESCRIPTOR
case 0x0681: case 0x0681:
for (list = usb_descriptor_list; 1; list++) for (list = usb_descriptor_list; 1; list++)
@ -105,6 +103,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
goto send; goto send;
} }
} }
printf("%s:%d couldn't find descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
@ -117,6 +116,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
datalen = MSFT_WCID_LEN; datalen = MSFT_WCID_LEN;
break; break;
} }
printf("%s:%d couldn't find microsoft descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
@ -131,13 +131,14 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
break; break;
} }
} }
// printf("%s:%d couldn't find webusb descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue); printf("%s:%d couldn't find webusb descriptor (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
case 0x0121: // DFU_DNLOAD case 0x0121: // DFU_DNLOAD
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
printf("%s:%d dfu download descriptor index invalid (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -152,49 +153,16 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
usb_ack(dev, 0); usb_ack(dev, 0);
return; return;
} }
// ACK the setup packet
usb_ack(dev, 0);
int bytes_remaining = setup->wLength;
int ep0_rx_offset = 0;
while (bytes_remaining > 0) {
// Fill the buffer, or if there is enough space transfer the whole packet.
unsigned int len = setup->wLength; unsigned int len = setup->wLength;
if (len > sizeof(rx_buffer)) if (len > sizeof(rx_buffer))
len = sizeof(rx_buffer); len = sizeof(rx_buffer);
unsigned int i; usb_recv(dev, rx_buffer, len);
for (i = 0; i < sizeof(rx_buffer)/4; i++)
rx_buffer[i] = 0xffffffff;
// Receive DATA packets (which are automatically ACKed)
len = usb_recv(dev, (void *)rx_buffer, len);
// Append the data to the download buffer.
dfu_download(setup->wValue, setup->wLength, ep0_rx_offset, len, (void *)rx_buffer);
bytes_remaining -= len;
ep0_rx_offset += len;
}
return;
case 0x0021: // DFU_DETACH
// Send the "ACK" packet and wait for it
// to be received.
usb_ack(dev, 0);
usb_wait_for_send_done(dev);
usb_disconnect();
// Issue a reboot
reboot_to_image(0);
while (1)
;
return; return;
case 0x03a1: // DFU_GETSTATUS case 0x03a1: // DFU_GETSTATUS
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -206,6 +174,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
} }
else else
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -214,6 +183,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
case 0x0421: // DFU_CLRSTATUS case 0x0421: // DFU_CLRSTATUS
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -223,6 +193,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
} }
else else
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -230,6 +201,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
case 0x05a1: // DFU_GETSTATE case 0x05a1: // DFU_GETSTATE
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -241,6 +213,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
case 0x0621: // DFU_ABORT case 0x0621: // DFU_ABORT
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
@ -250,19 +223,20 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
} }
else else
{ {
printf("%s:%d err (%d / %d)\n", __FILE__, __LINE__, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
default: default:
printf("%s:%d unrecognized request type (%04x) value: %02x index: %02x\n", __FILE__, __LINE__, setup->wRequestAndType, setup->wIndex, setup->wValue);
usb_err(dev, 0); usb_err(dev, 0);
return; return;
} }
send: send:
if (data && datalen) { if (data && datalen) {
if (datalen > setup->wLength) printf("%s:%d sending %d bytes from %08x\n", __FILE__, __LINE__, datalen, data);
datalen = setup->wLength;
usb_send(dev, 0, data, datalen); usb_send(dev, 0, data, datalen);
} }
else else

View File

@ -1,10 +1,10 @@
#include <grainuum.h>
#include <usb.h> #include <usb.h>
#include <irq.h> #include <irq.h>
#include <generated/csr.h> #include <generated/csr.h>
#include <string.h> #include <string.h>
#include <printf.h> #include <printf.h>
#include <uart.h> #include <uart.h>
#include <usb.h>
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR #ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
@ -12,7 +12,6 @@
enum CONTROL_STATE enum CONTROL_STATE
{ {
WAIT_SETUP, WAIT_SETUP,
IN_SETUP,
IN_DATA, IN_DATA,
OUT_DATA, OUT_DATA,
LAST_IN_DATA, LAST_IN_DATA,
@ -21,14 +20,10 @@ enum CONTROL_STATE
STALLED, STALLED,
} control_state; } control_state;
// Note that our PIDs are only bits 2 and 3 of the token, #define NUM_BUFFERS 4
// since all other bits are effectively redundant at this point. #define BUFFER_SIZE 64
enum USB_PID { #define EP_INTERVAL_MS 6
USB_PID_OUT = 0, static const char hex[] = "0123456789abcdef";
USB_PID_SOF = 1,
USB_PID_IN = 2,
USB_PID_SETUP = 3,
};
enum epfifo_response { enum epfifo_response {
EPF_ACK = 0, EPF_ACK = 0,
@ -40,13 +35,6 @@ enum epfifo_response {
#define USB_EV_ERROR 1 #define USB_EV_ERROR 1
#define USB_EV_PACKET 2 #define USB_EV_PACKET 2
void usb_disconnect(void) {
usb_ep_0_out_ev_enable_write(0);
usb_ep_0_in_ev_enable_write(0);
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
usb_pullup_out_write(0);
}
void usb_connect(void) { void usb_connect(void) {
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read()); usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
@ -64,20 +52,18 @@ void usb_connect(void) {
} }
void usb_init(void) { void usb_init(void) {
usb_pullup_out_write(0);
return; return;
} }
static volatile int irq_count = 0; volatile int irq_count = 0;
#define EP0OUT_BUFFERS 8 #define EP0OUT_BUFFERS 4
__attribute__((aligned(4))) __attribute__((aligned(4)))
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][256]; static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS]; static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS];
static uint8_t usb_ep0out_last_tok[EP0OUT_BUFFERS]; uint8_t usb_ep0out_wr_ptr;
static volatile uint8_t usb_ep0out_wr_ptr; uint8_t usb_ep0out_rd_ptr;
static volatile uint8_t usb_ep0out_rd_ptr; int max_byte_length = 8;
static const int max_byte_length = 64;
static const uint8_t *current_data; static const uint8_t *current_data;
static int current_length; static int current_length;
@ -86,18 +72,10 @@ static int current_to_send;
static int queue_more_data(int epnum) { static int queue_more_data(int epnum) {
(void)epnum; (void)epnum;
// Don't allow requeueing
// Don't allow requeueing -- only queue more data if we're
// currently set up to respond NAK.
if (usb_ep_0_in_respond_read() != EPF_NAK) if (usb_ep_0_in_respond_read() != EPF_NAK)
return -1; return -1;
// Prevent us from double-filling the buffer.
if (!usb_ep_0_in_ibuf_empty_read()) {
usb_ep_0_in_respond_write(EPF_ACK);
return -1;
}
int this_offset; int this_offset;
current_to_send = current_length - current_offset; current_to_send = current_length - current_offset;
if (current_to_send > max_byte_length) if (current_to_send > max_byte_length)
@ -112,52 +90,73 @@ static int queue_more_data(int epnum) {
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) { int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) {
(void)dev; (void)dev;
// Don't allow requeueing
while (current_data || current_length) // if (usb_ep_0_in_respond_read() != EPF_NAK)
; // return -1;
if (!usb_ep_0_in_ibuf_empty_read()) {
printf("IBUF isn't empty. Error? %d\n", usb_usb_transfer_error_state_read());
return -1;
}
/*
while (!usb_ep_0_in_ibuf_empty_read()) {
printf("Emptying out ibuf...\n");
usb_ep_0_in_ibuf_head_read();
}
*/
current_data = (uint8_t *)data; current_data = (uint8_t *)data;
current_length = total_count; current_length = total_count;
current_offset = 0; current_offset = 0;
control_state = IN_DATA; control_state = IN_DATA;
queue_more_data(epnum); queue_more_data(epnum);
return 0;
}
int usb_wait_for_send_done(struct usb_device *dev) {
while (current_data && current_length)
usb_poll(dev);
while ((usb_ep_0_in_dtb_read() & 1) == 1)
usb_poll(dev);
return 0; return 0;
} }
void usb_isr(void) { void usb_isr(void) {
#if 0
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
while (!usb_ep_0_out_obuf_empty_read()) {
usb_ep_0_out_obuf_head_write(0);
}
usb_ep_0_out_respond_write(EPF_ACK);
usb_ep_0_in_respond_write(EPF_ACK);
usb_ep_0_out_ev_pending_write(ep0o_pending);
usb_ep_0_in_ev_pending_write(ep0i_pending);
#else
irq_count++; irq_count++;
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read(); uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read(); uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
printf(">> %02x %02x <<\n", ep0o_pending, ep0i_pending);
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer // We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
// and clear the "pending" bit. // and clear the "pending" bit.
if (ep0o_pending) { if (ep0o_pending) {
uint8_t last_tok = usb_ep_0_out_last_tok_read();
int byte_count = 0; int byte_count = 0;
usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr]; uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
while (!usb_ep_0_out_obuf_empty_read()) { while (!usb_ep_0_out_obuf_empty_read()) {
obuf[byte_count++] = usb_ep_0_out_obuf_head_read(); obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
usb_ep_0_out_obuf_head_write(0); usb_ep_0_out_obuf_head_write(0);
} }
usb_ep_0_out_ev_pending_write(ep0o_pending); usb_ep_0_out_ev_pending_write(ep0o_pending);
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count - 2 /* Strip off CRC16 */;
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
if (last_tok == USB_PID_SETUP) { if (byte_count) {
current_offset = 0; printf("read %d bytes: [", byte_count);
current_length = 0; unsigned int i;
current_data = NULL; for (i = 0; i < byte_count; i++) {
control_state = IN_SETUP; uart_write(' ');
uart_write(hex[(obuf[i] >> 4) & 0xf]);
uart_write(hex[obuf[i] & (0xf)]);
}
uart_write(' ]');
uart_write('\r');
uart_write('\n');
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count;
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
}
else {
printf("read no bytes\n");
usb_ep_0_out_respond_write(EPF_ACK);
} }
} }
@ -167,9 +166,20 @@ void usb_isr(void) {
current_offset += current_to_send; current_offset += current_to_send;
queue_more_data(0); queue_more_data(0);
usb_ep_0_in_ev_pending_write(ep0i_pending); usb_ep_0_in_ev_pending_write(ep0i_pending);
// Get ready to respond with an empty data byte
if (current_offset >= current_length) {
current_offset = 0;
current_length = 0;
current_data = NULL;
if (control_state == IN_DATA) {
usb_ep_0_out_respond_write(EPF_ACK); usb_ep_0_out_respond_write(EPF_ACK);
} }
}
else
usb_ep_0_in_respond_write(EPF_NAK);
}
#endif
return; return;
} }
@ -183,74 +193,80 @@ int usb_irq_happened(void) {
} }
int usb_ack(struct usb_device *dev, int epnum) { int usb_ack(struct usb_device *dev, int epnum) {
(void)dev;
(void)epnum;
usb_ep_0_in_dtb_write(1);
usb_ep_0_out_dtb_write(1);
usb_ep_0_out_respond_write(EPF_ACK); usb_ep_0_out_respond_write(EPF_ACK);
usb_ep_0_in_respond_write(EPF_ACK); usb_ep_0_in_respond_write(EPF_ACK);
return 0;
} }
int usb_err(struct usb_device *dev, int epnum) { int usb_err(struct usb_device *dev, int epnum) {
(void)dev; printf("STALLING!!!\n");
(void)epnum;
usb_ep_0_out_respond_write(EPF_STALL); usb_ep_0_out_respond_write(EPF_STALL);
usb_ep_0_in_respond_write(EPF_STALL); usb_ep_0_in_respond_write(EPF_STALL);
return 0;
} }
// int puts_noendl(const char *s);
// static void print_eptype(void) {
// switch (usb_ep0out_last_tok[usb_ep0out_rd_ptr]) {
// case 0: puts("O"); break;
// // case 1: puts("SOF"); break;
// // case 2: puts("IN"); break;
// case 3: puts("S"); break;
// }
// }
int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len) { int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len) {
(void)dev; return;
// Set the OUT response to ACK, since we are in a position to receive data now.
usb_ep_0_out_respond_write(EPF_ACK);
while (1) {
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
if (ep0_buffer_len < buffer_len)
buffer_len = ep0_buffer_len;
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
memcpy(buffer, &usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
return buffer_len;
}
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
}
}
return 0;
} }
void usb_poll(struct usb_device *dev) {
(void)dev; void usb_poll(void) {
static int last_error_count;
int this_error_count = usb_usb_transfer_error_state_read();
if (last_error_count != this_error_count) {
printf("USB TRANSFER ERROR STATE # %d!! WaitHand? %d WaitData? %d PID: %02x (was: %02x, full: %02x)\n", this_error_count, usb_dbg_lwh_read(), usb_dbg_lwd_read(), usb_usb_transfer_o_pid_read(), usb_usb_transfer_error_pid_read(), usb_dbg_lfp_read());
last_error_count = this_error_count;
}
// If some data was received, then process it. // If some data was received, then process it.
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) { if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]); const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
// unsigned int len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
usb_setup(NULL, request);
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0; usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1); usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
if (last_tok == USB_PID_SETUP) {
usb_setup(NULL, request);
}
} }
if ((usb_ep_0_in_respond_read() == EPF_NAK) && (current_data)) { if ((usb_ep_0_in_respond_read() == EPF_NAK) && (current_data))
current_offset += current_to_send;
queue_more_data(0); queue_more_data(0);
// Cancel any pending transfers
if ((control_state == IN_DATA) && usb_ep_0_in_ibuf_empty_read()) {
printf("state is IN_DATA but ibuf is empty?\n");
usb_ack(NULL, 0);
printf("and obuf_empty_read(): %d\n", usb_ep_0_out_obuf_empty_read());
usb_ep_0_out_obuf_head_write(0);
control_state = WAIT_SETUP;
}
// if (!usb_ep_0_out_obuf_empty_read()) {
// printf("FATAL: obuf not empty, and pending is %d\n", usb_ep_0_out_ev_pending_read());
// printf("HALT");
// while (1)
// ;
// }
// if (!usb_ep_0_in_ibuf_empty_read()) {
// usb_ep_0_in_ibuf_head_write(0);
// }
// usb_ack(NULL, 0);
}
void usb_print_status(void) {
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
// printf("current_data: 0x%08x\n", current_data);
// printf("current_length: %d\n", current_length);
// printf("current_offset: %d\n", current_offset);
// printf("current_to_send: %d\n", current_to_send);
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
uint8_t cnt = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
unsigned int i;
if (cnt) {
for (i = 0; i < cnt; i++) {
uart_write(' ');
uart_write(hex[(obuf[i+1] >> 4) & 0xf]);
uart_write(hex[obuf[i+1] & (0xf)]);
}
uart_write('\r');
uart_write('\n');
}
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
} }
} }

121
sw/third_party/div.S vendored
View File

@ -1,121 +0,0 @@
.text
.align 2
#ifndef __riscv64
/* Our RV64 64-bit routines are equivalent to our RV32 32-bit routines. */
# define __udivdi3 __udivsi3
# define __umoddi3 __umodsi3
# define __divdi3 __divsi3
# define __moddi3 __modsi3
#else
.globl __udivsi3
__udivsi3:
/* Compute __udivdi3(a0 << 32, a1 << 32); cast result to uint32_t. */
sll a0, a0, 32
sll a1, a1, 32
move t0, ra
jal __udivdi3
sext.w a0, a0
jr t0
.globl __umodsi3
__umodsi3:
/* Compute __udivdi3((uint32_t)a0, (uint32_t)a1); cast a1 to uint32_t. */
sll a0, a0, 32
sll a1, a1, 32
srl a0, a0, 32
srl a1, a1, 32
move t0, ra
jal __udivdi3
sext.w a0, a1
jr t0
.globl __modsi3
__modsi3 = __moddi3
.globl __divsi3
__divsi3:
/* Check for special case of INT_MIN/-1. Otherwise, fall into __divdi3. */
li t0, -1
beq a1, t0, .L20
#endif
.globl __divdi3
__divdi3:
bltz a0, .L10
bltz a1, .L11
/* Since the quotient is positive, fall into __udivdi3. */
.globl __udivdi3
__udivdi3:
mv a2, a1
mv a1, a0
li a0, -1
beqz a2, .L5
li a3, 1
bgeu a2, a1, .L2
.L1:
blez a2, .L2
slli a2, a2, 1
slli a3, a3, 1
bgtu a1, a2, .L1
.L2:
li a0, 0
.L3:
bltu a1, a2, .L4
sub a1, a1, a2
or a0, a0, a3
.L4:
srli a3, a3, 1
srli a2, a2, 1
bnez a3, .L3
.L5:
ret
.globl __umoddi3
__umoddi3:
/* Call __udivdi3(a0, a1), then return the remainder, which is in a1. */
move t0, ra
jal __udivdi3
move a0, a1
jr t0
/* Handle negative arguments to __divdi3. */
.L10:
neg a0, a0
bgez a1, .L12 /* Compute __udivdi3(-a0, a1), then negate the result. */
neg a1, a1
j __divdi3 /* Compute __udivdi3(-a0, -a1). */
.L11: /* Compute __udivdi3(a0, -a1), then negate the result. */
neg a1, a1
.L12:
move t0, ra
jal __divdi3
neg a0, a0
jr t0
.globl __moddi3
__moddi3:
move t0, ra
bltz a1, .L31
bltz a0, .L32
.L30:
jal __udivdi3 /* The dividend is not negative. */
move a0, a1
jr t0
.L31:
neg a1, a1
bgez a0, .L30
.L32:
neg a0, a0
jal __udivdi3 /* The dividend is hella negative. */
neg a0, a1
jr t0
#ifdef __riscv64
/* continuation of __divsi3 */
.L20:
sll t0, t0, 31
bne a0, t0, __divdi3
ret
#endif

View File

@ -3,7 +3,6 @@
#include <generated/csr.h> #include <generated/csr.h>
#include <hw/flags.h> #include <hw/flags.h>
#ifdef CSR_UART_BASE
/* /*
* Buffer sizes must be a power of 2 so that modulos can be computed * Buffer sizes must be a power of 2 so that modulos can be computed
* with logical AND. * with logical AND.
@ -109,7 +108,3 @@ void uart_sync(void)
{ {
while(tx_consume != tx_produce); while(tx_consume != tx_produce);
} }
#else /* !CSR_UART_BASE */
void uart_init(void) {}
void uart_isr(void) {}
#endif

26
sw/third_party/mul.S vendored
View File

@ -1,26 +0,0 @@
.text
.align 2
#ifdef __riscv64
#define _RISCV_SZPTR 64
#define _RISCV_SZINT 64
#else
/* Our RV64 64-bit routine is equivalent to our RV32 32-bit routine. */
# define __muldi3 __mulsi3
#define _RISCV_SZPTR 32
#define _RISCV_SZINT 32
#endif
.globl __muldi3
__muldi3:
mv a2, a0
li a0, 0
.L1:
slli a3, a1, _RISCV_SZPTR-1
bgez a3, .L2
add a0, a0, a2
.L2:
srli a1, a1, 1
slli a2, a2, 1
bnez a1, .L1
ret

View File

@ -256,13 +256,8 @@ void tfp_sprintf(char *s, char *fmt, ...)
} }
int puts(const char *s) { int puts(const char *s) {
puts_noendl(s); while (*s++)
stdout_putf(stdout_putp, *s);
stdout_putf(stdout_putp, '\n'); stdout_putf(stdout_putp, '\n');
return 1; return 1;
} }
int puts_noendl(const char *s) {
while (*s)
stdout_putf(stdout_putp, *s++);
return 1;
}