diff --git a/README.md b/README.md index b8a166c..9b2e028 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ For more detail, check out this post about how I started the project: [Making a 68000 Emulator in Rust](https://jabberwocky.ca/posts/2021-11-making_an_emulator.html) -Running -------- +Computie +-------- For Computie, it can do everything the 68k-SMT board can do, including run the monitor program and load the Computie OS kernel and boot it from the @@ -32,6 +32,9 @@ host, and set up host routing. The exact commands in `src/machines/computie.rs` might need to be adjusted to work on different hosts. +TRS-80 +------ + For the TRS-80, it can run Level I or Level II Basic, but it doesn't yet support a cassette tape drive or floppy drive. I haven't tested it that thoroughly either, so any help with it would be welcome. I mostly made it to @@ -40,16 +43,50 @@ Genesis emulator. The frontend uses the [`minifb`](https://github.com/emoon/rust_minifb) rust crate to open a window and render the characters to screen, as well as accept input from the keyboard. ``` -cargo run -p moa-minifb --release --bin moa-trs-80 -- +cargo run -p moa-minifb --release --bin moa-trs-80 ``` By default it will start Level I Basic. To use the other rom, add the option `--rom binaries/trs80/level2.rom` -The Genesis emulator is a work in progress but can be run with: +![alt text](images/trs-80-level-ii-basic.png) + +Sega Genesis/MegaDrive +---------------------- + +It can be run with: ``` -cargo run -p moa-minifb --release --bin moa-genesis +cargo run -p moa-minifb --release --bin moa-genesis -- ``` +The Genesis emulator is a work in progress. It can play a few games but some +games won't run because the bank switching for the Z80 coprocessor is not +working yet, and some games will hang waiting for the Z80 to respond. For the +video processor, the window layer is not drawn and the layer priority is not +handled. The horizontal scroll also doesn't work on a line-by-line basis so it +tends to be quite jerky as you move, with the sprites and cells misaligned +until you've moved one complete cell over (8x8 pixels). + +On the Sonic 2 title screen, the colours for Tails are wonky, probably because +there's some trickery going on to get more than 16 colours per line, but the +emulator currently renders the whole frame at once instead of line by line, so +changes that should be made while the screen is updating don't show up +![alt text](images/sega-genesis-sonic2-title.png) + +In the first one, it's mostly working but the bottom of the clouds should be a +different colour. Highlight/Shadow colours are not yet supported +![alt text](sega-genesis-sonic2-start.png) + +I'm not yet sure why the clouds in the background are cut off suddenly +![alt text](sega-genesis-sonic2-bridge.png) + +There are some graphics glitches in Earthworm Jim, but it's almost playable if it +wasn't for the 'jump' button, which only makes him jump a few pixels +![alt text](sega-genesis-earthworm-jim.png) + + +General Options +--------------- + By default, the minifb frontend will scale the window by 2. This can be changed with the `--scale [1,2,4]` option. diff --git a/frontends/moa-minifb/src/bin/moa-genesis.rs b/frontends/moa-minifb/src/bin/moa-genesis.rs index b1bcb44..cb71e92 100644 --- a/frontends/moa-minifb/src/bin/moa-genesis.rs +++ b/frontends/moa-minifb/src/bin/moa-genesis.rs @@ -1,14 +1,20 @@ use moa_minifb; -use moa::machines::genesis::build_genesis; +use moa::machines::genesis::{build_genesis, SegaGenesisOptions}; fn main() { let matches = moa_minifb::new("Sega Genesis/Mega Drive Emulator") + .arg(" 'ROM file to load (must be flat binary)'") .get_matches(); + let mut options = SegaGenesisOptions::new(); + if let Some(filename) = matches.value_of("ROM") { + options.rom = filename.to_string(); + } + moa_minifb::run(matches, |frontend| { - build_genesis(frontend) + build_genesis(frontend, options) }); } diff --git a/images/sega-genesis-earthworm-jim.png b/images/sega-genesis-earthworm-jim.png new file mode 100644 index 0000000..35ac0e1 Binary files /dev/null and b/images/sega-genesis-earthworm-jim.png differ diff --git a/images/sega-genesis-sonic2-bridge.png b/images/sega-genesis-sonic2-bridge.png new file mode 100644 index 0000000..370cd8d Binary files /dev/null and b/images/sega-genesis-sonic2-bridge.png differ diff --git a/images/sega-genesis-sonic2-start.png b/images/sega-genesis-sonic2-start.png new file mode 100644 index 0000000..9c2d4ce Binary files /dev/null and b/images/sega-genesis-sonic2-start.png differ diff --git a/images/sega-genesis-sonic2-title.png b/images/sega-genesis-sonic2-title.png new file mode 100644 index 0000000..241368c Binary files /dev/null and b/images/sega-genesis-sonic2-title.png differ diff --git a/images/trs-80-level-ii-basic.png b/images/trs-80-level-ii-basic.png new file mode 100644 index 0000000..d825b6b Binary files /dev/null and b/images/trs-80-level-ii-basic.png differ diff --git a/src/machines/genesis.rs b/src/machines/genesis.rs index d02dbbe..8a953c8 100644 --- a/src/machines/genesis.rs +++ b/src/machines/genesis.rs @@ -14,15 +14,29 @@ use crate::peripherals::genesis; use crate::host::traits::{Host}; -pub fn build_genesis(host: &mut H) -> Result { +pub struct SegaGenesisOptions { + pub rom: String, +} + +impl SegaGenesisOptions { + pub fn new() -> Self { + Self { + rom: "".to_string(), + } + } +} + +pub fn build_genesis(host: &mut H, options: SegaGenesisOptions) -> Result { let mut system = System::new(); + let mut rom = MemoryBlock::load(&options.rom).unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/GenTestV3.0.bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/HDRV_Genesis_Test_v1_4.bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/ComradeOj's tiny demo.bin").unwrap(); + //let mut rom = MemoryBlock::load("binaries/genesis/Digital Rain demo.bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/Sonic The Hedgehog (W) (REV 00) [!].bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/Sonic The Hedgehog (W) (REV 01) [!].bin").unwrap(); - let mut rom = MemoryBlock::load("binaries/genesis/Sonic the Hedgehog 2 (JUE) [!].bin").unwrap(); + //let mut rom = MemoryBlock::load("binaries/genesis/Sonic the Hedgehog 2 (JUE) [!].bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/Sonic the Hedgehog 3 (U) [!].bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/Earthworm Jim (U) [h1].bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/Home Alone (beta).bin").unwrap(); @@ -50,7 +64,7 @@ pub fn build_genesis(host: &mut H) -> Result { let bus_request = coproc.bus_request.clone(); system.add_addressable_device(0x00a00000, coproc_mem)?; - //system.add_device("coproc", wrap_transmutable(coproc))?; + system.add_device("coproc", wrap_transmutable(coproc))?; @@ -65,27 +79,7 @@ pub fn build_genesis(host: &mut H) -> Result { system.add_peripheral("vdp", 0x00c00000, wrap_transmutable(vdp)).unwrap(); - // TODO this is temporarily a 68010 because GenTest tests the CPU type by relying on the illegal instruction - // exception which is bypassed to Error and I don't want to un-bypass yet while testing - let mut cpu = M68k::new(M68kType::MC68010, 7_670_454, BusPort::new(0, 24, 16, system.bus.clone())); - - //cpu.enable_tracing(); - //cpu.add_breakpoint(0x206); - //cpu.add_breakpoint(0x1dd0); // Sonic: some kind of palette fading function - //cpu.add_breakpoint(0x16ee); - //cpu.decoder.dump_disassembly(&mut system, 0x206, 0x2000); - - //cpu.add_breakpoint(0x16a0e); - //cpu.add_breakpoint(0x16812); - //cpu.add_breakpoint(0x166ec); - //cpu.add_breakpoint(0x13e18); - //cpu.add_breakpoint(0x16570); - //cpu.add_breakpoint(0x1714); - - //cpu.add_breakpoint(0x43c2); - - //cpu.add_breakpoint(0x21a); - + let mut cpu = M68k::new(M68kType::MC68000, 7_670_454, BusPort::new(0, 24, 16, system.bus.clone())); system.add_interruptable_device("cpu", wrap_transmutable(cpu)).unwrap(); Ok(system) diff --git a/src/peripherals/genesis/ym7101.rs b/src/peripherals/genesis/ym7101.rs index cd0019e..96b952a 100644 --- a/src/peripherals/genesis/ym7101.rs +++ b/src/peripherals/genesis/ym7101.rs @@ -418,9 +418,8 @@ impl Ym7101State { for cell_y in 0..cells_v { for cell_x in 0..cells_h { - let pattern_addr = self.get_pattern_addr(cell_table, cell_x as usize, cell_y as usize); - let pattern = read_beu16(&self.vram[pattern_addr..]); - self.draw_pattern(frame, pattern, (cell_x << 3) as u32, (cell_y << 3) as u32); + let pattern_w = read_beu16(&self.vram[self.get_pattern_addr(cell_table, cell_x as usize, cell_y as usize)..]); + self.draw_pattern(frame, pattern_w, (cell_x << 3) as u32, (cell_y << 3) as u32); } } }