From acd13837ffdc72626be7b32310839e2d07aafd6e Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 13:17:49 +0000 Subject: [PATCH] firmware: implement the new bootloader. --- artiq/firmware/Cargo.lock | 33 +++ artiq/firmware/Cargo.toml | 2 +- artiq/firmware/bootloader/Cargo.toml | 19 ++ artiq/firmware/bootloader/Makefile | 18 ++ artiq/firmware/bootloader/bootloader.ld | 46 +++ artiq/firmware/bootloader/build.rs | 5 + artiq/firmware/bootloader/main.rs | 171 +++++++++++ artiq/firmware/libboard/lib.rs | 1 + .../{libboard_artiq => libboard/or1k}/boot.rs | 32 ++- artiq/firmware/libboard/or1k/mod.rs | 1 + artiq/firmware/libboard/sdram.rs | 271 ++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 - artiq/firmware/runtime/main.rs | 8 +- artiq/firmware/runtime/mgmt.rs | 6 +- artiq/frontend/artiq_flash.py | 4 +- artiq/gateware/amp/soc.py | 8 +- conda/artiq-kc705-nist_clock/build.sh | 2 +- conda/artiq-kc705-nist_qc2/build.sh | 2 +- conda/artiq-sayma_amc-standalone/build.sh | 2 +- 19 files changed, 604 insertions(+), 29 deletions(-) create mode 100644 artiq/firmware/bootloader/Cargo.toml create mode 100644 artiq/firmware/bootloader/Makefile create mode 100644 artiq/firmware/bootloader/bootloader.ld create mode 100644 artiq/firmware/bootloader/build.rs create mode 100644 artiq/firmware/bootloader/main.rs rename artiq/firmware/{libboard_artiq => libboard/or1k}/boot.rs (59%) create mode 100644 artiq/firmware/libboard/sdram.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 794b0e2d3..a3a9dfd79 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -42,6 +42,17 @@ dependencies = [ "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]] name = "build_artiq" version = "0.0.0" @@ -49,6 +60,11 @@ dependencies = [ "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]] name = "build_misoc" version = "0.0.0" @@ -77,6 +93,14 @@ name = "compiler_builtins" version = "0.1.0" 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]] name = "cslice" version = "0.3.0" @@ -175,6 +199,11 @@ dependencies = [ "std_artiq 0.0.0", ] +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "runtime" version = "0.0.0" @@ -220,6 +249,7 @@ dependencies = [ "board 0.0.0", "board_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)", "drtioaux 0.0.0", "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] "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 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)" = "" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" +"checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "" "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)" = "" "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_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)" = "" +"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 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)" = "" diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index af13ba5ff..0f2007873 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["runtime", "ksupport", "satman"] +members = ["bootloader", "runtime", "ksupport", "satman"] diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml new file mode 100644 index 000000000..26521a87e --- /dev/null +++ b/artiq/firmware/bootloader/Cargo.toml @@ -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"] } diff --git a/artiq/firmware/bootloader/Makefile b/artiq/firmware/bootloader/Makefile new file mode 100644 index 000000000..f247c0994 --- /dev/null +++ b/artiq/firmware/bootloader/Makefile @@ -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) $@ diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld new file mode 100644 index 000000000..8fe809a49 --- /dev/null +++ b/artiq/firmware/bootloader/bootloader.ld @@ -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 +} diff --git a/artiq/firmware/bootloader/build.rs b/artiq/firmware/bootloader/build.rs new file mode 100644 index 000000000..3548ea5ff --- /dev/null +++ b/artiq/firmware/bootloader/build.rs @@ -0,0 +1,5 @@ +extern crate build_misoc; + +fn main() { + build_misoc::cfg(); +} diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs new file mode 100644 index 000000000..61ae7a48d --- /dev/null +++ b/artiq/firmware/bootloader/main.rs @@ -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 {} +} diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 9eb6bd31e..27de0b9e1 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -12,6 +12,7 @@ pub use arch::*; include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs")); +pub mod sdram; pub mod ident; pub mod clock; pub mod uart; diff --git a/artiq/firmware/libboard_artiq/boot.rs b/artiq/firmware/libboard/or1k/boot.rs similarity index 59% rename from artiq/firmware/libboard_artiq/boot.rs rename to artiq/firmware/libboard/or1k/boot.rs index 803a094a6..51a368e6e 100644 --- a/artiq/firmware/libboard_artiq/boot.rs +++ b/artiq/firmware/libboard/or1k/boot.rs @@ -1,18 +1,26 @@ -use board::irq; +use super::{irq, cache}; -pub unsafe fn reboot() -> ! { +pub unsafe fn reset() -> ! { irq::set_ie(false); - #[cfg(target_arch="or1k")] asm!(r#" - l.j _reset_handler - l.nop + l.j _reset_handler + l.nop "# : : : : "volatile"); 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); - #[cfg(target_arch="or1k")] asm!(r#" # This loop overwrites itself, but it's structured in such a way # 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 0: l.sfnei r5, 0 l.bf 1f - l.nop + l.nop l.jr r7 - l.nop + l.nop 1: l.lwz r6, 0(r3) l.sw 0(r4), r6 l.addi r3, r3, 4 l.addi r4, r4, 4 l.addi r5, r5, -4 l.bf 0b - l.nop + l.nop "# : - : "{r3}"(new_code.as_ptr() as usize), - "{r5}"(new_code.len()) + : "{r3}"(firmware.as_ptr() as usize), + "{r5}"(firmware.len()) : : "volatile"); loop {} diff --git a/artiq/firmware/libboard/or1k/mod.rs b/artiq/firmware/libboard/or1k/mod.rs index 01589ddc8..52a619d1b 100644 --- a/artiq/firmware/libboard/or1k/mod.rs +++ b/artiq/firmware/libboard/or1k/mod.rs @@ -1,3 +1,4 @@ pub mod spr; pub mod irq; pub mod cache; +pub mod boot; diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs new file mode 100644 index 000000000..fbedacff2 --- /dev/null +++ b/artiq/firmware/libboard/sdram.rs @@ -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 +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index c40f899c3..3307681b3 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -23,5 +23,3 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; - -pub mod boot; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 0cb4e6a58..d5e9462f5 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -244,12 +244,12 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 println!("{:#08x}", ip); }); - if config::read_str("panic_reboot", |r| r == Ok("1")) { - println!("rebooting..."); - unsafe { board_artiq::boot::reboot() } + if config::read_str("panic_reset", |r| r == Ok("1")) { + println!("restarting..."); + unsafe { board::boot::reset() } } else { 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 {} } } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 23898f0f3..2933102f5 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,4 +1,4 @@ -use board_artiq::boot; +use board::boot; use std::io::{self, Read, Write}; use log::LogLevelFilter; use logger_artiq::BufferLogger; @@ -92,8 +92,8 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { Request::Reboot => { Reply::RebootImminent.write_to(stream)?; stream.close()?; - warn!("rebooting"); - unsafe { boot::reboot() } + warn!("restarting"); + unsafe { boot::reset() } } }; } diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 112340428..72d5fd11e 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -259,8 +259,8 @@ def main(): if opts.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "software", "bios") - programmer.flash_binary(*config["bootloader"], os.path.join(path, "bios.bin")) + path = os.path.join(opts.srcbuild, "software", "bootloader") + programmer.flash_binary(*config["bootloader"], os.path.join(path, "bootloader.bin")) elif action == "storage": programmer.flash_binary(*config["storage"], opts.storage) elif action == "runtime": diff --git a/artiq/gateware/amp/soc.py b/artiq/gateware/amp/soc.py index d237822eb..1761fb72c 100644 --- a/artiq/gateware/amp/soc.py +++ b/artiq/gateware/amp/soc.py @@ -45,11 +45,15 @@ class AMPSoC: def build_artiq_soc(soc, argdict): + firmware_dir = os.path.join(artiq_dir, "firmware") builder = Builder(soc, **argdict) + builder.software_packages = [] builder.add_software_package("libm") + builder.add_software_package("libprintf") builder.add_software_package("libunwind") - builder.add_software_package("ksupport", os.path.join(artiq_dir, "firmware", "ksupport")) - builder.add_software_package("runtime", os.path.join(artiq_dir, "firmware", "runtime")) + builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) + builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport")) + builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime")) try: builder.build() except subprocess.CalledProcessError as e: diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh index 880719a42..e81da80f7 100644 --- a/conda/artiq-kc705-nist_clock/build.sh +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX 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/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 diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh index 403045dfa..a36df210d 100644 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ b/conda/artiq-kc705-nist_qc2/build.sh @@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX 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/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 diff --git a/conda/artiq-sayma_amc-standalone/build.sh b/conda/artiq-sayma_amc-standalone/build.sh index f256da963..512e14ad0 100644 --- a/conda/artiq-sayma_amc-standalone/build.sh +++ b/conda/artiq-sayma_amc-standalone/build.sh @@ -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 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