diff --git a/primes/.cargo/config.toml b/primes/.cargo/config.toml new file mode 100644 index 0000000..6dfb735 --- /dev/null +++ b/primes/.cargo/config.toml @@ -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", +] diff --git a/primes/.gitignore b/primes/.gitignore new file mode 100644 index 0000000..5ad8f69 --- /dev/null +++ b/primes/.gitignore @@ -0,0 +1,3 @@ +/target +text.bin +rodata.bin diff --git a/primes/.vscode/settings.json b/primes/.vscode/settings.json new file mode 100644 index 0000000..1f30ed8 --- /dev/null +++ b/primes/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.check.allTargets": false, + "rust-analyzer.cargo.allTargets": false, + "rust-analyzer.cargo.target": "riscv32i-unknown-none-elf" +} diff --git a/primes/Cargo.lock b/primes/Cargo.lock new file mode 100644 index 0000000..bd0aa2f --- /dev/null +++ b/primes/Cargo.lock @@ -0,0 +1,121 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[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 = "primes" +version = "0.1.0" +dependencies = [ + "lwcpu", + "riscv", + "riscv-rt", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +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.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/primes/Cargo.toml b/primes/Cargo.toml new file mode 100644 index 0000000..799a809 --- /dev/null +++ b/primes/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "primes" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[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" diff --git a/primes/Makefile b/primes/Makefile new file mode 100644 index 0000000..c191672 --- /dev/null +++ b/primes/Makefile @@ -0,0 +1,20 @@ +NAME=primes + +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 diff --git a/primes/build.rs b/primes/build.rs new file mode 100644 index 0000000..c941735 --- /dev/null +++ b/primes/build.rs @@ -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"); +} diff --git a/primes/memory.x b/primes/memory.x new file mode 100644 index 0000000..1c24f2c --- /dev/null +++ b/primes/memory.x @@ -0,0 +1,14 @@ +MEMORY +{ + INST : ORIGIN = 0x00000000, LENGTH = 256K + IO : ORIGIN = 0x10000000, LENGTH = 1K + CONST : ORIGIN = 0x20000000, LENGTH = 16K + RAM : ORIGIN = 0x40000000, LENGTH = 16K +} + +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); diff --git a/primes/src/main.rs b/primes/src/main.rs new file mode 100644 index 0000000..067e473 --- /dev/null +++ b/primes/src/main.rs @@ -0,0 +1,88 @@ +#![no_std] +#![no_main] + +use core::{panic::PanicInfo}; +use lwcpu::{NumberDisplay, TextDisplay}; +use riscv_rt::entry; + +const SEGMENT_MAX: usize = 8; +const SEGMENT_SIZE: usize = SEGMENT_MAX*SEGMENT_MAX; + +// Calculates the primes in the first segment using the simple sieve +// Returns the primes in the primes array with n being the number of found primes +fn simple_sieve(primes: &mut [usize; SEGMENT_SIZE], n: &mut usize) { + let mut segment = [true; SEGMENT_SIZE]; + segment[0] = false; + segment[1] = false; + + for x in 2..SEGMENT_MAX { + if segment[x] { + for y in ((x * x)..SEGMENT_SIZE).step_by(x) { + segment[y] = false; + } + } + } + let mut index = 0; + for (x,prime) in segment.iter().enumerate() { + if *prime { + primes[index] = x; + index += 1; + } + } + *n = index; +} + +fn segment_sieve(primes: &[usize], prime_multiple: &mut [usize]) { + 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 + let mut segment = [true; SEGMENT_SIZE]; + for (i,p) in primes.iter().enumerate() { + let mut multiple = prime_multiple[i]; + while multiple < high { + segment[multiple-low] = false; + multiple += *p; + } + prime_multiple[i] = multiple; + } + + for (x,prime) in segment.iter().enumerate() { + if *prime { + NumberDisplay::display_number((low+x) as u32); + } + } + + low = high; + high += SEGMENT_SIZE; + } +} + +#[panic_handler] +fn panic_handler(_info: &PanicInfo) -> ! { + NumberDisplay::display_number(0xDEADC0DE); + // let mut text = TextDisplay{}; + // let _ = write!(text, "Panic: {}", _info.message()); + loop {} +} + +#[entry] +fn main() -> ! { + // There will be no more than [SEGMENT_SIZE] primes in the segment + let mut primes_buffer = [0; SEGMENT_SIZE]; + let mut n = 0; + simple_sieve(&mut primes_buffer, &mut n); + + 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); + let mut multiple = *x; + while multiple < SEGMENT_SIZE { + multiple += x; + } + prime_multiple[i] = multiple; + } + segment_sieve(primes, &mut prime_multiple); + loop {} +}