From 2accfc22a4602a9decc161ee52a7857cbf8a3b0d Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sun, 16 Jun 2019 12:26:39 -0400 Subject: [PATCH] work --- initialize_memory.S | 46 ++++-- linker-script | 7 +- src/main.rs | 373 +++++++++++++++++++++++++++----------------- 3 files changed, 268 insertions(+), 158 deletions(-) diff --git a/initialize_memory.S b/initialize_memory.S index ccd8bc8..1129bbd 100644 --- a/initialize_memory.S +++ b/initialize_memory.S @@ -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 diff --git a/linker-script b/linker-script index 184cbda..ea9ed19 100644 --- a/linker-script +++ b/linker-script @@ -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 diff --git a/src/main.rs b/src/main.rs index 57b17a9..971faa4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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: + // + // I’m 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 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 = None; + static mut RX_WAKER: Option = 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 { - // 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 { + 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 { -// 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"); } } }