Skip to content

Instantly share code, notes, and snippets.

View yupferris's full-sized avatar

Jake Taylor yupferris

View GitHub Profile
@yupferris
yupferris / mt.rs
Last active August 20, 2018 08:44
Mario's Tennis graphics decompression routine in Rust-like pseudo-code. Manual decompilation is a bitch. :)
fn decompress(mut src: *const u8, dst: *mut u8) {
// Skip first 2 bytes (they're always zero)
src += 2;
let original_dst = dst;
// Load bytes_left
let mut bytes_left = ((*src as i32) << 8) + 1;
src += 1;
bytes_left += *src as i32;
@yupferris
yupferris / rustual-boy-arch.md
Created January 23, 2017 02:18
Steps to a more decoupled emulator

Generally, the emulator core should be more or less a black box, where you tell it to step and give it some sinks for audio/video, and it tells you how many clock cycles passed while stepping and it may or may not dump some data into those sinks. For the most part, the VirtualBoy struct already has this interface, along with AudioDriver and VideoDriver as sinks. However, it's a bit crap right now as the emu also relies on audio for a timing source, which means we can't really have a configuration that doesn't use that atm.

The reason we want to use audio as a timing source is because audio cards tend not to have timers that are perfectly synced to the computer's timer, esp. at weird sample rates. As a consequence, there will be periodic clicks and pops as the audio output buffers and the emulator go slightly out of sync. Relying on audio output as a timing source fixes this, but couples us to audio output.

It would be nice to have some kinds of abstractions; for example, a TimingSource abstraction,

@yupferris
yupferris / vf-notes.asm
Created February 12, 2017 13:03
Some Vertical Force reverse-engineering notes
- Lots of things seem to be indexed with r4; looks like it's always 0x05008000
- This is consistent with the "global data pointer" info in the tech scroll
- Looks like the offset into this mem is always negative
- Known globals (as negative offsets from r4):
-1402 (0x05007a86) - Effective OBJ group 3 ptr
Routine that hits obj group ptr's (occurs once per frame)
- r6 = data pointer. Appears to be 0x05007a80 every time (I believe this is only called from the code below).
- Looks like this just copies the 8 bytes starting at r6 into the OBJ group ptr reg's
@yupferris
yupferris / pinball-sample-playback-notes.asm
Last active November 22, 2018 13:25
Galactic Pinball sample playback disassembly/notes
// Super high-level playroutine overview:
// Timer reload set to 0x0002
// Timer int fires every ~50us (no, that's not a typo)
// Store 0x00 in timer control (large interval, zero interrupt disable, timer disable)
// Store 0x19 in timer control (small interval, zero interrupt enable, timer enable)
// Output volume to VOICE_1_ENVELOPE_DATA and VOICE_2_ENVELOPE_DATA
// Data stream
// 0xXX where 0xXX != 0x0f => envelope data <- 0xXX << 4 (reload value = 0xXX & 0x0f; count down to 0)
// 0x0f 0xXX 0xYY where 0xXX != 0x0f => voice volume <- 0xXX; envelope data <- 0xYY << 4
@yupferris
yupferris / tennis.rs
Created February 23, 2017 21:08
You know the drill
use std::io::{self, Read};
use std::fs::File;
use std::path::Path;
fn main() {
let rom_file_name = "C:\\msys64\\home\\ferris\\dev\\projects\\vb-rs-corpus\\Mario's Tennis (Japan, USA).vb";
let buf = load(rom_file_name).unwrap();
let src = 0xfff9fb4c;
let dst = 0x00078000;
@yupferris
yupferris / pinball.rs
Last active February 25, 2017 19:59
Sample extraction for Galactic Pinball
use std::io::{self, Write, Read, BufWriter};
use std::fs::File;
use std::path::Path;
const NUM_CHANNELS: usize = 1;
const BITS_PER_SAMPLE: usize = 16;
fn main() {
let rom_file_name = "C:\\msys64\\home\\ferris\\dev\\projects\\vb-rs-corpus\\Galactic Pinball (Japan, USA).vb";
let buf = load(rom_file_name).unwrap();
@yupferris
yupferris / tesoft.asm
Created March 2, 2017 20:35
Sample playback routine info for T&E soft logo in Red Alarm
// Super high-level playroutine overview:
// Timer reload set to 0x0004
// Timer int fires every 120us (sample rate of ~8333.3hz)
// Store 0x15 in timer control (small interval, zero interrupt disable, clear zero status, timer enable)
// Output volumes to VOICE_1_VOLUME - VOICE_5_VOLUME
// Store 0x19 in timer control (small interval, zero interrupt enable, timer enable)
* 0xfffffe10 7c44 add 28, r3
0xfffffe12 23dc0000 st.w r1, 0[r3]
0xfffffe16 20bc0207 movhi 0x702, r0, r1
@yupferris
yupferris / bowling.asm
Last active March 9, 2017 21:00
Virtual Bowling sample playback routine reversing notes
// Super high-level playroutine overview:
// Timer reload set to 12, 13, 5 (depending on sample)
// Timer int fires every ??us (sample rate of ??hz)
// Store 0x1d in timer control (small interval, zero interrupt enable, clear zero status, timer enable)
// Output volume to VOICE_1_ENVELOPE_DATA
// Sample value -> register value lookup table:
0xffffd258 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0
// Sample playback routine (only thing the timer is used for in this game)
@yupferris
yupferris / stuff.rs
Created June 25, 2017 19:29
wavy stuff
extern crate minifb;
extern crate time;
use minifb::{Key, Scale, WindowOptions, Window};
use std::f64::consts::PI;
fn circle(x: f64, y: f64, x_offset: f64, y_offset: f64, rad: f64) -> bool {
let x_distance = x - x_offset;
let y_distance = y - y_offset;
@yupferris
yupferris / vic.txt
Created September 10, 2017 20:09
VIC pseudocode (not necessarily accurate/rigorous, but useful enough to explain stuff)
// Sometime outside of display area..
VCBASE := 0
VIDEO_COLOR_BUFFER := 0
for RASTER in 0..312 {
for line_cycle in 0..63 {
badline_condition := (RASTER & 0x07) == (YSCROLL & 0x07)
if (badline_condition) {
MODE = MODE_DISPLAY
}