forked from M-Labs/artiq
firmware: implement the new bootloader.
This commit is contained in:
parent
b9754e7108
commit
acd13837ff
|
@ -42,6 +42,17 @@ dependencies = [
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bootloader"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"board 0.0.0",
|
||||||
|
"build_misoc 0.0.0",
|
||||||
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)",
|
||||||
|
"rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "build_artiq"
|
name = "build_artiq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -49,6 +60,11 @@ dependencies = [
|
||||||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "build_const"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "build_misoc"
|
name = "build_misoc"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -77,6 +93,14 @@ name = "compiler_builtins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc"
|
source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "git+git://github.com/whitequark/crc-rs?rev=51cd356#51cd3560aa9d3823061f2bb46797d8c61f4cfa9e"
|
||||||
|
dependencies = [
|
||||||
|
"build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cslice"
|
name = "cslice"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -175,6 +199,11 @@ dependencies = [
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rlibc"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "runtime"
|
name = "runtime"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -220,6 +249,7 @@ dependencies = [
|
||||||
"board 0.0.0",
|
"board 0.0.0",
|
||||||
"board_artiq 0.0.0",
|
"board_artiq 0.0.0",
|
||||||
"build_artiq 0.0.0",
|
"build_artiq 0.0.0",
|
||||||
|
"build_misoc 0.0.0",
|
||||||
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
||||||
"drtioaux 0.0.0",
|
"drtioaux 0.0.0",
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -263,10 +293,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||||
|
"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9"
|
||||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||||
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
|
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
|
||||||
"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "<none>"
|
"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "<none>"
|
||||||
"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "<none>"
|
"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "<none>"
|
||||||
|
"checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "<none>"
|
||||||
"checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
"checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
||||||
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "<none>"
|
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "<none>"
|
||||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||||
|
@ -275,6 +307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||||
"checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493"
|
"checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493"
|
||||||
"checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "<none>"
|
"checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "<none>"
|
||||||
|
"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe"
|
||||||
"checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704"
|
"checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704"
|
||||||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||||
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "<none>"
|
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "<none>"
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["runtime", "ksupport", "satman"]
|
members = ["bootloader", "runtime", "ksupport", "satman"]
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
name = "bootloader"
|
||||||
|
version = "0.0.0"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "bootloader"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
path = "main.rs"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
build_misoc = { path = "../libbuild_misoc" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rlibc = "1.0"
|
||||||
|
byteorder = { version = "1.0", default-features = false }
|
||||||
|
crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false }
|
||||||
|
board = { path = "../libboard", features = ["uart_console"] }
|
|
@ -0,0 +1,18 @@
|
||||||
|
include ../include/generated/variables.mak
|
||||||
|
include $(MISOC_DIRECTORY)/software/common.mak
|
||||||
|
|
||||||
|
RUSTFLAGS += -Cpanic=abort
|
||||||
|
|
||||||
|
all:: bootloader.bin
|
||||||
|
|
||||||
|
.PHONY: $(RUSTOUT)/libbootloader.a
|
||||||
|
$(RUSTOUT)/libbootloader.a:
|
||||||
|
$(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml -- \
|
||||||
|
-Clto
|
||||||
|
|
||||||
|
bootloader.elf: $(RUSTOUT)/libbootloader.a
|
||||||
|
$(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld
|
||||||
|
|
||||||
|
%.bin: %.elf
|
||||||
|
$(objcopy) -O binary
|
||||||
|
$(MSCIMG) $@
|
|
@ -0,0 +1,46 @@
|
||||||
|
INCLUDE generated/output_format.ld
|
||||||
|
INCLUDE generated/regions.ld
|
||||||
|
ENTRY(_reset_handler)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.vectors :
|
||||||
|
{
|
||||||
|
_begin = .;
|
||||||
|
*(.vectors)
|
||||||
|
} > rom
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text .text.*)
|
||||||
|
} > rom
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_end = .;
|
||||||
|
} > rom
|
||||||
|
|
||||||
|
.crc ALIGN(4) :
|
||||||
|
{
|
||||||
|
_crc = .;
|
||||||
|
. += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss ALIGN(4) :
|
||||||
|
{
|
||||||
|
_fbss = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
} > sram
|
||||||
|
|
||||||
|
.stack :
|
||||||
|
{
|
||||||
|
/* Ensure we have a certain amount of space available for stack. */
|
||||||
|
. = ORIGIN(sram) + LENGTH(sram) - 0x800;
|
||||||
|
. = ORIGIN(sram) + LENGTH(sram) - 4;
|
||||||
|
_fstack = .;
|
||||||
|
} > sram
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
extern crate build_misoc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
build_misoc::cfg();
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(lang_items)]
|
||||||
|
|
||||||
|
extern crate rlibc;
|
||||||
|
extern crate crc;
|
||||||
|
extern crate byteorder;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate board;
|
||||||
|
|
||||||
|
use core::{ptr, slice};
|
||||||
|
use crc::crc32;
|
||||||
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
|
use board::{boot, cache};
|
||||||
|
use board::uart_console::Console;
|
||||||
|
|
||||||
|
fn check_integrity() -> bool {
|
||||||
|
extern {
|
||||||
|
static _begin: u8;
|
||||||
|
static _end: u8;
|
||||||
|
static _crc: u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let length = &_end as *const u8 as usize -
|
||||||
|
&_begin as *const u8 as usize;
|
||||||
|
let bootloader = slice::from_raw_parts(&_begin as *const u8, length);
|
||||||
|
crc32::checksum_ieee(bootloader) == _crc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool {
|
||||||
|
const MEMORY: *mut u32 = board::mem::MAIN_RAM_BASE as *mut u32;
|
||||||
|
|
||||||
|
*total = 0;
|
||||||
|
*wrong = 0;
|
||||||
|
|
||||||
|
macro_rules! test {
|
||||||
|
(
|
||||||
|
$prepare:stmt;
|
||||||
|
for $i:ident in ($range:expr) {
|
||||||
|
MEMORY[$index:expr] = $data:expr
|
||||||
|
}
|
||||||
|
) => ({
|
||||||
|
$prepare;
|
||||||
|
for $i in $range {
|
||||||
|
ptr::write_volatile(MEMORY.offset($index as isize), $data);
|
||||||
|
*total += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache::flush_cpu_dcache();
|
||||||
|
cache::flush_l2_cache();
|
||||||
|
|
||||||
|
$prepare;
|
||||||
|
for $i in $range {
|
||||||
|
if ptr::read_volatile(MEMORY.offset($index as isize)) != $data {
|
||||||
|
*wrong += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prng32(seed: &mut u32) -> u32 { *seed = 1664525 * *seed + 1013904223; *seed }
|
||||||
|
fn prng16(seed: &mut u16) -> u16 { *seed = 25173 * *seed + 13849; *seed }
|
||||||
|
|
||||||
|
// Test data bus
|
||||||
|
test!((); for i in (0..0x100) { MEMORY[i] = 0xAAAAAAAA });
|
||||||
|
test!((); for i in (0..0x100) { MEMORY[i] = 0x55555555 });
|
||||||
|
|
||||||
|
// Test counter addressing with random data
|
||||||
|
test!(let mut seed = 0;
|
||||||
|
for i in (0..0x100000) { MEMORY[i] = prng32(&mut seed) });
|
||||||
|
|
||||||
|
// Test random addressing with counter data
|
||||||
|
test!(let mut seed = 0;
|
||||||
|
for i in (0..0x10000) { MEMORY[prng16(&mut seed)] = i });
|
||||||
|
|
||||||
|
*wrong == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn startup() -> bool {
|
||||||
|
if check_integrity() {
|
||||||
|
println!("Bootloader CRC passed");
|
||||||
|
} else {
|
||||||
|
println!("Bootloader CRC failed");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Initializing SDRAM...");
|
||||||
|
|
||||||
|
if unsafe { board::sdram::init(Some(&mut Console)) } {
|
||||||
|
println!("SDRAM initialized");
|
||||||
|
} else {
|
||||||
|
println!("SDRAM initialization failed");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut total, mut wrong) = (0, 0);
|
||||||
|
if unsafe { memory_test(&mut total, &mut wrong) } {
|
||||||
|
println!("Memory test passed");
|
||||||
|
} else {
|
||||||
|
println!("Memory test failed ({}/{} words incorrect)", wrong, total);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn flash_boot() {
|
||||||
|
const FIRMWARE: *mut u8 = board::mem::FLASH_BOOT_ADDRESS as *mut u8;
|
||||||
|
const MAIN_RAM: *mut u8 = board::mem::MAIN_RAM_BASE as *mut u8;
|
||||||
|
|
||||||
|
println!("Booting from flash...");
|
||||||
|
|
||||||
|
let header = slice::from_raw_parts(FIRMWARE, 8);
|
||||||
|
let length = BigEndian::read_u32(&header[0..]) as usize;
|
||||||
|
let expected_crc = BigEndian::read_u32(&header[4..]);
|
||||||
|
|
||||||
|
if length == 0xffffffff {
|
||||||
|
println!("No firmware present");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let firmware_in_flash = slice::from_raw_parts(FIRMWARE.offset(8), length);
|
||||||
|
let actual_crc = crc32::checksum_ieee(firmware_in_flash);
|
||||||
|
|
||||||
|
if actual_crc == expected_crc {
|
||||||
|
let firmware_in_sdram = slice::from_raw_parts_mut(MAIN_RAM, length);
|
||||||
|
firmware_in_sdram.copy_from_slice(firmware_in_flash);
|
||||||
|
|
||||||
|
println!("Starting firmware.");
|
||||||
|
boot::jump(MAIN_RAM as usize);
|
||||||
|
} else {
|
||||||
|
println!("Firmware CRC failed (actual {:08x}, expected {:08x}",
|
||||||
|
actual_crc, expected_crc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn main() -> i32 {
|
||||||
|
println!("");
|
||||||
|
println!(r" __ __ _ ____ ____ ");
|
||||||
|
println!(r"| \/ (_) ___| ___ / ___|");
|
||||||
|
println!(r"| |\/| | \___ \ / _ \| | ");
|
||||||
|
println!(r"| | | | |___) | (_) | |___ ");
|
||||||
|
println!(r"|_| |_|_|____/ \___/ \____|");
|
||||||
|
println!("");
|
||||||
|
println!("MiSoC Bootloader");
|
||||||
|
println!("Copyright (c) 2017 M-Labs Limited");
|
||||||
|
println!("");
|
||||||
|
|
||||||
|
if startup() {
|
||||||
|
println!("");
|
||||||
|
unsafe { flash_boot() };
|
||||||
|
} else {
|
||||||
|
println!("Halting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
||||||
|
panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[lang = "panic_fmt"]
|
||||||
|
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||||
|
println!("panic at {}:{}: {}", file, line, args);
|
||||||
|
loop {}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ pub use arch::*;
|
||||||
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs"));
|
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs"));
|
||||||
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs"));
|
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs"));
|
||||||
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs"));
|
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs"));
|
||||||
|
pub mod sdram;
|
||||||
pub mod ident;
|
pub mod ident;
|
||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod uart;
|
pub mod uart;
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
use board::irq;
|
use super::{irq, cache};
|
||||||
|
|
||||||
pub unsafe fn reboot() -> ! {
|
pub unsafe fn reset() -> ! {
|
||||||
irq::set_ie(false);
|
irq::set_ie(false);
|
||||||
#[cfg(target_arch="or1k")]
|
|
||||||
asm!(r#"
|
asm!(r#"
|
||||||
l.j _reset_handler
|
l.j _reset_handler
|
||||||
l.nop
|
l.nop
|
||||||
"# : : : : "volatile");
|
"# : : : : "volatile");
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn hotswap(new_code: &[u8]) -> ! {
|
pub unsafe fn jump(addr: usize) -> ! {
|
||||||
|
irq::set_ie(false);
|
||||||
|
cache::flush_cpu_icache();
|
||||||
|
asm!(r#"
|
||||||
|
l.jr $0
|
||||||
|
l.nop
|
||||||
|
"# : : "r"(addr) : : "volatile");
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn hotswap(firmware: &[u8]) -> ! {
|
||||||
irq::set_ie(false);
|
irq::set_ie(false);
|
||||||
#[cfg(target_arch="or1k")]
|
|
||||||
asm!(r#"
|
asm!(r#"
|
||||||
# This loop overwrites itself, but it's structured in such a way
|
# This loop overwrites itself, but it's structured in such a way
|
||||||
# that before that happens, it loads itself into I$$ fully.
|
# that before that happens, it loads itself into I$$ fully.
|
||||||
|
@ -21,20 +29,20 @@ pub unsafe fn hotswap(new_code: &[u8]) -> ! {
|
||||||
l.or r7, r4, r0
|
l.or r7, r4, r0
|
||||||
0: l.sfnei r5, 0
|
0: l.sfnei r5, 0
|
||||||
l.bf 1f
|
l.bf 1f
|
||||||
l.nop
|
l.nop
|
||||||
l.jr r7
|
l.jr r7
|
||||||
l.nop
|
l.nop
|
||||||
1: l.lwz r6, 0(r3)
|
1: l.lwz r6, 0(r3)
|
||||||
l.sw 0(r4), r6
|
l.sw 0(r4), r6
|
||||||
l.addi r3, r3, 4
|
l.addi r3, r3, 4
|
||||||
l.addi r4, r4, 4
|
l.addi r4, r4, 4
|
||||||
l.addi r5, r5, -4
|
l.addi r5, r5, -4
|
||||||
l.bf 0b
|
l.bf 0b
|
||||||
l.nop
|
l.nop
|
||||||
"#
|
"#
|
||||||
:
|
:
|
||||||
: "{r3}"(new_code.as_ptr() as usize),
|
: "{r3}"(firmware.as_ptr() as usize),
|
||||||
"{r5}"(new_code.len())
|
"{r5}"(firmware.len())
|
||||||
:
|
:
|
||||||
: "volatile");
|
: "volatile");
|
||||||
loop {}
|
loop {}
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod spr;
|
pub mod spr;
|
||||||
pub mod irq;
|
pub mod irq;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
pub mod boot;
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
#[cfg(has_ddrphy)]
|
||||||
|
mod ddr {
|
||||||
|
use core::{ptr, fmt};
|
||||||
|
use core::cell::Cell;
|
||||||
|
use csr::{dfii, ddrphy};
|
||||||
|
use sdram_phy::{self, spin_cycles};
|
||||||
|
use sdram_phy::{DFII_COMMAND_CS, DFII_COMMAND_WE, DFII_COMMAND_CAS, DFII_COMMAND_RAS,
|
||||||
|
DFII_COMMAND_WRDATA, DFII_COMMAND_RDDATA};
|
||||||
|
use sdram_phy::{DFII_NPHASES, DFII_PIX_DATA_SIZE, DFII_PIX_WRDATA_ADDR, DFII_PIX_RDDATA_ADDR};
|
||||||
|
|
||||||
|
unsafe fn enable_write_leveling(enabled: bool) {
|
||||||
|
dfii::pi0_address_write(sdram_phy::DDR3_MR1 as u16 | ((enabled as u16) << 7));
|
||||||
|
dfii::pi0_baddress_write(1);
|
||||||
|
sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
|
||||||
|
ddrphy::wlevel_en_write(enabled as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(kusddrphy)]
|
||||||
|
const DDRPHY_MAX_DELAY: u16 = 512;
|
||||||
|
#[cfg(not(kusddrphy))]
|
||||||
|
const DDRPHY_MAX_DELAY: u16 = 32;
|
||||||
|
|
||||||
|
const DQS_SIGNAL_COUNT: usize = DFII_PIX_DATA_SIZE / 2;
|
||||||
|
|
||||||
|
macro_rules! log {
|
||||||
|
($logger:expr, $( $arg:expr ),+) => (
|
||||||
|
if let &mut Some(ref mut f) = $logger {
|
||||||
|
let _ = write!(f, $( $arg ),+);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_level(logger: &mut Option<&mut fmt::Write>,
|
||||||
|
delay: &mut [u16; DQS_SIGNAL_COUNT],
|
||||||
|
high_skew: &mut [bool; DQS_SIGNAL_COUNT]) -> bool {
|
||||||
|
log!(logger, "Write leveling: ");
|
||||||
|
|
||||||
|
enable_write_leveling(true);
|
||||||
|
spin_cycles(100);
|
||||||
|
|
||||||
|
let mut failed = false;
|
||||||
|
for n in 0..DQS_SIGNAL_COUNT {
|
||||||
|
let dq_addr = dfii::PI0_RDDATA_ADDR
|
||||||
|
.offset((DQS_SIGNAL_COUNT - 1 - n) as isize);
|
||||||
|
|
||||||
|
delay[n] = 0;
|
||||||
|
high_skew[n] = false;
|
||||||
|
|
||||||
|
ddrphy::dly_sel_write(1 << n);
|
||||||
|
|
||||||
|
ddrphy::wdly_dq_rst_write(1);
|
||||||
|
ddrphy::wdly_dqs_rst_write(1);
|
||||||
|
ddrphy::wlevel_strobe_write(1);
|
||||||
|
spin_cycles(10);
|
||||||
|
|
||||||
|
let mut incr_delay = || {
|
||||||
|
delay[n] += 1;
|
||||||
|
if delay[n] >= DDRPHY_MAX_DELAY {
|
||||||
|
failed = true;
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ddrphy::wdly_dq_inc_write(1);
|
||||||
|
ddrphy::wdly_dqs_inc_write(1);
|
||||||
|
ddrphy::wlevel_strobe_write(1);
|
||||||
|
spin_cycles(10);
|
||||||
|
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dq = ptr::read_volatile(dq_addr);
|
||||||
|
|
||||||
|
if dq != 0 {
|
||||||
|
// Assume this DQ group has between 1 and 2 bit times of skew.
|
||||||
|
// Bring DQS into the CK=0 zone before continuing leveling.
|
||||||
|
high_skew[n] = true;
|
||||||
|
|
||||||
|
while dq != 0 {
|
||||||
|
if !incr_delay() { break }
|
||||||
|
dq = ptr::read_volatile(dq_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while dq == 0 {
|
||||||
|
if !incr_delay() { break }
|
||||||
|
dq = ptr::read_volatile(dq_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_write_leveling(false);
|
||||||
|
|
||||||
|
for n in (0..DQS_SIGNAL_COUNT).rev() {
|
||||||
|
log!(logger, "{}{} ", delay[n], if high_skew[n] { "*" } else { "" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if !failed {
|
||||||
|
log!(logger, "done\n")
|
||||||
|
} else {
|
||||||
|
log!(logger, "failed\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
!failed
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_bitslip(logger: &mut Option<&mut fmt::Write>,
|
||||||
|
delay: &[u16; DQS_SIGNAL_COUNT],
|
||||||
|
high_skew: &[bool; DQS_SIGNAL_COUNT]) {
|
||||||
|
let threshold_opt = delay.iter().zip(high_skew.iter())
|
||||||
|
.filter_map(|(&delay, &high_skew)|
|
||||||
|
if high_skew { Some(delay) } else { None })
|
||||||
|
.min()
|
||||||
|
.map(|threshold| threshold / 2);
|
||||||
|
|
||||||
|
if let Some(threshold) = threshold_opt {
|
||||||
|
log!(logger, "Read bitslip: ");
|
||||||
|
|
||||||
|
for n in (0..DQS_SIGNAL_COUNT).rev() {
|
||||||
|
if delay[n] > threshold {
|
||||||
|
ddrphy::dly_sel_write(1 << n);
|
||||||
|
|
||||||
|
#[cfg(kusddrphy)]
|
||||||
|
ddrphy::rdly_dq_bitslip_write(1);
|
||||||
|
#[cfg(not(kusddrphy))]
|
||||||
|
for _ in 0..3 {
|
||||||
|
ddrphy::rdly_dq_bitslip_write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
log!(logger, "{} ", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log!(logger, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read_delays(logger: &mut Option<&mut fmt::Write>) {
|
||||||
|
log!(logger, "Read delays: ");
|
||||||
|
|
||||||
|
// Generate pseudo-random sequence
|
||||||
|
let mut prs = [0; DFII_NPHASES * DFII_PIX_DATA_SIZE];
|
||||||
|
let mut prv = 42;
|
||||||
|
for b in prs.iter_mut() {
|
||||||
|
prv = 1664525 * prv + 1013904223;
|
||||||
|
*b = prv as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate
|
||||||
|
dfii::pi0_address_write(0);
|
||||||
|
dfii::pi0_baddress_write(0);
|
||||||
|
sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
|
||||||
|
spin_cycles(15);
|
||||||
|
|
||||||
|
// Write test pattern
|
||||||
|
for p in 0..DFII_NPHASES {
|
||||||
|
for offset in 0..DFII_PIX_DATA_SIZE {
|
||||||
|
let addr = DFII_PIX_WRDATA_ADDR[p].offset(offset as isize);
|
||||||
|
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
||||||
|
ptr::write_volatile(addr, data as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sdram_phy::dfii_piwr_address_write(0);
|
||||||
|
sdram_phy::dfii_piwr_baddress_write(0);
|
||||||
|
sdram_phy::command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|
|
||||||
|
DFII_COMMAND_WRDATA);
|
||||||
|
|
||||||
|
// Calibrate each DQ in turn
|
||||||
|
sdram_phy::dfii_pird_address_write(0);
|
||||||
|
sdram_phy::dfii_pird_baddress_write(0);
|
||||||
|
for n in 0..DQS_SIGNAL_COUNT {
|
||||||
|
ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1));
|
||||||
|
|
||||||
|
ddrphy::rdly_dq_rst_write(1);
|
||||||
|
|
||||||
|
let delay = Cell::new(0);
|
||||||
|
let incr_delay_until = |expected| {
|
||||||
|
while delay.get() < DDRPHY_MAX_DELAY {
|
||||||
|
sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|
|
||||||
|
DFII_COMMAND_RDDATA);
|
||||||
|
spin_cycles(15);
|
||||||
|
|
||||||
|
let mut working = true;
|
||||||
|
for p in 0..DFII_NPHASES {
|
||||||
|
for &offset in [n, n + DQS_SIGNAL_COUNT].iter() {
|
||||||
|
let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize);
|
||||||
|
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
||||||
|
if ptr::read_volatile(addr) as u8 != data {
|
||||||
|
working = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if working == expected {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
delay.set(delay.get() + 1);
|
||||||
|
ddrphy::rdly_dq_inc_write(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find smallest working delay
|
||||||
|
incr_delay_until(true);
|
||||||
|
let min_delay = delay.get();
|
||||||
|
|
||||||
|
// Get a bit further into the working zone
|
||||||
|
#[cfg(kusddrphy)]
|
||||||
|
for _ in 0..8 {
|
||||||
|
delay.set(delay.get() + 1);
|
||||||
|
ddrphy::rdly_dq_inc_write(1);
|
||||||
|
}
|
||||||
|
#[cfg(not(kusddrphy))]
|
||||||
|
{
|
||||||
|
delay.set(delay.get() + 1);
|
||||||
|
ddrphy::rdly_dq_inc_write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find largest working delay
|
||||||
|
incr_delay_until(false);
|
||||||
|
let max_delay = delay.get();
|
||||||
|
|
||||||
|
log!(logger, "{}:{:02}-{:02} ", DQS_SIGNAL_COUNT - n - 1,
|
||||||
|
min_delay, max_delay);
|
||||||
|
|
||||||
|
// Set delay to the middle
|
||||||
|
ddrphy::rdly_dq_rst_write(1);
|
||||||
|
for _ in 0..(min_delay + max_delay) / 2 {
|
||||||
|
ddrphy::rdly_dq_inc_write(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precharge
|
||||||
|
dfii::pi0_address_write(0);
|
||||||
|
dfii::pi0_baddress_write(0);
|
||||||
|
sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
|
||||||
|
spin_cycles(15);
|
||||||
|
|
||||||
|
log!(logger, "done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn level(logger: &mut Option<&mut fmt::Write>) -> bool {
|
||||||
|
let mut delay = [0; DQS_SIGNAL_COUNT];
|
||||||
|
let mut high_skew = [false; DQS_SIGNAL_COUNT];
|
||||||
|
|
||||||
|
if !write_level(logger, &mut delay, &mut high_skew) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
read_bitslip(logger, &delay, &high_skew);
|
||||||
|
read_delays(logger);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use csr;
|
||||||
|
use sdram_phy;
|
||||||
|
|
||||||
|
pub unsafe fn init(mut _logger: Option<&mut fmt::Write>) -> bool {
|
||||||
|
sdram_phy::initialize();
|
||||||
|
|
||||||
|
#[cfg(has_ddrphy)]
|
||||||
|
{
|
||||||
|
if !ddr::level(&mut _logger) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
csr::dfii::control_write(sdram_phy::DFII_CONTROL_SEL);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
|
@ -23,5 +23,3 @@ pub mod hmc830_7043;
|
||||||
mod ad9154_reg;
|
mod ad9154_reg;
|
||||||
#[cfg(has_ad9154)]
|
#[cfg(has_ad9154)]
|
||||||
pub mod ad9154;
|
pub mod ad9154;
|
||||||
|
|
||||||
pub mod boot;
|
|
||||||
|
|
|
@ -244,12 +244,12 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3
|
||||||
println!("{:#08x}", ip);
|
println!("{:#08x}", ip);
|
||||||
});
|
});
|
||||||
|
|
||||||
if config::read_str("panic_reboot", |r| r == Ok("1")) {
|
if config::read_str("panic_reset", |r| r == Ok("1")) {
|
||||||
println!("rebooting...");
|
println!("restarting...");
|
||||||
unsafe { board_artiq::boot::reboot() }
|
unsafe { board::boot::reset() }
|
||||||
} else {
|
} else {
|
||||||
println!("halting.");
|
println!("halting.");
|
||||||
println!("use `artiq_coreconfig write -s panic_reboot 1` to reboot instead");
|
println!("use `artiq_coreconfig write -s panic_reset 1` to restart instead");
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use board_artiq::boot;
|
use board::boot;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use log::LogLevelFilter;
|
use log::LogLevelFilter;
|
||||||
use logger_artiq::BufferLogger;
|
use logger_artiq::BufferLogger;
|
||||||
|
@ -92,8 +92,8 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> {
|
||||||
Request::Reboot => {
|
Request::Reboot => {
|
||||||
Reply::RebootImminent.write_to(stream)?;
|
Reply::RebootImminent.write_to(stream)?;
|
||||||
stream.close()?;
|
stream.close()?;
|
||||||
warn!("rebooting");
|
warn!("restarting");
|
||||||
unsafe { boot::reboot() }
|
unsafe { boot::reset() }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,8 +259,8 @@ def main():
|
||||||
if opts.srcbuild is None:
|
if opts.srcbuild is None:
|
||||||
path = bin_dir
|
path = bin_dir
|
||||||
else:
|
else:
|
||||||
path = os.path.join(opts.srcbuild, "software", "bios")
|
path = os.path.join(opts.srcbuild, "software", "bootloader")
|
||||||
programmer.flash_binary(*config["bootloader"], os.path.join(path, "bios.bin"))
|
programmer.flash_binary(*config["bootloader"], os.path.join(path, "bootloader.bin"))
|
||||||
elif action == "storage":
|
elif action == "storage":
|
||||||
programmer.flash_binary(*config["storage"], opts.storage)
|
programmer.flash_binary(*config["storage"], opts.storage)
|
||||||
elif action == "runtime":
|
elif action == "runtime":
|
||||||
|
|
|
@ -45,11 +45,15 @@ class AMPSoC:
|
||||||
|
|
||||||
|
|
||||||
def build_artiq_soc(soc, argdict):
|
def build_artiq_soc(soc, argdict):
|
||||||
|
firmware_dir = os.path.join(artiq_dir, "firmware")
|
||||||
builder = Builder(soc, **argdict)
|
builder = Builder(soc, **argdict)
|
||||||
|
builder.software_packages = []
|
||||||
builder.add_software_package("libm")
|
builder.add_software_package("libm")
|
||||||
|
builder.add_software_package("libprintf")
|
||||||
builder.add_software_package("libunwind")
|
builder.add_software_package("libunwind")
|
||||||
builder.add_software_package("ksupport", os.path.join(artiq_dir, "firmware", "ksupport"))
|
builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader"))
|
||||||
builder.add_software_package("runtime", os.path.join(artiq_dir, "firmware", "runtime"))
|
builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport"))
|
||||||
|
builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime"))
|
||||||
try:
|
try:
|
||||||
builder.build()
|
builder.build()
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
|
|
|
@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX
|
||||||
|
|
||||||
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock
|
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock
|
||||||
cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX
|
cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX
|
||||||
cp misoc_nist_clock_kc705/software/bios/bios.bin $SOC_PREFIX
|
cp misoc_nist_clock_kc705/software/bootloader/bootloader.bin $SOC_PREFIX
|
||||||
cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
||||||
|
|
|
@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX
|
||||||
|
|
||||||
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2
|
V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2
|
||||||
cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX
|
cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX
|
||||||
cp misoc_nist_qc2_kc705/software/bios/bios.bin $SOC_PREFIX
|
cp misoc_nist_qc2_kc705/software/bootloader/bootloader.bin $SOC_PREFIX
|
||||||
cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
||||||
|
|
|
@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX
|
||||||
|
|
||||||
V=1 $PYTHON -m artiq.gateware.targets.sayma_amc_standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv
|
V=1 $PYTHON -m artiq.gateware.targets.sayma_amc_standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv
|
||||||
cp misoc_standalone_sayma_amc/gateware/top.bit $SOC_PREFIX
|
cp misoc_standalone_sayma_amc/gateware/top.bit $SOC_PREFIX
|
||||||
cp misoc_standalone_sayma_amc/software/bios/bios.bin $SOC_PREFIX
|
cp misoc_standalone_sayma_amc/software/bootloader/bootloader.bin $SOC_PREFIX
|
||||||
cp misoc_standalone_sayma_amc/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
cp misoc_standalone_sayma_amc/software/runtime/runtime.{elf,fbi} $SOC_PREFIX
|
||||||
|
|
Loading…
Reference in New Issue