This commit is contained in:
Jake Goulding
2019-06-16 12:26:39 -04:00
parent 2a01039391
commit 2accfc22a4
3 changed files with 268 additions and 158 deletions

View File

@@ -4,26 +4,40 @@
;;; Does not handle the region pointer!
__initialize_memory:
ldi r31, hi8(__data_load_start)
ldi r30, lo8(__data_load_start) ; Z
ldi r29, hi8(__data_load_end)
ldi r28, lo8(__data_load_end) ; Y
__initialize_memory_init_data:
ldi r30, lo8(__data_load_start)
ldi r31, hi8(__data_load_start) ; Z
ldi r24, lo8(__data_end)
ldi r25, hi8(__data_end)
ldi r26, lo8(__data_start)
ldi r27, hi8(__data_start) ; X
rjmp __initialize_memory_init_data_check
ldi r27, hi8(__data_start)
ldi r26, lo8(__data_start) ; X
__initialize_memory_init_data_copy:
lpm r18, Z+
st X+, r18
sub r28, r30
sbc r29, r31 ; Y now contains the length of bytes
rjmp check
__initialize_memory_init_data_check:
cp r26, r24
cpc r27, r25
brne __initialize_memory_init_data_copy
entrypoint:
lpm r0, Z+ ; Load from program memory, increment pointer
st X+, r0 ; Store to RAM, increment pointer
__initialize_memory_init_bss:
ldi r24, lo8(__bss_end)
ldi r25, hi8(__bss_end)
ldi r26, lo8(__data_end) ; X
ldi r27, hi8(__data_end)
ldi r18, 0x00
rjmp __initialize_memory_init_bss_check
subi r28, 1 ; Decrement the count
sbci r29, 0
__initialize_memory_init_bss_copy:
st X+, r18
check:
brne entrypoint ; Exit when all bytes copied
__initialize_memory_init_bss_check:
cp r26, r24
cpc r27, r25
brne __initialize_memory_init_bss_copy
__initialize_memory_finish:
ret

View File

@@ -6,8 +6,9 @@
/* TODO: Verify memory addresses and lengths */
MEMORY {
text (rx) : ORIGIN = 0x000000, LENGTH = 64K
data (rw!x) : ORIGIN = 0x800100, LENGTH = 0xFFA0
text (rx) : ORIGIN = 0x000000, LENGTH = 32K
registers (rw!x) : ORIGIN = 0x800000, LENGTH = 256
data (rw!x) : ORIGIN = 0x800100, LENGTH = 2K
}
SECTIONS {
@@ -34,8 +35,10 @@ SECTIONS {
/* Data not initialized to a value */
/* Even possible in Rust? */
/* Yes: zero-initialized */
.bss : AT(ADDR(.data) + SIZEOF(.data)) {
__bss_start = .;
/* Can we avoid actually copying this in? */
* (.bss*);
__bss_end = .;
} >data

View File

@@ -6,6 +6,8 @@
#![feature(async_await)]
#![feature(generators)]
#![allow(unused_imports)]
#![no_std]
#![no_main]
@@ -26,10 +28,12 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
loop {
crate::write_str("PANIC ");
if let Some(l) = info.location() {
crate::write_slice_hex(&l.line().to_le_bytes());
crate::write_str(l.file());
crate::write_str(" (");
crate::write_slice_hex(&l.line().to_be_bytes());
crate::write_str(" / ");
crate::write_slice_hex(&l.column().to_le_bytes());
// crate::write_strln(l.file());
crate::write_slice_hex(&l.column().to_be_bytes());
crate::write_str(" )");
}
crate::write_strln("");
}
@@ -41,10 +45,10 @@ pub unsafe extern "avr-interrupt" fn _ivr_timer1_compare_a() {
write_volatile(PORTB, prev_value ^ PINB5);
}
// #[no_mangle]
// pub unsafe extern "avr-interrupt" fn _ivr_usart_rx_complete() {
// fut::rx_interrupt_handler();
// }
#[no_mangle]
pub unsafe extern "avr-interrupt" fn _ivr_usart_rx_complete() {
fut::rx_interrupt_handler();
}
#[no_mangle]
pub unsafe extern "avr-interrupt" fn _ivr_usart_udr_empty() {
@@ -52,7 +56,9 @@ pub unsafe extern "avr-interrupt" fn _ivr_usart_udr_empty() {
}
const CPU_FREQUENCY_HZ: u64 = 16_000_000;
const CPU_REGISTER_BYTES: u16 = 256;
const CPU_RAM_BYTES: u16 = 2048;
const CPU_INITIAL_STACK_POINTER: u16 = CPU_REGISTER_BYTES + CPU_RAM_BYTES - 1;
const DESIRED_HZ_TIM1: f64 = 2.0;
const TIM1_PRESCALER: u64 = 1024;
@@ -66,34 +72,90 @@ const INTERRUPT_EVERY_1_HZ_1024_PRESCALER: u16 =
const BAUD: u64 = 9600;
const MYUBRR: u16 = (CPU_FREQUENCY_HZ / 16 / BAUD - 1) as u16;
extern {
#[naked]
fn __initialize_memory();
}
mod initialize {
use core::ptr::{read_volatile, write_volatile};
fn initialize_memory() {
unsafe {
__initialize_memory();
extern "C" {
#[naked]
fn __initialize_memory();
#[no_mangle]
static mut __data_start: u8;
#[no_mangle]
static mut __data_end: u8;
#[no_mangle]
static mut __data_load_start: u8;
#[no_mangle]
static mut __bss_start: u8;
#[no_mangle]
static mut __bss_end: u8;
}
#[inline(never)]
unsafe fn zero_out_bss() {
let mut bss: *mut u8 = &mut __bss_start;
let bss_end: *mut u8 = &mut __bss_end;
while bss != bss_end {
write_volatile(bss, 0);
bss = bss.offset(1);
}
}
#[inline(never)]
unsafe fn load_data() {
let mut data: *mut u8 = &mut __data_start;
let data_end: *mut u8 = &mut __data_end;
let mut data_load: *mut u8 = &mut __data_load_start;
while data != data_end {
let d;
asm! {"lpm $0, $1+"
: /* output */ "=r"(d), "=Z"(data_load)
: /* input */ "Z"(data_load)
: /* clobber */
: /* options */
};
write_volatile(data, d);
data = data.offset(1);
}
}
#[inline(never)]
pub unsafe fn memory() {
load_data();
zero_out_bss();
//__initialize_memory();
}
#[inline(never)]
#[allow(unused)]
pub fn info() -> (usize, usize) {
unsafe {
let data_len = &__data_end as *const u8 as usize - &__data_start as *const u8 as usize;
let bss_len = &__bss_end as *const u8 as usize - &__bss_start as *const u8 as usize;
(data_len, bss_len)
}
}
}
#[no_mangle]
pub extern fn main() -> ! {
without_interrupts(|| { // TODO: we know interrupts are off, don't we?
// The ABI requires that r1 starts as zero
unsafe { asm!("eor r1, r1"); }
unsafe {
write_volatile(SP, CPU_RAM_BYTES);
// The ABI requires that r1 starts as zero
asm!("eor r1, r1");
write_volatile(SP, CPU_INITIAL_STACK_POINTER);
initialize::memory();
}
initialize_memory();
unsafe {
// Configure all Port B pins as outputs
write_volatile(DDRB, 0xFF);
// Turn on all Port B pins
write_volatile(PORTB, 0xFF);
// write_volatile(PORTB, 0xFF);
}
timer1::Timer::new()
@@ -110,58 +172,68 @@ pub extern fn main() -> ! {
.configure();
});
// serial::transmit(b'A');
// write_newline();
serial::transmit(b'O');
serial::transmit(b'K');
serial::transmit(b'\r');
serial::transmit(b'\n');
// serial::receive();
// for i in 0..4 {
// let b = unsafe { *TO_HEX.get_unchecked(i) };
// serial::transmit(b);
// }
// write_newline();
// write_u8_hex(0x00);
// write_newline();
// write_u8_hex(0x05);
// write_newline();
// write_u8_hex(0x50);
// write_newline();
// write_u8_hex(0xFF);
// write_newline();
write_slice_hex(&[0x00, 0x05, 0x50, 0xFF]);
// write_newline();
// write_raw("write_raw");
// crate::write_strln("Booted");
// // Formatting code disabled in libcore
// // writeln!(SuperSerial, "writeln!").unwrap();
// // write_newline();
// serial::transmit(b'Z');
// write_newline();
use ruduino::Bit::*;
unsafe {
// Configure all Port D pins as outputs
write_volatile(DDRD, 0xFF);
// Turn off all Port D pins
write_volatile(PORTD, 0x00);
}
// PORT_D.configuration().set_all_as_output().configure();
PORT_D.data().set(0);
// exercise_serial();
fut::do_futures();
//loop {
// fn alpha(i: i32) -> i32 { i + 1 }
// static FOO: fn(i32) -> i32 = alpha;
//}
// spin_loop();
// bracketed_echo();
}
/*
#[allow(unused)]
fn exercise_serial() {
serial::transmit(b'A');
write_newline();
for i in 0..4 {
let b = unsafe { *TO_HEX.get_unchecked(i) };
serial::transmit(b);
}
write_newline();
write_u8_hex(0x00);
write_newline();
write_u8_hex(0x05);
write_newline();
write_u8_hex(0x50);
write_newline();
write_u8_hex(0xFF);
write_newline();
write_slice_hex(&[0x00, 0x05, 0x50, 0xFF]);
write_newline();
write_raw("write_raw");
// Formatting code disabled in libcore
// writeln!(SuperSerial, "writeln!").unwrap();
// write_newline();
serial::transmit(b'Z');
write_newline();
}
#[allow(unused)]
fn spin_loop() {
loop {
crate::write_strln("....loooooooooping...");
for i in b'0'..=b'9' {
serial::transmit(i);
serial::transmit(b' ');
}
serial::transmit(b'\r');
serial::transmit(b'\n');
}
}
#[allow(unused)]
fn bracketed_echo() -> ! {
loop {
if let Some(b) = serial::try_receive() {
serial::transmit(b'>');
@@ -170,10 +242,9 @@ pub extern fn main() -> ! {
}
// forever!
}
*/
}
pub static TO_HEX: &'static [u8; 16] = b"0123456789ABCDEF";
pub static TO_HEX: &[u8; 16] = b"0123456789ABCDEF";
#[inline(never)]
pub fn write_slice_hex(v: &[u8]) {
@@ -190,23 +261,32 @@ pub fn write_u8_hex(v: u8) {
let top = unsafe { *TO_HEX.get_unchecked(top_idx as usize) };
let bot = unsafe { *TO_HEX.get_unchecked(bot_idx as usize) };
// Useful for avoiding global variables
// let c = |v| match v {
// 0..=9 => b'0' + v,
// _ => v - 10 + b'A',
// };
// let top = c(top_idx);
// let bot = c(bot_idx);
serial::transmit(top);
serial::transmit(bot);
}
// #[inline(never)]
// fn write_newline() {
// serial::transmit(b'\r');
// serial::transmit(b'\n');
// }
#[inline(never)]
pub fn write_newline() {
serial::transmit(b'\r');
serial::transmit(b'\n');
}
// #[inline(never)]
// fn write_raw(s: &str) {
// for b in s.bytes() {
// serial::transmit(b);
// }
// write_newline();
// }
#[inline(never)]
fn write_raw(s: &str) {
for b in s.bytes() {
serial::transmit(b);
}
write_newline();
}
fn write_str(s: &str) {
@@ -233,7 +313,6 @@ mod fut {
use core::{pin::Pin, future::Future, task::{Context, Poll, Waker}};
use ruduino::{UCSR0B, RXCIE0, UDRIE0, serial};
use embrio_async::embrio_async;
// use embrio_executor::executor::block_on;
fn set_bit_in(register: *mut u8, bit: u8) {
use core::ptr::{read_volatile, write_volatile};
@@ -253,6 +332,18 @@ mod fut {
}
}
// Nemo157:
//
// Im pretty sure that implementation is unsound for spurious
// wakeups
//
// You could poll the future once, set the waker and enable the
// interrupt, then poll the future again and have the interrupt
// trigger during setting the waker again
//
// If the interrupt occurs mid-write to TX_WAKER then you will be
// creating an &mut Option<Waker> for .take() during that
// concurrent modification
struct Serial;
@@ -263,62 +354,62 @@ mod fut {
}
// TODO: Maybe take a slice instead?
// fn rx<'a>(&self, byte: &'a mut u8) -> SerialRx<'a> {
// SerialRx(byte)
// }
fn rx<'a>(&self, byte: &'a mut u8) -> SerialRx<'a> {
SerialRx(byte)
}
}
// struct SerialRx<'a>(&'a mut u8);
struct SerialRx<'a>(&'a mut u8);
// static mut RX_WAKER: Option<Waker> = None;
static mut RX_WAKER: Option<Waker> = None;
// #[inline(always)]
// pub fn rx_interrupt_handler() {
// // Safety:
// // We are on a single-threaded CPU, so static mutable shoudn't matter.
// unsafe {
// if let Some(waker) = RX_WAKER.take() {
// // Notify our waker to poll the future again
// waker.wake();
#[inline(always)]
pub fn rx_interrupt_handler() {
// Safety:
// We are on a single-threaded CPU, so static mutable shoudn't matter.
unsafe {
if let Some(waker) = RX_WAKER.take() {
// Notify our waker to poll the future again
waker.wake();
// // We must either read from the buffer or disable the
// // interrupt to prevent re-invoking the interrupt
// // handler immediately.
// disable_serial_rx_interrupt();
// }
// }
// }
// We must either read from the buffer or disable the
// interrupt to prevent re-invoking the interrupt
// handler immediately.
disable_serial_rx_interrupt();
}
}
}
// fn enable_serial_rx_interrupt() {
// set_bit_in(UCSR0B, RXCIE0);
// }
fn enable_serial_rx_interrupt() {
set_bit_in(UCSR0B, RXCIE0);
}
// fn disable_serial_rx_interrupt() {
// unset_bit_in(UCSR0B, RXCIE0);
// }
fn disable_serial_rx_interrupt() {
unset_bit_in(UCSR0B, RXCIE0);
}
// impl<'a> Future for SerialRx<'a> {
// type Output = ();
impl<'a> Future for SerialRx<'a> {
type Output = ();
// fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
// match serial::try_receive() {
// Some(v) => {
// *Pin::get_mut(self).0 = v;
// Poll::Ready(())
// },
// None => {
// // Safety:
// // We are on a single-threaded CPU, so static mutable shoudn't matter.
// unsafe {
// RX_WAKER = Some(ctx.waker().clone());
// }
// enable_serial_rx_interrupt();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
match serial::try_receive() {
Some(v) => {
*Pin::get_mut(self).0 = v;
Poll::Ready(())
},
None => {
// Safety:
// We are on a single-threaded CPU, so static mutable shoudn't matter.
unsafe {
RX_WAKER = Some(ctx.waker().clone());
}
enable_serial_rx_interrupt();
// Poll::Pending
// }
// }
// }
// }
Poll::Pending
}
}
}
}
struct SerialTx(u8);
@@ -333,7 +424,7 @@ mod fut {
// Notify our waker to poll the future again
waker.wake();
// We must either read from the buffer or disable the
// We must either write to the buffer or disable the
// interrupt to prevent re-invoking the interrupt
// handler immediately.
disable_serial_tx_empty_interrupt();
@@ -353,8 +444,8 @@ mod fut {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
// use ruduino::{Bit::*, io::PORT_D};
// PORT_D.data().toggle_bit(Bit3);
use ruduino::{Bit::*, io::PORT_D};
PORT_D.data().toggle_bit(Bit3);
match serial::try_transmit(self.0) {
Ok(()) => {
@@ -376,24 +467,26 @@ mod fut {
#[embrio_async]
async fn example() {
Serial.tx(b'X').await;
// Serial.tx(b'X').await;
// Serial.tx(b'\r').await;
// Serial.tx(b'\n').await;
// let mut buf = 0;
// Serial.rx(&mut buf).await;
// Serial.tx(b'>').await;
// Serial.tx(buf).await;
// Serial.tx(b'<').await;
let mut buf = 0;
Serial.rx(&mut buf).await;
Serial.tx(b'>').await;
Serial.tx(buf).await;
Serial.tx(b'<').await;
}
pub fn do_futures() -> ! {
use embrio_executor::Executor;
//crate::write_strln("do_futures starting");
static mut EXECUTOR: Executor = Executor::new();
loop {
crate::write_strln("loop ->");
let executor = unsafe { &mut EXECUTOR };
executor.block_on(example());
crate::write_strln("<- loop");
}
}
}