rich keyboard

This commit is contained in:
Mwa
2026-03-16 01:48:39 +01:00
parent 8cb41c61cd
commit 2d50702acc
4 changed files with 81 additions and 34 deletions

View File

@@ -28,7 +28,11 @@ syntaxe supplémentaire supportée:
- depuis le sous dossier simu - depuis le sous dossier simu
`cargo run --release fichierentre` `cargo run --release fichierentre`
Pour rajouter le support de multiplication/division: rajouter --features=div_mul ## Features
rajouter --features=[liste séparé par des virgules]
- div_mul: Support des instruction de multiplication / division
- rgba: Écran au format RGBA plutot que 0BGR
- rich_keyboard: rajoute trois champs de mmio pour le clavier. Voir MMIO
### instruction spéciale: ### instruction spéciale:
halt (jump 0) met le programme en pause, mais on peut se reveiller par des interuptions halt (jump 0) met le programme en pause, mais on peut se reveiller par des interuptions
@@ -45,6 +49,13 @@ Passage au format RGBA (a pour alpha) avec la feature rgba
- 0x01200010 : Position verticale de la souris (en pixels, -1 si hors de l'écran) (lecture seule) - 0x01200010 : Position verticale de la souris (en pixels, -1 si hors de l'écran) (lecture seule)
- 0x01201000 : Activation des Interupts de MMIO. Remis a zero par `dint`. Attention, Écrire ici sans activer les interruptions va bloquer les intéruptions et l'affichage (écriture seule) - 0x01201000 : Activation des Interupts de MMIO. Remis a zero par `dint`. Attention, Écrire ici sans activer les interruptions va bloquer les intéruptions et l'affichage (écriture seule)
Si la feature rich_keyboard est active, tout en lecture seule:
- 0x01200000 - 12 : Clavier : Representation ascii multichar de la touche pressé, modifié par Alt, Ctrl ... (eg ascii(a), ascii(A), ascii(^)<<8 | ascii(a))
- 0x01200000 - 8 : Clavier Representation ascii multichar non modifié (eg ascii(a), ascii(\)<<8 | ascii(r))
- 0x01200000 - 4: Clavier (press | repeat << 1) press: 1 si appuis, 0 si relache. repeat: 1 si l'appuis vient d'une répétition due a l'OS
- 0x01200000 : Clavier (scancode, comme précédement) (lecture seule)
## Interuptions: ## Interuptions:
Si les interruptions sont activées (avec eint), qu'il y a une raison de faire une interruption, Si les interruptions sont activées (avec eint), qu'il y a une raison de faire une interruption,
et qu'on n'est pas déjà dans une routine d'interruption de priorité >=, et qu'on n'est pas déjà dans une routine d'interruption de priorité >=,

View File

@@ -11,3 +11,5 @@ winit_input_helper = "0.17.0"
[features] [features]
div_mul = [] div_mul = []
rgba = []
rich_keyboard = []

View File

@@ -10,7 +10,7 @@ use std::{
}; };
pub(crate) struct SharedState { pub(crate) struct SharedState {
pub(crate) keyboard: AtomicU32, pub(crate) keyboard: [AtomicU32; 4],
pub(crate) screen_buf: [AtomicU32; 480 * 640], pub(crate) screen_buf: [AtomicU32; 480 * 640],
pub(crate) external_interupts: AtomicU32, pub(crate) external_interupts: AtomicU32,
pub(crate) external_enabled_interupts: AtomicU32, pub(crate) external_enabled_interupts: AtomicU32,
@@ -18,7 +18,7 @@ pub(crate) struct SharedState {
} }
pub(crate) static SHARED: SharedState = SharedState { pub(crate) static SHARED: SharedState = SharedState {
keyboard: AtomicU32::new(0), keyboard: [const { AtomicU32::new(0) }; 4],
screen_buf: [const { AtomicU32::new(0) }; 480 * 640], screen_buf: [const { AtomicU32::new(0) }; 480 * 640],
external_interupts: AtomicU32::new(0), external_interupts: AtomicU32::new(0),
external_enabled_interupts: AtomicU32::new(0), external_enabled_interupts: AtomicU32::new(0),
@@ -432,9 +432,17 @@ impl Computer {
let buf_addr = (addr - 0x0100_0000) / 4; let buf_addr = (addr - 0x0100_0000) / 4;
(&SHARED.screen_buf[buf_addr]) (&SHARED.screen_buf[buf_addr])
.load(std::sync::atomic::Ordering::Relaxed) .load(std::sync::atomic::Ordering::Relaxed)
} else if 0x0120_0000 <= addr && addr <= 0x0120_0010 { } else {
match addr - 0x0120_0000 { match addr as isize - 0x0120_0000 {
0 => SHARED.keyboard.load(std::sync::atomic::Ordering::Relaxed), #[cfg(feature = "rich_keyboard")]
-12 => {
SHARED.keyboard[0].load(std::sync::atomic::Ordering::Relaxed)
}
#[cfg(feature = "rich_keyboard")]
-8 => SHARED.keyboard[1].load(std::sync::atomic::Ordering::Relaxed),
#[cfg(feature = "rich_keyboard")]
-4 => SHARED.keyboard[2].load(std::sync::atomic::Ordering::Relaxed),
0 => SHARED.keyboard[3].load(std::sync::atomic::Ordering::Relaxed),
4 => time::Instant::now() 4 => time::Instant::now()
.duration_since(self.creation) .duration_since(self.creation)
.as_millis() as u32, .as_millis() as u32,
@@ -442,11 +450,11 @@ impl Computer {
12 => SHARED.mouse[1].load(std::sync::atomic::Ordering::Relaxed), 12 => SHARED.mouse[1].load(std::sync::atomic::Ordering::Relaxed),
16 => SHARED.mouse[2].load(std::sync::atomic::Ordering::Relaxed), 16 => SHARED.mouse[2].load(std::sync::atomic::Ordering::Relaxed),
//guaranted by the inequality and is multiple of 4 //guaranted by the inequality and is multiple of 4
_ => unsafe { unreachable_unchecked() }, _ => {
}
} else {
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]); self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
return; return;
}
}
}; };
} }
Instruction::Push(op2) => { Instruction::Push(op2) => {
@@ -506,7 +514,7 @@ impl Computer {
match kind { match kind {
InteruptKind::MMIO => { InteruptKind::MMIO => {
(&SHARED.external_interupts) (&SHARED.external_interupts)
.store(0, std::sync::atomic::Ordering::Relaxed); .store(0, std::sync::atomic::Ordering::Release);
atomic_wait::wake_all(&SHARED.external_interupts); atomic_wait::wake_all(&SHARED.external_interupts);
//no need to check prev because MMIO is the lowest priority //no need to check prev because MMIO is the lowest priority
self.interupts = InteruptState::Enabled self.interupts = InteruptState::Enabled

View File

@@ -11,7 +11,7 @@ use std::hint::unlikely;
use std::process::exit; use std::process::exit;
use std::sync::{ use std::sync::{
Arc, Arc,
atomic::Ordering::{Relaxed, Release}, atomic::Ordering::{Acquire, Relaxed, Release},
}; };
use std::thread::scope; use std::thread::scope;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -21,6 +21,7 @@ use winit::application::ApplicationHandler;
use winit::dpi::LogicalSize; use winit::dpi::LogicalSize;
use winit::event::WindowEvent; use winit::event::WindowEvent;
use winit::event_loop::EventLoop; use winit::event_loop::EventLoop;
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
use winit::platform::scancode::PhysicalKeyExtScancode; use winit::platform::scancode::PhysicalKeyExtScancode;
use winit::window::Window; use winit::window::Window;
// use winit_input_helper::WinitInputHelper; // use winit_input_helper::WinitInputHelper;
@@ -31,11 +32,11 @@ mod cpu;
use cpu::SHARED; use cpu::SHARED;
fn wait_int() { fn wait_int() {
let mut v = (&SHARED.external_interupts).load(Relaxed); let mut v = (&SHARED.external_interupts).load(Acquire);
while unlikely(v != 0) { while unlikely(v != 0) {
println!("wating for interupt clear {v}"); println!("wating for interupt clear {v}");
atomic_wait::wait(&SHARED.external_interupts, v); atomic_wait::wait(&SHARED.external_interupts, v);
v = (&SHARED.external_interupts).load(std::sync::atomic::Ordering::Relaxed); v = (&SHARED.external_interupts).load(Acquire);
} }
} }
@@ -76,7 +77,9 @@ impl<'a> ApplicationHandler for App<'a> {
) { ) {
// Draw the current frame // Draw the current frame
match event { match event {
WindowEvent::KeyboardInput { event, .. } => { WindowEvent::KeyboardInput {
event: key_event, ..
} => {
let enabled = (&SHARED.external_enabled_interupts).load(Relaxed) let enabled = (&SHARED.external_enabled_interupts).load(Relaxed)
& Into::<u32>::into(MMIOInterupt::Keyboard) & Into::<u32>::into(MMIOInterupt::Keyboard)
!= 0; != 0;
@@ -84,18 +87,31 @@ impl<'a> ApplicationHandler for App<'a> {
if enabled { if enabled {
wait_int(); wait_int();
} }
match event.state { #[cfg(feature = "rich_keyboard")]
winit::event::ElementState::Pressed => { {
if let Some(val) = event.physical_key.to_scancode() { let txt = key_event
cpu::SHARED .logical_key
.keyboard .to_text()
.store(val + 8, std::sync::atomic::Ordering::Relaxed); .unwrap_or("")
} .as_bytes()
} .into_iter()
winit::event::ElementState::Released => SHARED .fold(0, |a, e| a << 8 | (*e as u32));
.keyboard SHARED.keyboard[0].store(txt, Relaxed);
.store(0, std::sync::atomic::Ordering::Relaxed), let txt = key_event
.key_without_modifiers()
.to_text()
.unwrap_or("")
.as_bytes()
.into_iter()
.fold(0, |a, e| a << 8 | (*e as u32));
SHARED.keyboard[1].store(txt, Relaxed);
SHARED.keyboard[2].store(
key_event.state.is_pressed() as u32 | ((key_event.repeat as u32) << 1),
Relaxed,
);
} }
SHARED.keyboard[3]
.store(key_event.physical_key.to_scancode().unwrap_or(0), Relaxed);
if enabled { if enabled {
(&SHARED.external_interupts).store(MMIOInterupt::Keyboard.into(), Release); (&SHARED.external_interupts).store(MMIOInterupt::Keyboard.into(), Release);
atomic_wait::wake_all(&SHARED.external_interupts); atomic_wait::wake_all(&SHARED.external_interupts);
@@ -105,7 +121,9 @@ impl<'a> ApplicationHandler for App<'a> {
let enabled = (&SHARED.external_enabled_interupts).load(Relaxed) let enabled = (&SHARED.external_enabled_interupts).load(Relaxed)
& Into::<u32>::into(MMIOInterupt::MouseMove) & Into::<u32>::into(MMIOInterupt::MouseMove)
!= 0; != 0;
if enabled {wait_int();} if enabled {
wait_int();
}
match self match self
.pixels .pixels
.as_ref() .as_ref()
@@ -113,10 +131,8 @@ impl<'a> ApplicationHandler for App<'a> {
.window_pos_to_pixel((position.x as f32, position.y as f32)) .window_pos_to_pixel((position.x as f32, position.y as f32))
{ {
Ok((x, y)) => { Ok((x, y)) => {
(&cpu::SHARED.mouse[1]) (&cpu::SHARED.mouse[1]).store(x as u32, Relaxed);
.store(x as u32, Relaxed); (&cpu::SHARED.mouse[2]).store(y as u32, Relaxed);
(&cpu::SHARED.mouse[2])
.store(y as u32, Relaxed);
} }
Err(_) => { Err(_) => {
(&SHARED.mouse[1]).store(u32::MAX, Relaxed); (&SHARED.mouse[1]).store(u32::MAX, Relaxed);
@@ -137,7 +153,9 @@ impl<'a> ApplicationHandler for App<'a> {
let enabled = (&SHARED.external_enabled_interupts).load(Relaxed) let enabled = (&SHARED.external_enabled_interupts).load(Relaxed)
& Into::<u32>::into(MMIOInterupt::MouseClick) & Into::<u32>::into(MMIOInterupt::MouseClick)
!= 0; != 0;
if enabled {wait_int();} if enabled {
wait_int();
}
let but = 1 let but = 1
<< match button { << match button {
winit::event::MouseButton::Left => 0, winit::event::MouseButton::Left => 0,
@@ -177,8 +195,16 @@ impl<'a> ApplicationHandler for App<'a> {
let screen = pix.frame_mut(); let screen = pix.frame_mut();
for (addr, ubgr) in cpu::SHARED.screen_buf.iter().enumerate() { for (addr, ubgr) in cpu::SHARED.screen_buf.iter().enumerate() {
let ubgr = ubgr.load(std::sync::atomic::Ordering::Relaxed); let raw = ubgr.load(std::sync::atomic::Ordering::Relaxed);
let rgba = [ubgr as u8, (ubgr >> 8) as u8, (ubgr >> 16) as u8, 0xff]; #[cfg(not(feature = "rgba"))]
let rgba = [raw as u8, (raw >> 8) as u8, (raw >> 16) as u8, 0xff];
#[cfg(feature = "rgba")]
let rgba = [
(raw >> 24) as u8,
(raw >> 16) as u8,
(raw >> 8) as u8,
raw as u8,
];
for i in 0..4 { for i in 0..4 {
screen[addr * 4 + i] = rgba[i]; screen[addr * 4 + i] = rgba[i];
} }