Add assembly example code (#80)

* Add assembly example code

This should make it easier for beginners to understand
how to test this emulator.

* cleanup

* fix typo
This commit is contained in:
Matthias Endler 2023-06-20 10:32:28 +02:00 committed by GitHub
parent 62d4b73cd5
commit e88c971625
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 130 additions and 1 deletions

View File

@ -65,6 +65,57 @@ fn main() {
}
```
The same can be achieved, by compiling the euclid example yourself.
First install a 6502 assembler and linker, e.g. [cc65](https://cc65.github.io/cc65/).
```sh
brew install cc65
```
Then compile and link the assembly file:
```sh
cd examples/asm/euclid
ca65 euclid.a65
ld65 -C ../linker.cfg -o euclid.bin euclid.o
```
This will create a binary file `euclid.bin` that you can load into the emulator:
```rust
use mos6502::memory::Bus;
use mos6502::memory::Memory;
use mos6502::cpu;
use std::fs::read;
fn main() {
// Calculate the greatest common divisor of 56 and 49
// using Euclid's algorithm.
let zero_page_data = [56, 49];
// Load the binary file from disk
let program = match read("examples/asm/euclid/euclid.bin") {
Ok(data) => data,
Err(err) => {
println!("Error reading euclid.bin: {}", err);
return;
}
};
let mut cpu = cpu::CPU::new(Memory::new());
cpu.memory.set_bytes(0x00, &zero_page_data);
cpu.memory.set_bytes(0x10, &program);
cpu.registers.program_counter = 0x10;
cpu.run();
// The expected GCD is 7
assert_eq!(7, cpu.registers.accumulator);
}
```
## Credits
This started off as a fork of [amw-zero/6502-rs](https://github.com/amw-zero/6502-rs),

View File

@ -0,0 +1,33 @@
; euclid.a65
; A program to find the greatest common divisor of two numbers
.ORG $1000
; .algo
LDA $00 ; Load from F to A
; .algo_
sec ; Set carry flag
SBC $01 ; Subtract S from the number in A (from F)
BEQ end ; Jump to .end if the difference is zero
BMI swap ; Jump to .swap if the difference is negative
STA $00 ; Load A to F
JMP algo_ ; Jump to .algo_
; .end
end:
LDA $00 ; Load from F to A
BRK ; Break (end program)
; .swap
swap:
LDX $00 ; Load F to X
LDY $01 ; Load S to Y
STX $01 ; Store X to S
STY $00 ; Store Y to F
JMP algo ; Jump to .algo
algo:
JMP algo ; Infinite loop to prevent program from ending
algo_:
JMP algo_ ; Infinite loop to prevent program from ending

Binary file not shown.

11
examples/asm/linker.cfg Normal file
View File

@ -0,0 +1,11 @@
MEMORY {
ZP: start = $0000, size = $0100, type = rw, define = yes;
RAM: start = $0100, size = $0200, type = rw, define = yes;
ROM: start = $8000, size = $8000, type = ro;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
DATA: load = RAM, type = rw;
CODE: load = ROM, type = ro;
}

34
examples/euclid.rs Normal file
View File

@ -0,0 +1,34 @@
use mos6502::cpu;
use mos6502::memory::Bus;
use mos6502::memory::Memory;
use std::fs::read;
fn main() {
println!("Enter two numbers (< 128) separated by a space to know their GCD.");
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
let zero_page_data = input
.split_whitespace()
.map(|s| s.parse::<u8>().unwrap())
.collect::<Vec<u8>>();
// Load the binary file from disk
let program = match read("examples/asm/euclid/euclid.bin") {
Ok(data) => data,
Err(err) => {
println!("Error reading euclid.bin: {}", err);
return;
}
};
let mut cpu = cpu::CPU::new(Memory::new());
cpu.memory.set_bytes(0x00, &zero_page_data);
cpu.memory.set_bytes(0x10, &program);
cpu.registers.program_counter = 0x10;
cpu.run();
println!("GCD is {}", cpu.registers.accumulator);
}

View File

@ -5,7 +5,7 @@ use mos6502::memory::Bus;
use mos6502::memory::Memory;
fn main() {
println!("Enter two numbers (< 128) to know their GCD:");
println!("Enter two numbers (< 128) separated by a space to know their GCD.");
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();