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)",
|
"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]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["runtime", "libksupport"]
|
members = ["runtime", "libksupport", "satman"]
|
||||||
|
|
|
@ -104,7 +104,7 @@ pub unsafe extern fn rust_main() {
|
||||||
BufferLogger::new(&mut LOG_BUFFER[..])
|
BufferLogger::new(&mut LOG_BUFFER[..])
|
||||||
.register(move || {
|
.register(move || {
|
||||||
board::clock::init();
|
board::clock::init();
|
||||||
info!("booting ARTIQ");
|
info!("ARTIQ runtime starting...");
|
||||||
info!("software version {}", GIT_COMMIT);
|
info!("software version {}", GIT_COMMIT);
|
||||||
info!("gateware version {}", board::ident(&mut [0; 64]));
|
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 argparse
|
||||||
|
import os
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.build.generic_platform 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.transceiver import gtx_7series
|
||||||
from artiq.gateware.drtio import DRTIOSatellite
|
from artiq.gateware.drtio import DRTIOSatellite
|
||||||
from artiq import __version__ as artiq_version
|
from artiq import __version__ as artiq_version
|
||||||
|
from artiq import __artiq_dir__ as artiq_dir
|
||||||
|
|
||||||
|
|
||||||
# TODO: parameters for sawg_3g
|
# TODO: parameters for sawg_3g
|
||||||
|
@ -215,6 +217,8 @@ def main():
|
||||||
|
|
||||||
soc = Satellite(args.config, args.medium, **soc_kc705_argdict(args))
|
soc = Satellite(args.config, args.medium, **soc_kc705_argdict(args))
|
||||||
builder = Builder(soc, **builder_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()
|
builder.build()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue