firmware: add satellite manager

The code duplication with the runtime should be cleaned up later.
This commit is contained in:
Sebastien Bourdeauducq 2017-01-18 16:50:32 -06:00
parent 62274a6c0d
commit ce31ffddb0
11 changed files with 424 additions and 2 deletions

View File

@ -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"

View File

@ -1,2 +1,2 @@
[workspace]
members = ["runtime", "libksupport"]
members = ["runtime", "libksupport", "satman"]

View File

@ -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]));

View File

@ -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" }

View File

@ -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

View File

@ -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
})
}

View File

@ -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()
}
}

View File

@ -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());
}
}
}
}

View File

@ -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;
}

View File

@ -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)
}
}

View File

@ -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()