Compare commits

...

4 Commits

@ -0,0 +1,8 @@
[build]
target = "riscv32i-unknown-none-elf"
[target.riscv32i-unknown-none-elf]
rustflags = [
"-C", "link-arg=-Tmemory.x",
"-C", "link-arg=-Tlink.x",
]

@ -0,0 +1,3 @@
/target
text.bin
rodata.bin

@ -0,0 +1,5 @@
{
"rust-analyzer.check.allTargets": false,
"rust-analyzer.cargo.allTargets": false,
"rust-analyzer.cargo.target": "riscv32i-unknown-none-elf"
}

121
bad-apple/Cargo.lock generated

@ -0,0 +1,121 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bad-apple"
version = "0.1.0"
dependencies = [
"lwcpu",
"riscv",
"riscv-rt",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "embedded-hal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
[[package]]
name = "lwcpu"
version = "0.1.0"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "riscv"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7"
dependencies = [
"critical-section",
"embedded-hal",
"paste",
"riscv-macros",
"riscv-pac",
]
[[package]]
name = "riscv-macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "riscv-pac"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436"
[[package]]
name = "riscv-rt"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "753f1bd7eb4e0003cec5e2fb60ea8e253a71d0b041bc7d1ba0fffe22e3c0294d"
dependencies = [
"riscv",
"riscv-pac",
"riscv-rt-macros",
]
[[package]]
name = "riscv-rt-macros"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"

@ -0,0 +1,20 @@
[package]
name = "bad-apple"
version = "0.1.0"
edition = "2021"
[dependencies]
riscv = "0.12.1"
riscv-rt = { version = "0.13.0", features=["single-hart"] }
lwcpu = { path = "../lwcpu" }
# https://docs.rust-embedded.org/book/unsorted/speed-vs-size.html
[profile.release]
# symbols are nice and they don't increase the size on Flash
debug = true
codegen-units = 1
opt-level = "z"
[profile.dev.package."*"]
codegen-units = 1
opt-level = "z"

@ -0,0 +1,20 @@
NAME=bad-apple
default: extract
build:
cargo build --release
extract: build
riscv32-elf-objcopy -O binary --only-section=.text "target/riscv32i-unknown-none-elf/release/${NAME}" /tmp/text.bin
riscv32-elf-objcopy -O binary --only-section=.rodata "target/riscv32i-unknown-none-elf/release/${NAME}" /tmp/rodata.bin
size: extract
cargo size --release -- -A
disassemble: extract
riscv32-elf-objdump -Cd "target/riscv32i-unknown-none-elf/release/${NAME}" | less
clean:
cargo clean
rm /tmp/text.bin /tmp/rodata.bin

@ -0,0 +1,14 @@
// build.rs
use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
// Put the linker script somewhere the linker can find it.
fs::write(out_dir.join("memory.x"), include_bytes!("memory.x")).unwrap();
println!("cargo:rustc-link-search={}", out_dir.display());
println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rerun-if-changed=build.rs");
}

Binary file not shown.

@ -0,0 +1,14 @@
MEMORY
{
INST : ORIGIN = 0x00000000, LENGTH = 256K
IO : ORIGIN = 0x10000000, LENGTH = 1K
CONST : ORIGIN = 0x20000000, LENGTH = 64K
RAM : ORIGIN = 0x40000000, LENGTH = 64K
}
REGION_ALIAS("REGION_TEXT", INST);
REGION_ALIAS("REGION_RODATA", CONST);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
REGION_ALIAS("REGION_HEAP", RAM);
REGION_ALIAS("REGION_STACK", RAM);

@ -0,0 +1,47 @@
#![no_std]
#![no_main]
use core::fmt::Write;
use core::panic::PanicInfo;
use lwcpu::{Audio, CharDisplay, NumberDisplay, Screen, ScreenMode};
use riscv_rt::entry;
#[panic_handler]
fn panic_handler(_info: &PanicInfo) -> ! {
NumberDisplay::display_number(0xDEADC0DE);
let mut text = CharDisplay {};
let _ = write!(text, "Panic: {}", _info.message());
loop {}
}
const DATA_RAW: &[u8] = include_bytes!("../media/bad-apple.bin");
const LEN: usize = DATA_RAW.len() / 4;
const DATA: [u32; LEN] = to_u32_array(DATA_RAW);
const fn to_u32_array(bytes: &[u8]) -> [u32; LEN] {
let mut result = [0u32; LEN];
let mut i = 0;
while i < LEN {
let idx = i * 4;
result[i] = u32::from_le_bytes([
bytes[idx + 0],
bytes[idx + 1],
bytes[idx + 2],
bytes[idx + 3],
]);
i += 1;
}
return result;
}
#[entry]
fn main() -> ! {
NumberDisplay::display_number(0);
Screen::init(ScreenMode::Buffered);
for index in (0..LEN).step_by(2) {
Audio::play_upper(DATA[index]);
Audio::play_lower(DATA[index + 1]);
}
Audio::stop();
loop {}
}

@ -0,0 +1,8 @@
[build]
target = "riscv32i-unknown-none-elf"
[target.riscv32i-unknown-none-elf]
rustflags = [
"-C", "link-arg=-Tmemory.x",
"-C", "link-arg=-Tlink.x",
]

@ -0,0 +1,5 @@
{
"rust-analyzer.check.allTargets": false,
"rust-analyzer.cargo.allTargets": false,
"rust-analyzer.cargo.target": "riscv32i-unknown-none-elf"
}

@ -11,6 +11,8 @@ pub const KEYBOARD_OFFSET : u32 = 0x10;
pub const CHAR_CONTROL_OFFSET : u32 = 0x20;
pub const SCREEN_CONTROL_OFFSET : u32 = 0x22;
pub const CHAR_DISPLAY_OFFSET : u32 = 0x24;
pub const TEXT_DISPLAY_OFFSET : u32 = 0x28; // cheeseutil modded display 64x64 characters
pub const AUDIO_MAIN_OFFSET : u32 = 0x30;
pub const SCREEN_OFFSET : u32 = 0x80;
pub const NUMBER_DISPLAY_POINTER : *mut u32 = (BASE_POINTER + NUMBER_DISPLAY_OFFSET) as *mut u32;
@ -20,6 +22,8 @@ pub const CHAR_DISPLAY_POINTER : *mut u8 = (BASE_POINTER + CHAR_DISPLAY_OFFSE
pub const KEYBOARD_POINTER : *mut u32 = (BASE_POINTER + KEYBOARD_OFFSET) as *mut u32;
pub const SCREEN_CONTROL_POINTER : *mut u16 = (BASE_POINTER + SCREEN_CONTROL_OFFSET) as *mut u16;
pub const CHAR_CONTROL_POINTER : *mut u16 = (BASE_POINTER + CHAR_CONTROL_OFFSET) as *mut u16;
pub const TEXT_DISPLAY_POINTER : *mut u8 = (BASE_POINTER + TEXT_DISPLAY_OFFSET) as *mut u8;
pub const AUDIO_MAIN_POINTER : *mut u32 = (BASE_POINTER + AUDIO_MAIN_OFFSET) as *mut u32;
pub const SCREEN_POINTER : *mut u32 = (BASE_POINTER + SCREEN_OFFSET) as *mut u32;
@ -139,6 +143,82 @@ impl core::fmt::Write for CharDisplay {
}
}
pub struct TextDisplay {
pos: u16
}
impl TextDisplay {
const CLEAR : u8 = 0b00000001;
const SET_CHAR : u8 = 0b00000010;
const SET_CURSOR : u8 = 0b00000100;
const BLINK : u8 = 0b00001000;
const SCROLL_UP : u8 = 0b00010000;
// const SCROLL_DOWN : u8 = 0b00100000;
// const SCROLL_LEFT : u8 = 0b01000000;
// const SCROLL_RIGHT : u8 = 0b10000000;
#[inline]
pub fn clear(&mut self, blink: bool) {
unsafe {
let control_ptr = TEXT_DISPLAY_POINTER.offset(3);
write_volatile(control_ptr, Self::CLEAR);
match blink {
true => {
write_volatile(TEXT_DISPLAY_POINTER as *mut u16, self.pos);
write_volatile(control_ptr, Self::SET_CURSOR);
write_volatile(control_ptr, Self::BLINK);
},
false => {
write_volatile(control_ptr, 0);
},
}
}
}
#[inline]
pub fn put_char(&mut self, ch: u8) {
unsafe {
let control_ptr = TEXT_DISPLAY_POINTER.offset(3);
let control = read_volatile(control_ptr);
if ch == b'\n' {
if self.pos >= 63*64 { // last row
write_volatile(control_ptr, Self::SCROLL_UP);
write_volatile(control_ptr, control);
} else {
self.pos += 64; // increment row
}
self.pos &= !63u16; // set column to 0
} else {
write_volatile(TEXT_DISPLAY_POINTER as *mut u16, self.pos);
write_volatile(TEXT_DISPLAY_POINTER.offset(2), ch);
write_volatile(control_ptr, Self::SET_CHAR);
write_volatile(control_ptr, control);
self.pos += 1;
write_volatile(TEXT_DISPLAY_POINTER as *mut u16, self.pos);
}
write_volatile(control_ptr, Self::SET_CURSOR);
write_volatile(control_ptr, control);
}
}
}
impl Default for TextDisplay {
#[inline]
fn default() -> Self {
Self { pos: 0 }
}
}
impl core::fmt::Write for TextDisplay {
#[inline]
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for ch in s.bytes() {
self.put_char(ch);
}
return Ok(());
}
}
pub struct NumberDisplay {}
impl NumberDisplay {
#[inline]
@ -147,6 +227,13 @@ impl NumberDisplay {
write_volatile(NUMBER_DISPLAY_POINTER, number);
}
}
#[inline]
pub fn increment() {
unsafe {
let value = read_volatile(NUMBER_DISPLAY_POINTER);
write_volatile(NUMBER_DISPLAY_POINTER, value + 1);
}
}
}
pub struct RNG {}
@ -181,3 +268,27 @@ impl Buttons {
return unsafe { read_volatile(BUTTONS_POINTER.byte_offset(3)) };
}
}
pub struct Audio {}
impl Audio {
#[inline]
pub fn play_upper(notes: u32) {
unsafe {
write_volatile(AUDIO_MAIN_POINTER, notes);
}
}
#[inline]
pub fn play_lower(notes: u32) {
unsafe {
write_volatile(AUDIO_MAIN_POINTER.offset(1), notes);
}
}
#[inline]
pub fn stop() {
unsafe {
write_volatile(AUDIO_MAIN_POINTER.offset(0), 0);
write_volatile(AUDIO_MAIN_POINTER.offset(1), 0);
}
}
}

@ -1,9 +1,9 @@
MEMORY
{
INST : ORIGIN = 0x00000000, LENGTH = 256K
IO : ORIGIN = 0x20000000, LENGTH = 1K
CONST : ORIGIN = 0x40000000, LENGTH = 16K
RAM : ORIGIN = 0x80000000, LENGTH = 16K
IO : ORIGIN = 0x10000000, LENGTH = 1K
CONST : ORIGIN = 0x20000000, LENGTH = 64K
RAM : ORIGIN = 0x40000000, LENGTH = 64K
}
REGION_ALIAS("REGION_TEXT", INST);

@ -2,8 +2,8 @@ MEMORY
{
INST : ORIGIN = 0x00000000, LENGTH = 256K
IO : ORIGIN = 0x10000000, LENGTH = 1K
CONST : ORIGIN = 0x20000000, LENGTH = 16K
RAM : ORIGIN = 0x40000000, LENGTH = 16K
CONST : ORIGIN = 0x20000000, LENGTH = 64K
RAM : ORIGIN = 0x40000000, LENGTH = 64K
}
REGION_ALIAS("REGION_TEXT", INST);

@ -3,7 +3,7 @@
use core::fmt::Write;
use core::panic::PanicInfo;
use lwcpu::{NumberDisplay, CharDisplay};
use lwcpu::{NumberDisplay, CharDisplay, TextDisplay};
use riscv_rt::entry;
const SEGMENT_MAX: usize = 8;
@ -33,10 +33,11 @@ fn simple_sieve(primes: &mut [usize; SEGMENT_SIZE], n: &mut usize) {
*n = index;
}
fn segment_sieve(primes: &[usize], prime_multiple: &mut [usize]) {
fn segment_sieve(primes: &[usize], prime_multiple: &mut [usize], char: &mut CharDisplay, text: &mut TextDisplay) {
let mut low: usize = SEGMENT_SIZE;
let mut high: usize = SEGMENT_SIZE*2;
for _ in 1..SEGMENT_SIZE { // there are [SEGMENT_SIZE] number of segments
char.show();
let mut segment = [true; SEGMENT_SIZE];
for (i,p) in primes.iter().enumerate() {
let mut multiple = prime_multiple[i];
@ -46,10 +47,12 @@ fn segment_sieve(primes: &[usize], prime_multiple: &mut [usize]) {
}
prime_multiple[i] = multiple;
}
char.hide();
for (x,prime) in segment.iter().enumerate() {
if *prime {
NumberDisplay::display_number((low+x) as u32);
NumberDisplay::increment();
writeln!(text, "{} is prime", low+x).ok();
}
}
@ -61,29 +64,43 @@ fn segment_sieve(primes: &[usize], prime_multiple: &mut [usize]) {
#[panic_handler]
fn panic_handler(_info: &PanicInfo) -> ! {
NumberDisplay::display_number(0xDEADC0DE);
let mut text = CharDisplay{};
let mut text = TextDisplay::default();
text.clear(false);
let _ = write!(text, "Panic: {}", _info.message());
loop {}
}
#[entry]
fn main() -> ! {
NumberDisplay::display_number(0);
let mut char = CharDisplay{};
char.init();
char.hide();
char.write_str("SIEVING...").ok();
let mut text = TextDisplay::default();
text.clear(true);
// There will be no more than [SEGMENT_SIZE] primes in the segment
let mut primes_buffer = [0; SEGMENT_SIZE];
let mut n = 0;
char.show();
simple_sieve(&mut primes_buffer, &mut n);
char.hide();
let primes = &primes_buffer[..n];
let mut prime_multiple = [0; SEGMENT_SIZE];
for (i,x) in primes.iter().enumerate() {
NumberDisplay::display_number(*x as u32);
NumberDisplay::increment();
writeln!(text, "{} is prime", *x).ok();
let mut multiple = *x;
while multiple < SEGMENT_SIZE {
multiple += x;
}
prime_multiple[i] = multiple;
}
segment_sieve(primes, &mut prime_multiple);
segment_sieve(primes, &mut prime_multiple, &mut char, &mut text);
loop {}
}

@ -2,8 +2,8 @@ MEMORY
{
INST : ORIGIN = 0x00000000, LENGTH = 256K
IO : ORIGIN = 0x10000000, LENGTH = 1K
CONST : ORIGIN = 0x20000000, LENGTH = 16K
RAM : ORIGIN = 0x40000000, LENGTH = 16K
CONST : ORIGIN = 0x20000000, LENGTH = 64K
RAM : ORIGIN = 0x40000000, LENGTH = 64K
}
REGION_ALIAS("REGION_TEXT", INST);

@ -2,7 +2,7 @@
#![no_main]
use core::{fmt::Write, panic::PanicInfo, ptr::{read_volatile, write_volatile}};
use lwcpu::{NumberDisplay, Screen, ScreenMode, CharDisplay, SCREEN_POINTER};
use lwcpu::{CharDisplay, NumberDisplay, Screen, ScreenMode, TextDisplay, SCREEN_POINTER};
use riscv_rt::entry;
#[panic_handler]
@ -16,8 +16,20 @@ fn panic_handler(_info: &PanicInfo) -> ! {
const HELLO_WORLD: &str = " Hello world!";
#[inline(never)]
fn test_text_display() {
let mut text = TextDisplay::default();
text.init(true);
text.write_str("Lmao yeet\nlook at this!\nI have a text display I can type into.\nSo cool!!!").ok();
for _ in 0..100 {
text.write_str("aaa\n").ok();
}
}
#[entry]
fn main() -> ! {
test_text_display();
NumberDisplay::display_number(0);
Screen::init(ScreenMode::Buffered);
let mut text = CharDisplay{};

Loading…
Cancel
Save