1use crate::superfx::gsu::GraphicsSupportUnit;
2use crate::superfx::gsu::instructions::{
3    MemoryType, clear_prefix_flags, read_register, write_register,
4};
5use jgenesis_common::num::{GetBit, SignBit};
6
7pub(super) fn from(
8    opcode: u8,
9    memory_type: MemoryType,
10    gsu: &mut GraphicsSupportUnit,
11    rom: &[u8],
12    ram: &[u8],
13) -> u8 {
14    // FROM: Set source register
15    // If B flag is set, this executes a MOVE that also sets flags (MOVES)
16    let cycles = if !gsu.b {
17        gsu.sreg = opcode & 0x0F;
18        0
19    } else {
20        let register = opcode & 0x0F;
21        let value = read_register(gsu, register);
22        let cycles = write_register(gsu, gsu.dreg, value, rom, ram);
23
24        gsu.zero_flag = value == 0;
25        gsu.overflow_flag = value.bit(7);
26        gsu.sign_flag = value.sign_bit();
27
28        clear_prefix_flags(gsu);
29        cycles
30    };
31
32    cycles + memory_type.access_cycles(gsu.clock_speed)
33}
34
35pub(super) fn to(
36    opcode: u8,
37    memory_type: MemoryType,
38    gsu: &mut GraphicsSupportUnit,
39    rom: &[u8],
40    ram: &[u8],
41) -> u8 {
42    // TO: Set destination register
43    // If B flag is set, this executes a MOVE
44    let cycles = if !gsu.b {
45        gsu.dreg = opcode & 0x0F;
46        0
47    } else {
48        let register = opcode & 0xF;
49        let value = read_register(gsu, gsu.sreg);
50        let cycles = write_register(gsu, register, value, rom, ram);
51
52        clear_prefix_flags(gsu);
53        cycles
54    };
55
56    cycles + memory_type.access_cycles(gsu.clock_speed)
57}
58
59pub(super) fn with(opcode: u8, memory_type: MemoryType, gsu: &mut GraphicsSupportUnit) -> u8 {
60    // WITH: Set source and destination registers
61    let register = opcode & 0x0F;
62    gsu.sreg = register;
63    gsu.dreg = register;
64    gsu.b = true;
65
66    memory_type.access_cycles(gsu.clock_speed)
67}
68
69pub(super) fn alt1(memory_type: MemoryType, gsu: &mut GraphicsSupportUnit) -> u8 {
70    // ALT1: Set ALT1 flag (modifies instructions)
71    gsu.alt1 = true;
72    memory_type.access_cycles(gsu.clock_speed)
73}
74
75pub(super) fn alt2(memory_type: MemoryType, gsu: &mut GraphicsSupportUnit) -> u8 {
76    // ALT2: Set ALT2 flag (modifies instructions)
77    gsu.alt2 = true;
78    memory_type.access_cycles(gsu.clock_speed)
79}
80
81pub(super) fn alt3(memory_type: MemoryType, gsu: &mut GraphicsSupportUnit) -> u8 {
82    // ALT3: Set both ALT1 and ALT2 flags (modifies instructions)
83    gsu.alt1 = true;
84    gsu.alt2 = true;
85    memory_type.access_cycles(gsu.clock_speed)
86}