Skip to content

Commit

Permalink
GSU: fix up a lot of load/store ops
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Feb 28, 2024
1 parent 59eac7d commit 8737441
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 33 deletions.
122 changes: 89 additions & 33 deletions src/cpu_gsu/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ impl CpuGsu {
if self.verbose {
println!("{}", self.regs);
println!("SREG: R{} DREG: R{}", sreg, dreg);
println!("--> {}", Self::instr_str(instr, alt1, alt2, sreg, dreg));
println!(
"--> {}",
Self::instr_str(instr, alt1, alt2, flag_b, sreg, dreg)
);
}

// SREG/DREG/ALTx are reset after execution, but should persist
Expand Down Expand Up @@ -347,19 +350,29 @@ impl CpuGsu {
}
(0x30..=0x3B, false, false) => {
// STW (Rn)
let addr = (usize::from(self.regs.read(Register::RAMBR)) << 8)
| usize::from(self.regs.read_r((instr & 0x0F) as usize));
let addr = self.regs.read_r((instr & 0x0F) as usize);
let addr_l =
(usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(addr & !1);
let addr_h =
(usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(addr | 1);
let v = self.regs.read_r(sreg);
self.ram[addr] = v as u8;
self.ram[addr + 1] = (v >> 8) as u8;
self.last_ramaddr = addr;

if addr & 1 != 0 {
self.ram[addr_h] = v as u8;
self.ram[addr_l] = (v >> 8) as u8;
} else {
self.ram[addr_l] = v as u8;
self.ram[addr_h] = (v >> 8) as u8;
}
self.last_ramaddr = addr as usize;
self.cycles(1)?;
}
(0x30..=0x3B, true, false) => {
// STB (Rn)
let addr = (usize::from(self.regs.read(Register::RAMBR)) << 8)
let addr = (usize::from(self.regs.read(Register::RAMBR)) << 16)
| usize::from(self.regs.read_r((instr & 0x0F) as usize));
let v = self.regs.read_r(sreg);
// Ignores high byte
self.ram[addr] = v as u8;
self.last_ramaddr = addr;
self.cycles(1)?;
Expand Down Expand Up @@ -395,19 +408,26 @@ impl CpuGsu {
}
(0x40..=0x4B, false, false) => {
// LDW (Rn)
let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 8)
| usize::from(self.regs.read_r((instr & 0x0F) as usize));
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 8)
| usize::from(self.regs.read_r((instr & 0x0F) as usize).wrapping_add(1));
let v = self.ram[addr_l] as u16 | ((self.ram[addr_h] as u16) << 8);
let addr = self.regs.read_r((instr & 0x0F) as usize);
let addr_l =
(usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(addr & !1);
let addr_h =
(usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(addr | 1);
let v = if addr & 1 != 0 {
((self.ram[addr_l] as u16) << 8) | (self.ram[addr_h] as u16)
} else {
self.ram[addr_l] as u16 | ((self.ram[addr_h] as u16) << 8)
};

self.last_ramaddr = addr_l;
self.regs.write_r(dreg, v);
self.cycles(7)?;
}
(0x40..=0x4B, true, false) => {
// LDB (Rn)
let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 8)
let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 16)
| usize::from(self.regs.read_r((instr & 0x0F) as usize));
// Zero-expanded
let v = self.ram[addr_l] as u16;
self.last_ramaddr = addr_l;
self.regs.write_r(dreg, v);
Expand Down Expand Up @@ -643,8 +663,13 @@ impl CpuGsu {
let addr = self.last_ramaddr;
let v = self.regs.read_r(sreg);

self.ram[addr] = v as u8;
self.ram[addr + 1] = (v >> 8) as u8;
if addr & 1 != 0 {
self.ram[(addr & !1) + 1] = v as u8;
self.ram[addr & !1] = (v >> 8) as u8;
} else {
self.ram[addr & !1] = v as u8;
self.ram[(addr & !1) + 1] = (v >> 8) as u8;
}
self.last_ramaddr = addr;
self.cycles(1)?;
}
Expand Down Expand Up @@ -771,9 +796,10 @@ impl CpuGsu {
let reg = (instr & 0x0F) as usize;
let yy = (self.fetch() as u16).wrapping_mul(2);

let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 8) | usize::from(yy);
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 8)
let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(yy);
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 16)
| usize::from(yy.wrapping_add(1));

let val = ((self.ram[addr_h] as u16) << 8) | (self.ram[addr_l] as u16);
self.last_ramaddr = addr_l;
self.regs.write_r(reg, val);
Expand All @@ -784,8 +810,8 @@ impl CpuGsu {
let reg = (instr & 0x0F) as usize;
let yy = (self.fetch() as u16).wrapping_mul(2);

let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 8) | usize::from(yy);
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 8)
let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(yy);
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 16)
| usize::from(yy.wrapping_add(1));
let val = self.regs.read_r(reg);
self.ram[addr_l] = val as u8;
Expand All @@ -800,7 +826,7 @@ impl CpuGsu {
if flag_b {
// MOVES
let val = self.regs.read_r(reg);
self.regs.write_r(sreg, val);
self.regs.write_r(dreg, val);
self.regs.write_flags(&[
(Flag::S, val & 0x8000 != 0),
(Flag::Z, val == 0),
Expand Down Expand Up @@ -947,13 +973,19 @@ impl CpuGsu {
let hi = self.fetch() as u16;
let yy = (hi << 8) | lo;

let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 8) | usize::from(yy);
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 8)
| usize::from(yy.wrapping_add(1));
let addr_l =
(usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(yy & !1);
let addr_h =
(usize::from(self.regs.read(Register::RAMBR)) << 16) | usize::from(yy | 1);
let val = self.regs.read_r(reg);
self.ram[addr_l] = val as u8;
self.ram[addr_h] = (val >> 8) as u8;
self.last_ramaddr = addr_l;
if yy & 1 != 0 {
self.ram[addr_h] = val as u8;
self.ram[addr_l] = (val >> 8) as u8;
} else {
self.ram[addr_l] = val as u8;
self.ram[addr_h] = (val >> 8) as u8;
}
self.last_ramaddr = yy as usize;
self.cycles(4)?;
}
(0xF0..=0xFF, true, false) => {
Expand All @@ -963,11 +995,16 @@ impl CpuGsu {
let hi = self.fetch() as u16;
let yy = (hi << 8) | lo;

let addr_l = (usize::from(self.regs.read(Register::RAMBR)) << 8) | usize::from(yy);
let addr_h = (usize::from(self.regs.read(Register::RAMBR)) << 8)
| usize::from(yy.wrapping_add(1));
let val = ((self.ram[addr_h] as u16) << 8) | (self.ram[addr_l] as u16);
self.last_ramaddr = addr_l;
let addr_l =
(usize::from(self.regs.read(Register::RAMBR)) << 8) | usize::from(yy & !1);
let addr_h =
(usize::from(self.regs.read(Register::RAMBR)) << 8) | usize::from(yy | 1);
let val = if yy & 1 != 0 {
((self.ram[addr_l] as u16) << 8) | (self.ram[addr_h] as u16)
} else {
((self.ram[addr_h] as u16) << 8) | (self.ram[addr_l] as u16)
};
self.last_ramaddr = yy as usize;
self.regs.write_r(reg, val);
self.cycles(4)?;
}
Expand Down Expand Up @@ -1039,11 +1076,30 @@ impl CpuGsu {
v
}

pub fn instr_str(instr: u8, alt1: bool, alt2: bool, sreg: usize, dreg: usize) -> String {
pub fn instr_str(
instr: u8,
alt1: bool,
alt2: bool,
b_flag: bool,
sreg: usize,
dreg: usize,
) -> String {
let l = instr & 0x0F;
match (instr, alt1, alt2) {
(0x20..=0x2F, false, false) => format!("WITH/MOVE R{}", l),
(0x00, false, false) => "STOP".to_string(),
(0x01, false, false) => "NOP".to_string(),
(0x03, false, false) => format!("LSR R{} = R{} << 1", dreg, sreg),
(0x04, false, false) => "ROL".to_string(),
(0x09, _, _) => "BEQ".to_string(),
(0x10..=0x1F, _, _) if b_flag => format!("MOVE R{}, R{}", l, sreg),
(0x10..=0x1F, _, _) => format!("TO R{}", l),
(0x20..=0x2F, false, false) => format!("WITH R{}", l),
(0x3C, false, false) => "LOOP".to_string(),
(0x97, false, false) => "ROR".to_string(),
(0xB0..=0xBF, _, _) if b_flag => format!("MOVES R{}, R{}", dreg, sreg),
(0xB0..=0xBF, _, _) => format!("FROM R{}", l),
(0xC1..=0xCF, false, false) => format!("OR R{}", l),
(0xC1..=0xCF, false, true) => format!("OR #{:02X}", l),
_ => format!(
"? {} {:02X}",
match (alt1, alt2) {
Expand Down
134 changes: 134 additions & 0 deletions src/cpu_gsu/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,52 @@ const TO: u8 = 0x10;
const WITH: u8 = 0x20;
const FROM: u8 = 0xB0;
const IWT: u8 = 0xF0;
const LDW: u8 = 0x40; // 0..11
const STW: u8 = 0x30; // 0..11
const LM: u8 = 0xF0;
const LMS: u8 = 0xA0;
const SM: u8 = 0xF0;
const SMS: u8 = 0xA0;

fn cpu(code: &[u8]) -> CpuGsu {
let c = CpuGsu::new(code);
c
}

fn cpu_ram(code: &[u8], ram: &[(usize, u8)]) -> CpuGsu {
let mut c = CpuGsu::new(code);
for (addr, val) in ram {
c.ram[*addr] = *val;
}
c
}

fn cpu_ram_steps(code: &[u8], ram: &[(usize, u8)], steps: usize) -> CpuGsu {
let mut c = cpu_ram(code, ram);
c.regs.write_flags(&[(Flag::G, true)]);
for _ in 0..steps {
c.step().unwrap();
}
c
}

fn cpu_ram_reg_steps(
code: &[u8],
ram: &[(usize, u8)],
regs: &[(Register, u16)],
steps: usize,
) -> CpuGsu {
let mut c = cpu_ram(code, ram);
for (reg, val) in regs {
c.regs.write(*reg, *val);
}
c.regs.write_flags(&[(Flag::G, true)]);
for _ in 0..steps {
c.step().unwrap();
}
c
}

fn cpu_steps(code: &[u8], steps: usize) -> CpuGsu {
let mut c = cpu(code);
c.regs.write_flags(&[(Flag::G, true)]);
Expand Down Expand Up @@ -141,3 +181,97 @@ fn op_move_clears_altx_b() {
assert!(!c.regs.test_flag(Flag::ALT1));
assert!(!c.regs.test_flag(Flag::ALT2));
}

#[test]
fn op_ldw() {
let c = cpu_ram_steps(
&[IWT | 4, 0x22, 0x11, TO | 3, LDW | 4],
&[(0x1122, 0xBB), (0x1123, 0xAA)],
3,
);
assert_eq!(c.regs.read(Register::R3), 0xAABB);

let c = cpu_ram_steps(
&[IWT | 4, 0x23, 0x11, TO | 3, LDW | 4],
&[(0x1122, 0xBB), (0x1123, 0xAA)],
3,
);
assert_eq!(c.regs.read(Register::R3), 0xBBAA);
}

#[test]
fn op_lm() {
let c = cpu_ram_steps(
&[ALT1, LM | 4, 0x22, 0x11],
&[(0x1122, 0xBB), (0x1123, 0xAA)],
2,
);
assert_eq!(c.regs.read(Register::R4), 0xAABB);

let c = cpu_ram_steps(
&[ALT1, LM | 4, 0x23, 0x11],
&[(0x1122, 0xBB), (0x1123, 0xAA)],
2,
);
assert_eq!(c.regs.read(Register::R4), 0xBBAA);
}

#[test]
fn op_lms() {
let c = cpu_ram_steps(&[ALT1, LMS | 3, 0x08], &[(0x10, 0xBB), (0x11, 0xAA)], 2);
assert_eq!(c.regs.read(Register::R3), 0xAABB);
}

#[test]
fn op_ldb() {
let c = cpu_ram_reg_steps(
&[IWT | 4, 0x22, 0x11, TO | 3, ALT1, LDW | 4],
&[(0x1122, 0xBB), (0x1123, 0xAA)],
&[(Register::R3, 0xFFFF)],
4,
);
assert_eq!(c.regs.read(Register::R3), 0x00BB);

let c = cpu_ram_reg_steps(
&[IWT | 4, 0x23, 0x11, ALT1, TO | 3, LDW | 4],
&[(0x1122, 0xBB), (0x1123, 0xAA)],
&[(Register::R3, 0xFFFF)],
4,
);
assert_eq!(c.regs.read(Register::R3), 0xAA);
}

#[test]
fn op_stw() {
let c = cpu_steps(
&[IWT | 4, 0x22, 0x11, IWT | 5, 0xBB, 0xAA, FROM | 5, STW | 4],
4,
);
assert_eq!(c.ram[0x1122], 0xBB);
assert_eq!(c.ram[0x1123], 0xAA);

let c = cpu_steps(
&[IWT | 4, 0x23, 0x11, IWT | 5, 0xBB, 0xAA, FROM | 5, STW | 4],
4,
);
assert_eq!(c.ram[0x1122], 0xAA);
assert_eq!(c.ram[0x1123], 0xBB);
}

#[test]
fn op_sm() {
let c = cpu_steps(&[IWT | 5, 0xBB, 0xAA, ALT2, SM | 5, 0x22, 0x11], 3);
assert_eq!(c.ram[0x1122], 0xBB);
assert_eq!(c.ram[0x1123], 0xAA);

let c = cpu_steps(&[IWT | 5, 0xBB, 0xAA, ALT2, SM | 5, 0x23, 0x11], 3);
assert_eq!(c.ram[0x1122], 0xAA);
assert_eq!(c.ram[0x1123], 0xBB);
}

#[test]
fn op_sms() {
let c = cpu_steps(&[IWT | 4, 0xBB, 0xAA, ALT2, SMS | 4, 0x08], 4);
assert_eq!(c.ram[0x10], 0xBB);
assert_eq!(c.ram[0x11], 0xAA);
}

0 comments on commit 8737441

Please sign in to comment.