Skip to content

Commit

Permalink
Add PUSH and DEO opcodes and implement system/debug deo
Browse files Browse the repository at this point in the history
  • Loading branch information
belen-albeza committed Jul 17, 2024
1 parent b0e2668 commit 9ab38d2
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 61 deletions.
43 changes: 34 additions & 9 deletions coco-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#![cfg_attr(not(test), no_std)]
#![forbid(unsafe_code)]

use core::cmp;
use core::fmt;

mod stack;
use stack::Stack;

mod opcodes;
pub mod opcodes;

/// The trait to implement for COCO virtual machines.
pub trait Machine {
fn deo(&mut self, cpu: &mut Cpu, target: u8) -> bool;
fn deo(&mut self, cpu: &mut Cpu, target: u8);
fn dei(&mut self, cpu: &mut Cpu, target: u8);
}

Expand Down Expand Up @@ -39,7 +40,7 @@ impl Cpu {
pub fn new(rom: &[u8]) -> Self {
// load rom at address 0x100
let mut ram = [0; 0x10000];
ram[0x100..].copy_from_slice(rom);
ram[0x100..cmp::min(0x100 + rom.len(), 0x10000)].copy_from_slice(rom);

Self {
ram,
Expand All @@ -52,13 +53,14 @@ impl Cpu {

/// Runs the code starting the PC in the given address until
/// it finds a BRK opcode
pub fn run<M: Machine>(&mut self, addr: u16, _: &mut M) -> u16 {
pub fn run(&mut self, addr: u16, machine: &mut impl Machine) -> u16 {
self.pc = addr;
loop {
let op = self.read_byte();
match op {
opcodes::BRK => break,
opcodes::PUSH => self.op_push(),
opcodes::DEO => self.op_deo(machine),
_ => {}
}
}
Expand Down Expand Up @@ -89,6 +91,18 @@ impl Cpu {
let value = self.read_byte();
self.stack.push_byte(value);
}

#[inline]
fn op_deo(&mut self, machine: &mut impl Machine) {
let target = self.stack.pop_byte();

// write value to device port
let value = self.stack.pop_byte();
self.devices[target as usize] = value;

// callback for I/O
machine.deo(self, target);
}
}

impl fmt::Display for Cpu {
Expand All @@ -100,13 +114,12 @@ impl fmt::Display for Cpu {

#[cfg(test)]
mod tests {
use super::opcodes::*;
use super::*;

pub struct AnyMachine {}
impl Machine for AnyMachine {
fn deo(&mut self, _: &mut Cpu, _: u8) -> bool {
false
}
fn deo(&mut self, _: &mut Cpu, _: u8) {}
fn dei(&mut self, _: &mut Cpu, _: u8) {}
}

Expand All @@ -130,7 +143,7 @@ mod tests {

#[test]
pub fn runs_until_break() {
let rom = rom_from(&[0x01, 0x01, 0x00]);
let rom = rom_from(&[0x01, 0x01, BRK]);
let mut cpu = Cpu::new(&rom);

let pc = cpu.run(0x100, &mut AnyMachine {});
Expand All @@ -153,12 +166,24 @@ mod tests {

#[test]
pub fn push_opcode() {
let rom = rom_from(&[0x80, 0xab, 0x00]);
let rom = rom_from(&[PUSH, 0xab, BRK]);
let mut cpu = Cpu::new(&rom);

let pc = cpu.run(0x100, &mut AnyMachine {});
assert_eq!(pc, 0x103);
assert_eq!(cpu.stack.len(), 1);
assert_eq!(cpu.stack.byte_at(0), 0xab);
}

#[test]
pub fn deo_opcode() {
let rom = rom_from(&[PUSH, 0xab, PUSH, 0x02, DEO, BRK]);
let mut cpu = Cpu::new(&rom);

let pc = cpu.run(0x100, &mut AnyMachine {});
assert_eq!(pc, 0x106);
assert_eq!(cpu.stack.len(), 0);
assert_eq!(cpu.devices[0x02], 0xab);
// TODO: check AnyMachine.deo has been called with 0xab as target arg
}
}
1 change: 1 addition & 0 deletions coco-core/src/opcodes.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub const BRK: u8 = 0x00;
pub const DEO: u8 = 0x17;
pub const PUSH: u8 = 0x80;
18 changes: 12 additions & 6 deletions coco-core/src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@ impl Stack {
pub fn new() -> Self {
Self {
data: [0_u8; 0x100],
index: 0,
index: u8::MAX,
}
}

pub fn len(&self) -> usize {
self.index as usize
self.index.wrapping_add(1) as usize
}

pub fn push_byte(&mut self, x: u8) {
self.data[self.index as usize] = x;
self.index = self.index.wrapping_add(1);
self.data[self.index as usize] = x;
}

pub fn pop_byte(&mut self) -> u8 {
let res = self.data[self.index as usize];
self.index = self.index.wrapping_sub(1);
res
}

pub fn byte_at(&self, i: u8) -> u8 {
Expand All @@ -30,9 +36,9 @@ impl Stack {

impl fmt::Display for Stack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for i in self.index.saturating_sub(8)..self.index {
write!(f, "{:02x}", self.byte_at(i))?;
if i < self.index - 1 {
for i in self.len().saturating_sub(8)..self.len() {
write!(f, "{:02x}", self.byte_at(i as u8))?;
if i < self.len() - 1 {
write!(f, " ")?;
}
}
Expand Down
3 changes: 2 additions & 1 deletion coco-ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>👻 COCO-8</title>
<script type="module" defer src="./index.js"></script>
<link rel="stylesheet" href="styles.css" type="text/css"
<link rel="stylesheet" href="styles.css" type="text/css">
</head>
<body>
<header>
Expand All @@ -15,6 +15,7 @@ <h1>👻-8</h1>
<p>
<select name="rom" id="coco-rom-selector">
<option value="empty.rom">Empty</option>
<option value="deo_system_debug.rom">Debug</option>
</select>
</p>
</main>
Expand Down
8 changes: 4 additions & 4 deletions coco-ui/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import initWasm, { runRom } from "./vendor/coco_ui.js";

async function handleFile(file) {
const buffer = file.arrayBuffer();
const buffer = await file.arrayBuffer();
const rom = new Uint8Array(buffer);

const output = runRom(rom);
if (output.message) {
console.log(output.message);
if (output.debug) {
console.log(output.debug);
}
}

Expand Down Expand Up @@ -37,7 +37,7 @@ async function main() {
const _ = await initWasm("./vendor/coco_ui_bg.wasm");
const romSelector = document.querySelector("#coco-rom-selector");

const defaultRom = "empty.rom";
const defaultRom = "deo_system_debug.rom";
await setupRomSelector(romSelector, defaultRom);

const rom = await fetchRom(`/roms/${defaultRom}`);
Expand Down
Binary file added coco-ui/roms/deo_system_debug.rom
Binary file not shown.
11 changes: 9 additions & 2 deletions coco-ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use coco_vm::{Vm, SCREEN_HEIGHT, SCREEN_WIDTH};
#[wasm_bindgen(getter_with_clone)]
#[derive(Debug)]
pub struct Output {
pub message: Option<String>,
pub debug: String,
}

pub type Result<T> = core::result::Result<T, JsValue>;
Expand Down Expand Up @@ -38,6 +38,13 @@ const THEME: [RGB; 0x10] = [

#[wasm_bindgen(js_name=runRom)]
pub fn run_rom(rom: &[u8]) -> Result<Output> {
web_sys::console::log_1(&JsValue::from(
rom.iter()
.map(|x| format!("{:02x}", x))
.collect::<Vec<String>>()
.join(" "),
));

let cpu = Rc::new(RefCell::new(Cpu::new(&rom)));
let vm = Rc::new(RefCell::new(Vm::new()));

Expand All @@ -59,7 +66,7 @@ pub fn run_rom(rom: &[u8]) -> Result<Output> {
request_animation_frame(g.borrow().as_ref().unwrap());

Ok(Output {
message: output.message,
debug: output.sys_stdout,
})
}

Expand Down
57 changes: 30 additions & 27 deletions coco-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,38 @@ use video::{VideoBuffer, VideoDevice};

pub use video::{SCREEN_HEIGHT, SCREEN_WIDTH};

#[derive(Debug)]
pub struct Vm {
video: VideoDevice,
system: SystemDevice,
}

impl Machine for Vm {
fn dei(&mut self, cpu: &mut Cpu, target: u8) {}
fn deo(&mut self, cpu: &mut Cpu, target: u8) -> bool {
false
}
}

trait Device {
fn dei(&mut self, cpu: &mut Cpu, target: u8);
fn deo(&mut self, cpu: &mut Cpu, target: u8) -> DeviceOutput;
fn deo(&mut self, cpu: &mut Cpu, target: u8);
}

#[derive(Debug, Clone)]
pub struct DeviceOutput {
pub shall_halt: bool,
pub message: Option<String>,
pub sys_stdout: String,
}

impl core::default::Default for DeviceOutput {
fn default() -> Self {
DeviceOutput {
shall_halt: false,
message: None,
sys_stdout: String::from(""),
}
}
}

#[derive(Debug)]
pub struct Vm {
video: VideoDevice,
system: SystemDevice,
}

impl Machine for Vm {
fn dei(&mut self, cpu: &mut Cpu, target: u8) {}
fn deo(&mut self, cpu: &mut Cpu, target: u8) {
match target & 0xf0 {
0x00 => self.system.deo(cpu, target),
_ => unimplemented!(),
}
}
}
Expand All @@ -49,24 +53,23 @@ impl Vm {

pub fn on_reset(&mut self, cpu: &mut Cpu) -> DeviceOutput {
cpu.run(0x100, self);

DeviceOutput {
shall_halt: false,
message: Some(format!("{}", cpu)),
}
self.output()
}

pub fn on_video(&mut self, cpu: &mut Cpu) -> DeviceOutput {
// TODO: call video vector
cpu.run(0x100, self);

DeviceOutput {
shall_halt: false,
message: Some(format!("{}", cpu)),
}
cpu.run(0x200, self);
self.output()
}

pub fn pixels(&self) -> (&VideoBuffer, &VideoBuffer) {
(&self.video.background, &self.video.foreground)
}

pub fn output(&mut self) -> DeviceOutput {
DeviceOutput {
shall_halt: false,
sys_stdout: self.system.stdout(),
}
}
}
32 changes: 20 additions & 12 deletions coco-vm/src/system.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::DeviceOutput;

use super::Device;
use coco_core::Ports;

Expand All @@ -11,37 +9,47 @@ impl Ports for SystemPorts {
}

impl SystemPorts {
const DEBUG: u8 = 0x00;
const VECTOR: u8 = 0x00;
const DEBUG: u8 = 0x02;
}

#[derive(Debug)]
pub struct SystemDevice {}
pub struct SystemDevice {
stdout: String,
}

impl SystemDevice {
pub fn new() -> Self {
Self {}
Self {
stdout: "".to_string(),
}
}

pub fn debug(&self, cpu: &mut coco_core::Cpu) -> DeviceOutput {
pub fn debug(&mut self, cpu: &mut coco_core::Cpu) {
let ports = cpu.device_page::<SystemPorts>();

if !ports[SystemPorts::DEBUG as usize] > 0 {
return DeviceOutput::default();
if !ports[SystemPorts::DEBUG as usize] == 0 {
return;
}

// reset debug port to zero
ports[SystemPorts::DEBUG as usize] = 0x00;

// output debug info
let mut res = DeviceOutput::default();
res.message = Some(format!("{}", cpu));
self.stdout += &format!("{}", cpu);
}

/// Returns the stdout buffer and flushes it
pub fn stdout(&mut self) -> String {
let res = self.stdout.to_owned();
self.stdout = "".to_string();
res
}
}

impl Device for SystemDevice {
fn deo(&mut self, cpu: &mut coco_core::Cpu, target: u8) -> DeviceOutput {
fn deo(&mut self, cpu: &mut coco_core::Cpu, target: u8) {
match target {
SystemPorts::VECTOR => {}
SystemPorts::DEBUG => self.debug(cpu),
_ => panic!("Unimplemented device port {}", target),
}
Expand Down
Loading

0 comments on commit 9ab38d2

Please sign in to comment.