forked from M-Labs/artiq
firmware: add satellite manager
The code duplication with the runtime should be cleaned up later.
This commit is contained in:
parent
62274a6c0d
commit
ce31ffddb0
|
@ -91,6 +91,18 @@ dependencies = [
|
|||
"walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "satman"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc_artiq 0.0.0",
|
||||
"board 0.0.0",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"std_artiq 0.0.0",
|
||||
"walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "1.0.3"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["runtime", "libksupport"]
|
||||
members = ["runtime", "libksupport", "satman"]
|
||||
|
|
|
@ -104,7 +104,7 @@ pub unsafe extern fn rust_main() {
|
|||
BufferLogger::new(&mut LOG_BUFFER[..])
|
||||
.register(move || {
|
||||
board::clock::init();
|
||||
info!("booting ARTIQ");
|
||||
info!("ARTIQ runtime starting...");
|
||||
info!("software version {}", GIT_COMMIT);
|
||||
info!("gateware version {}", board::ident(&mut [0; 64]));
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
authors = ["M-Labs"]
|
||||
name = "satman"
|
||||
version = "0.0.0"
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
walkdir = "1.0"
|
||||
|
||||
[lib]
|
||||
name = "satman"
|
||||
crate-type = ["staticlib"]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
alloc_artiq = { path = "../liballoc_artiq" }
|
||||
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
|
||||
board = { path = "../libboard" }
|
||||
log = { version = "0.3", default-features = false }
|
||||
log_buffer = { version = "1.0" }
|
|
@ -0,0 +1,49 @@
|
|||
include ../include/generated/variables.mak
|
||||
include $(MISOC_DIRECTORY)/software/common.mak
|
||||
|
||||
PYTHON ?= python3.5
|
||||
|
||||
OBJECTS := main.o
|
||||
|
||||
RUSTOUT := cargo/or1k-unknown-none/debug
|
||||
|
||||
CFLAGS += -I$(LIBALLOC_DIRECTORY)
|
||||
|
||||
LDFLAGS += --gc-sections \
|
||||
-L../libcompiler-rt \
|
||||
-L../libbase \
|
||||
-L../liballoc
|
||||
|
||||
all: satman.bin satman.fbi
|
||||
|
||||
.PHONY: $(RUSTOUT)/libsatman.a
|
||||
$(RUSTOUT)/libsatman.a:
|
||||
RUSTFLAGS="-C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s -Cpanic=abort" \
|
||||
CARGO_TARGET_DIR=$(realpath .)/cargo \
|
||||
cargo build --target=or1k-unknown-none \
|
||||
--manifest-path $(realpath $(SATMAN_DIRECTORY))/Cargo.toml
|
||||
|
||||
satman.elf: $(OBJECTS) $(RUSTOUT)/libsatman.a
|
||||
$(LD) $(LDFLAGS) \
|
||||
-T $(SATMAN_DIRECTORY)/satman.ld \
|
||||
-o $@ \
|
||||
$^ \
|
||||
-lbase-nofloat -lcompiler-rt -lalloc
|
||||
@chmod -x $@
|
||||
|
||||
%.o: $(SATMAN_DIRECTORY)/%.c
|
||||
$(compile)
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
@chmod -x $@
|
||||
|
||||
%.fbi: %.bin
|
||||
@echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJECTS)
|
||||
$(RM) satman.elf satman.bin satman.fbi .*~ *~
|
||||
$(RM) -rf cargo
|
||||
|
||||
.PHONY: all clean
|
|
@ -0,0 +1,53 @@
|
|||
extern crate walkdir;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{Write, BufRead, BufReader};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("BUILDINC_DIRECTORY").unwrap();
|
||||
let cfg_path = Path::new(&out_dir).join("generated").join("rust-cfg");
|
||||
println!("cargo:rerun-if-changed={}", cfg_path.to_str().unwrap());
|
||||
|
||||
let f = BufReader::new(File::open(&cfg_path).unwrap());
|
||||
for line in f.lines() {
|
||||
println!("cargo:rustc-cfg={}", line.unwrap());
|
||||
}
|
||||
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let dest_path = Path::new(&out_dir).join("git_info.rs");
|
||||
let mut f = File::create(&dest_path).unwrap();
|
||||
|
||||
let id = git_describe().unwrap();
|
||||
let id = id.split("-").collect::<Vec<_>>();
|
||||
let id = format!("{}+{}.{}", id[0], id[1], id[2]);
|
||||
writeln!(f, "const GIT_COMMIT: &'static str = {:?};", id).unwrap();
|
||||
|
||||
println!("cargo:rerun-if-changed=../../../.git/HEAD");
|
||||
for entry in WalkDir::new("../../../.git/refs") {
|
||||
let entry = entry.unwrap();
|
||||
println!("cargo:rerun-if-changed={}", entry.path().display());
|
||||
}
|
||||
}
|
||||
|
||||
// Returns `None` if git is not available.
|
||||
fn git_describe() -> Option<String> {
|
||||
Command::new("git")
|
||||
.arg("describe")
|
||||
.arg("--tags")
|
||||
.arg("--dirty")
|
||||
.arg("--always")
|
||||
.arg("--long")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||
.map(|mut s| {
|
||||
let len = s.trim_right().len();
|
||||
s.truncate(len);
|
||||
s
|
||||
})
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#![no_std]
|
||||
#![feature(libc, const_fn, repr_simd, asm, lang_items)]
|
||||
|
||||
extern crate alloc_artiq;
|
||||
#[macro_use]
|
||||
extern crate std_artiq as std;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate log_buffer;
|
||||
extern crate board;
|
||||
|
||||
use core::fmt::Write;
|
||||
use logger::BufferLogger;
|
||||
|
||||
extern {
|
||||
fn putchar(c: libc::c_int) -> libc::c_int;
|
||||
fn readchar() -> libc::c_char;
|
||||
fn readchar_nonblock() -> libc::c_int;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => ($crate::print_fmt(format_args!($($arg)*)));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
||||
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
||||
}
|
||||
|
||||
pub struct Console;
|
||||
|
||||
impl core::fmt::Write for Console {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
||||
for c in s.bytes() { unsafe { putchar(c as i32); } }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_fmt(args: self::core::fmt::Arguments) {
|
||||
let _ = Console.write_fmt(args);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[lang = "panic_fmt"]
|
||||
pub extern fn panic_fmt(args: self::core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||
let _ = write!(Console, "panic at {}:{}: {}\n", file, line, args);
|
||||
let _ = write!(Console, "waiting for debugger...\n");
|
||||
unsafe {
|
||||
let _ = readchar();
|
||||
loop { asm!("l.trap 0") }
|
||||
}
|
||||
}
|
||||
|
||||
mod logger;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
|
||||
|
||||
// Allow linking with crates that are built as -Cpanic=unwind even if we use -Cpanic=abort.
|
||||
// This is never called.
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _Unwind_Resume() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn rust_main() {
|
||||
static mut LOG_BUFFER: [u8; 65536] = [0; 65536];
|
||||
BufferLogger::new(&mut LOG_BUFFER[..])
|
||||
.register(move || {
|
||||
board::clock::init();
|
||||
info!("ARTIQ satellite manager starting...");
|
||||
info!("software version {}", GIT_COMMIT);
|
||||
info!("gateware version {}", board::ident(&mut [0; 64]));
|
||||
|
||||
loop {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn isr() {
|
||||
use board::{irq, csr};
|
||||
extern { fn uart_isr(); }
|
||||
|
||||
let irqs = irq::pending() & irq::get_mask();
|
||||
if irqs & (1 << csr::UART_INTERRUPT) != 0 {
|
||||
uart_isr()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
use core::{mem, ptr};
|
||||
use core::cell::{Cell, RefCell};
|
||||
use log::{self, Log, LogLevel, LogMetadata, LogRecord, LogLevelFilter};
|
||||
use log_buffer::LogBuffer;
|
||||
use board;
|
||||
|
||||
pub struct BufferLogger {
|
||||
buffer: RefCell<LogBuffer<&'static mut [u8]>>,
|
||||
trace_to_uart: Cell<bool>
|
||||
}
|
||||
|
||||
unsafe impl Sync for BufferLogger {}
|
||||
|
||||
static mut LOGGER: *const BufferLogger = ptr::null();
|
||||
|
||||
impl BufferLogger {
|
||||
pub fn new(buffer: &'static mut [u8]) -> BufferLogger {
|
||||
BufferLogger {
|
||||
buffer: RefCell::new(LogBuffer::new(buffer)),
|
||||
trace_to_uart: Cell::new(true)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register<F: FnOnce()>(&self, f: F) {
|
||||
// log::set_logger_raw captures a pointer to ourselves, so we must prevent
|
||||
// ourselves from being moved or dropped after that function is called (and
|
||||
// before log::shutdown_logger_raw is called).
|
||||
unsafe {
|
||||
log::set_logger_raw(|max_log_level| {
|
||||
max_log_level.set(LogLevelFilter::Trace);
|
||||
self as *const Log
|
||||
}).expect("global logger can only be initialized once");
|
||||
LOGGER = self;
|
||||
}
|
||||
f();
|
||||
log::shutdown_logger_raw().unwrap();
|
||||
unsafe {
|
||||
LOGGER = ptr::null();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_instance<R, F: FnOnce(&BufferLogger) -> R>(f: F) -> R {
|
||||
f(unsafe { mem::transmute::<*const BufferLogger, &BufferLogger>(LOGGER) })
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.buffer.borrow_mut().clear()
|
||||
}
|
||||
|
||||
pub fn extract<R, F: FnOnce(&str) -> R>(&self, f: F) -> R {
|
||||
f(self.buffer.borrow_mut().extract())
|
||||
}
|
||||
|
||||
pub fn disable_trace_to_uart(&self) {
|
||||
if self.trace_to_uart.get() {
|
||||
trace!("disabling tracing to UART; all further trace messages \
|
||||
are sent to core log only");
|
||||
self.trace_to_uart.set(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Log for BufferLogger {
|
||||
fn enabled(&self, _metadata: &LogMetadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &LogRecord) {
|
||||
if self.enabled(record.metadata()) {
|
||||
use core::fmt::Write;
|
||||
writeln!(self.buffer.borrow_mut(),
|
||||
"[{:12}us] {:>5}({}): {}",
|
||||
board::clock::get_us(), record.level(), record.target(), record.args()).unwrap();
|
||||
|
||||
// Printing to UART is really slow, so avoid doing that when we have an alternative
|
||||
// route to retrieve the debug messages.
|
||||
if self.trace_to_uart.get() || record.level() <= LogLevel::Info {
|
||||
println!("[{:12}us] {:>5}({}): {}",
|
||||
board::clock::get_us(), record.level(), record.target(), record.args());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include <alloc.h>
|
||||
#include <irq.h>
|
||||
#include <uart.h>
|
||||
#include <system.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
extern void _fheap, _eheap;
|
||||
|
||||
extern void rust_main();
|
||||
|
||||
int main(void)
|
||||
{
|
||||
irq_setmask(0);
|
||||
irq_setie(1);
|
||||
uart_init();
|
||||
|
||||
alloc_give(&_fheap, &_eheap - &_fheap);
|
||||
|
||||
rust_main();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
INCLUDE generated/output_format.ld
|
||||
STARTUP(crt0-or1k.o)
|
||||
ENTRY(_start)
|
||||
|
||||
INCLUDE generated/regions.ld
|
||||
|
||||
/* Assume ORIGIN(main_ram) = 0x40000000. Unfortunately,
|
||||
* ld does not allow this expression here.
|
||||
*/
|
||||
MEMORY {
|
||||
runtime (RWX) : ORIGIN = 0x40000000, LENGTH = 0x400000 /* 4M */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_ftext = .;
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
_etext = .;
|
||||
} > runtime
|
||||
|
||||
/* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */
|
||||
.got : {
|
||||
_GLOBAL_OFFSET_TABLE_ = .;
|
||||
*(.got)
|
||||
} > runtime
|
||||
|
||||
.got.plt : {
|
||||
*(.got.plt)
|
||||
} > runtime
|
||||
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_frodata = .;
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
_erodata = .;
|
||||
} > runtime
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_fdata = .;
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
*(.data1)
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
_edata = .;
|
||||
} > runtime
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_fbss = .;
|
||||
*(.dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} > runtime
|
||||
|
||||
.stack :
|
||||
{
|
||||
. = ALIGN(0x1000);
|
||||
_estack = .;
|
||||
. += 0x4000;
|
||||
_fstack = . - 4;
|
||||
} > runtime
|
||||
|
||||
.heap :
|
||||
{
|
||||
_fheap = .;
|
||||
. = ORIGIN(runtime) + LENGTH(runtime);
|
||||
_eheap = .;
|
||||
} > runtime
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.eh_frame)
|
||||
*(.gcc_except_table)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import argparse
|
||||
import os
|
||||
|
||||
from migen import *
|
||||
from migen.build.generic_platform import *
|
||||
|
@ -14,6 +15,7 @@ from artiq.gateware.rtio.phy import ttl_simple
|
|||
from artiq.gateware.drtio.transceiver import gtx_7series
|
||||
from artiq.gateware.drtio import DRTIOSatellite
|
||||
from artiq import __version__ as artiq_version
|
||||
from artiq import __artiq_dir__ as artiq_dir
|
||||
|
||||
|
||||
# TODO: parameters for sawg_3g
|
||||
|
@ -215,6 +217,8 @@ def main():
|
|||
|
||||
soc = Satellite(args.config, args.medium, **soc_kc705_argdict(args))
|
||||
builder = Builder(soc, **builder_argdict(args))
|
||||
builder.add_software_package("liballoc")
|
||||
builder.add_software_package("satman", os.path.join(artiq_dir, "firmware", "satman"))
|
||||
builder.build()
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue