1use crate::superfx::gsu::GraphicsSupportUnit; 2use crate::superfx::gsu::instructions::{ 3 MemoryType, clear_prefix_flags, fetch_opcode, fill_cache_from_pc, fill_cache_to_pc, 4 read_register, 5}; 6use jgenesis_common::num::SignBit; 7 8pub(super) fn link(opcode: u8, memory_type: MemoryType, gsu: &mut GraphicsSupportUnit) -> u8 { 9 // LINK #n: Link return address 10 let n = opcode & 0x0F; 11 gsu.r[11] = gsu.r[15].wrapping_add(n.into()).wrapping_sub(1); 12 13 clear_prefix_flags(gsu); 14 memory_type.access_cycles(gsu.clock_speed) 15} 16 17macro_rules! impl_branch { 18 ($name:ident $(, $flag:ident $(^ $other:ident)? == $value:expr)?) => { 19 pub(super) fn $name(memory_type: MemoryType, gsu: &mut GraphicsSupportUnit, rom: &[u8], ram: &[u8]) -> u8 { 20 let e = gsu.state.opcode_buffer as i8; 21 fetch_opcode(gsu, rom, ram); 22 23 $( 24 if gsu.$flag $(^ gsu.$other)? != $value { 25 return 2 * memory_type.access_cycles(gsu.clock_speed); 26 } 27 )? 28 29 let cycles = fill_cache_from_pc(gsu, rom, ram); 30 31 gsu.r[15] = gsu.r[15].wrapping_add(e as u16).wrapping_sub(1); 32 gsu.state.just_jumped = true; 33 34 cycles + 2 * memory_type.access_cycles(gsu.clock_speed) 35 } 36 } 37}
Branch instructions
40impl_branch!(bra); 41impl_branch!(bge, sign_flag ^ overflow_flag == false); 42impl_branch!(blt, sign_flag ^ overflow_flag == true); 43impl_branch!(bne, zero_flag == false); 44impl_branch!(beq, zero_flag == true); 45impl_branch!(bpl, sign_flag == false); 46impl_branch!(bmi, sign_flag == true); 47impl_branch!(bcc, carry_flag == false); 48impl_branch!(bcs, carry_flag == true); 49impl_branch!(bvc, overflow_flag == false); 50impl_branch!(bvs, overflow_flag == true);
52pub(super) fn jmp( 53 opcode: u8, 54 memory_type: MemoryType, 55 gsu: &mut GraphicsSupportUnit, 56 rom: &[u8], 57 ram: &[u8], 58) -> u8 { 59 // JMP Rn: Jump 60 let cycles = fill_cache_from_pc(gsu, rom, ram); 61 62 gsu.r[15] = gsu.r[(opcode & 0x0F) as usize]; 63 gsu.state.just_jumped = true; 64 65 cycles + memory_type.access_cycles(gsu.clock_speed) 66} 67 68pub(super) fn ljmp( 69 opcode: u8, 70 memory_type: MemoryType, 71 gsu: &mut GraphicsSupportUnit, 72 rom: &[u8], 73 ram: &[u8], 74) -> u8 { 75 // LJMP Rn: Long jump 76 gsu.r[15] = read_register(gsu, gsu.sreg); 77 gsu.pbr = gsu.r[(opcode & 0x0F) as usize] as u8; 78 79 let cbr = gsu.r[15] & 0xFFF0; 80 gsu.code_cache.update_cbr(cbr); 81 let cycles = fill_cache_to_pc(gsu, gsu.r[15], rom, ram); 82 83 clear_prefix_flags(gsu); 84 cycles + memory_type.access_cycles(gsu.clock_speed) 85} 86 87pub(super) fn loop_( 88 memory_type: MemoryType, 89 gsu: &mut GraphicsSupportUnit, 90 rom: &[u8], 91 ram: &[u8], 92) -> u8 { 93 // LOOP: Loop 94 gsu.r[12] = gsu.r[12].wrapping_sub(1); 95 gsu.zero_flag = gsu.r[12] == 0; 96 gsu.sign_flag = gsu.r[12].sign_bit(); 97 98 let cycles = if !gsu.zero_flag { 99 let cycles = fill_cache_from_pc(gsu, rom, ram); 100 gsu.r[15] = gsu.r[13]; 101 gsu.state.just_jumped = true; 102 103 cycles 104 } else { 105 0 106 }; 107 108 clear_prefix_flags(gsu); 109 cycles + memory_type.access_cycles(gsu.clock_speed) 110}