work
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
373
src/main.rs
373
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<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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user