Split kernel/user trap handler && Fix user tests.
This commit is contained in:
parent
1008d92c35
commit
485db04a2b
13 changed files with 45 additions and 161 deletions
|
@ -3,6 +3,7 @@ use std::fs::{File, read_dir};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-changed=../user/src/");
|
println!("cargo:rerun-if-changed=../user/src/");
|
||||||
|
println!("cargo:rerun-if-changed={}", TARGET_PATH);
|
||||||
insert_app_data().unwrap();
|
insert_app_data().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
pub const USER_STACK_SIZE: usize = 4096 * 2;
|
pub const USER_STACK_SIZE: usize = 4096 * 2;
|
||||||
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
||||||
pub const MAX_APP_NUM: usize = 4;
|
|
||||||
pub const APP_BASE_ADDRESS: usize = 0x80100000;
|
|
||||||
pub const APP_SIZE_LIMIT: usize = 0x20000;
|
|
||||||
pub const KERNEL_HEAP_SIZE: usize = 0x30_0000;
|
pub const KERNEL_HEAP_SIZE: usize = 0x30_0000;
|
||||||
pub const MEMORY_END: usize = 0x80800000;
|
pub const MEMORY_END: usize = 0x80800000;
|
||||||
pub const PAGE_SIZE: usize = 0x1000;
|
pub const PAGE_SIZE: usize = 0x1000;
|
||||||
|
|
127
os/src/loader.rs
127
os/src/loader.rs
|
@ -1,54 +1,3 @@
|
||||||
use crate::trap::TrapContext;
|
|
||||||
use crate::task::TaskContext;
|
|
||||||
use crate::config::*;
|
|
||||||
use xmas_elf::ElfFile;
|
|
||||||
|
|
||||||
/*
|
|
||||||
#[repr(align(4096))]
|
|
||||||
struct KernelStack {
|
|
||||||
data: [u8; KERNEL_STACK_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(align(4096))]
|
|
||||||
struct UserStack {
|
|
||||||
data: [u8; USER_STACK_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [
|
|
||||||
KernelStack { data: [0; KERNEL_STACK_SIZE], };
|
|
||||||
MAX_APP_NUM
|
|
||||||
];
|
|
||||||
|
|
||||||
static USER_STACK: [UserStack; MAX_APP_NUM] = [
|
|
||||||
UserStack { data: [0; USER_STACK_SIZE], };
|
|
||||||
MAX_APP_NUM
|
|
||||||
];
|
|
||||||
|
|
||||||
impl KernelStack {
|
|
||||||
fn get_sp(&self) -> usize {
|
|
||||||
self.data.as_ptr() as usize + KERNEL_STACK_SIZE
|
|
||||||
}
|
|
||||||
pub fn push_context(&self, trap_cx: TrapContext, task_cx: TaskContext) -> &'static mut TaskContext {
|
|
||||||
unsafe {
|
|
||||||
let trap_cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;
|
|
||||||
*trap_cx_ptr = trap_cx;
|
|
||||||
let task_cx_ptr = (trap_cx_ptr as usize - core::mem::size_of::<TaskContext>()) as *mut TaskContext;
|
|
||||||
*task_cx_ptr = task_cx;
|
|
||||||
task_cx_ptr.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserStack {
|
|
||||||
fn get_sp(&self) -> usize {
|
|
||||||
self.data.as_ptr() as usize + USER_STACK_SIZE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
fn get_base_i(app_id: usize) -> usize {
|
|
||||||
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_num_app() -> usize {
|
pub fn get_num_app() -> usize {
|
||||||
extern "C" { fn _num_app(); }
|
extern "C" { fn _num_app(); }
|
||||||
unsafe { (_num_app as usize as *const usize).read_volatile() }
|
unsafe { (_num_app as usize as *const usize).read_volatile() }
|
||||||
|
@ -69,79 +18,3 @@ pub fn get_app_data(app_id: usize) -> &'static [u8] {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn debug_elf(start_addr: usize, end_addr: usize) {
|
|
||||||
let data_array = unsafe {
|
|
||||||
core::slice::from_raw_parts(start_addr as *const u8, end_addr - start_addr)
|
|
||||||
};
|
|
||||||
let elf = ElfFile::new(data_array).unwrap();
|
|
||||||
let elf_header = elf.header;
|
|
||||||
let magic = elf_header.pt1.magic;
|
|
||||||
assert_eq!(magic, [0x7f, 0x45, 0x4c, 0x46], "invalid elf!");
|
|
||||||
let ph_count = elf_header.pt2.ph_count();
|
|
||||||
println!("ph_count = {}", ph_count);
|
|
||||||
for i in 0..ph_count {
|
|
||||||
let ph = elf.program_header(i).unwrap();
|
|
||||||
if ph.get_type().unwrap() == xmas_elf::program::Type::Load {
|
|
||||||
println!(
|
|
||||||
"offset={:#x},va={:#x},pa={:#x},filesz={:#x},memsz={:#x},align={:#x},flag={:?}",
|
|
||||||
ph.offset(),
|
|
||||||
ph.virtual_addr(),
|
|
||||||
ph.physical_addr(),
|
|
||||||
ph.file_size(),
|
|
||||||
ph.mem_size(),
|
|
||||||
ph.align(),
|
|
||||||
ph.flags(),
|
|
||||||
);
|
|
||||||
//println!("len={:?}", ph.get_data(&elf).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_apps() {
|
|
||||||
extern "C" { fn _num_app(); }
|
|
||||||
let num_app_ptr = _num_app as usize as *const usize;
|
|
||||||
let num_app = get_num_app();
|
|
||||||
let app_start = unsafe {
|
|
||||||
core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1)
|
|
||||||
};
|
|
||||||
println!("num_app = {}", num_app);
|
|
||||||
for i in 0..num_app {
|
|
||||||
println!(
|
|
||||||
"app_{} [{:#x},{:#x}) size={:#x}",
|
|
||||||
i,
|
|
||||||
app_start[i],
|
|
||||||
app_start[i + 1],
|
|
||||||
app_start[i + 1] - app_start[i]
|
|
||||||
);
|
|
||||||
debug_elf(app_start[i], app_start[i + 1]);
|
|
||||||
}
|
|
||||||
loop {}
|
|
||||||
// clear i-cache first
|
|
||||||
unsafe { llvm_asm!("fence.i" :::: "volatile"); }
|
|
||||||
// load apps
|
|
||||||
for i in 0..num_app {
|
|
||||||
let base_i = get_base_i(i);
|
|
||||||
// clear region
|
|
||||||
(base_i..base_i + APP_SIZE_LIMIT).for_each(|addr| unsafe {
|
|
||||||
(addr as *mut u8).write_volatile(0)
|
|
||||||
});
|
|
||||||
// load app from data section to memory
|
|
||||||
let src = unsafe {
|
|
||||||
core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i])
|
|
||||||
};
|
|
||||||
let dst = unsafe {
|
|
||||||
core::slice::from_raw_parts_mut(base_i as *mut u8, src.len())
|
|
||||||
};
|
|
||||||
dst.copy_from_slice(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_app_cx(app_id: usize) -> &'static TaskContext {
|
|
||||||
KERNEL_STACK[app_id].push_context(
|
|
||||||
TrapContext::app_init_context(get_base_i(app_id), USER_STACK[app_id].get_sp()),
|
|
||||||
TaskContext::goto_restore(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -44,10 +44,9 @@ pub fn rust_main() -> ! {
|
||||||
println!("[kernel] back to world!");
|
println!("[kernel] back to world!");
|
||||||
mm::remap_test();
|
mm::remap_test();
|
||||||
trap::init();
|
trap::init();
|
||||||
//loader::load_apps();
|
|
||||||
//trap::enable_interrupt();
|
//trap::enable_interrupt();
|
||||||
//trap::enable_timer_interrupt();
|
trap::enable_timer_interrupt();
|
||||||
//timer::set_next_trigger();
|
timer::set_next_trigger();
|
||||||
task::run_first_task();
|
task::run_first_task();
|
||||||
panic!("Unreachable in rust_main!");
|
panic!("Unreachable in rust_main!");
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@ use super::{PageTable, PageTableEntry, PTEFlags};
|
||||||
use super::{VirtPageNum, VirtAddr, PhysPageNum, PhysAddr};
|
use super::{VirtPageNum, VirtAddr, PhysPageNum, PhysAddr};
|
||||||
use super::{FrameTracker, frame_alloc};
|
use super::{FrameTracker, frame_alloc};
|
||||||
use super::{VPNRange, StepByOne};
|
use super::{VPNRange, StepByOne};
|
||||||
use core::ops::Range;
|
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use riscv::register::satp;
|
use riscv::register::satp;
|
||||||
|
@ -16,7 +15,6 @@ use crate::config::{
|
||||||
TRAP_CONTEXT,
|
TRAP_CONTEXT,
|
||||||
USER_STACK_SIZE
|
USER_STACK_SIZE
|
||||||
};
|
};
|
||||||
use xmas_elf::ElfFile;
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn stext();
|
fn stext();
|
||||||
|
@ -169,7 +167,7 @@ impl MemorySet {
|
||||||
}
|
}
|
||||||
// map user stack with U flags
|
// map user stack with U flags
|
||||||
//println!("mapping user stack!");
|
//println!("mapping user stack!");
|
||||||
let mut max_end_va: VirtAddr = max_end_vpn.into();
|
let max_end_va: VirtAddr = max_end_vpn.into();
|
||||||
let mut user_stack_bottom: usize = max_end_va.into();
|
let mut user_stack_bottom: usize = max_end_va.into();
|
||||||
// guard page
|
// guard page
|
||||||
user_stack_bottom += PAGE_SIZE;
|
user_stack_bottom += PAGE_SIZE;
|
||||||
|
@ -227,8 +225,7 @@ impl MapArea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
||||||
let mut pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
|
let ppn: PhysPageNum;
|
||||||
let mut ppn = PhysPageNum(0);
|
|
||||||
match self.map_type {
|
match self.map_type {
|
||||||
MapType::Identical => {
|
MapType::Identical => {
|
||||||
ppn = PhysPageNum(vpn.0);
|
ppn = PhysPageNum(vpn.0);
|
||||||
|
@ -239,8 +236,10 @@ impl MapArea {
|
||||||
self.data_frames.insert(vpn, frame);
|
self.data_frames.insert(vpn, frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
|
||||||
page_table.map(vpn, ppn, pte_flags);
|
page_table.map(vpn, ppn, pte_flags);
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
||||||
match self.map_type {
|
match self.map_type {
|
||||||
MapType::Framed => {
|
MapType::Framed => {
|
||||||
|
@ -255,6 +254,7 @@ impl MapArea {
|
||||||
self.map_one(page_table, vpn);
|
self.map_one(page_table, vpn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn unmap(&mut self, page_table: &mut PageTable) {
|
pub fn unmap(&mut self, page_table: &mut PageTable) {
|
||||||
for vpn in self.vpn_range {
|
for vpn in self.vpn_range {
|
||||||
self.unmap_one(page_table, vpn);
|
self.unmap_one(page_table, vpn);
|
||||||
|
|
|
@ -113,12 +113,14 @@ impl PageTable {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
|
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
|
||||||
//println!("mapping {:?} {:?}", vpn, ppn);
|
//println!("mapping {:?} {:?}", vpn, ppn);
|
||||||
let pte = self.find_pte_create(vpn).unwrap();
|
let pte = self.find_pte_create(vpn).unwrap();
|
||||||
assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
|
assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
|
||||||
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
|
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn unmap(&mut self, vpn: VirtPageNum) {
|
pub fn unmap(&mut self, vpn: VirtPageNum) {
|
||||||
let pte = self.find_pte_create(vpn).unwrap();
|
let pte = self.find_pte_create(vpn).unwrap();
|
||||||
assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
|
assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
|
||||||
|
|
|
@ -2,7 +2,6 @@ mod context;
|
||||||
mod switch;
|
mod switch;
|
||||||
mod task;
|
mod task;
|
||||||
|
|
||||||
use crate::config::MAX_APP_NUM;
|
|
||||||
use crate::loader::{get_num_app, get_app_data};
|
use crate::loader::{get_num_app, get_app_data};
|
||||||
use crate::trap::TrapContext;
|
use crate::trap::TrapContext;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|
|
@ -71,7 +71,6 @@ impl TaskControlBlock {
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum TaskStatus {
|
pub enum TaskStatus {
|
||||||
UnInit,
|
|
||||||
Ready,
|
Ready,
|
||||||
Running,
|
Running,
|
||||||
Exited,
|
Exited,
|
||||||
|
|
|
@ -21,11 +21,7 @@ impl TrapContext {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut sstatus = sstatus::read();
|
let mut sstatus = sstatus::read();
|
||||||
sstatus.set_spp(SPP::User);
|
sstatus.set_spp(SPP::User);
|
||||||
let mut temp_sstatus: usize;
|
sstatus.set_spie(true);
|
||||||
unsafe {
|
|
||||||
llvm_asm!("csrr $0, sstatus" : "=r"(temp_sstatus) ::: "volatile");
|
|
||||||
}
|
|
||||||
println!("sstatus={:#x}", temp_sstatus);
|
|
||||||
let mut cx = Self {
|
let mut cx = Self {
|
||||||
x: [0; 32],
|
x: [0; 32],
|
||||||
sstatus,
|
sstatus,
|
||||||
|
|
|
@ -26,11 +26,22 @@ use crate::config::{TRAP_CONTEXT, TRAMPOLINE};
|
||||||
global_asm!(include_str!("trap.S"));
|
global_asm!(include_str!("trap.S"));
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
set_kernel_trap_entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_kernel_trap_entry() {
|
||||||
unsafe {
|
unsafe {
|
||||||
stvec::write(TRAMPOLINE, TrapMode::Direct);
|
stvec::write(trap_from_kernel as usize, TrapMode::Direct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_user_trap_entry() {
|
||||||
|
unsafe {
|
||||||
|
stvec::write(TRAMPOLINE as usize, TrapMode::Direct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub fn enable_interrupt() {
|
pub fn enable_interrupt() {
|
||||||
unsafe { sstatus::set_sie(); }
|
unsafe { sstatus::set_sie(); }
|
||||||
}
|
}
|
||||||
|
@ -42,6 +53,7 @@ pub fn enable_timer_interrupt() {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trap_handler() -> ! {
|
pub fn trap_handler() -> ! {
|
||||||
//println!("into trap_handler!");
|
//println!("into trap_handler!");
|
||||||
|
set_kernel_trap_entry();
|
||||||
let cx = current_trap_cx();
|
let cx = current_trap_cx();
|
||||||
let scause = scause::read();
|
let scause = scause::read();
|
||||||
let stval = stval::read();
|
let stval = stval::read();
|
||||||
|
@ -73,6 +85,7 @@ pub fn trap_handler() -> ! {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trap_return() -> ! {
|
pub fn trap_return() -> ! {
|
||||||
|
set_user_trap_entry();
|
||||||
//println!("into trap_return");
|
//println!("into trap_return");
|
||||||
let trap_cx_ptr = TRAP_CONTEXT;
|
let trap_cx_ptr = TRAP_CONTEXT;
|
||||||
let user_satp = current_user_token();
|
let user_satp = current_user_token();
|
||||||
|
@ -90,4 +103,9 @@ pub fn trap_return() -> ! {
|
||||||
panic!("Unreachable in back_to_user!");
|
panic!("Unreachable in back_to_user!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn trap_from_kernel() -> ! {
|
||||||
|
panic!("a trap from kernel!");
|
||||||
|
}
|
||||||
|
|
||||||
pub use context::{TrapContext};
|
pub use context::{TrapContext};
|
||||||
|
|
|
@ -6,24 +6,24 @@ extern crate user_lib;
|
||||||
|
|
||||||
const LEN: usize = 100;
|
const LEN: usize = 100;
|
||||||
|
|
||||||
static mut s: [u64; LEN] = [0u64; LEN];
|
static mut S: [u64; LEN] = [0u64; LEN];
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe fn main() -> i32 {
|
unsafe fn main() -> i32 {
|
||||||
let p = 3u64;
|
let p = 3u64;
|
||||||
let m = 998244353u64;
|
let m = 998244353u64;
|
||||||
let iter: usize = 100000;
|
let iter: usize = 300000;
|
||||||
let mut cur = 0usize;
|
let mut cur = 0usize;
|
||||||
s[cur] = 1;
|
S[cur] = 1;
|
||||||
for i in 1..=iter {
|
for i in 1..=iter {
|
||||||
let next = if cur + 1 == LEN { 0 } else { cur + 1 };
|
let next = if cur + 1 == LEN { 0 } else { cur + 1 };
|
||||||
s[next] = s[cur] * p % m;
|
S[next] = S[cur] * p % m;
|
||||||
cur = next;
|
cur = next;
|
||||||
if i % 10000 == 0 {
|
if i % 10000 == 0 {
|
||||||
println!("power_3 [{}/{}]", i, iter);
|
println!("power_3 [{}/{}]", i, iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{}^{} = {}", p, iter, s[cur]);
|
println!("{}^{} = {}(mod {})", p, iter, S[cur], m);
|
||||||
println!("Test power_3 OK!");
|
println!("Test power_3 OK!");
|
||||||
0
|
0
|
||||||
}
|
}
|
|
@ -6,24 +6,24 @@ extern crate user_lib;
|
||||||
|
|
||||||
const LEN: usize = 100;
|
const LEN: usize = 100;
|
||||||
|
|
||||||
static mut s: [u64; LEN] = [0u64; LEN];
|
static mut S: [u64; LEN] = [0u64; LEN];
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe fn main() -> i32 {
|
unsafe fn main() -> i32 {
|
||||||
let p = 5u64;
|
let p = 5u64;
|
||||||
let m = 998244353u64;
|
let m = 998244353u64;
|
||||||
let iter: usize = 70000;
|
let iter: usize = 210000;
|
||||||
let mut cur = 0usize;
|
let mut cur = 0usize;
|
||||||
s[cur] = 1;
|
S[cur] = 1;
|
||||||
for i in 1..=iter {
|
for i in 1..=iter {
|
||||||
let next = if cur + 1 == LEN { 0 } else { cur + 1 };
|
let next = if cur + 1 == LEN { 0 } else { cur + 1 };
|
||||||
s[next] = s[cur] * p % m;
|
S[next] = S[cur] * p % m;
|
||||||
cur = next;
|
cur = next;
|
||||||
if i % 10000 == 0 {
|
if i % 10000 == 0 {
|
||||||
println!("power_5 [{}/{}]", i, iter);
|
println!("power_5 [{}/{}]", i, iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{}^{} = {}", p, iter, s[cur]);
|
println!("{}^{} = {}(mod {})", p, iter, S[cur], m);
|
||||||
println!("Test power_5 OK!");
|
println!("Test power_5 OK!");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,24 +6,24 @@ extern crate user_lib;
|
||||||
|
|
||||||
const LEN: usize = 100;
|
const LEN: usize = 100;
|
||||||
|
|
||||||
static mut s: [u64; LEN] = [0u64; LEN];
|
static mut S: [u64; LEN] = [0u64; LEN];
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe fn main() -> i32 {
|
unsafe fn main() -> i32 {
|
||||||
let p = 7u64;
|
let p = 7u64;
|
||||||
let m = 998244353u64;
|
let m = 998244353u64;
|
||||||
let iter: usize = 80000;
|
let iter: usize = 240000;
|
||||||
let mut cur = 0usize;
|
let mut cur = 0usize;
|
||||||
s[cur] = 1;
|
S[cur] = 1;
|
||||||
for i in 1..=iter {
|
for i in 1..=iter {
|
||||||
let next = if cur + 1 == LEN { 0 } else { cur + 1 };
|
let next = if cur + 1 == LEN { 0 } else { cur + 1 };
|
||||||
s[next] = s[cur] * p % m;
|
S[next] = S[cur] * p % m;
|
||||||
cur = next;
|
cur = next;
|
||||||
if i % 10000 == 0 {
|
if i % 10000 == 0 {
|
||||||
println!("power_7 [{}/{}]", i, iter);
|
println!("power_7 [{}/{}]", i, iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{}^{} = {}", p, iter, s[cur]);
|
println!("{}^{} = {}(mod {})", p, iter, S[cur], m);
|
||||||
println!("Test power_7 OK!");
|
println!("Test power_7 OK!");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue