Implement segmented sieve for finding primes

master
D4VID 3 months ago
parent bc96bad885
commit 2c8863208e

@ -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",
]

3
primes/.gitignore vendored

@ -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
primes/Cargo.lock generated

@ -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"

@ -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"

@ -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

@ -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");
}

@ -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);

@ -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 {}
}
Loading…
Cancel
Save