Split up into pim-os, pim-vm and pim-isa crate
This commit is contained in:
6
pim-os/.cargo/config
Normal file
6
pim-os/.cargo/config
Normal file
@@ -0,0 +1,6 @@
|
||||
[build]
|
||||
target = "aarch64-unknown-none"
|
||||
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Taarch64-gem5.ld",
|
||||
]
|
||||
225
pim-os/Cargo.lock
generated
Normal file
225
pim-os/Cargo.lock
generated
Normal file
@@ -0,0 +1,225 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aarch64-cpu"
|
||||
version = "9.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac42a04a61c19fc8196dd728022a784baecc5d63d7e256c01ad1b3fbfab26287"
|
||||
dependencies = [
|
||||
"tock-registers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
"rustc_version",
|
||||
"spin",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pim-isa"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pim-os"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aarch64-cpu",
|
||||
"half",
|
||||
"pim-isa",
|
||||
"serde",
|
||||
"serde-json-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-json-core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c9e1ab533c0bc414c34920ec7e5f097101d126ed5eac1a1aac711222e0bbb33"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tock-registers"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
17
pim-os/Cargo.toml
Normal file
17
pim-os/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "pim-os"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
aarch64-cpu = "9.4.0"
|
||||
half = { version = "2.3.1", default-features = false }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
serde-json-core = "0.5.1"
|
||||
pim-isa = { path = "../pim-isa", default-features = false }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
21
pim-os/aarch64-gem5.ld
Normal file
21
pim-os/aarch64-gem5.ld
Normal file
@@ -0,0 +1,21 @@
|
||||
MEMORY
|
||||
{
|
||||
bootmem : ORIGIN = 0x0, LENGTH = 0x10000
|
||||
dram : ORIGIN = 0x80000000, LENGTH = 0x100000000
|
||||
}
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.init : { *(.init) } > bootmem
|
||||
.pim_config : { KEEP(*(.pim_config)) } > dram
|
||||
# . = . + 0x4000;
|
||||
.text : { KEEP(*(.text)) } > dram
|
||||
.data : { *(.data) } > dram
|
||||
.rodata : { *(.rodata) } > dram
|
||||
.bss : { *(.bss) } > dram
|
||||
|
||||
. = ALIGN(8);
|
||||
. = . + 0x8000;
|
||||
LD_STACK_PTR = .;
|
||||
}
|
||||
16
pim-os/src/m5ops.rs
Normal file
16
pim-os/src/m5ops.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use core::arch::asm;
|
||||
|
||||
const M5OPS_ADDR: u64 = 0x10010000;
|
||||
|
||||
const EXIT_ADDR: *const u64 = (M5OPS_ADDR + (0x21 << 8)) as _;
|
||||
// const DUMP_STATS_ADDR: *const u64 = (M5OPS_ADDR + (0x40 << 8)) as _;
|
||||
// const RESET_STATS_ADDR: *const u64 = (M5OPS_ADDR + (0x41 << 8)) as _;
|
||||
// const DUMP_RESET_STATS_ADDR: *const u64 = (M5OPS_ADDR + (0x42 << 8)) as _;
|
||||
// const CHECKPOINT_ADDR: *const u64 = (M5OPS_ADDR + (0x43 << 8)) as _;
|
||||
|
||||
pub fn exit() {
|
||||
unsafe {
|
||||
core::ptr::read_volatile(EXIT_ADDR);
|
||||
asm!("dsb sy");
|
||||
}
|
||||
}
|
||||
107
pim-os/src/main.rs
Normal file
107
pim-os/src/main.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{
|
||||
arch::{asm, global_asm},
|
||||
fmt::Write,
|
||||
panic::PanicInfo,
|
||||
sync::atomic::{self, Ordering},
|
||||
};
|
||||
use half::f16;
|
||||
use pim::{array::BankArray, kernel::TEST_KERNEL};
|
||||
use pim_isa::{BankMode, PimConfig};
|
||||
use uart::Uart0;
|
||||
|
||||
mod m5ops;
|
||||
mod pim;
|
||||
mod uart;
|
||||
|
||||
global_asm!(include_str!("start.s"));
|
||||
|
||||
static mut TEST_ARRAY: BankArray = BankArray([f16::ZERO; 512]);
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn entry() -> ! {
|
||||
let mut pim_config = PimConfig {
|
||||
bank_mode: BankMode::PimAllBank,
|
||||
kernel: TEST_KERNEL,
|
||||
};
|
||||
let mut pim_writer = pim::config::PimWriter;
|
||||
|
||||
let mut uart = Uart0 {};
|
||||
unsafe {
|
||||
writeln!(
|
||||
&mut uart,
|
||||
"PIM array is at {:x?}",
|
||||
core::ptr::addr_of!(TEST_ARRAY)
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(&mut uart, "Read from all banks").unwrap();
|
||||
|
||||
// Invalidate and flush array just in case
|
||||
for element in TEST_ARRAY.0.iter().step_by(8) {
|
||||
asm!("dc civac, {val}", val = in(reg) element);
|
||||
}
|
||||
asm!("dsb sy");
|
||||
|
||||
|
||||
// Fetch single cache line in array
|
||||
// core::ptr::read_volatile(&TEST_ARRAY.0[0]);
|
||||
|
||||
// Zero array to prevent fetch
|
||||
// for element in TEST_ARRAY.0.iter().step_by(8) {
|
||||
// asm!("dc zva, {val}", val = in(reg) element);
|
||||
// }
|
||||
asm!("dc zva, {val}", val = in(reg) &TEST_ARRAY.0[0]);
|
||||
asm!("dsb sy");
|
||||
|
||||
pim_writer.write(
|
||||
serde_json_core::to_string::<PimConfig, 1024>(&pim_config)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
core::ptr::write_volatile(&mut TEST_ARRAY.0[0], f16::ZERO);
|
||||
|
||||
// Invalidate and flush
|
||||
// for element in TEST_ARRAY.0.iter().step_by(8) {
|
||||
asm!("dc civac, {val}", val = in(reg) &TEST_ARRAY.0[0]);
|
||||
// }
|
||||
asm!("dsb sy");
|
||||
|
||||
pim_config.bank_mode = BankMode::SingleBank;
|
||||
pim_writer.write(
|
||||
serde_json_core::to_string::<PimConfig, 1024>(&pim_config)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
// Invalidate array
|
||||
for element in TEST_ARRAY.0.iter().step_by(8) {
|
||||
asm!("dc ivac, {val}", val = in(reg) element);
|
||||
}
|
||||
|
||||
writeln!(
|
||||
&mut uart,
|
||||
"{:?}: {:x?}",
|
||||
core::ptr::addr_of!(TEST_ARRAY),
|
||||
TEST_ARRAY
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
m5ops::exit();
|
||||
|
||||
loop {
|
||||
atomic::compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
writeln!(Uart0, "{info}").unwrap();
|
||||
|
||||
loop {
|
||||
atomic::compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
3
pim-os/src/pim.rs
Normal file
3
pim-os/src/pim.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod array;
|
||||
pub mod config;
|
||||
pub mod kernel;
|
||||
8
pim-os/src/pim/array.rs
Normal file
8
pim-os/src/pim/array.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use half::f16;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C, align(1024))]
|
||||
pub struct BankArray(pub [f16; 512]);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComputeArray<const N: usize>(pub [BankArray; N]);
|
||||
26
pim-os/src/pim/config.rs
Normal file
26
pim-os/src/pim/config.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use core::arch::asm;
|
||||
|
||||
|
||||
#[link_section = ".pim_config"]
|
||||
static mut PIM_CONFIG_REGION: [u8; 0x4000] = [0; 0x4000];
|
||||
|
||||
const CACHE_LINE_SIZE: usize = 32;
|
||||
|
||||
pub struct PimWriter;
|
||||
|
||||
impl PimWriter {
|
||||
pub fn write(&mut self, s: &str) {
|
||||
unsafe {
|
||||
PIM_CONFIG_REGION[..s.len()].copy_from_slice(s.as_bytes());
|
||||
PIM_CONFIG_REGION[s.len()] = b'\0';
|
||||
|
||||
// Flush all cache lines that were affected by write operation
|
||||
for element in PIM_CONFIG_REGION[..s.len()].iter().step_by(CACHE_LINE_SIZE) {
|
||||
asm!("dc civac, {val}", val = in(reg) element);
|
||||
}
|
||||
|
||||
// Wait on all flushes to complete
|
||||
asm!("dsb sy");
|
||||
}
|
||||
}
|
||||
}
|
||||
45
pim-os/src/pim/kernel.rs
Normal file
45
pim-os/src/pim/kernel.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use pim_isa::{File, Instruction, Kernel};
|
||||
|
||||
pub const TEST_KERNEL: Kernel = Kernel([
|
||||
Instruction::FILL {
|
||||
src: File::Grf { index: 0 },
|
||||
dst: File::Bank,
|
||||
},
|
||||
Instruction::MOV {
|
||||
src: File::Bank,
|
||||
dst: File::Grf { index: 1 },
|
||||
},
|
||||
Instruction::JUMP {
|
||||
offset: 1,
|
||||
count: 12,
|
||||
},
|
||||
Instruction::EXIT,
|
||||
Instruction::NOP,
|
||||
Instruction::EXIT,
|
||||
Instruction::NOP,
|
||||
Instruction::EXIT,
|
||||
Instruction::NOP,
|
||||
Instruction::EXIT,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
Instruction::NOP,
|
||||
]);
|
||||
74
pim-os/src/start.s
Normal file
74
pim-os/src/start.s
Normal file
@@ -0,0 +1,74 @@
|
||||
.globl _start
|
||||
.extern LD_STACK_PTR
|
||||
|
||||
// Put a 64-bit value with little endianness.
|
||||
.macro PUT_64B high, low
|
||||
.word \low
|
||||
.word \high
|
||||
.endm
|
||||
|
||||
// Create an entry pointing to a next-level table.
|
||||
.macro TABLE_ENTRY PA, ATTR
|
||||
PUT_64B \ATTR, (\PA) + 0x3
|
||||
.endm
|
||||
|
||||
// Create an entry for a 1GB block.
|
||||
.macro BLOCK_1GB PA, ATTR_HI, ATTR_LO
|
||||
PUT_64B \ATTR_HI | ((\PA) >> 32), ((\PA) & 0xC0000000) | \ATTR_LO | 0x1
|
||||
.endm
|
||||
|
||||
// Create an entry for a 2MB block.
|
||||
.macro BLOCK_2MB PA, ATTR_HI, ATTR_LO
|
||||
PUT_64B \ATTR_HI, ((\PA) & 0xFFE00000) | \ATTR_LO | 0x1
|
||||
.endm
|
||||
|
||||
.section .init
|
||||
|
||||
.align 12
|
||||
ttb0_base:
|
||||
.set ADDR, 0x000
|
||||
.rept 0x02
|
||||
BLOCK_1GB (ADDR << 29), 0, 0x740
|
||||
.set ADDR, ADDR+2
|
||||
.endr
|
||||
.rept 0x3E
|
||||
BLOCK_1GB (ADDR << 29), 0, 0x74C
|
||||
.set ADDR, ADDR+2
|
||||
.endr
|
||||
|
||||
_start:
|
||||
ldr x30, =LD_STACK_PTR
|
||||
mov sp, x30
|
||||
|
||||
// Initialize translation table control registers
|
||||
LDR X1, =0x13520 // 64GB space 4KB granularity Inner-shareable. Normal Inner and Outer Cacheable.
|
||||
MSR TCR_EL3, X1
|
||||
|
||||
LDR X1, =0xFF440400
|
||||
MSR MAIR_EL3, X1 // ATTR0 Device-nGnRnE ATTR1 Device. ATTR2 Normal Non-Cacheable. ATTR3 Normal Cacheable.
|
||||
|
||||
ADR X0, ttb0_base
|
||||
MSR TTBR0_EL3, X0
|
||||
|
||||
// Enable MMU and caches
|
||||
// It is implemented in the CPUECTLR register.
|
||||
MRS X0, S3_1_C15_C2_1
|
||||
ORR X0, X0, #(0x1 << 6) // The SMP bit.
|
||||
MSR S3_1_C15_C2_1, X0
|
||||
|
||||
// Enable caches and the MMU.
|
||||
MRS X0, SCTLR_EL3
|
||||
ORR X0, X0, #(0x1 << 2) // The C bit (data cache).
|
||||
ORR X0, X0, #(0x1 << 12) // The I bit (instruction cache).
|
||||
ORR X0, X0, #0x1 // The M bit (MMU).
|
||||
MSR SCTLR_EL3, X0
|
||||
DSB SY
|
||||
ISB
|
||||
|
||||
bl entry
|
||||
|
||||
.equ PSCI_SYSTEM_OFF, 0x84000008
|
||||
.globl system_off
|
||||
system_off:
|
||||
ldr x0, =PSCI_SYSTEM_OFF
|
||||
hvc #0
|
||||
16
pim-os/src/uart.rs
Normal file
16
pim-os/src/uart.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use core::{fmt::Write, ptr::write_volatile};
|
||||
|
||||
const UART0_ADDR: *mut u32 = 0x1c090000 as _;
|
||||
|
||||
pub struct Uart0;
|
||||
|
||||
impl Write for Uart0 {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
for &byte in s.as_bytes() {
|
||||
unsafe {
|
||||
write_volatile(UART0_ADDR, byte as _);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user