From f95fb273f145a42d5e7d4ec3008a4f1fdb8f1901 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 28 Feb 2018 16:46:23 +0000 Subject: [PATCH] firmware: Sayma RTM FPGA bitstream loading prototype (#813). --- artiq/firmware/libboard_artiq/lib.rs | 3 +- artiq/firmware/libboard_artiq/rtm_fpga.rs | 46 +++++++++++++++++++++++ artiq/firmware/runtime/main.rs | 12 ++++-- artiq/frontend/artiq_flash.py | 30 +++++++++++---- 4 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/rtm_fpga.rs diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 127a55db8..a0f1a5c8a 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -1,4 +1,3 @@ -#![feature(asm, lang_items)] #![no_std] #[macro_use] @@ -25,3 +24,5 @@ mod ad9154_reg; pub mod ad9154; #[cfg(has_allaki_atts)] pub mod hmc542; +#[cfg(has_rtm_fpga_cfg)] +pub mod rtm_fpga; diff --git a/artiq/firmware/libboard_artiq/rtm_fpga.rs b/artiq/firmware/libboard_artiq/rtm_fpga.rs new file mode 100644 index 000000000..88fc6730e --- /dev/null +++ b/artiq/firmware/libboard_artiq/rtm_fpga.rs @@ -0,0 +1,46 @@ +use core::slice; +use board::csr::rtm_fpga_cfg; +use board::clock; + +const ADDR: *const u8 = 0x150000 as *const u8; + +pub fn program_bitstream() -> Result<(), ()> { + unsafe { + let length = *(ADDR as *const usize); + let bitstream = slice::from_raw_parts(ADDR.offset(4) as *const u32, length / 4); + + debug!("resetting"); + + rtm_fpga_cfg::divisor_write(15); + rtm_fpga_cfg::program_write(1); + clock::spin_us(1000); + rtm_fpga_cfg::program_write(0); + clock::spin_us(1000); + + while rtm_fpga_cfg::error_read() != 0 {} + + debug!("programming"); + + for word in bitstream { + rtm_fpga_cfg::data_write(*word); + rtm_fpga_cfg::start_write(1); + while rtm_fpga_cfg::busy_read() == 1 {} + } + + debug!("finishing"); + + loop { + if rtm_fpga_cfg::error_read() != 0 { + error!("programming error"); + + return Err(()) + } + + if rtm_fpga_cfg::done_read() != 0 { + debug!("done"); + + return Ok(()) + } + } + } +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 21d0edf85..6b6765195 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -49,11 +49,20 @@ mod moninj; mod analyzer; fn startup() { + log::set_max_level(log::LevelFilter::TRACE); + logger_artiq::BufferLogger::with(|logger| + logger.set_uart_log_level(log::LevelFilter::TRACE)); + board::clock::init(); info!("ARTIQ runtime starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); info!("gateware version {}", board::ident::read(&mut [0; 64])); + #[cfg(has_rtm_fpga_cfg)] + board_artiq::rtm_fpga::program_bitstream().expect("cannot program RTM FPGA"); + #[cfg(has_serwb_phy_amc)] + board_artiq::serwb::wait_init(); + match config::read_str("log_level", |r| r.map(|s| s.parse())) { Ok(Ok(log_level_filter)) => { info!("log level set to {} by `log_level` config key", @@ -72,9 +81,6 @@ fn startup() { _ => info!("UART log level set to INFO by default") } - #[cfg(has_serwb_phy_amc)] - board_artiq::serwb::wait_init(); - let t = board::clock::get_ms(); info!("press 'e' to erase startup and idle kernels..."); while board::clock::get_ms() < t + 1000 { diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index ee5c93994..33b627236 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -6,6 +6,7 @@ import subprocess import tempfile import shutil import re +import io import atexit from functools import partial from collections import defaultdict @@ -278,6 +279,7 @@ def main(): "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), "firmware": ("spi1", 0x050000), + "rtm_gateware": ("spi1", 0x150000), }, }[args.target] @@ -309,18 +311,30 @@ def main(): else: return os.path.join(args.srcbuild, *path_filename) + def convert_gateware(bit_filename, prefix_size=False): + bin_io = io.BytesIO() + with open(bit_filename, "rb") as bit_file: + bit2bin(bit_file, bin_io) + bin_data = bin_io.getvalue() + + bin_handle, bin_filename = tempfile.mkstemp( + prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) + with open(bin_handle, "wb") as bin_file: + if prefix_size: + bin_file.write(len(bin_data).to_bytes(4, byteorder="big")) + bin_file.write(bin_data) + atexit.register(lambda: os.unlink(bin_filename)) + return bin_filename + try: for action in args.action: if action == "gateware": - gateware_bin = artifact_path(variant, "gateware", "top.bin") - if not os.access(gateware_bin, os.R_OK): - bin_handle, gateware_bin = tempfile.mkstemp() - gateware_bit = artifact_path(variant, "gateware", "top.bit") - with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: - bit2bin(bit_file, bin_file) - atexit.register(lambda: os.unlink(gateware_bin)) - + gateware_bin = convert_gateware(artifact_path(variant, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) + + if args.target == "sayma": + rtm_gateware_bin = convert_gateware(artifact_path("rtm_gateware", "top.bit")) + programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin)