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
`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:
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)
- 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:
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é >=,

View File

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

View File

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

View File

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