mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-03 07:55:17 -04:00
First commit: flag registers and imgui example code (stolen from gh)
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
imgui.ini
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["snes-core", "snes-frontend"]
|
||||||
|
resolver = "2"
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snes"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "snes-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
struct Registers {
|
||||||
|
sp: u16, // Stack pointer
|
||||||
|
x: u16, // Index X
|
||||||
|
y: u16, // Index Y
|
||||||
|
a: u16, // Accumulator
|
||||||
|
p: u8, // Status register
|
||||||
|
d: u16, // Direct page register
|
||||||
|
pbr: u8, // Program bank register
|
||||||
|
dbr: u8, // Data bank register
|
||||||
|
pc: u16, // Program counter
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registers {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
sp: 0,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
a: 0,
|
||||||
|
p: 0,
|
||||||
|
d: 0,
|
||||||
|
pbr: 0,
|
||||||
|
dbr: 0,
|
||||||
|
pc: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_p(&self) -> u8 {
|
||||||
|
self.p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_p(&mut self, val: u8) {
|
||||||
|
self.p = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_carry_flag(&self) -> bool {
|
||||||
|
(self.p & 0b0000_0001) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_carry_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b1111_1110;
|
||||||
|
self.p = self.p | (val as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_zero_flag(&self) -> bool {
|
||||||
|
((self.p & 0b0000_0010) >> 1) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_zero_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b1111_1101;
|
||||||
|
self.p = self.p | ((val as u8) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_irq_disable_flag(&self) -> bool {
|
||||||
|
((self.p & 0b0000_0100) >> 2) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_irq_disable_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b1111_1011;
|
||||||
|
self.p = self.p | ((val as u8) << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_decimal_mode_flag(&self) -> bool {
|
||||||
|
((self.p & 0b0000_1000) >> 3) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_decimal_mode_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b1111_0111;
|
||||||
|
self.p = self.p | ((val as u8) << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_break_instruction_flag(&self) -> bool {
|
||||||
|
((self.p & 0b0001_0000) >> 4) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_break_instruction_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b1110_1111;
|
||||||
|
self.p = self.p | ((val as u8) << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_overflow_flag(&self) -> bool {
|
||||||
|
((self.p & 0b0100_0000) >> 6) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_overflow_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b1011_1111;
|
||||||
|
self.p = self.p | ((val as u8) << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_negative_flag(&self) -> bool {
|
||||||
|
((self.p & 0b1000_0000) >> 7) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_negative_flag(&mut self, val: bool) {
|
||||||
|
self.p = self.p & 0b0111_1111;
|
||||||
|
self.p = self.p | ((val as u8) << 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CPU {
|
||||||
|
registers: Registers,
|
||||||
|
cycles: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CPU {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
registers: Registers::new(),
|
||||||
|
cycles: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn adc_const(&mut self, value: u16) {
|
||||||
|
self.cycles += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod cpu_instructions_tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_adc_const() {
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
assert!(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod cpu_registers_tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_status_registers() {
|
||||||
|
let mut registers = Registers::new();
|
||||||
|
registers.set_p(0x00);
|
||||||
|
|
||||||
|
registers.set_carry_flag(true);
|
||||||
|
assert!(registers.get_carry_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0001);
|
||||||
|
registers.set_carry_flag(false);
|
||||||
|
assert!(!registers.get_carry_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0000);
|
||||||
|
|
||||||
|
registers.set_zero_flag(true);
|
||||||
|
assert!(registers.get_zero_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0010);
|
||||||
|
registers.set_zero_flag(false);
|
||||||
|
assert!(!registers.get_zero_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0000);
|
||||||
|
|
||||||
|
registers.set_irq_disable_flag(true);
|
||||||
|
assert!(registers.get_irq_disable_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0100);
|
||||||
|
registers.set_irq_disable_flag(false);
|
||||||
|
assert!(!registers.get_irq_disable_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0000);
|
||||||
|
|
||||||
|
registers.set_decimal_mode_flag(true);
|
||||||
|
assert!(registers.get_decimal_mode_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_1000);
|
||||||
|
registers.set_decimal_mode_flag(false);
|
||||||
|
assert!(!registers.get_decimal_mode_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0000);
|
||||||
|
|
||||||
|
registers.set_break_instruction_flag(true);
|
||||||
|
assert!(registers.get_break_instruction_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0001_0000);
|
||||||
|
registers.set_break_instruction_flag(false);
|
||||||
|
assert!(!registers.get_break_instruction_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0000);
|
||||||
|
|
||||||
|
registers.set_overflow_flag(true);
|
||||||
|
assert!(registers.get_overflow_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0100_0000);
|
||||||
|
registers.set_overflow_flag(false);
|
||||||
|
assert!(!registers.get_overflow_flag());
|
||||||
|
assert_eq!(registers.get_p(), 0b0000_0000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod cpu;
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snes"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "snes-frontend"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
winit = "0.26.1"
|
||||||
|
imgui = "0.8.2"
|
||||||
|
wgpu = "0.12.0"
|
||||||
|
imgui-wgpu = "0.19.0"
|
||||||
|
pollster = "0.2.5"
|
||||||
|
[dependencies.imgui-winit-support]
|
||||||
|
version = "0.8.2"
|
||||||
|
features = ["winit-26"]
|
||||||
|
default-features = false
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
extern crate imgui_winit_support;
|
||||||
|
|
||||||
|
use imgui::*;
|
||||||
|
use imgui_wgpu::{Renderer, RendererConfig};
|
||||||
|
use pollster::block_on;
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
use winit::{
|
||||||
|
dpi::LogicalSize,
|
||||||
|
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::Window,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Set up window and GPU
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
|
let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY);
|
||||||
|
|
||||||
|
let (window, size, surface) = {
|
||||||
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
let window = Window::new(&event_loop).unwrap();
|
||||||
|
window.set_inner_size(LogicalSize {
|
||||||
|
width: 1280.0,
|
||||||
|
height: 720.0,
|
||||||
|
});
|
||||||
|
window.set_title(&format!("imgui-wgpu {}", version));
|
||||||
|
let size = window.inner_size();
|
||||||
|
|
||||||
|
let surface = unsafe { instance.create_surface(&window) };
|
||||||
|
|
||||||
|
(window, size, surface)
|
||||||
|
};
|
||||||
|
|
||||||
|
let hidpi_factor = window.scale_factor();
|
||||||
|
|
||||||
|
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||||
|
compatible_surface: Some(&surface),
|
||||||
|
force_fallback_adapter: false,
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (device, queue) =
|
||||||
|
block_on(adapter.request_device(&wgpu::DeviceDescriptor::default(), None)).unwrap();
|
||||||
|
|
||||||
|
// Set up swap chain
|
||||||
|
let surface_desc = wgpu::SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||||
|
width: size.width as u32,
|
||||||
|
height: size.height as u32,
|
||||||
|
present_mode: wgpu::PresentMode::Mailbox,
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.configure(&device, &surface_desc);
|
||||||
|
|
||||||
|
// Set up dear imgui
|
||||||
|
let mut imgui = imgui::Context::create();
|
||||||
|
let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui);
|
||||||
|
platform.attach_window(
|
||||||
|
imgui.io_mut(),
|
||||||
|
&window,
|
||||||
|
imgui_winit_support::HiDpiMode::Default,
|
||||||
|
);
|
||||||
|
imgui.set_ini_filename(None);
|
||||||
|
|
||||||
|
let font_size = (13.0 * hidpi_factor) as f32;
|
||||||
|
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
|
||||||
|
|
||||||
|
imgui.fonts().add_font(&[FontSource::DefaultFontData {
|
||||||
|
config: Some(imgui::FontConfig {
|
||||||
|
oversample_h: 1,
|
||||||
|
pixel_snap_h: true,
|
||||||
|
size_pixels: font_size,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
}]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set up dear imgui wgpu renderer
|
||||||
|
//
|
||||||
|
let clear_color = wgpu::Color {
|
||||||
|
r: 0.1,
|
||||||
|
g: 0.2,
|
||||||
|
b: 0.3,
|
||||||
|
a: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let renderer_config = RendererConfig {
|
||||||
|
texture_format: surface_desc.format,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut renderer = Renderer::new(&mut imgui, &device, &queue, renderer_config);
|
||||||
|
|
||||||
|
let mut last_frame = Instant::now();
|
||||||
|
let mut demo_open = true;
|
||||||
|
|
||||||
|
let mut last_cursor = None;
|
||||||
|
|
||||||
|
// Event loop
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
*control_flow = if cfg!(feature = "metal-auto-capture") {
|
||||||
|
ControlFlow::Exit
|
||||||
|
} else {
|
||||||
|
ControlFlow::Poll
|
||||||
|
};
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let size = window.inner_size();
|
||||||
|
|
||||||
|
let surface_desc = wgpu::SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||||
|
width: size.width as u32,
|
||||||
|
height: size.height as u32,
|
||||||
|
present_mode: wgpu::PresentMode::Mailbox,
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.configure(&device, &surface_desc);
|
||||||
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event:
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input:
|
||||||
|
KeyboardInput {
|
||||||
|
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}
|
||||||
|
| Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
Event::MainEventsCleared => window.request_redraw(),
|
||||||
|
Event::RedrawEventsCleared => {
|
||||||
|
let delta_s = last_frame.elapsed();
|
||||||
|
let now = Instant::now();
|
||||||
|
imgui.io_mut().update_delta_time(now - last_frame);
|
||||||
|
last_frame = now;
|
||||||
|
|
||||||
|
let frame = match surface.get_current_texture() {
|
||||||
|
Ok(frame) => frame,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("dropped frame: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
platform
|
||||||
|
.prepare_frame(imgui.io_mut(), &window)
|
||||||
|
.expect("Failed to prepare frame");
|
||||||
|
let ui = imgui.frame();
|
||||||
|
|
||||||
|
{
|
||||||
|
let window = imgui::Window::new("Hello world");
|
||||||
|
window
|
||||||
|
.size([300.0, 100.0], Condition::FirstUseEver)
|
||||||
|
.build(&ui, || {
|
||||||
|
ui.text("Hello world!");
|
||||||
|
ui.text("This...is...imgui-rs on WGPU!");
|
||||||
|
ui.separator();
|
||||||
|
let mouse_pos = ui.io().mouse_pos;
|
||||||
|
ui.text(format!(
|
||||||
|
"Mouse Position: ({:.1},{:.1})",
|
||||||
|
mouse_pos[0], mouse_pos[1]
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
let window = imgui::Window::new("Hello too");
|
||||||
|
window
|
||||||
|
.size([400.0, 200.0], Condition::FirstUseEver)
|
||||||
|
.position([400.0, 200.0], Condition::FirstUseEver)
|
||||||
|
.build(&ui, || {
|
||||||
|
ui.text(format!("Frametime: {:?}", delta_s));
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.show_demo_window(&mut demo_open);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut encoder: wgpu::CommandEncoder =
|
||||||
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
|
||||||
|
if last_cursor != Some(ui.mouse_cursor()) {
|
||||||
|
last_cursor = Some(ui.mouse_cursor());
|
||||||
|
platform.prepare_render(&ui, &window);
|
||||||
|
}
|
||||||
|
|
||||||
|
let view = frame
|
||||||
|
.texture
|
||||||
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||||
|
view: &view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(clear_color),
|
||||||
|
store: true,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderer
|
||||||
|
.render(ui.render(), &queue, &device, &mut rpass)
|
||||||
|
.expect("Rendering failed");
|
||||||
|
|
||||||
|
drop(rpass);
|
||||||
|
|
||||||
|
queue.submit(Some(encoder.finish()));
|
||||||
|
|
||||||
|
frame.present();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.handle_event(imgui.io_mut(), &window, &event);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user