reworking workspace

This commit is contained in:
Mwa
2026-03-11 03:40:23 +01:00
parent e747425381
commit e277c11eef
4 changed files with 0 additions and 0 deletions

383
simu/src/cpu.rs Normal file
View File

@@ -0,0 +1,383 @@
use std::{
hint::{likely, unlikely},
io::Read,
process::exit,
sync::{Mutex, atomic::AtomicU32},
thread::sleep,
time::{self, Duration, Instant},
};
use pixels::Pixels;
enum Op2 {
Direct(u32),
Register(u8),
}
struct Reg(u8);
enum Cond {
Ifeq,
Ifne,
Iflt,
Ifge,
Ifgt,
Ifle,
Ifult,
Ifuge,
Ifugt,
Ifule,
}
impl From<u8> for Cond {
fn from(value: u8) -> Self {
match value {
0b0000 => Cond::Ifeq,
0b0001 => Cond::Ifne,
0b1000 => Cond::Iflt,
0b1001 => Cond::Ifge,
0b1010 => Cond::Ifgt,
0b1011 => Cond::Ifle,
0b1100 => Cond::Ifult,
0b1101 => Cond::Ifuge,
0b1110 => Cond::Ifugt,
0b1111 => Cond::Ifule,
_ => {
unreachable!()
}
}
}
}
impl Cond {
fn eval(self, a: u32, b: u32) -> bool {
match self {
Cond::Ifeq => a == b,
Cond::Ifne => a != b,
Cond::Iflt => (a as i32) < (b as i32),
Cond::Ifge => (a as i32) >= (b as i32),
Cond::Ifgt => (a as i32) > (b as i32),
Cond::Ifle => (a as i32) <= (b as i32),
Cond::Ifult => a < b,
Cond::Ifuge => a >= b,
Cond::Ifugt => a > b,
Cond::Ifule => a <= b,
}
}
}
enum Instruction {
Copy(Reg, Op2),
Add(Reg, Reg, Op2),
Sub(Reg, Reg, Op2),
Or(Reg, Reg, Op2),
And(Reg, Reg, Op2),
Xor(Reg, Reg, Op2),
Lsl(Reg, Reg, Op2),
Lsr(Reg, Reg, Op2),
Asr(Reg, Reg, Op2),
Smull(Reg, Reg, Op2),
Smulh(Reg, Reg, Op2),
Umull(Reg, Reg, Op2),
Umulh(Reg, Reg, Op2),
Div(Reg, Reg, Op2),
Mod(Reg, Reg, Op2),
Store(Reg, Op2, Reg),
Load(Reg, Reg, Op2),
Push(Op2),
Pop(Reg),
Skip(u8, Cond, Reg, Op2),
Jump(u32), //address / 4
Call(u32), //address / 4
Ret(),
GetStack(Reg),
SetStack(Op2),
}
impl From<u32> for Instruction {
fn from(value: u32) -> Self {
match value >> 30 {
0b00 => {
let t = value & (1 << 29); // 3rd bit set
let value = value - t;
let t = t != 0;
if t {
Self::Call(value)
} else {
Self::Jump(value)
}
}
fmt => {
let imediate = (value & (1 << 28)) != 0;
let s = (value & 1 << 29) != 0;
const MASK: u32 = 0b1111;
let opcode = (value >> 24) & MASK;
let rd = Reg(((value >> 20) & MASK) as u8);
let rx = Reg(((value >> 16) & MASK) as u8);
let op2 = {
if imediate {
let value = if s {
value | 0xFFFF0000
} else {
value & 0x0000FFFF
};
Op2::Direct(value)
} else {
Op2::Register((value >> 12 & MASK) as u8)
}
};
match (fmt, opcode) {
(1, 0b0000) => Self::Copy(rd, op2),
(1, 0b0001) => Self::Add(rd, rx, op2),
(1, 0b0010) => Self::Sub(rd, rx, op2),
(1, 0b0011) => Self::Or(rd, rx, op2),
(1, 0b0100) => Self::And(rd, rx, op2),
(1, 0b0101) => Self::Xor(rd, rx, op2),
(1, 0b0110) => Self::Lsl(rd, rx, op2),
(1, 0b0111) => Self::Lsr(rd, rx, op2),
(1, 0b1000) => Self::Asr(rd, rx, op2),
(1, 0b1001) => Self::Smull(rd, rx, op2),
(1, 0b1010) => Self::Smulh(rd, rx, op2),
(1, 0b1011) => Self::Umull(rd, rx, op2),
(1, 0b1100) => Self::Umulh(rd, rx, op2),
(1, 0b1101) => Self::Div(rd, rx, op2),
(1, 0b1110) => Self::Mod(rd, rx, op2),
(2, 0b0000) => Self::Store(rx, op2, rd),
(2, 0b0001) => Self::Load(rd, rx, op2),
(2, 0b0010) => Self::Push(op2),
(2, 0b0011) => Self::Pop(rd),
(2, 0b1000) => Self::Ret(),
(2, 0b1101) => Self::GetStack(rd),
(2, 0b1110) => Self::SetStack(op2),
(3, skip) => Self::Skip(rd.0, (skip as u8).into(), rx, op2),
_ => unreachable!(),
}
}
}
}
}
pub struct Computer<'a, 'b> {
creation: Instant,
ram: Box<[u32; 0x01000000 / 4]>,
regs: [u32; 16],
pc: usize,
sp: usize,
screen: &'b Mutex<Pixels<'a>>,
key: &'b AtomicU32,
}
fn iot() -> ! {
exit(1);
}
impl<'a, 'b> Computer<'a, 'b> {
pub fn new(filename: String, screen: &'b Mutex<Pixels<'a>>, key: &'b AtomicU32) -> Self {
let mut new = Self {
creation: Instant::now(),
ram: Box::new([0; 0x01000000 / 4]),
regs: [0; 16],
pc: 0,
sp: 0,
screen,
key,
};
let mut buf = String::new();
std::fs::File::open(filename)
.unwrap()
.read_to_string(&mut buf)
.unwrap();
for (i, line) in buf.lines().enumerate() {
match u32::from_str_radix(line, 16) {
Ok(val) => new.ram[i] = val,
Err(_) => break,
}
}
new
}
pub fn step(&mut self) {
let next_opcode = self.ram[self.pc];
match Instruction::from(next_opcode) {
Instruction::Copy(reg, op2) => {
self.rg_wr(reg, self.resolve(op2));
self.pc += 1;
}
Instruction::Add(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) + self.resolve(op2));
self.pc += 1;
}
Instruction::Sub(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) - self.resolve(op2));
self.pc += 1;
}
Instruction::Or(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) | self.resolve(op2));
self.pc += 1;
}
Instruction::And(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) & self.resolve(op2));
self.pc += 1;
}
Instruction::Xor(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) ^ self.resolve(op2));
self.pc += 1;
}
Instruction::Lsl(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) << self.resolve(op2));
self.pc += 1;
}
Instruction::Lsr(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) >> self.resolve(op2));
self.pc += 1;
}
Instruction::Asr(reg, reg1, op2) => {
self.rg_wr(reg, (self.rg_r(reg1) as i32 >> self.resolve(op2)) as u32);
self.pc += 1;
}
Instruction::Umull(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1).wrapping_mul(self.resolve(op2)));
self.pc += 1;
}
Instruction::Smull(reg, reg1, op2) => {
self.rg_wr(
reg,
(self.rg_r(reg1) as i32).wrapping_mul(self.resolve(op2) as i32) as u32,
);
self.pc += 1;
}
Instruction::Umulh(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1).widening_mul(self.resolve(op2)).1);
self.pc += 1;
}
Instruction::Smulh(reg, reg1, op2) => {
self.rg_wr(
reg,
(self.rg_r(reg1) as i32)
.widening_mul(self.resolve(op2) as i32)
.1 as u32,
);
self.pc += 1;
}
Instruction::Div(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) / self.resolve(op2));
self.pc += 1
}
Instruction::Mod(reg, reg1, op2) => {
self.rg_wr(reg, self.rg_r(reg1) % self.resolve(op2));
self.pc += 1
}
Instruction::Store(reg, op2, reg1) => {
let addr = (self.rg_r(reg) + self.resolve(op2)) as usize;
if !addr.is_multiple_of(4) {
iot();
}
if addr <= 0x00ffffff {
self.ram[addr / 4] = self.rg_r(reg1);
} else if addr <= 0x00ffffff + 480 * 640 * 4 {
let addr_screen = addr - 0x01000000;
let ubgr = self.rg_r(reg1);
let rgba = [ubgr as u8, (ubgr >> 8) as u8, (ubgr >> 16) as u8, 0xff];
let mut pixels = self.screen.lock().unwrap();
let screen = pixels.frame_mut();
for i in 0..4 {
screen[addr_screen + i] = rgba[i];
}
} else {
iot();
}
self.pc += 1;
}
Instruction::Load(reg, reg1, op2) => {
let addr = (self.rg_r(reg1) + self.resolve(op2)) as usize;
if !addr.is_multiple_of(4) {
iot();
}
self.rg_wr(
reg,
if addr <= 0x00ffffff {
self.ram[addr / 4]
} else if addr <= 0x00ffffff + 480 * 640 * 4 {
let pixels = self.screen.lock().unwrap();
let buffer = pixels.frame();
let mut res = 0;
let addr_screen = addr - 0x01000000;
for i in 0..3 {
res += (buffer[addr_screen + i] as u32) << (i as u32 * 8)
}
res
} else if addr == 0x01200000 {
self.key.load(std::sync::atomic::Ordering::Relaxed)
} else if addr == 0x01200004{
time::Instant::now().duration_since(self.creation).as_millis() as u32
} else {
iot();
},
);
self.pc += 1;
}
Instruction::Push(op2) => {
self.sp -= 1;
self.ram[self.sp] = self.resolve(op2);
self.pc += 1;
}
Instruction::Pop(reg) => {
self.rg_wr(reg, self.ram[self.sp]);
self.sp += 1;
self.pc += 1;
}
Instruction::Skip(d, cond, reg, op2) => {
self.pc += 1;
if cond.eval(self.rg_r(reg), self.resolve(op2)) {
self.pc += d as usize
}
}
Instruction::Jump(mut addr) => {
if addr & (1 << 28) != 0 {
addr += 7 << 29;
} else if unlikely(addr == 0) {
sleep(Duration::from_hours(1));
}
self.pc = (addr + self.pc as u32) as usize;
}
Instruction::Call(mut addr) => {
self.sp -= 1;
self.ram[self.sp] = ((self.pc << 2) + 4) as u32;
if addr & (1 << 28) != 0 {
addr += 7 << 29;
} else if unlikely(addr == 0) {
sleep(Duration::from_hours(1));
}
self.pc = (addr + self.pc as u32) as usize;
}
Instruction::Ret() => {
self.pc = (self.ram[self.sp] >> 2) as usize;
self.sp += 1;
}
Instruction::GetStack(reg) => {
self.rg_wr(reg, (self.sp << 2) as u32);
self.pc += 1;
}
Instruction::SetStack(op2) => {
let v = self.resolve(op2);
if likely(v.is_multiple_of(4)) {
self.sp = (v >> 2) as usize;
} else {
self.sp = usize::MAX //Yes, that means that clever program using sp to store information wont work on my emulator. Deal with it
}
self.pc += 1;
}
};
}
fn resolve(&self, op2: Op2) -> u32 {
match op2 {
Op2::Direct(v) => v,
Op2::Register(r) => self.regs[r as usize],
}
}
fn rg_wr(&mut self, reg: Reg, v: u32) {
self.regs[reg.0 as usize] = v
}
fn rg_r(&self, reg: Reg) -> u32 {
self.regs[reg.0 as usize]
}
}

136
simu/src/main.rs Normal file
View File

@@ -0,0 +1,136 @@
#![feature(likely_unlikely, widening_mul)]
#![deny(clippy::all)]
use std::env::args;
use std::process::exit;
use std::sync::atomic::AtomicU32;
use std::sync::{Arc, Mutex};
use std::thread::{scope, sleep};
use std::time::Duration;
use pixels::{Error, Pixels, SurfaceTexture};
use winit::dpi::LogicalSize;
use winit::event::{Event, WindowEvent};
use winit::event_loop::EventLoop;
use winit::platform::scancode::PhysicalKeyExtScancode;
use winit::window::Window;
use winit_input_helper::WinitInputHelper;
use crate::cpu::Computer;
const WIDTH: u32 = 640;
const HEIGHT: u32 = 480;
mod cpu;
fn main() -> Result<(), Error> {
let event_loop = EventLoop::new().unwrap();
let mut input = WinitInputHelper::new();
let window = {
let size = LogicalSize::new((WIDTH * 3) as f64, (HEIGHT * 3) as f64);
#[allow(deprecated)]
Arc::new(
event_loop
.create_window(
Window::default_attributes()
.with_title("bisare screen")
.with_inner_size(size)
.with_min_inner_size(size),
)
.unwrap(),
)
};
let pixels = Mutex::new({
let window_size = window.inner_size();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(WIDTH, HEIGHT, surface_texture)?
});
let keyboard = AtomicU32::new(0);
let program = args()
.nth(1)
.expect("you must supply the exec name as the first argument");
let kbref = &keyboard;
let pixelref = &pixels;
scope(|sc| {
sc.spawn(|| {
let mut simulation = Computer::new(program, pixelref, kbref);
loop {
simulation.step();
}
});
#[allow(deprecated)]
let res = event_loop.run(|event, elwt| {
match event {
Event::Resumed => {}
Event::NewEvents(_) => input.step(),
Event::AboutToWait => input.end_step(),
Event::DeviceEvent { event, .. } => {
input.process_device_event(&event);
}
Event::WindowEvent { event, .. } => {
// Draw the current frame
if event == WindowEvent::RedrawRequested {
if let Err(_) = pixels.lock().unwrap().render() {
elwt.exit();
return;
}
sleep(Duration::from_millis(30));
}
if let WindowEvent::KeyboardInput {
device_id: _,
ref event,
is_synthetic: _,
} = event
{
match event.state {
winit::event::ElementState::Pressed => {
if let Some(val) = event.physical_key.to_scancode() {
kbref.store(val + 8, std::sync::atomic::Ordering::Relaxed);
}
}
winit::event::ElementState::Released => {
kbref.store(0, std::sync::atomic::Ordering::Relaxed)
}
}
}
// Handle input events
if input.process_window_event(&event) {
// Close events
if input.close_requested() {
elwt.exit();
return;
}
// Resize the window
if let Some(size) = input.window_resized() {
if let Err(_) = pixels
.lock()
.unwrap()
.resize_surface(size.width, size.height)
{
elwt.exit();
return;
}
}
// Update internal state and request a redraw
window.request_redraw();
}
}
_ => {}
}
});
match res {
Ok(_) => exit(0),
Err(e) => {
println!("{e}");
exit(1);
}
}
})
}