From d7cb4963e16a78f756509fea8ee1f51da54c4fee Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 Dec 2017 19:14:41 +0000 Subject: [PATCH] firmware: prepare config block for access from BIOS/bootloader. * remove liballoc dependency from mod config, * move mod config to libboard, * move config sector immediately after BIOS sector. --- artiq/firmware/Cargo.lock | 1 + artiq/firmware/libboard/Cargo.toml | 3 +- .../firmware/{runtime => libboard}/config.rs | 63 ++++++------ artiq/firmware/libboard/lib.rs | 6 +- artiq/firmware/libboard/spiflash.rs | 99 +++++++++---------- artiq/firmware/runtime/lib.rs | 3 +- artiq/firmware/runtime/rtio_mgt.rs | 3 +- artiq/firmware/runtime/runtime.ld | 9 -- artiq/firmware/runtime/session.rs | 4 +- artiq/frontend/artiq_flash.py | 31 +++--- conda/artiq-dev/meta.yaml | 2 +- 11 files changed, 105 insertions(+), 119 deletions(-) rename artiq/firmware/{runtime => libboard}/config.rs (82%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 0fcaac872..36a5db4e9 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -28,6 +28,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_artiq 0.0.0", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index 825c9cf81..c9eb425fc 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -12,8 +12,9 @@ path = "lib.rs" build_artiq = { path = "../libbuild_artiq" } [dependencies] +bitflags = "1.0" +byteorder = { version = "1.0", default-features = false } log = { version = "0.3", default-features = false } -bitflags = { version = "1.0" } [features] uart_console = [] diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/libboard/config.rs similarity index 82% rename from artiq/firmware/runtime/config.rs rename to artiq/firmware/libboard/config.rs index fd3c14efe..5c673da5b 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/libboard/config.rs @@ -1,14 +1,17 @@ #[cfg(has_spiflash)] mod imp { use core::str; - use std::btree_map::BTreeMap; use byteorder::{ByteOrder, BigEndian}; - use board::{cache, spiflash}; + use cache; + use spiflash; + + // One flash sector immediately after the bootloader. + const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::PAGE_SIZE; + const SIZE: usize = spiflash::PAGE_SIZE; mod lock { use core::slice; use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; - use board; static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT; @@ -24,22 +27,7 @@ mod imp { } pub fn data(&self) -> &'static [u8] { - extern { - static _ftext: u8; - static _fstorage: u8; - static _estorage: u8; - } - - unsafe { - let base = &_ftext as *const _ as usize; - let begin = &_fstorage as *const _ as usize; - let end = &_estorage as *const _ as usize; - - let ptr = board::mem::FLASH_BOOT_ADDRESS + (begin - base); - let len = end - begin; - - slice::from_raw_parts(ptr as *const u8, len) - } + unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) } } } @@ -52,6 +40,7 @@ mod imp { use self::lock::Lock; + #[derive(Clone)] struct Iter<'a> { data: &'a [u8], offset: usize @@ -140,28 +129,39 @@ mod imp { spiflash::write(data.as_ptr() as usize, value); data = &data[value.len()..]; + cache::flush_l2_cache(); + Ok(data) } fn compact() -> Result<(), ()> { let lock = Lock::take()?; - let mut items = BTreeMap::new(); - { - let mut iter = Iter::new(lock.data()); - while let Some(result) = iter.next() { - let (key, value) = result?; - items.insert(key, value); - } - } + static mut OLD_DATA: [u8; SIZE] = [0; SIZE]; + let old_data = unsafe { + OLD_DATA.copy_from_slice(lock.data()); + &OLD_DATA[..] + }; let mut data = lock.data(); - spiflash::erase_sector(data.as_ptr() as usize); - for (key, value) in items { + unsafe { spiflash::erase_sector(data.as_ptr() as usize) }; + + // This is worst-case quadratic, but we're limited by a small SPI flash sector size, + // so it does not really matter. + let mut iter = Iter::new(old_data); + while let Some(result) = iter.next() { + let (key, mut value) = result?; + + let mut next_iter = iter.clone(); + while let Some(next_result) = next_iter.next() { + let (next_key, next_value) = next_result?; + if key == next_key { + value = next_value + } + } data = unsafe { append_at(data, key, value)? }; } - cache::flush_l2_cache(); Ok(()) } @@ -178,7 +178,6 @@ mod imp { unsafe { append_at(free, key.as_bytes(), value)? }; - cache::flush_l2_cache(); Ok(()) } @@ -200,7 +199,7 @@ mod imp { pub fn erase() -> Result<(), ()> { let lock = Lock::take()?; - spiflash::erase_sector(lock.data().as_ptr() as usize); + unsafe { spiflash::erase_sector(lock.data().as_ptr() as usize) }; cache::flush_l2_cache(); Ok(()) diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index d25a54d80..b25e98837 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -1,10 +1,11 @@ #![feature(asm, lang_items)] #![no_std] -#[macro_use] -extern crate log; #[macro_use] extern crate bitflags; +extern crate byteorder; +#[macro_use] +extern crate log; use core::{cmp, ptr, str}; @@ -21,6 +22,7 @@ pub mod uart_console; #[cfg(has_spiflash)] pub mod spiflash; +pub mod config; pub mod i2c; pub mod spi; diff --git a/artiq/firmware/libboard/spiflash.rs b/artiq/firmware/libboard/spiflash.rs index 26c5cbbc6..643a2160c 100644 --- a/artiq/firmware/libboard/spiflash.rs +++ b/artiq/firmware/libboard/spiflash.rs @@ -3,6 +3,10 @@ use core::cmp; use csr; +pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; + +const PAGE_MASK: usize = PAGE_SIZE - 1; + const CMD_PP: u8 = 0x02; const CMD_WRDI: u8 = 0x04; const CMD_RDSR: u8 = 0x05; @@ -15,28 +19,24 @@ const PIN_DQ_I: u8 = 1 << 3; const SR_WIP: u8 = 1; -fn write_byte(mut byte: u8) { - unsafe { - csr::spiflash::bitbang_write(0); - for _ in 0..8 { - csr::spiflash::bitbang_write((byte & 0x80) >> 7); - csr::spiflash::bitbang_write((byte & 0x80) >> 7 | PIN_CLK); - byte <<= 1; - } - csr::spiflash::bitbang_write(0); +unsafe fn write_byte(mut byte: u8) { + csr::spiflash::bitbang_write(0); + for _ in 0..8 { + csr::spiflash::bitbang_write((byte & 0x80) >> 7); + csr::spiflash::bitbang_write((byte & 0x80) >> 7 | PIN_CLK); + byte <<= 1; } + csr::spiflash::bitbang_write(0); } -fn write_addr(mut addr: usize) { - unsafe { - csr::spiflash::bitbang_write(0); - for _ in 0..24 { - csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8); - csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8 | PIN_CLK); - addr <<= 1; - } - csr::spiflash::bitbang_write(0); +unsafe fn write_addr(mut addr: usize) { + csr::spiflash::bitbang_write(0); + for _ in 0..24 { + csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8); + csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8 | PIN_CLK); + addr <<= 1; } + csr::spiflash::bitbang_write(0); } fn wait_until_ready() { @@ -59,54 +59,47 @@ fn wait_until_ready() { } } -pub fn erase_sector(addr: usize) { - unsafe { - let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1); +pub unsafe fn erase_sector(addr: usize) { + let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1); - csr::spiflash::bitbang_en_write(1); + csr::spiflash::bitbang_en_write(1); - wait_until_ready(); + wait_until_ready(); - write_byte(CMD_WREN); - csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_WREN); + csr::spiflash::bitbang_write(PIN_CS_N); - write_byte(CMD_SE); - write_addr(sector_addr); - csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_SE); + write_addr(sector_addr); + csr::spiflash::bitbang_write(PIN_CS_N); - wait_until_ready(); + wait_until_ready(); - csr::spiflash::bitbang_en_write(0); - } + csr::spiflash::bitbang_en_write(0); } -fn write_page(addr: usize, data: &[u8]) { - unsafe { - csr::spiflash::bitbang_en_write(1); +unsafe fn write_page(addr: usize, data: &[u8]) { + csr::spiflash::bitbang_en_write(1); - wait_until_ready(); + wait_until_ready(); - write_byte(CMD_WREN); - csr::spiflash::bitbang_write(PIN_CS_N); - write_byte(CMD_PP); - write_addr(addr); - for &byte in data { - write_byte(byte) - } - - csr::spiflash::bitbang_write(PIN_CS_N); - csr::spiflash::bitbang_write(0); - - wait_until_ready(); - - csr::spiflash::bitbang_en_write(0); + write_byte(CMD_WREN); + csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_PP); + write_addr(addr); + for &byte in data { + write_byte(byte) } + + csr::spiflash::bitbang_write(PIN_CS_N); + csr::spiflash::bitbang_write(0); + + wait_until_ready(); + + csr::spiflash::bitbang_en_write(0); } -const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; -const PAGE_MASK: usize = PAGE_SIZE - 1; - -pub fn write(mut addr: usize, mut data: &[u8]) { +pub unsafe fn write(mut addr: usize, mut data: &[u8]) { if addr & PAGE_MASK != 0 { let size = cmp::min((PAGE_SIZE - (addr & PAGE_MASK)) as usize, data.len()); write_page(addr, &data[..size]); diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index c30c6c8d5..2723ebb9c 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -23,10 +23,11 @@ extern crate amp; extern crate drtioaux; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; + +use board::config; use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; use amp::{mailbox, rpc_queue}; -mod config; #[cfg(has_ethmac)] mod ethmac; #[cfg(has_rtio_core)] diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 9fd924936..35083315c 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,5 +1,4 @@ -use config; -use board::csr; +use board::{csr, config}; use sched::Io; #[cfg(has_rtio_crg)] diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index d629e4ff8..1d21c61fb 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -66,15 +66,6 @@ SECTIONS _edata = .; } > runtime - .storage : - { - /* Keep in sync with artiq_flash.py */ - . = _ftext + 0x100000; - _fstorage = .; - . += /*SPIFLASH_SECTOR_SIZE*/ 0x10000; - _estorage = .; - } > runtime - .bss : { . = ALIGN(4); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 349ba782f..dd1fe3fde 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -8,8 +8,8 @@ use byteorder::{ByteOrder, NetworkEndian}; use urc::Urc; use sched::{ThreadHandle, Io}; use sched::{TcpListener, TcpStream}; -use board; -use {config, mailbox, rpc_queue, kernel}; +use board::{self, config}; +use {mailbox, rpc_queue, kernel}; #[cfg(has_rtio_core)] use rtio_mgt; use rtio_dma::Manager as DmaManager; diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 4e7e85eb3..112340428 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -20,9 +20,9 @@ Valid actions: * proxy: load the flash proxy gateware bitstream * gateware: write gateware bitstream to flash - * bios: write bios to flash - * runtime: write runtime to flash + * bootloader: write bootloader to flash * storage: write storage image to flash + * runtime: write runtime to flash * load: load gateware bitstream into device (volatile but fast) * start: trigger the target to (re)load its gateware bitstream from flash @@ -48,7 +48,7 @@ Prerequisites: parser.add_argument("--srcbuild", help="look for bitstream, BIOS and runtime in this " "ARTIQ source build tree") parser.add_argument("action", metavar="ACTION", nargs="*", - default="proxy gateware bios runtime start".split(), + default="proxy gateware bootloader runtime start".split(), help="actions to perform, default: %(default)s") return parser @@ -188,25 +188,24 @@ def main(): parser = get_argparser() opts = parser.parse_args() - storage_at = 0x100000 # Keep in sync with runtime.ld config = { "kc705": { "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), "proxy_bitfile": "bscan_spi_xc7k325t.bit", "variants": ["nist_clock", "nist_qc2"], - "gateware": (0, 0x000000), - "bios": (0, 0xaf0000), - "runtime": (0, 0xb00000), - "storage": (0, 0xb00000 + storage_at), + "gateware": (0, 0x000000), + "bootloader": (0, 0xaf0000), + "storage": (0, 0xb00000), + "runtime": (0, 0xb10000), }, "sayma": { "programmer_factory": ProgrammerSayma, "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", "variants": ["standalone"], - "gateware": (0, 0x000000), - "bios": (1, 0x000000), - "runtime": (1, 0x010000), - "storage": (1, 0x010000 + storage_at), + "gateware": (0, 0x000000), + "bootloader": (1, 0x000000), + "storage": (1, 0x010000), + "runtime": (1, 0x020000), }, }[opts.target] @@ -256,20 +255,20 @@ def main(): bit2bin(f, g) conv = True programmer.flash_binary(*config["gateware"], bin) - elif action == "bios": + elif action == "bootloader": if opts.srcbuild is None: path = bin_dir else: path = os.path.join(opts.srcbuild, "software", "bios") - programmer.flash_binary(*config["bios"], os.path.join(path, "bios.bin")) + programmer.flash_binary(*config["bootloader"], os.path.join(path, "bios.bin")) + elif action == "storage": + programmer.flash_binary(*config["storage"], opts.storage) elif action == "runtime": if opts.srcbuild is None: path = bin_dir else: path = os.path.join(opts.srcbuild, "software", "runtime") programmer.flash_binary(*config["runtime"], os.path.join(path, "runtime.fbi")) - elif action == "storage": - programmer.flash_binary(*config["storage"], opts.storage) elif action == "load": if opts.srcbuild is None: path = bin_dir diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index a00d82173..23f86a710 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_30+gitd95f4edb + - misoc 0.8.dev py35_35+git6845fc0a - jesd204b 0.4 - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1