Skip to content

Commit

Permalink
148 pending opcodes. Use of pseudo-register (HL)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Feb 10, 2020
1 parent 48140c5 commit 0c3d1f3
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 170 deletions.
75 changes: 24 additions & 51 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,26 +224,11 @@ impl Decoder {
1 => Some(build_inc_dec_rr(RP[p.p], false)), // DEC rr -- 16-bit dec
_ => panic!("Unreachable")
},
4 => match p.y {
6 => Some(build_inc_dec_phl(true)), // INC (HL) -- 8 bit inc
0..=7 => Some(build_inc_dec_r(R[p.y], true)), // INC r -- 8 bit inc
_ => panic!("Unreachable")
},
5 => match p.y {
6 => Some(build_inc_dec_phl(false)), // DEC (HL) -- 8 bit dec
0..=7 => Some(build_inc_dec_r(R[p.y], false)), // DEC r -- 8 bit dec
_ => panic!("Unreachable")
},
6 => match p.y {
6 => Some(build_ld_prr_n(Reg16::HL)), // LD (HL), n -- 8 bit load imm
0..=7 => Some(build_ld_r_n(R[p.y])), // LD r, n -- 8 bit load imm
_ => panic!("Unreachable")
},
4 => Some(build_inc_dec_r(R[p.y], true)), // INC r -- 8 bit inc
5 => Some(build_inc_dec_r(R[p.y], false)), // DEC r -- 8 bit dec
6 => Some(build_ld_r_n(R[p.y])), // LD r, n -- 8 bit load imm
7 => match p.y {
0 => Some(build_left_r(Reg8::A, ShiftMode::RotateCarry, true)),
1 => Some(build_right_r(Reg8::A, ShiftMode::RotateCarry, true)),
2 => Some(build_left_r(Reg8::A, ShiftMode::Rotate, true)),
3 => Some(build_right_r(Reg8::A, ShiftMode::Rotate, true)),
0..=3 => Some(build_rot_r(Reg8::A, ROT[p.y], true)), // rotA
4 => None, // DAA, decimal adjust A
5 => Some(build_cpl()), // CPL, complement adjust A
6 => Some(build_scf()), // SCF, set carry flag
Expand All @@ -252,18 +237,9 @@ impl Decoder {
},
_ => panic!("Unreachable")
},
1 => match p.y {
6 => match p.z {
6 => Some(build_halt()),
0..=7 => None, // LD (HL), r -- 8 bit loading
_ => panic!("Unreachable")
},
0..=7 => match p.z {
6 => Some(build_ld_r_prr(R[p.y], Reg16::HL)), // LD r, (HL) -- 8 bit loading
0..=7 => Some(build_ld_r_r(R[p.y], R[p.z], false)), // LD r[y], r[z] -- 8 bit load imm
_ => panic!("Unreachable")
}
_ => panic!("Unreachable")
1 => match (p.z, p.y) {
(6, 6) => Some(build_halt()), // HALT, excetion instead of LD (HL), (HL)
_ => Some(build_ld_r_r(R[p.y], R[p.z], false)), // LD r[y], r[z] -- 8 bit load imm
},
2 => None,
3 => match p.z {
Expand Down Expand Up @@ -321,26 +297,12 @@ impl Decoder {
fn load_prefix_cb(&mut self) {
for c in 0..=255 {
let p = DecodingHelper::parts(c);
let opcode = match p.z {
6 => None, // (HL) bit manipulation
0..=7 => match p.x {
0 => match p.y {
0 => Some(build_left_r(R[p.z], ShiftMode::RotateCarry, false)), // RLC r
1 => Some(build_right_r(R[p.z], ShiftMode::RotateCarry, false)), // RRC r
2 => Some(build_left_r(R[p.z], ShiftMode::Rotate, false)), // RL r
3 => Some(build_right_r(R[p.z], ShiftMode::Rotate, false)), // RR r
4 => Some(build_left_r(R[p.z], ShiftMode::Arithmetic, false)), // SLA r
5 => Some(build_right_r(R[p.z], ShiftMode::Arithmetic, false)), // SRA r
6 => Some(build_left_r(R[p.z], ShiftMode::Logical, false)), // SSL r
7 => Some(build_right_r(R[p.z], ShiftMode::Logical, false)), // SRL r
_ => panic!("Unreachable")
},
1 => Some(build_bit_r(p.y as u8, R[p.z])), // BIT
2 => Some(build_res_r(p.y as u8, R[p.z])), // RES
3 => Some(build_set_r(p.y as u8, R[p.z])), // SET
4..=7 => None, // Invalid instruction NONI + NOP
_ => panic!("Unreachable")
},
let opcode = match p.x {
0 => Some(build_rot_r(R[p.z], ROT[p.y], false)), // Shifts
1 => Some(build_bit_r(p.y as u8, R[p.z])), // BIT
2 => Some(build_res_r(p.y as u8, R[p.z])), // RES
3 => Some(build_set_r(p.y as u8, R[p.z])), // SET
4..=7 => None, // Invalid instruction NONI + NOP
_ => panic!("Unreachable")
};

Expand Down Expand Up @@ -436,3 +398,14 @@ pub const CC: [(Flag, bool, &'static str); 8] = [
(Flag::S, false, "P"),
(Flag::S, true, "N")
];

pub const ROT: [(ShiftDir, ShiftMode, &'static str); 8] = [
(ShiftDir::Left, ShiftMode::RotateCarry, "RLC"),
(ShiftDir::Right, ShiftMode::RotateCarry, "RRC"),
(ShiftDir::Left, ShiftMode::Rotate, "RL" ),
(ShiftDir::Right, ShiftMode::Rotate, "RR" ),
(ShiftDir::Left, ShiftMode::Arithmetic, "SLA"),
(ShiftDir::Right, ShiftMode::Arithmetic, "SRA"),
(ShiftDir::Left, ShiftMode::Logical, "SLL"),
(ShiftDir::Right, ShiftMode::Logical, "SRL"),
];
33 changes: 4 additions & 29 deletions src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,43 +81,18 @@ pub fn build_inc_dec_r(r: Reg8, inc: bool) -> Opcode {
let overflow = if inc {0x80} else {0x7f};
let half_overflow = if inc {0x00} else {0x0f};
Opcode {
name: format!("{} {:?}", mnemonic, r),
name: format!("{} {}", mnemonic, r),
bytes: 1,
cycles: 4,
action: Box::new(move |state: &mut State| {
let mut v = state.reg.get8(r);
v = v.wrapping_add(delta);
state.reg.set8(r, v);

state.reg.update_sz53_flags(v);
state.reg.clear_flag(Flag::N);
state.reg.put_flag(Flag::P, v == overflow);
state.reg.put_flag(Flag::H, (v & 0x0F) == half_overflow);
// Flag::C is not affected
})
}
}

pub fn build_inc_dec_phl(inc: bool) -> Opcode {
let delta = if inc {1} else {-1 as i8 as u8};
let mnemonic = if inc {"INC"} else {"DEC"};
let overflow = if inc {0x80} else {0x7f};
let half_overflow = if inc {0x00} else {0x0f};
Opcode {
name: format!("{} (HL)", mnemonic),
bytes: 1,
cycles: 11,
cycles: 4, // (HL) 11, (IX+d) 23
action: Box::new(move |state: &mut State| {
let p = state.reg.get16(Reg16::HL);
let mut v = state.mem.peek(p);
let mut v = state.get_reg(r);
v = v.wrapping_add(delta);
state.mem.poke(p, v);
state.set_reg(r, v);

state.reg.update_sz53_flags(v);
state.reg.clear_flag(Flag::N);
state.reg.put_flag(Flag::P, v == overflow);
state.reg.put_flag(Flag::H, (v & 0x0F) == half_overflow);
// Flag::C is not affected
})
}
}
Expand Down
130 changes: 52 additions & 78 deletions src/opcode_bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,81 +10,55 @@ pub enum ShiftMode {
RotateCarry
}

pub fn build_left_r(r: Reg8, mode: ShiftMode, fast: bool) -> Opcode {
let separator = if fast {""} else {" "};
let mnemonic = match mode {
ShiftMode::Arithmetic => "SLA",
ShiftMode::Logical => "SLL", // Undocumented
ShiftMode::Rotate => "RL",
ShiftMode::RotateCarry => "RLC"
};

Opcode {
name: format!("{}{}{:?}", mnemonic, separator, r),
bytes: 1,
cycles: if fast {4} else {8},
action: Box::new(move |state: &mut State| {
let mut v = state.reg.get8(r);
let upper_bit = v >= 0x80;
v = v << 1;
let set_lower_bit = match mode {
ShiftMode::Arithmetic => false, // always 0 in bit 0
ShiftMode::Logical => true, // always 1 in bit 0
ShiftMode::Rotate => state.reg.get_flag(Flag::C), // carry in bit 0
ShiftMode::RotateCarry => upper_bit, // bit 7 moves to bit 0
};
if set_lower_bit { // bit 0 is 0 already
v = v | 1;
}

println!("left {} {} {}", v, upper_bit, set_lower_bit);

state.reg.set8(r, v);
state.reg.put_flag(Flag::C, upper_bit);

state.reg.clear_flag(Flag::H);
state.reg.clear_flag(Flag::N);
if !fast {
state.reg.update_sz53_flags(v);
state.reg.update_p_flag(v);
}
})
}
#[derive(Copy, Clone)]
pub enum ShiftDir {
Left,
Right
}

pub fn build_right_r(r: Reg8, mode: ShiftMode, fast: bool) -> Opcode {
pub fn build_rot_r(r: Reg8, (dir, mode, name): (ShiftDir, ShiftMode, &str), fast: bool) -> Opcode {
let separator = if fast {""} else {" "};
let mnemonic = match mode {
ShiftMode::Arithmetic => "SRA",
ShiftMode::Logical => "SRL",
ShiftMode::Rotate => "RR",
ShiftMode::RotateCarry => "RRC",
};

Opcode {
name: format!("{}{}{:?}", mnemonic, separator, r),
name: format!("{}{}{}", name, separator, r),
bytes: 1,
cycles: if fast {4} else {8},
action: Box::new(move |state: &mut State| {
let mut v = state.reg.get8(r);
let upper_bit = v >= 0x80;
let lower_bit = (v & 1) == 1;
v = v >> 1;
let set_upper_bit = match mode {
ShiftMode::Arithmetic => upper_bit, // extend bit 7
ShiftMode::Logical => false, // always 0 in bit 7
ShiftMode::Rotate => state.reg.get_flag(Flag::C), // carry in bit 0
ShiftMode::RotateCarry => lower_bit, // bit 0 goes to bit 7
};
if set_upper_bit { // bit 7 is 0 already
v = v | 0x80;
}

println!("{} {} {} {}", v, upper_bit, lower_bit, set_upper_bit);

state.reg.set8(r, v);
state.reg.put_flag(Flag::C, lower_bit);
let mut v = state.get_reg(r);
let carry: bool;

match dir {
ShiftDir::Left => {
let upper_bit = v >= 0x80;
v = v << 1;
let set_lower_bit = match mode {
ShiftMode::Arithmetic => false, // always 0 in bit 0
ShiftMode::Logical => true, // always 1 in bit 0
ShiftMode::Rotate => state.reg.get_flag(Flag::C), // carry in bit 0
ShiftMode::RotateCarry => upper_bit, // bit 7 moves to bit 0
};
if set_lower_bit { // bit 0 is 0 already
v = v | 1;
}
carry = upper_bit;
},
ShiftDir::Right => {
let upper_bit = v >= 0x80;
let lower_bit = (v & 1) == 1;
v = v >> 1;
let set_upper_bit = match mode {
ShiftMode::Arithmetic => upper_bit, // extend bit 7
ShiftMode::Logical => false, // always 0 in bit 7
ShiftMode::Rotate => state.reg.get_flag(Flag::C), // carry in bit 0
ShiftMode::RotateCarry => lower_bit, // bit 0 goes to bit 7
};
if set_upper_bit { // bit 7 is 0 already
v = v | 0x80;
}
carry = lower_bit;
}
}
state.set_reg(r, v);
state.reg.put_flag(Flag::C, carry);
state.reg.clear_flag(Flag::H);
state.reg.clear_flag(Flag::N);
if !fast {
Expand All @@ -97,11 +71,11 @@ pub fn build_right_r(r: Reg8, mode: ShiftMode, fast: bool) -> Opcode {

pub fn build_bit_r(bit: u8, r: Reg8) -> Opcode {
Opcode {
name: format!("BIT {}, {:?}", bit, r),
name: format!("BIT {}, {}", bit, r),
bytes: 1,
cycles: 8,
cycles: 8, // (HL) 8, (IX+d) 20
action: Box::new(move |state: &mut State| {
let v8 = state.reg.get8(r);
let v8 = state.get_reg(r);
let v1 = (v8 & (1<<bit)) != 0;
state.reg.put_flag(Flag::Z, v1);
})
Expand All @@ -110,26 +84,26 @@ pub fn build_bit_r(bit: u8, r: Reg8) -> Opcode {

pub fn build_set_r(bit: u8, r: Reg8) -> Opcode {
Opcode {
name: format!("SET {}, {:?}", bit, r),
name: format!("SET {}, {}", bit, r),
bytes: 1,
cycles: 8,
cycles: 8, // (HL) 15, (IX+d) 23
action: Box::new(move |state: &mut State| {
let mut v = state.reg.get8(r);
let mut v = state.get_reg(r);
v = v | (1<<bit);
state.reg.set8(r, v);
state.set_reg(r, v);
})
}
}

pub fn build_res_r(bit: u8, r: Reg8) -> Opcode {
Opcode {
name: format!("RES {}, {:?}", bit, r),
name: format!("RES {}, {}", bit, r),
bytes: 1,
cycles: 8,
cycles: 8, // (HL) 15, (IX+d) 23
action: Box::new(move |state: &mut State| {
let mut v = state.reg.get8(r);
let mut v = state.get_reg(r);
v = v & !(1<<bit);
state.reg.set8(r, v);
state.set_reg(r, v);
})
}
}
20 changes: 10 additions & 10 deletions src/opcode_ld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,31 +52,31 @@ use super::registers::*;
// 8 bit load
pub fn build_ld_r_r(dst: Reg8, src: Reg8, special: bool) -> Opcode {
Opcode {
name: format!("LD {:?}, {:?}", dst, src),
name: format!("LD {}, {}", dst, src),
bytes: 1,
cycles: if special {9} else {4},
cycles: if special {9} else {4}, // (HL) 7, (IX+d) 19
action: Box::new(move |state: &mut State| {
let value = state.reg.get8(src);
state.reg.set8(dst, value);
let value = state.get_reg(src);
state.set_reg(dst, value);
})
}
}

pub fn build_ld_r_n(r: Reg8) -> Opcode {
Opcode {
name: format!("LD {:?}, X", r),
name: format!("LD {}, X", r),
bytes: 2,
cycles: 7,
action: Box::new(move |state: &mut State| {
let value = state.advance_pc();
state.reg.set8(r, value);
state.set_reg(r, value);
})
}
}

pub fn build_ld_r_prr(r: Reg8, rr: Reg16) -> Opcode {
Opcode {
name: format!("LD {:?}, ({:?})", r, rr),
name: format!("LD {}, ({:?})", r, rr),
bytes: 1,
cycles: 7,
action: Box::new(move |state: &mut State| {
Expand All @@ -89,7 +89,7 @@ pub fn build_ld_r_prr(r: Reg8, rr: Reg16) -> Opcode {

pub fn build_ld_r_pnn(r: Reg8) -> Opcode {
Opcode {
name: format!("LD {:?}, (XX)", r),
name: format!("LD {}, (XX)", r),
bytes: 1,
cycles: 13,
action: Box::new(move |state: &mut State| {
Expand All @@ -102,7 +102,7 @@ pub fn build_ld_r_pnn(r: Reg8) -> Opcode {

pub fn build_ld_prr_r(rr: Reg16, r: Reg8) -> Opcode {
Opcode {
name: format!("LD {:?}, ({:?})", r, rr),
name: format!("LD {}, ({:?})", r, rr),
bytes: 1,
cycles: 7,
action: Box::new(move |state: &mut State| {
Expand Down Expand Up @@ -130,7 +130,7 @@ pub fn build_ld_prr_n(rr: Reg16) -> Opcode {

pub fn build_ld_pnn_r(r: Reg8) -> Opcode {
Opcode {
name: format!("LD {:?}, (XX)", r),
name: format!("LD {}, (XX)", r),
bytes: 1,
cycles: 13,
action: Box::new(move |state: &mut State| {
Expand Down
Loading

0 comments on commit 0c3d1f3

Please sign in to comment.