bfloat16 starter ...

master
kaqu 1 year ago
commit 8838cf4f9d
  1. 7
      .gitignore
  2. 28
      .vscode/launch.json
  3. 3
      .vscode/settings.json
  4. 298
      bfloat16nn.py
  5. 9
      firmware/README.md
  6. 688
      firmware/boot.c
  7. 684
      firmware/boot.c.original
  8. 622
      firmware/cmd_mem.c
  9. 312
      firmware/cmd_mem.c.original
  10. 131
      firmware/console.c
  11. 87
      firmware/console.c.original
  12. 328
      firmware/main.c
  13. 174
      firmware/main.c.original
  14. 10
      helpers/README.md
  15. 160
      helpers/bit_to_flash.py
  16. 89
      helpers/eraser.svf
  17. 1
      helpers/ffffffff.img
  18. 187
      helpers/imageflasher.py
  19. 43
      helpers/load_to_flash.py
  20. 76
      helpers/prepare_firmware.py
  21. 107
      helpers/remotetest.py
  22. 31
      libmodules/README.md
  23. 229
      libmodules/bfloat16nncore.py
  24. 509
      libmodules/bfloat16processor.py
  25. 321
      libmodules/dramtransfer.py
  26. 129
      libmodules/systime.py
  27. 265
      litex/litedram/frontend/dma.py
  28. 5
      prog/openocd.cfg
  29. 13
      prog/openocd_colorlight_5a_75b (copy).cfg
  30. 13
      prog/openocd_colorlight_5a_75b.cfg
  31. 15
      software/README.md
  32. 16
      software/flashclearapp.sh
  33. 19
      software/flashcreate.sh
  34. 16
      software/include/bfloat16nnlib.h
  35. 19
      software/include/dramtransfer.h
  36. 16
      software/include/systime.h
  37. BIN
      software/lib/rv32ilibgcc.a
  38. BIN
      software/lib/rv32ilibm.a
  39. 1
      software/linker/output_format.ld
  40. 92
      software/linker/ram1.ld
  41. 90
      software/linker/ram2.ld
  42. 130
      software/ramcreate.sh
  43. 6
      software/source/README.md
  44. 161
      software/source/bfloat16nnlib.c
  45. 201
      software/source/dramtransfer.c
  46. 117
      software/source/fpga2dram.c
  47. 217
      software/source/illumination.c
  48. 128
      software/source/main.c
  49. 437
      software/source/my_vsnprintf.c
  50. 47
      software/source/systime.c
  51. 42
      start_terminal_service.sh

7
.gitignore vendored

@ -0,0 +1,7 @@
build/*
__pycache__/*
backup/*
software/build/*
helpers/__pycache__/*
libmodules/__pycache__/*
NeuralNetworkTest/*

@ -0,0 +1,28 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"args": ["--build",
"--load", // May be used separately ...
//"--flash", // May be used separately ...
"--revision=7.0",
"--uart-name=crossover",
//"--with-ethernet", // Not to be used together w/ etherbone! Won't TFTP ...
"--with-etherbone",
"--ip-address=192.168.1.20",
"--csr-csv=build/csr.csv", // Only this one for remotetest.py!
"--doc"
],
//"args": ["--build"],
//"pythonArgs": ["--build", "--uart-name=crossover"],
"console": "integratedTerminal"
}
]
}

@ -0,0 +1,3 @@
{
"python.pythonPath": "/home/kln/fpga/bin/python"
}

@ -0,0 +1,298 @@
#!/usr/bin/env python3
#
# bfloat16nn.py
#
# This file has been derived from LiteX-Boards/colorlight_5b_75x.py
# Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
#
# Disclaimer: Still a proof of concept with large timings violations on the IP/UDP and
# Etherbone stack that need to be optimized. It was initially just used to validate the reversed
# pinout but happens to work on hardware...
#
# History:
# --------
# 21.04.21/KQ Initially derived version
#
# Build/Use ----------------------------------------------------------------------------------------
# - 'python3 bfloat16nn.py --build --revision=7.0 --uart-name=crossover --with-etherbone --ip-address=192.168.1.20 --csr-csv=build/csr.csv'
# to generate
# - 'python3 bfloat16nn.py --load' to download to FPGA
# - 'ping 192.168.1.20' to verify ethernet connection - via LEFT(!) RJ45 port
# - 'wishbone-tool --ethernet-host 192.168.1.20 --server terminal --csr-csv build/csr.csv'
# You should see the LiteX BIOS and be able to interact with it
# - To load a file to RAM (@0x40000000 len=0x400000) use:
# wishbone-tool --ethernet-host 192.168.1.20 --server load-file --csr-csv build/csr.csv
# --load-address 0x40000000
# --load-name build/colorlight_5a_75b/software/<filename>
# To disassemble raw file:
# ../fpga/litex/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14/bin/riscv64-unknown-elf-objdump
# -D -b binary ./build/colorlight_5a_75b/software/bios/bios.bin -m riscv
#
import os
import argparse
import sys
import time
from migen import *
from migen.genlib.misc import WaitTimer
from migen.genlib.resetsync import AsyncResetSynchronizer
from litex.build.io import DDROutput
from litex_boards.platforms import colorlight_5a_75b
from litex.build.lattice.trellis import trellis_args, trellis_argdict
from litex.soc.cores.clock import *
from litex.soc.cores.spi_flash import ECP5SPIFlash
from litex.soc.cores.gpio import GPIOOut
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage, CSRField
from litex.soc.interconnect.stream import SyncFIFO
from litedram.modules import M12L16161A, M12L64322A
from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY
from litedram.frontend.dma import LiteDRAMDMAReader, LiteDRAMDMAWriter
from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
from litex.build.generic_platform import *
import litex.soc.doc as lxsocdoc
from libmodules.dramtransfer import DRAM2FPGA, FPGA2DRAM
from libmodules.systime import SysTime
from libmodules.bfloat16nncore import bfloat16NeuralNetworkCore
from helpers.prepare_firmware import copyjob
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module):
def __init__(self, platform, sys_clk_freq, use_internal_osc=False, with_usb_pll=False, with_rst=True, sdram_rate="1:1"):
self.clock_domains.cd_sys = ClockDomain()
if sdram_rate == "1:2":
self.clock_domains.cd_sys2x = ClockDomain()
self.clock_domains.cd_sys2x_ps = ClockDomain(reset_less=True)
else:
self.clock_domains.cd_sys_ps = ClockDomain(reset_less=True)
# # #
# Clk / Rst
if not use_internal_osc:
clk = platform.request("clk25")
clk_freq = 25e6
else:
clk = Signal()
div = 5
self.specials += Instance("OSCG",
p_DIV = div,
o_OSC = clk)
clk_freq = 310e6/div
rst_n = 1 if not with_rst else platform.request("user_btn_n", 0)
# PLL
self.submodules.pll = pll = ECP5PLL()
self.comb += pll.reset.eq(~rst_n)
pll.register_clkin(clk, clk_freq)
pll.create_clkout(self.cd_sys, sys_clk_freq)
if sdram_rate == "1:2":
pll.create_clkout(self.cd_sys2x, 2*sys_clk_freq)
pll.create_clkout(self.cd_sys2x_ps, 2*sys_clk_freq, phase=180) # Idealy 90° but needs to be increased.
else:
pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=180) # Idealy 90° but needs to be increased.
# USB PLL
if with_usb_pll:
self.submodules.usb_pll = usb_pll = ECP5PLL()
self.comb += usb_pll.reset.eq(~rst_n)
usb_pll.register_clkin(clk, clk_freq)
self.clock_domains.cd_usb_12 = ClockDomain()
self.clock_domains.cd_usb_48 = ClockDomain()
usb_pll.create_clkout(self.cd_usb_12, 12e6, margin=0)
usb_pll.create_clkout(self.cd_usb_48, 48e6, margin=0)
# SDRAM clock
sdram_clk = ClockSignal("sys2x_ps" if sdram_rate == "1:2" else "sys_ps")
self.specials += DDROutput(1, 0, platform.request("sdram_clock"), sdram_clk)
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
def __init__(self, board, revision, with_ethernet=False, with_etherbone=False, eth_phy=0, ip_address=None, mac_address=None, sys_clk_freq=60e6, use_internal_osc=False, sdram_rate="1:1", **kwargs):
platform = colorlight_5a_75b.Platform(revision="7.0")
# SoCCore ----------------------------------------------------------------------------------
SoCCore.__init__(self, platform, int(sys_clk_freq),
ident = "LiteX SoC on Colorlight " + board.upper(),
ident_version = True,
**kwargs)
# CRG --------------------------------------------------------------------------------------
with_rst = kwargs["uart_name"] not in ["serial", "bridge"] # serial_rx shared with user_btn_n.
with_usb_pll = kwargs.get("uart_name", None) == "usb_acm"
self.submodules.crg = _CRG(platform, sys_clk_freq, use_internal_osc=use_internal_osc, with_usb_pll=with_usb_pll,with_rst=with_rst, sdram_rate=sdram_rate)
# SDR SDRAM --------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
sdrphy_cls = HalfRateGENSDRPHY if sdram_rate == "1:2" else GENSDRPHY
self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"))
if board == "5a-75e" and revision == "6.0":
sdram_cls = M12L64322A
sdram_size = 0x80000000
else:
sdram_cls = M12L16161A
sdram_size = 0x40000000
self.add_sdram("sdram",
phy = self.sdrphy,
module = sdram_cls(sys_clk_freq, sdram_rate),
origin = self.mem_map["main_ram"],
size = kwargs.get("max_sdram_size", sdram_size),
l2_cache_size = kwargs.get("l2_size", 8192),
l2_cache_min_data_width = kwargs.get("min_l2_data_width", 128),
l2_cache_reverse = True
)
# Ethernet / Etherbone ---------------------------------------------------------------------
if with_ethernet or with_etherbone:
self.submodules.ethphy = LiteEthPHYRGMII(
clock_pads = self.platform.request("eth_clocks", eth_phy),
pads = self.platform.request("eth", eth_phy))
self.add_csr("ethphy")
if with_ethernet:
self.add_ethernet(phy=self.ethphy)
if with_etherbone:
self.add_etherbone(
phy=self.ethphy,
ip_address = ip_address,
mac_address = mac_address,
)
# Base counter (used for clocking)
counter = Signal(32) # 32-Bit counter
self.sync += counter.eq(counter + 1)
# System time (count)
self.submodules.systime = systime = SysTime(comparecount=0x0000EA90)
self.add_csr("systime")
# DRAM access section
MAXWORDS = 512 #512 # Transfer length 32 x 32-bit, FIFO depth (511 L1 cache currently possible = 9-bit!)
# Load unit memory access
self.submodules.dma_reader = dma_reader = LiteDRAMDMAReader(self.sdram.crossbar.get_port(), fifo_depth=MAXWORDS, fifo_buffered=True)
dma_reader.add_csr()
self.add_csr("dma_reader")
# Load unit transfer
self.submodules.sync_fifo_in = sync_fifo_in = SyncFIFO([("data", 32)], MAXWORDS, True)
self.comb += dma_reader.source.connect(sync_fifo_in.sink) # Connect DMA-Reader.source -> FIFO.sink
# Load unit (LU)
self.submodules.dram2fpga = dram2fpga = DRAM2FPGA(maxwords=MAXWORDS, dma_reader=dma_reader, sync_fifo=sync_fifo_in)
self.add_csr("dram2fpga")
""" *** Not used currently ! ***
MAXWRITEWORDS = 1 # Transfer length 1 x 32-bit = 4 byte maximum (SU)
# Store unit memory access
self.submodules.dma_writer = dma_writer = LiteDRAMDMAWriter(self.sdram.crossbar.get_port(), fifo_depth=MAXWRITEWORDS, fifo_buffered=True)
dma_writer.add_csr()
self.add_csr("dma_writer")
# Store unit transfer
self.submodules.sync_fifo_out = sync_fifo_out = SyncFIFO([("data", 32)], MAXWRITEWORDS, True)
self.comb += sync_fifo_out.source.connect(dma_writer.sink) # Connect FIFO.source -> DMA-Writer.sink
# Store unit (SU)
self.submodules.fpga2dram = fpga2dram = FPGA2DRAM(dma_writer=dma_writer, sync_fifo=sync_fifo_out)
self.add_csr("fpga2dram")
"""
# Integrate bfloat16NN processor
RAMWAITTIME=1 # Minimum wait!
self.submodules.bfloat16nn = bfloat16nn = bfloat16NeuralNetworkCore(
RAMWaitTime=RAMWAITTIME,
LUCacheSize=MAXWORDS,
LoadUnit=dram2fpga,
StoreUnit=None, # *** Not used currently: fpga2dram,
)
self.add_csr("bfloat16nn")
# USERLED blink (on-board LED)
# only w/ uart-name=crossover option:
if kwargs["uart_name"] not in ["serial", "bridge"]:
self.comb += platform.request("user_led_n").eq(~(bfloat16nn.bReady))
# Build --------------------------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="LiteX SoC on Colorlight 5A-75X")
builder_args(parser)
soc_core_args(parser)
trellis_args(parser)
parser.add_argument("--build", action="store_true", help="Build bitstream")
parser.add_argument("--load", action="store_true", help="Load bitstream")
parser.add_argument("--board", default="5a-75b", help="Board type: 5a-75b (default) & don't change!")
parser.add_argument("--revision", default="7.0", type=str, help="Board revision 7.0 (default) & don't change!")
parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support")
parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support")
parser.add_argument("--eth-phy", default=0, type=int, help="Ethernet PHY 0 or 1 (default=0)")
parser.add_argument("--ip-address", default="192.168.1.50", help="Ethernet IP address of the board.")
parser.add_argument("--mac-address", default="0x726b895bc2e2", help="Ethernet MAC address of the board.")
parser.add_argument("--sys-clk-freq", default=60e6, type=float, help="System clock frequency (default=60MHz)")
parser.add_argument("--use-internal-osc", action="store_true", help="Use internal oscillator")
parser.add_argument("--sdram-rate", default="1:1", help="SDRAM Rate 1:1 Full Rate (default), 1:2 Half Rate")
parser.add_argument("--csr_csv", default="build/csr.csv", help="CSR list location")
parser.add_argument("--doc", action="store_true", help="Create doc files for sphinx generator")
parser.add_argument("--flash", action="store_true", help="Load bitstream to flash")
args = parser.parse_args()
#assert not (args.with_ethernet and args.with_etherbone)
soc = BaseSoC(board=args.board, revision=args.revision,
with_ethernet = args.with_ethernet,
with_etherbone = args.with_etherbone,
eth_phy = args.eth_phy,
ip_address = args.ip_address,
mac_address = int(args.mac_address, 0),
sys_clk_freq = args.sys_clk_freq,
use_internal_osc = args.use_internal_osc,
sdram_rate = args.sdram_rate,
**soc_core_argdict(args))
# 32MBit SPIFlash ------------------------------------------------------------------------
flashbase = 0xc0000000
flashoffset = 0x100000 # Used to be zero (default)
soc.mem_map["spiflash"] = flashbase # Length: 0x01000000 ('til 0xc1000000 - 1)
# Boot at +1MB
soc.add_constant("FLASH_BOOT_ADDRESS", soc.mem_map["spiflash"] + 1024*1024) # 0xc0100000
soc.add_spi_flash(name="spiflash", mode="1x", dummy_cycles=8, clk_freq=5e6)
builder = Builder(soc, **builder_argdict(args))
# Now override boot address (used to be zero/default)
args.ecppack_bootaddr = flashbase + flashoffset # 0xC0100000
builder.build(**trellis_argdict(args), run=args.build) # Written here to (local) build tree
if args.doc:
print("Generating documentation for sphinx ...")
lxsocdoc.generate_docs(soc, "build/documentation/", project_name="neopixelar", author="KQ")
print("Generate via: 'sphinx-build -b html build/documentation build/documentation/html'")
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".svf"))
return
if args.flash: # Convert Bit File to Jtag Write Flash command
name = os.path.join(builder.gateware_dir, soc.build_name)
print(f"Executing ./bit_to_flash.py {name}.bit {name}.svf.flash")
from helpers.bit_to_flash import convertBitToFlashFile
convertBitToFlashFile(name + ".bit", name + ".svf.flash", address=0)
from helpers.load_to_flash import load2flash
load2flash(name + ".svf.flash")
return
if __name__ == "__main__":
starttime = time.time()
copyjob() # Create backup if nec. & move our firmware to the correct location
main() # Create FPGA & load/flash
print("Time used: {0} min.".format(int((time.time() - starttime)/60.0)))

@ -0,0 +1,9 @@
# FIRMWARE #
This directory contains the modified versions of several BIOS related files.
The modifications are:
1. boot.c - doRAMBoot introduced (permitting RAM boot - automatically selecting the currently inactive RAM bank)
2. cmd_mem.c - additional commands dumpregs & ramboot introduced (mx, mhsig no longer used)
3. console.c - non-blocking feature implemented (set_console, kbhit introduced, putchar modified)
4. main.c - BIOS starter, modified for non-blocking operation

@ -0,0 +1,688 @@
// This file is Copyright (c) 2014-2020 Florent Kermarrec <florent@enjoy-digital.fr>
// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
// This file is Copyright (c) 2018 Ewen McNeill <ewen@naos.co.nz>
// This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
// This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
// This file is Copyright (c) 2017 Tim 'mithro' Ansell <mithro@mithis.com>
// This file is Copyright (c) 2018 William D. Jones <thor0505@comcast.net>
// License: BSD
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <console.h>
#include <uart.h>
#include <system.h>
#include <crc.h>
#include <string.h>
#include <irq.h>
#include <generated/mem.h>
#include <generated/csr.h>
#include <generated/soc.h>
#include "sfl.h"
#include "boot.h"
#include "jsmn.h"
#include <progress.h>
#include <spiflash.h>
#include <libliteeth/udp.h>
#include <libliteeth/tftp.h>
#include <liblitesdcard/spisdcard.h>
#include <liblitesdcard/sdcard.h>
#include <liblitesdcard/fat/ff.h>
/*-----------------------------------------------------------------------*/
/* Helpers */
/*-----------------------------------------------------------------------*/
#define max(x, y) (((x) > (y)) ? (x) : (y))
#define min(x, y) (((x) < (y)) ? (x) : (y))
/*-----------------------------------------------------------------------*/
/* Boot */
/*-----------------------------------------------------------------------*/
extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr);
static void __attribute__((noreturn)) boot(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr)
{
//printf("Executing booted program at 0x%08x\n\n", addr);
//printf("--============= \e[1mLiftoff!\e[0m ===============--\n");
//uart_sync(); // This is a 'boot-locker'!
#ifdef CONFIG_CPU_HAS_INTERRUPT
irq_setmask(0);
irq_setie(0);
#endif
flush_cpu_icache();
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
#if defined(CONFIG_CPU_TYPE_MOR1KX) && defined(CONFIG_CPU_VARIANT_LINUX)
/* Mainline Linux expects to have exception vector base address set to the
* base address of Linux kernel; it also expects to be run with an offset
* of 0x100. */
mtspr(SPR_EVBAR, addr);
addr += 0x100;
#endif
boot_helper(r1, r2, r3, addr);
while(1);
}
enum {
ACK_TIMEOUT,
ACK_CANCELLED,
ACK_OK
};
/*-----------------------------------------------------------------------*/
/* ROM Boot */
/*-----------------------------------------------------------------------*/
#ifdef ROM_BOOT_ADDRESS
/* Running the application code from ROM is the fastest way to execute code
and could be interesting when the code is small enough, on large devices
where many blockrams are available or simply when the execution speed is
critical. Defining ROM_BOOT_ADDRESS in the SoC will make the BIOS jump to
it at boot. */
void romboot(void)
{
boot(0, 0, 0, ROM_BOOT_ADDRESS);
}
#endif
/*-----------------------------------------------------------------------*/
/* Serial Boot */
/*-----------------------------------------------------------------------*/
static int check_ack(void)
{
int recognized;
static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
timer0_en_write(0);
timer0_reload_write(0);
timer0_load_write(CONFIG_CLOCK_FREQUENCY/4);
timer0_en_write(1);
timer0_update_value_write(1);
recognized = 0;
while(timer0_value_read()) {
if(uart_read_nonblock()) {
char c;
c = uart_read();
if((c == 'Q') || (c == '\e'))
return ACK_CANCELLED;
if(c == str[recognized]) {
recognized++;
if(recognized == SFL_MAGIC_LEN)
return ACK_OK;
} else {
if(c == str[0])
recognized = 1;
else
recognized = 0;
}
}
timer0_update_value_write(1);
}
return ACK_TIMEOUT;
}
static uint32_t get_uint32(unsigned char* data)
{
return ((uint32_t) data[0] << 24) |
((uint32_t) data[1] << 16) |
((uint32_t) data[2] << 8) |
(uint32_t) data[3];
}
#define MAX_FAILED 5
/* Returns 1 if other boot methods should be tried */
int serialboot(void)
{
struct sfl_frame frame;
int failed;
static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
const char *c;
int ack_status;
printf("Booting from serial...\n");
printf("Press Q or ESC to abort boot completely.\n");
/* Send the serialboot "magic" request to Host */
c = str;
while(*c) {
uart_write(*c);
c++;
}
ack_status = check_ack();
if(ack_status == ACK_TIMEOUT) {
printf("Timeout\n");
return 1;
}
if(ack_status == ACK_CANCELLED) {
printf("Cancelled\n");
return 0;
}
/* Assume ACK_OK */
failed = 0;
while(1) {
int i;
int actualcrc;
int goodcrc;
/* Get one Frame */
frame.payload_length = uart_read();
frame.crc[0] = uart_read();
frame.crc[1] = uart_read();
frame.cmd = uart_read();
for(i=0;i<frame.payload_length;i++)
frame.payload[i] = uart_read();
/* Check Frame CRC (if CMD has a CRC) */
if (frame.cmd != SFL_CMD_LOAD_NO_CRC) {
actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
goodcrc = crc16(&frame.cmd, frame.payload_length+1);
if(actualcrc != goodcrc) {
/* Clear out the RX buffer */
while (uart_read_nonblock()) uart_read();
failed++;
if(failed == MAX_FAILED) {
printf("Too many consecutive errors, aborting");
return 1;
}
uart_write(SFL_ACK_CRCERROR);
continue;
}
}
/* Execute Frame CMD */
switch(frame.cmd) {
case SFL_CMD_ABORT:
failed = 0;
uart_write(SFL_ACK_SUCCESS);
return 1;
case SFL_CMD_LOAD:
case SFL_CMD_LOAD_NO_CRC: {
char *writepointer;
failed = 0;
writepointer = (char *) get_uint32(&frame.payload[0]);
for(i=4;i<frame.payload_length;i++)
*(writepointer++) = frame.payload[i];
if (frame.cmd == SFL_CMD_LOAD)
uart_write(SFL_ACK_SUCCESS);
break;
}
case SFL_CMD_JUMP: {
uint32_t addr;
failed = 0;
addr = get_uint32(&frame.payload[0]);
uart_write(SFL_ACK_SUCCESS);
boot(0, 0, 0, addr);
break;
}
case SFL_CMD_FLASH: {
#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
uint32_t addr;
failed = 0;
addr = get_uint32(&frame.payload[0]);
for (i = 4; i < frame.payload_length; i++) {
/* Erase page at sector boundaries before writing */
if ((addr & (SPIFLASH_SECTOR_SIZE - 1)) == 0) {
erase_flash_sector(addr);
}
write_to_flash(addr, &frame.payload[i], 1);
addr++;
}
uart_write(SFL_ACK_SUCCESS);
#endif
break;
}
case SFL_CMD_REBOOT:
#ifdef CSR_CTRL_RESET_ADDR
uart_write(SFL_ACK_SUCCESS);
ctrl_reset_write(1);
#endif
break;
default:
failed++;
if(failed == MAX_FAILED) {
printf("Too many consecutive errors, aborting");
return 1;
}
uart_write(SFL_ACK_UNKNOWN);
break;
}
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Ethernet Boot */
/*-----------------------------------------------------------------------*/
#ifdef CSR_ETHMAC_BASE
#ifndef LOCALIP1
#define LOCALIP1 192
#define LOCALIP2 168
#define LOCALIP3 1
#define LOCALIP4 20 // KQ
#endif
#ifndef REMOTEIP1
#define REMOTEIP1 192
#define REMOTEIP2 168
#define REMOTEIP3 1
#define REMOTEIP4 11 // KQ
#endif
#ifndef TFTP_SERVER_PORT
#define TFTP_SERVER_PORT 69
#endif
static const unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
static int copy_file_from_tftp_to_ram(unsigned int ip, unsigned short server_port,
const char *filename, char *buffer)
{
int size;
printf("Copying %s to 0x%08x... ", filename, buffer);
size = tftp_get(ip, server_port, filename, buffer);
if(size > 0)
printf("(%d bytes)", size);
printf("\n");
return size;
}
static void netboot_from_json(const char * filename, unsigned int ip, unsigned short tftp_port)
{
int size;
uint8_t i;
uint8_t count;
/* FIXME: modify/increase if too limiting */
char json_buffer[1024];
char json_name[32];
char json_value[32];
unsigned long boot_r1 = 0;
unsigned long boot_r2 = 0;
unsigned long boot_r3 = 0;
unsigned long boot_addr = 0;
uint8_t image_found = 0;
uint8_t boot_addr_found = 0;
/* Read JSON file */
size = tftp_get(ip, tftp_port, filename, json_buffer);
if (size <= 0)
return;
/* Parse JSON file */
jsmntok_t t[32];
jsmn_parser p;
jsmn_init(&p);
count = jsmn_parse(&p, json_buffer, strlen(json_buffer), t, sizeof(t)/sizeof(*t));
for (i=0; i<count-1; i++) {
memset(json_name, 0, sizeof(json_name));
memset(json_value, 0, sizeof(json_value));
/* Elements are JSON strings with 1 children */
if ((t[i].type == JSMN_STRING) && (t[i].size == 1)) {
/* Get Element's filename */
memcpy(json_name, json_buffer + t[i].start, t[i].end - t[i].start);
/* Get Element's address */
memcpy(json_value, json_buffer + t[i+1].start, t[i+1].end - t[i+1].start);
/* Skip bootargs (optional) */
if (strncmp(json_name, "bootargs", 8) == 0) {
continue;
}
/* Get boot addr (optional) */
else if (strncmp(json_name, "addr", 4) == 0) {
boot_addr = strtoul(json_value, NULL, 0);
boot_addr_found = 1;
}
/* Get boot r1 (optional) */
else if (strncmp(json_name, "r1", 2) == 0) {
memcpy(json_name, json_buffer + t[i].start, t[i].end - t[i].start);
boot_r1 = strtoul(json_value, NULL, 0);
}
/* Get boot r2 (optional) */
else if (strncmp(json_name, "r2", 2) == 0) {
boot_r2 = strtoul(json_value, NULL, 0);
}
/* Get boot r3 (optional) */
else if (strncmp(json_name, "r3", 2) == 0) {
boot_r3 = strtoul(json_value, NULL, 0);
/* Copy Image from Network to address */
} else {
size = copy_file_from_tftp_to_ram(ip, tftp_port, json_name, (void *)strtoul(json_value, NULL, 0));
if (size <= 0)
return;
image_found = 1;
if (boot_addr_found == 0) /* Boot to last Image address if no bootargs.addr specified */
boot_addr = strtoul(json_value, NULL, 0);
}
}
}
/* Boot */
if (image_found)
boot(boot_r1, boot_r2, boot_r3, boot_addr);
}
static void netboot_from_bin(const char * filename, unsigned int ip, unsigned short tftp_port)
{
int size;
size = copy_file_from_tftp_to_ram(ip, tftp_port, filename, (void *)MAIN_RAM_BASE);
if (size <= 0)
return;
boot(0, 0, 0, MAIN_RAM_BASE);
}
void netboot(void)
{
unsigned int ip;
printf("Booting from network...\n");
printf("Local IP : %d.%d.%d.%d\n", LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4);
printf("Remote IP: %d.%d.%d.%d\n", REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
udp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4));
/* Boot from boot.json */
printf("Booting from boot.json...\n");
netboot_from_json("boot.json", ip, TFTP_SERVER_PORT);
/* Boot from boot.bin */
printf("Booting from boot.bin...\n");
netboot_from_bin("boot.bin", ip, TFTP_SERVER_PORT);
/* Boot failed if we are here... */
printf("Network boot failed.\n");
}
#endif
/*-----------------------------------------------------------------------*/
/* Flash Boot */
/*-----------------------------------------------------------------------*/
#ifdef FLASH_BOOT_ADDRESS
static unsigned int check_image_in_flash(unsigned int base_address)
{
uint32_t length;
uint32_t crc;
uint32_t got_crc;
length = MMPTR(base_address);
if((length < 32) || (length > 16*1024*1024)) {
printf("Error: Invalid image length 0x%08x\n", length);
return 0;
}
crc = MMPTR(base_address + 4);
got_crc = crc32((unsigned char *)(base_address + 8), length);
if(crc != got_crc) {
printf("CRC failed (expected %08x, got %08x)\n", crc, got_crc);
return 0;
}
return length;
}
#if defined(MAIN_RAM_BASE) && defined(FLASH_BOOT_ADDRESS)
static int copy_image_from_flash_to_ram(unsigned int flash_address, unsigned long ram_address)
{
uint32_t length;
uint32_t offset;
length = check_image_in_flash(flash_address);
if(length > 0) {
printf("Copying 0x%08x to 0x%08x (%d bytes)...\n", flash_address, ram_address, length);
offset = 0;
//init_progression_bar(length);
while (length > 0) {
uint32_t chunk_length;
chunk_length = min(length, 0x8000); /* 32KB chunks */
memcpy((void *) ram_address + offset, (void*) flash_address + offset + 8, chunk_length);
offset += chunk_length;
length -= chunk_length;
//show_progress(offset);
}
//show_progress(offset);
//printf("\n");
return 1;
}
return 0;
}
#endif
void flashboot(void)
{
uint32_t length;
uint32_t result;
printf("Booting from flash...\n");
length = check_image_in_flash(FLASH_BOOT_ADDRESS);
if(!length)
return;
#ifdef MAIN_RAM_BASE
/* When Main RAM is available, copy the code from the Flash and execute it
from Main RAM since faster */
result = copy_image_from_flash_to_ram(FLASH_BOOT_ADDRESS, MAIN_RAM_BASE);
if(!result)
return;
boot(0, 0, 0, MAIN_RAM_BASE);
#else
/* When Main RAM is not available, execute the code directly from Flash (XIP).
The code starts after (a) length and (b) CRC -- both uint32_t */
boot(0, 0, 0, (FLASH_BOOT_ADDRESS + 2 * sizeof(uint32_t)));
#endif
}
#endif
/*-----------------------------------------------------------------------*/
/* SDCard Boot */
/*-----------------------------------------------------------------------*/
#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE)
static int copy_file_from_sdcard_to_ram(const char * filename, unsigned long ram_address)
{
FRESULT fr;
FATFS fs;
FIL file;
uint32_t br;
uint32_t offset;
uint32_t length;
fr = f_mount(&fs, "", 1);
if (fr != FR_OK)
return 0;
fr = f_open(&file, filename, FA_READ);
if (fr != FR_OK) {
printf("%s file not found.\n", filename);
f_mount(0, "", 0);
return 0;
}
length = f_size(&file);
printf("Copying %s to 0x%08x (%d bytes)...\n", filename, ram_address, length);
init_progression_bar(length);
offset = 0;
for (;;) {
fr = f_read(&file, (void*) ram_address + offset, 0x8000, &br);
if (fr != FR_OK) {
printf("file read error.\n");
f_close(&file);
f_mount(0, "", 0);
return 0;
}
if (br == 0)
break;
offset += br;
show_progress(offset);
}
show_progress(offset);
printf("\n");
f_close(&file);
f_mount(0, "", 0);
return 1;
}
static void sdcardboot_from_json(const char * filename)
{
FRESULT fr;
FATFS fs;
FIL file;
uint8_t i;
uint8_t count;
uint32_t length;
uint32_t result;
/* FIXME: modify/increase if too limiting */
char json_buffer[1024];
char json_name[32];
char json_value[32];
unsigned long boot_r1 = 0;
unsigned long boot_r2 = 0;
unsigned long boot_r3 = 0;
unsigned long boot_addr = 0;
uint8_t image_found = 0;
uint8_t boot_addr_found = 0;
/* Read JSON file */
fr = f_mount(&fs, "", 1);
if (fr != FR_OK)
return;
fr = f_open(&file, filename, FA_READ);
if (fr != FR_OK) {
printf("%s file not found.\n", filename);
f_mount(0, "", 0);
return;
}
fr = f_read(&file, json_buffer, sizeof(json_buffer), &length);
/* Close JSON file */
f_close(&file);
f_mount(0, "", 0);
/* Parse JSON file */
jsmntok_t t[32];
jsmn_parser p;
jsmn_init(&p);
count = jsmn_parse(&p, json_buffer, strlen(json_buffer), t, sizeof(t)/sizeof(*t));
for (i=0; i<count-1; i++) {
memset(json_name, 0, sizeof(json_name));
memset(json_value, 0, sizeof(json_value));
/* Elements are JSON strings with 1 children */
if ((t[i].type == JSMN_STRING) && (t[i].size == 1)) {
/* Get Element's filename */
memcpy(json_name, json_buffer + t[i].start, t[i].end - t[i].start);
/* Get Element's address */
memcpy(json_value, json_buffer + t[i+1].start, t[i+1].end - t[i+1].start);
/* Skip bootargs (optional) */
if (strncmp(json_name, "bootargs", 8) == 0) {
continue;
}
/* Get boot addr (optional) */
else if (strncmp(json_name, "addr", 4) == 0) {
boot_addr = strtoul(json_value, NULL, 0);
boot_addr_found = 1;
}
/* Get boot r1 (optional) */
else if (strncmp(json_name, "r1", 2) == 0) {
memcpy(json_name, json_buffer + t[i].start, t[i].end - t[i].start);
boot_r1 = strtoul(json_value, NULL, 0);
}
/* Get boot r2 (optional) */
else if (strncmp(json_name, "r2", 2) == 0) {
boot_r2 = strtoul(json_value, NULL, 0);
}
/* Get boot r3 (optional) */
else if (strncmp(json_name, "r3", 2) == 0) {
boot_r3 = strtoul(json_value, NULL, 0);
/* Copy Image from SDCard to address */
} else {
result = copy_file_from_sdcard_to_ram(json_name, strtoul(json_value, NULL, 0));
if (result == 0)
return;
image_found = 1;
if (boot_addr_found == 0) /* Boot to last Image address if no bootargs.addr specified */
boot_addr = strtoul(json_value, NULL, 0);
}
}
}
/* Boot */
if (image_found)
boot(boot_r1, boot_r2, boot_r3, boot_addr);
}
static void sdcardboot_from_bin(const char * filename)
{
uint32_t result;
result = copy_file_from_sdcard_to_ram(filename, MAIN_RAM_BASE);
if (result == 0)
return;
boot(0, 0, 0, MAIN_RAM_BASE);
}
void sdcardboot(void)
{
#ifdef CSR_SPISDCARD_BASE
printf("Booting from SDCard in SPI-Mode...\n");
#endif
#ifdef CSR_SDCORE_BASE
printf("Booting from SDCard in SD-Mode...\n");
#endif
/* Boot from boot.json */
printf("Booting from boot.json...\n");
sdcardboot_from_json("boot.json");
/* Boot from boot.bin */
printf("Booting from boot.bin...\n");
sdcardboot_from_bin("boot.bin");
/* Boot failed if we are here... */
printf("SDCard boot failed.\n");
}
#endif
#define RAM_BOOT_OPTION 1
#ifdef RAM_BOOT_OPTION
extern void doRAMboot(int ramno);
void doRAMboot(int ramno)
{
printf("Trying RAM boot [%d]...\n", ramno);
if(ramno == 2)
boot(0, 0, 0, MAIN_RAM_BASE + (MAIN_RAM_SIZE / 2));
else
boot(0, 0, 0, MAIN_RAM_BASE);
}
#endif

@ -0,0 +1,684 @@
// This file is Copyright (c) 2014-2020 Florent Kermarrec <florent@enjoy-digital.fr>
// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
// This file is Copyright (c) 2018 Ewen McNeill <ewen@naos.co.nz>
// This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
// This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
// This file is Copyright (c) 2017 Tim 'mithro' Ansell <mithro@mithis.com>
// This file is Copyright (c) 2018 William D. Jones <thor0505@comcast.net>
// License: BSD
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <console.h>
#include <uart.h>
#include <system.h>
#include <crc.h>
#include <string.h>
#include <irq.h>
#include <generated/mem.h>
#include <generated/csr.h>
#include <generated/soc.h>
#include "sfl.h"
#include "boot.h"
#include "jsmn.h"
#include <progress.h>
#include <spiflash.h>
#include <libliteeth/udp.h>
#include <libliteeth/tftp.h>
#include <liblitesdcard/spisdcard.h>
#include <liblitesdcard/sdcard.h>
#include <liblitesdcard/fat/ff.h>
/*-----------------------------------------------------------------------*/
/* Helpers */
/*-----------------------------------------------------------------------*/
#define max(x, y) (((x) > (y)) ? (x) : (y))
#define min(x, y) (((x) < (y)) ? (x) : (y))
/*-----------------------------------------------------------------------*/
/* Boot */
/*-----------------------------------------------------------------------*/
extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr);
static void __attribute__((noreturn)) boot(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr)
{
printf("Executing booted program at 0x%08x\n\n", addr);
printf("--============= \e[1mLiftoff!\e[0m ===============--\n");
uart_sync();
#ifdef CONFIG_CPU_HAS_INTERRUPT
irq_setmask(0);
irq_setie(0);
#endif
flush_cpu_icache();
flush_cpu_dcache();
#ifdef CONFIG_L2_SIZE
flush_l2_cache();
#endif
#if defined(CONFIG_CPU_TYPE_MOR1KX) && defined(CONFIG_CPU_VARIANT_LINUX)
/* Mainline Linux expects to have exception vector base address set to the
* base address of Linux kernel; it also expects to be run with an offset
* of 0x100. */
mtspr(SPR_EVBAR, addr);
addr += 0x100;
#endif
boot_helper(r1, r2, r3, addr);
while(1);
}
enum {
ACK_TIMEOUT,
ACK_CANCELLED,
ACK_OK
};
/*-----------------------------------------------------------------------*/
/* ROM Boot */
/*-----------------------------------------------------------------------*/
#ifdef ROM_BOOT_ADDRESS
/* Running the application code from ROM is the fastest way to execute code
and could be interesting when the code is small enough, on large devices
where many blockrams are available or simply when the execution speed is
critical. Defining ROM_BOOT_ADDRESS in the SoC will make the BIOS jump to
it at boot. */
void romboot(void)
{
boot(0, 0, 0, ROM_BOOT_ADDRESS);
}
#endif
/*-----------------------------------------------------------------------*/
/* Serial Boot */
/*-----------------------------------------------------------------------*/
static int check_ack(void)
{
int recognized;
static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
timer0_en_write(0);
timer0_reload_write(0);
timer0_load_write(CONFIG_CLOCK_FREQUENCY/4);
timer0_en_write(1);
timer0_update_value_write(1);
recognized = 0;
while(timer0_value_read()) {
if(uart_read_nonblock()) {
char c;
c = uart_read();
if((c == 'Q') || (c == '\e'))
return ACK_CANCELLED;
if(c == str[recognized]) {
recognized++;
if(recognized == SFL_MAGIC_LEN)
return ACK_OK;
} else {
if(c == str[0])
recognized = 1;
else
recognized = 0;
}
}
timer0_update_value_write(1);
}
return ACK_TIMEOUT;
}
static uint32_t get_uint32(unsigned char* data)
{
return ((uint32_t) data[0] << 24) |
((uint32_t) data[1] << 16) |
((uint32_t) data[2] << 8) |
(uint32_t) data[3];
}
#define MAX_FAILED 5
/* Returns 1 if other boot methods should be tried */
int serialboot(void)
{
struct sfl_frame frame;
int failed;
static const char str[SFL_MAGIC_LEN+1] = SFL_MAGIC_REQ;
const char *c;
int ack_status;
printf("Booting from serial...\n");
printf("Press Q or ESC to abort boot completely.\n");
/* Send the serialboot "magic" request to Host */
c = str;
while(*c) {
uart_write(*c);
c++;
}
ack_status = check_ack();
if(ack_status == ACK_TIMEOUT) {
printf("Timeout\n");
return 1;
}
if(ack_status == ACK_CANCELLED) {
printf("Cancelled\n");
return 0;
}
/* Assume ACK_OK */
failed = 0;
while(1) {
int i;
int actualcrc;
int goodcrc;
/* Get one Frame */
frame.payload_length = uart_read();
frame.crc[0] = uart_read();
frame.crc[1] = uart_read();
frame.cmd = uart_read();
for(i=0;i<frame.payload_length;i++)
frame.payload[i] = uart_read();
/* Check Frame CRC (if CMD has a CRC) */
if (frame.cmd != SFL_CMD_LOAD_NO_CRC) {
actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
goodcrc = crc16(&frame.cmd, frame.payload_length+1);
if(actualcrc != goodcrc) {
/* Clear out the RX buffer */
while (uart_read_nonblock()) uart_read();
failed++;
if(failed == MAX_FAILED) {
printf("Too many consecutive errors, aborting");
return 1;
}
uart_write(SFL_ACK_CRCERROR);
continue;
}
}
/* Execute Frame CMD */
switch(frame.cmd) {
case SFL_CMD_ABORT:
failed = 0;
uart_write(SFL_ACK_SUCCESS);
return 1;
case SFL_CMD_LOAD:
case SFL_CMD_LOAD_NO_CRC: {
char *writepointer;
failed = 0;
writepointer = (char *) get_uint32(&frame.payload[0]);
for(i=4;i<frame.payload_length;i++)
*(writepointer++) = frame.payload[i];
if (frame.cmd == SFL_CMD_LOAD)
uart_write(SFL_ACK_SUCCESS);
break;
}
case SFL_CMD_JUMP: {
uint32_t addr;
failed = 0;
addr = get_uint32(&frame.payload[0]);
uart_write(SFL_ACK_SUCCESS);
boot(0, 0, 0, addr);
break;
}
case SFL_CMD_FLASH: {
#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
uint32_t addr;
failed = 0;
addr = get_uint32(&frame.payload[0]);
for (i = 4; i < frame.payload_length; i++) {
/* Erase page at sector boundaries before writing */
if ((addr & (SPIFLASH_SECTOR_SIZE - 1)) == 0) {
erase_flash_sector(addr);
}
write_to_flash(addr, &frame.payload[i], 1);
addr++;
}
uart_write(SFL_ACK_SUCCESS);
#endif
break;
}
case SFL_CMD_REBOOT:
#ifdef CSR_CTRL_RESET_ADDR
uart_write(SFL_ACK_SUCCESS);
ctrl_reset_write(1);
#endif
break;
default:
failed++;
if(failed == MAX_FAILED) {
printf("Too many consecutive errors, aborting");
return 1;
}
uart_write(SFL_ACK_UNKNOWN);
break;
}
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Ethernet Boot */
/*-----------------------------------------------------------------------*/
#ifdef CSR_ETHMAC_BASE
#ifndef LOCALIP1
#define LOCALIP1 192
#define LOCALIP2 168
#define LOCALIP3 1
#define LOCALIP4 20 // KQ
#endif
#ifndef REMOTEIP1
#define REMOTEIP1 192
#define REMOTEIP2 168
#define REMOTEIP3 1
#define REMOTEIP4 11 // KQ
#endif
#ifndef TFTP_SERVER_PORT
#define TFTP_SERVER_PORT 69
#endif
static const unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
static int copy_file_from_tftp_to_ram(unsigned int ip, unsigned short server_port,
const char *filename, char *buffer)
{
int size;
printf("Copying %s to 0x%08x... ", filename, buffer);
size = tftp_get(ip, server_port, filename, buffer);
if(size > 0)
printf("(%d bytes)", size);
printf("\n");
return size;
}
static void netboot_from_json(const char * filename, unsigned int ip, unsigned short tftp_port)
{
int size;
uint8_t i;
uint8_t count;
/* FIXME: modify/increase if too limiting */
char json_buffer[1024];
char json_name[32];
char json_value[32];
unsigned long boot_r1 = 0;
unsigned long boot_r2 = 0;
unsigned long boot_r3 = 0;
unsigned long boot_addr = 0;
uint8_t image_found = 0;
uint8_t boot_addr_found = 0;
/* Read JSON file */
size = tftp_get(ip, tftp_port, filename, json_buffer);
if (size <= 0)
return;
/* Parse JSON file */
jsmntok_t t[32];
jsmn_parser p;
jsmn_init(&p);
count = jsmn_parse(&p, json_buffer, strlen(json_buffer), t, sizeof(t)/sizeof(*t));
for (i=0; i<count-1; i++) {
memset(json_name, 0, sizeof(json_name));
memset(json_value, 0, sizeof(json_value));
/* Elements are JSON strings with 1 children */
if ((t[i].type == JSMN_STRING) && (t[i].size == 1)) {
/* Get Element's filename */
memcpy(json_name, json_buffer + t[i].start, t[i].end - t[i].start);
/* Get Element's address */
memcpy(json_value, json_buffer + t[i+1].start, t[i+1].end - t[i+1].start);
/* Skip bootargs (optional) */
if (strncmp(json_name, "bootargs", 8) == 0) {
continue;
}
/* Get boot addr (optional) */
else if (strncmp(json_name, "addr", 4) == 0) {
boot_addr = strtoul(json_value, NULL, 0);
boot_addr_found = 1;
}
/* Get boot r1 (optional) */
else if (strncmp(json_name, "r1", 2) == 0) {
memcpy(json_name, json_buffer + t[i].start, t[i].end - t[i].start);
boot_r1 = strtoul(json_value, NULL, 0);
}
/* Get boot r2 (optional) */
else if (strncmp(json_name, "r2", 2) == 0) {
boot_r2 = strtoul(json_value, NULL, 0);
}
/* Get boot r3 (optional) */
else if (strncmp(json_name, "r3", 2) == 0) {
boot_r3 = strtoul(json_value, NULL, 0);
/* Copy Image from Network to address */
} else {
size = copy_file_from_tftp_to_ram(ip, tftp_port, json_name, (void *)strtoul(json_value, NULL, 0));
if (size <= 0)
return;
image_found = 1;
if (boot_addr_found == 0) /* Boot to last Image address if no bootargs.addr specified */
boot_addr = strtoul(json_value, NULL, 0);
}
}
}
/* Boot */
if (image_found)
boot(boot_r1, boot_r2, boot_r3, boot_addr);
}
static void netboot_from_bin(const char * filename, unsigned int ip, unsigned short tftp_port)
{
int size;