1use crate::superfx::gsu::instructions::{ 2 MemoryType, clear_prefix_flags, fetch_opcode, read_register, write_register, 3}; 4use crate::superfx::gsu::{ClockSpeed, GraphicsSupportUnit}; 5use jgenesis_common::num::{SignBit, U16Ext}; 6 7pub(super) fn ldb( 8 opcode: u8, 9 memory_type: MemoryType, 10 gsu: &mut GraphicsSupportUnit, 11 rom: &[u8], 12 ram: &[u8], 13) -> u8 { 14 // LDB (Rm): Load byte from RAM 15 let m = opcode & 0x0F; 16 let ram_addr = (gsu.r[m as usize] as usize) & (ram.len() - 1); 17 let value = ram[ram_addr]; 18 19 let cycles = write_register(gsu, gsu.dreg, value.into(), rom, ram); 20 21 gsu.state.ram_address_buffer = ram_addr as u16; 22 23 log::trace!("Loaded {value:02X} from RAM[{ram_addr:X}]"); 24 25 clear_prefix_flags(gsu); 26 cycles 27 + match (gsu.clock_speed, memory_type) { 28 (ClockSpeed::Slow, MemoryType::CodeCache) => 5, 29 (ClockSpeed::Fast, MemoryType::CodeCache) => 7, 30 (ClockSpeed::Slow, MemoryType::Rom) => 8, 31 (ClockSpeed::Fast, MemoryType::Rom) => 9, 32 (ClockSpeed::Slow, MemoryType::Ram) => 10, 33 (ClockSpeed::Fast, MemoryType::Ram) => 11, 34 } 35} 36 37pub(super) fn ldw( 38 opcode: u8, 39 memory_type: MemoryType, 40 gsu: &mut GraphicsSupportUnit, 41 rom: &[u8], 42 ram: &[u8], 43) -> u8 { 44 // LDW (Rm): Load word from RAM 45 let m = opcode & 0x0F; 46 let ram_addr = (gsu.r[m as usize] as usize) & (ram.len() - 1); 47 let value_lsb = ram[ram_addr]; 48 let value_msb = ram[ram_addr ^ 1]; 49 let value = u16::from_le_bytes([value_lsb, value_msb]); 50 51 let cycles = write_register(gsu, gsu.dreg, value, rom, ram); 52 53 log::trace!("Loaded {value:04X} from RAM[{ram_addr:X}]"); 54 55 gsu.state.ram_address_buffer = ram_addr as u16; 56 57 clear_prefix_flags(gsu); 58 cycles 59 + match (gsu.clock_speed, memory_type) { 60 (ClockSpeed::Slow, MemoryType::CodeCache) => 7, 61 (ClockSpeed::Fast, MemoryType::CodeCache) => 11, 62 (ClockSpeed::Slow, MemoryType::Rom) => 10, 63 (ClockSpeed::Fast, MemoryType::Rom) => 13, 64 (ClockSpeed::Slow, MemoryType::Ram) => 12, 65 (ClockSpeed::Fast, MemoryType::Ram) => 15, 66 } 67} 68 69pub(super) fn stb( 70 opcode: u8, 71 memory_type: MemoryType, 72 gsu: &mut GraphicsSupportUnit, 73 ram: &mut [u8], 74) -> u8 { 75 // STB (Rm): Store byte in RAM 76 let byte = read_register(gsu, gsu.sreg) as u8; 77 78 let register = opcode & 0x0F; 79 let ram_addr = (gsu.r[register as usize] as usize) & (ram.len() - 1); 80 ram[ram_addr] = byte; 81 82 log::trace!("Stored {byte:02X} at RAM[{ram_addr:X}]"); 83 84 let cycles = gsu.state.ram_buffer_wait_cycles; 85 gsu.state.ram_buffer_wait_cycles = gsu.clock_speed.memory_access_cycles(); 86 gsu.state.ram_buffer_written = true; 87 88 clear_prefix_flags(gsu); 89 cycles 90 + match memory_type { 91 MemoryType::CodeCache => 1, 92 MemoryType::Rom => 3, 93 MemoryType::Ram => 6, 94 } 95} 96 97pub(super) fn stw( 98 opcode: u8, 99 memory_type: MemoryType, 100 gsu: &mut GraphicsSupportUnit, 101 ram: &mut [u8], 102) -> u8 { 103 // STW (Rm): Store word in RAM 104 let source = read_register(gsu, gsu.sreg); 105 let [source_lsb, source_msb] = source.to_le_bytes(); 106 107 let register = opcode & 0x0F; 108 let ram_addr = (gsu.r[register as usize] as usize) & (ram.len() - 1); 109 ram[ram_addr] = source_lsb; 110 ram[ram_addr ^ 1] = source_msb; 111 112 log::trace!("Stored {source:04X} at RAM[{ram_addr:X}]"); 113 114 let cycles = gsu.state.ram_buffer_wait_cycles; 115 gsu.state.ram_buffer_wait_cycles = 2 * gsu.clock_speed.memory_access_cycles(); 116 gsu.state.ram_buffer_written = true; 117 118 clear_prefix_flags(gsu); 119 match memory_type { 120 MemoryType::CodeCache => 1 + cycles.saturating_sub(1), 121 MemoryType::Rom | MemoryType::Ram => gsu.clock_speed.memory_access_cycles() + cycles, 122 } 123} 124 125pub(super) fn ibt( 126 opcode: u8, 127 memory_type: MemoryType, 128 gsu: &mut GraphicsSupportUnit, 129 rom: &[u8], 130 ram: &[u8], 131) -> u8 { 132 // IBT Rn, #pp: Load immediate byte (sign extended to 16 bits) 133 let pp = gsu.state.opcode_buffer; 134 fetch_opcode(gsu, rom, ram); 135 136 let register = opcode & 0xF; 137 let value = (pp as i8) as u16; 138 let write_cycles = write_register(gsu, register, value, rom, ram); 139 140 clear_prefix_flags(gsu); 141 write_cycles + 2 * memory_type.access_cycles(gsu.clock_speed) 142} 143 144pub(super) fn iwt( 145 opcode: u8, 146 memory_type: MemoryType, 147 gsu: &mut GraphicsSupportUnit, 148 rom: &[u8], 149 ram: &[u8], 150) -> u8 { 151 // IWT Rn, #xx: Load immediate word 152 let lsb = gsu.state.opcode_buffer; 153 fetch_opcode(gsu, rom, ram); 154 let msb = gsu.state.opcode_buffer; 155 fetch_opcode(gsu, rom, ram); 156 157 let value = u16::from_le_bytes([lsb, msb]); 158 let register = opcode & 0x0F; 159 let cycles = write_register(gsu, register, value, rom, ram); 160 161 clear_prefix_flags(gsu); 162 cycles + 3 * memory_type.access_cycles(gsu.clock_speed) 163} 164 165pub(super) fn lm( 166 opcode: u8, 167 memory_type: MemoryType, 168 gsu: &mut GraphicsSupportUnit, 169 rom: &[u8], 170 ram: &[u8], 171) -> u8 { 172 // LM Rn, (xx): Load from RAM 173 let ram_addr_lsb = gsu.state.opcode_buffer; 174 fetch_opcode(gsu, rom, ram); 175 let ram_addr_msb = gsu.state.opcode_buffer; 176 fetch_opcode(gsu, rom, ram); 177 178 let ram_addr = (u16::from_le_bytes([ram_addr_lsb, ram_addr_msb]) as usize) & (ram.len() - 1); 179 let value_lsb = ram[ram_addr]; 180 let value_msb = ram[ram_addr ^ 1]; 181 let value = u16::from_le_bytes([value_lsb, value_msb]); 182 183 log::trace!("Loaded {value:04X} from RAM[{ram_addr:X}"); 184 185 let register = opcode & 0x0F; 186 let cycles = write_register(gsu, register, value, rom, ram); 187 188 gsu.state.ram_address_buffer = ram_addr as u16; 189 190 clear_prefix_flags(gsu); 191 cycles 192 + match (gsu.clock_speed, memory_type) { 193 (ClockSpeed::Slow, MemoryType::CodeCache) => 9, 194 (ClockSpeed::Fast, MemoryType::CodeCache) => 13, 195 (ClockSpeed::Slow, MemoryType::Rom) => 17, 196 (ClockSpeed::Fast, MemoryType::Rom) => 24, 197 (ClockSpeed::Slow, MemoryType::Ram) => 18, 198 (ClockSpeed::Fast, MemoryType::Ram) => 25, 199 } 200} 201 202pub(super) fn lms( 203 opcode: u8, 204 memory_type: MemoryType, 205 gsu: &mut GraphicsSupportUnit, 206 rom: &[u8], 207 ram: &[u8], 208) -> u8 { 209 // LMS Rn, (yy): Load from RAM short 210 let kk = gsu.state.opcode_buffer; 211 fetch_opcode(gsu, rom, ram); 212 213 let yy = u16::from(kk) << 1; 214 let ram_addr = (yy as usize) & (ram.len() - 1); 215 let lsb = ram[ram_addr]; 216 let msb = ram[ram_addr ^ 1]; 217 let value = u16::from_le_bytes([lsb, msb]); 218 219 let register = opcode & 0x0F; 220 let cycles = write_register(gsu, register, value, rom, ram); 221 222 log::trace!("Loaded {value:04X} from RAM[{ram_addr:X}]"); 223 224 gsu.state.ram_address_buffer = ram_addr as u16; 225 226 clear_prefix_flags(gsu); 227 cycles 228 + match (gsu.clock_speed, memory_type) { 229 (ClockSpeed::Slow, MemoryType::CodeCache) => 8, 230 (ClockSpeed::Fast, MemoryType::CodeCache) => 12, 231 (ClockSpeed::Slow, MemoryType::Rom | MemoryType::Ram) => 15, 232 (ClockSpeed::Fast, MemoryType::Rom | MemoryType::Ram) => 20, 233 } 234} 235 236pub(super) fn sm( 237 opcode: u8, 238 memory_type: MemoryType, 239 gsu: &mut GraphicsSupportUnit, 240 rom: &[u8], 241 ram: &mut [u8], 242) -> u8 { 243 // SM (xx), Rn: Store in RAM 244 let ram_addr_lsb = gsu.state.opcode_buffer; 245 fetch_opcode(gsu, rom, ram); 246 let ram_addr_msb = gsu.state.opcode_buffer; 247 fetch_opcode(gsu, rom, ram); 248 249 let ram_addr = (u16::from_le_bytes([ram_addr_lsb, ram_addr_msb]) as usize) & (ram.len() - 1); 250 251 let register = opcode & 0x0F; 252 let [value_lsb, value_msb] = read_register(gsu, register).to_le_bytes(); 253 ram[ram_addr] = value_lsb; 254 ram[ram_addr ^ 1] = value_msb; 255 256 log::trace!("Stored {value_msb:02X}{value_lsb:02X} at RAM[{ram_addr:X}]"); 257 258 let cycles = gsu.state.ram_buffer_wait_cycles; 259 gsu.state.ram_buffer_wait_cycles = 2 * gsu.clock_speed.memory_access_cycles(); 260 gsu.state.ram_buffer_written = true; 261 262 clear_prefix_flags(gsu); 263 cycles 264 + match memory_type { 265 MemoryType::CodeCache => 2, 266 MemoryType::Rom => 9, 267 MemoryType::Ram => 15, 268 } 269} 270 271pub(super) fn sms( 272 opcode: u8, 273 memory_type: MemoryType, 274 gsu: &mut GraphicsSupportUnit, 275 rom: &[u8], 276 ram: &mut [u8], 277) -> u8 { 278 // SMS (yy), Rn: Store in RAM short 279 let kk = gsu.state.opcode_buffer; 280 fetch_opcode(gsu, rom, ram); 281 282 let yy = u16::from(kk) << 1; 283 let ram_addr = (yy as usize) & (ram.len() - 1); 284 285 let register = opcode & 0x0F; 286 let [lsb, msb] = read_register(gsu, register).to_le_bytes(); 287 ram[ram_addr] = lsb; 288 ram[ram_addr ^ 1] = msb; 289 290 log::trace!("Stored {msb:02X}{lsb:02X} at RAM[{ram_addr:X}]"); 291 292 let cycles = gsu.state.ram_buffer_wait_cycles; 293 gsu.state.ram_buffer_wait_cycles = 2 * gsu.clock_speed.memory_access_cycles(); 294 gsu.state.ram_buffer_written = true; 295 296 clear_prefix_flags(gsu); 297 cycles 298 + match memory_type { 299 MemoryType::CodeCache => 1, 300 MemoryType::Rom => 6, 301 MemoryType::Ram => 10, 302 } 303} 304 305pub(super) fn sbk(memory_type: MemoryType, gsu: &mut GraphicsSupportUnit, ram: &mut [u8]) -> u8 { 306 // SBK: Store word in RAM at last address used 307 let [source_lsb, source_msb] = read_register(gsu, gsu.sreg).to_le_bytes(); 308 let ram_addr = gsu.state.ram_address_buffer; 309 ram[ram_addr as usize] = source_lsb; 310 ram[(ram_addr ^ 1) as usize] = source_msb; 311 312 log::trace!("Stored {source_msb:02X}{source_lsb:02X} at RAM[{ram_addr:X}]"); 313 314 let cycles = gsu.state.ram_buffer_wait_cycles; 315 gsu.state.ram_buffer_wait_cycles = 2 * gsu.clock_speed.memory_access_cycles(); 316 gsu.state.ram_buffer_written = true; 317 318 clear_prefix_flags(gsu); 319 match memory_type { 320 MemoryType::CodeCache => 1 + cycles.saturating_sub(1), 321 MemoryType::Rom | MemoryType::Ram => gsu.clock_speed.memory_access_cycles() + cycles, 322 } 323} 324 325pub(super) fn romb(memory_type: MemoryType, gsu: &mut GraphicsSupportUnit) -> u8 { 326 // ROMB: Set ROM bank register 327 gsu.rombr = read_register(gsu, gsu.sreg) as u8; 328 329 log::trace!(" Set ROMBR to {:02X}", gsu.rombr); 330 331 let cycles = gsu.state.rom_buffer_wait_cycles; 332 gsu.state.rom_buffer_wait_cycles = 0; 333 334 clear_prefix_flags(gsu); 335 cycles + memory_type.access_cycles(gsu.clock_speed) 336} 337 338pub(super) fn getb( 339 memory_type: MemoryType, 340 gsu: &mut GraphicsSupportUnit, 341 rom: &[u8], 342 ram: &[u8], 343) -> u8 { 344 // GETB/GETBH/GETBL/GETBS: Get byte from ROM 345 // !ALT1 && !ALT2: GETB (Write to LSB, zero extend) 346 // ALT1 && !ALT2: GETBH (Write to MSB, leave LSB unchanged) 347 // !ALT1 && ALT2: GETBL (Write to LSB, leave MSB unchanged) 348 // ALT1 && ALT2: GETBS (Write to LSB, sign extend) 349 let byte = gsu.state.rom_buffer; 350 let source = read_register(gsu, gsu.sreg); 351 352 let value = match (gsu.alt1, gsu.alt2) { 353 (false, false) => u16::from(byte), 354 (true, false) => u16::from_le_bytes([source.lsb(), byte]), 355 (false, true) => u16::from_le_bytes([byte, source.msb()]), 356 (true, true) => byte as i8 as u16, 357 }; 358 359 let mut cycles = write_register(gsu, gsu.dreg, value, rom, ram); 360 361 cycles += gsu.state.rom_buffer_wait_cycles; 362 gsu.state.rom_buffer_wait_cycles = 0; 363 364 clear_prefix_flags(gsu); 365 cycles + memory_type.access_cycles(gsu.clock_speed) 366} 367 368pub(super) fn hib( 369 memory_type: MemoryType, 370 gsu: &mut GraphicsSupportUnit, 371 rom: &[u8], 372 ram: &[u8], 373) -> u8 { 374 // HIB: High byte of register 375 let source = read_register(gsu, gsu.sreg); 376 let source_msb = source.msb(); 377 let cycles = write_register(gsu, gsu.dreg, source_msb.into(), rom, ram); 378 379 gsu.zero_flag = source_msb == 0; 380 gsu.sign_flag = source_msb.sign_bit(); 381 382 clear_prefix_flags(gsu); 383 cycles + memory_type.access_cycles(gsu.clock_speed) 384} 385 386pub(super) fn lob( 387 memory_type: MemoryType, 388 gsu: &mut GraphicsSupportUnit, 389 rom: &[u8], 390 ram: &[u8], 391) -> u8 { 392 // LOB: Low byte of register 393 let source = read_register(gsu, gsu.sreg); 394 let source_lsb = source as u8; 395 let cycles = write_register(gsu, gsu.dreg, source_lsb.into(), rom, ram); 396 397 gsu.zero_flag = source_lsb == 0; 398 gsu.sign_flag = source_lsb.sign_bit(); 399 400 clear_prefix_flags(gsu); 401 cycles + memory_type.access_cycles(gsu.clock_speed) 402} 403 404pub(super) fn swap( 405 memory_type: MemoryType, 406 gsu: &mut GraphicsSupportUnit, 407 rom: &[u8], 408 ram: &[u8], 409) -> u8 { 410 // SWAP: Swap bytes 411 let source = read_register(gsu, gsu.sreg); 412 let swapped = source.swap_bytes(); 413 let cycles = write_register(gsu, gsu.dreg, swapped, rom, ram); 414 415 gsu.zero_flag = swapped == 0; 416 gsu.sign_flag = swapped.sign_bit(); 417 418 clear_prefix_flags(gsu); 419 cycles + memory_type.access_cycles(gsu.clock_speed) 420} 421 422pub(super) fn merge( 423 memory_type: MemoryType, 424 gsu: &mut GraphicsSupportUnit, 425 rom: &[u8], 426 ram: &[u8], 427) -> u8 { 428 // MERGE: Merge high bytes 429 // Dreg.H = R7.H, Dreg.L = R8.H 430 let merged = (gsu.r[7] & 0xFF00) | (gsu.r[8] >> 8); 431 let cycles = write_register(gsu, gsu.dreg, merged, rom, ram); 432 433 gsu.zero_flag = merged & 0xF0F0 != 0; 434 gsu.carry_flag = merged & 0xE0E0 != 0; 435 gsu.sign_flag = merged & 0x8080 != 0; 436 gsu.overflow_flag = merged & 0xC0C0 != 0; 437 438 clear_prefix_flags(gsu); 439 cycles + memory_type.access_cycles(gsu.clock_speed) 440}