From 242f3d916defb8658718c5ce53bdd3018a687962 Mon Sep 17 00:00:00 2001 From: moonie <67006455+Kim-Dewelski@users.noreply.github.com> Date: Sun, 17 Dec 2023 02:47:09 +0100 Subject: [PATCH] formatted files --- src/arm7.h | 3240 ++++++----- src/gb.h | 2929 +++++----- src/gba.h | 6382 ++++++++++---------- src/ios_support.h | 4 +- src/localization.c | 1395 +++-- src/localization.h | 42 +- src/main.c | 10500 ++++++++++++++++----------------- src/nds.h | 13457 +++++++++++++++++++++++-------------------- 8 files changed, 19856 insertions(+), 18093 deletions(-) diff --git a/src/arm7.h b/src/arm7.h index c890bdd47..db3645e10 100644 --- a/src/arm7.h +++ b/src/arm7.h @@ -9,44 +9,44 @@ // Data Types // //////////////// -#define LR 14 -#define PC 15 +#define LR 14 +#define PC 15 #define CPSR 16 -#define SPSR 17 - -#define R13_fiq 22 -#define R13_irq 24 -#define R13_svc 26 -#define R13_abt 28 -#define R13_und 30 - -#define R14_fiq 23 -#define R14_irq 25 -#define R14_svc 27 -#define R14_abt 29 -#define R14_und 31 - -#define SPSR_fiq 32 -#define SPSR_irq 33 -#define SPSR_svc 34 -#define SPSR_abt 35 -#define SPSR_und 36 +#define SPSR 17 + +#define R13_fiq 22 +#define R13_irq 24 +#define R13_svc 26 +#define R13_abt 28 +#define R13_und 30 + +#define R14_fiq 23 +#define R14_irq 25 +#define R14_svc 27 +#define R14_abt 29 +#define R14_und 31 + +#define SPSR_fiq 32 +#define SPSR_irq 33 +#define SPSR_svc 34 +#define SPSR_abt 35 +#define SPSR_und 36 #define UNINTIALIZED_PREFETCH_PC -3 // Memory IO functions for the emulated CPU (these must be defined by the user) -typedef uint32_t (*arm_read32_fn_t)(void* user_data, uint32_t address); -typedef uint32_t (*arm_read16_fn_t)(void* user_data, uint32_t address); -typedef uint32_t (*arm_read32_seq_fn_t)(void* user_data, uint32_t address,bool is_sequential); -typedef uint32_t (*arm_read16_seq_fn_t)(void* user_data, uint32_t address,bool is_sequential); -typedef uint8_t (*arm_read8_fn_t)(void* user_data, uint32_t address); -typedef void (*arm_write32_fn_t)(void* user_data, uint32_t address, uint32_t data); -typedef void (*arm_write16_fn_t)(void* user_data, uint32_t address, uint16_t data); -typedef void (*arm_write8_fn_t)(void* user_data, uint32_t address, uint8_t data); -typedef uint32_t (*arm_coproc_read_fn_t)(void* user_data, int coproc,int opcode,int Cn, int Cm,int Cp); -typedef void (*arm_coproc_write_fn_t)(void* user_data, int coproc,int opcode,int Cn, int Cm,int Cp, uint32_t data); +typedef uint32_t (*arm_read32_fn_t)(void *user_data, uint32_t address); +typedef uint32_t (*arm_read16_fn_t)(void *user_data, uint32_t address); +typedef uint32_t (*arm_read32_seq_fn_t)(void *user_data, uint32_t address, bool is_sequential); +typedef uint32_t (*arm_read16_seq_fn_t)(void *user_data, uint32_t address, bool is_sequential); +typedef uint8_t (*arm_read8_fn_t)(void *user_data, uint32_t address); +typedef void (*arm_write32_fn_t)(void *user_data, uint32_t address, uint32_t data); +typedef void (*arm_write16_fn_t)(void *user_data, uint32_t address, uint16_t data); +typedef void (*arm_write8_fn_t)(void *user_data, uint32_t address, uint8_t data); +typedef uint32_t (*arm_coproc_read_fn_t)(void *user_data, int coproc, int opcode, int Cn, int Cm, int Cp); +typedef void (*arm_coproc_write_fn_t)(void *user_data, int coproc, int opcode, int Cn, int Cm, int Cp, uint32_t data); #define ARM_DEBUG_BRANCH_RING_SIZE 32 -#define ARM_DEBUG_SWI_RING_SIZE 32 +#define ARM_DEBUG_SWI_RING_SIZE 32 typedef struct { // Registers /* @@ -64,56 +64,56 @@ typedef struct { 36: SPSR_und */ - uint32_t debug_branch_ring[ARM_DEBUG_BRANCH_RING_SIZE]; - uint32_t debug_branch_ring_offset; - uint32_t debug_swi_ring[ARM_DEBUG_SWI_RING_SIZE]; - uint32_t debug_swi_ring_times[ARM_DEBUG_SWI_RING_SIZE]; - uint32_t debug_swi_ring_offset; - uint32_t prefetch_pc; - uint32_t step_instructions;//Instructions to step before triggering a breakpoint - uint32_t prefetch_opcode[5]; - uint32_t i_cycles;//Executed i-cycles minus 1 - bool next_fetch_sequential; - uint32_t registers[37]; - uint64_t executed_instructions; - bool trigger_breakpoint; - bool print_instructions; - void* user_data; - FILE* log_cmp_file; - arm_read32_fn_t read32; - arm_read16_fn_t read16; - arm_read32_seq_fn_t read32_seq; - arm_read16_seq_fn_t read16_seq; - arm_read8_fn_t read8; - arm_write32_fn_t write32; - arm_write16_fn_t write16; - arm_write8_fn_t write8; - arm_coproc_read_fn_t coprocessor_read; + uint32_t debug_branch_ring[ARM_DEBUG_BRANCH_RING_SIZE]; + uint32_t debug_branch_ring_offset; + uint32_t debug_swi_ring[ARM_DEBUG_SWI_RING_SIZE]; + uint32_t debug_swi_ring_times[ARM_DEBUG_SWI_RING_SIZE]; + uint32_t debug_swi_ring_offset; + uint32_t prefetch_pc; + uint32_t step_instructions; // Instructions to step before triggering a breakpoint + uint32_t prefetch_opcode[5]; + uint32_t i_cycles; // Executed i-cycles minus 1 + bool next_fetch_sequential; + uint32_t registers[37]; + uint64_t executed_instructions; + bool trigger_breakpoint; + bool print_instructions; + void *user_data; + FILE *log_cmp_file; + arm_read32_fn_t read32; + arm_read16_fn_t read16; + arm_read32_seq_fn_t read32_seq; + arm_read16_seq_fn_t read16_seq; + arm_read8_fn_t read8; + arm_write32_fn_t write32; + arm_write16_fn_t write16; + arm_write8_fn_t write8; + arm_coproc_read_fn_t coprocessor_read; arm_coproc_write_fn_t coprocessor_write; - bool wait_for_interrupt; - uint32_t irq_table_address; - uint32_t phased_opcode; - uint32_t phased_op_id; - uint32_t phase; - struct{ + bool wait_for_interrupt; + uint32_t irq_table_address; + uint32_t phased_opcode; + uint32_t phased_op_id; + uint32_t phase; + struct { uint32_t addr; uint32_t r15_off; uint32_t last_bank; uint32_t base_addr; uint32_t cycle; uint32_t num_regs; - }block; -} arm7_t; + } block; +} arm7_t; typedef void (*arm7_handler_t)(arm7_t *cpu, uint32_t opcode); -typedef struct{ - arm7_handler_t handler; - char name[12]; - char bitfield[33]; -}arm7_instruction_t; - -#define ARM_PHASED_NONE 0 -#define ARM_PHASED_FILL_PIPE 1 +typedef struct { + arm7_handler_t handler; + char name[12]; + char bitfield[33]; +} arm7_instruction_t; + +#define ARM_PHASED_NONE 0 +#define ARM_PHASED_FILL_PIPE 1 #define ARM_PHASED_BLOCK_TRANSFER 2 //////////////////////// @@ -121,87 +121,87 @@ typedef struct{ //////////////////////// // This function initializes the internal state needed for the arm7 core emulation -static arm7_t arm7_init(void* user_data); -static void arm7_exec_instruction(arm7_t* cpu); +static arm7_t arm7_init(void *user_data); +static void arm7_exec_instruction(arm7_t *cpu); // Write the dissassembled opcode from mem_address into the out_disasm string up to out_size characters -static void arm7_get_disasm(arm7_t * cpu, uint32_t mem_address, char* out_disasm, size_t out_size); +static void arm7_get_disasm(arm7_t *cpu, uint32_t mem_address, char *out_disasm, size_t out_size); // Used to send an interrupt to the emulated CPU. The n'th set bit triggers the n'th interrupt -static void arm7_process_interrupts(arm7_t* cpu, uint32_t interrupts); +static void arm7_process_interrupts(arm7_t *cpu, uint32_t interrupts); /////////////////////////////////////////// // Functions for Internal Implementation // /////////////////////////////////////////// // ARM Instruction Implementations -static void arm7_data_processing(arm7_t* cpu, uint32_t opcode); -static void arm7_multiply(arm7_t* cpu, uint32_t opcode); -static void arm7_multiply_long(arm7_t* cpu, uint32_t opcode); -static void arm7_single_data_swap(arm7_t* cpu, uint32_t opcode); -static void arm7_branch_exchange(arm7_t* cpu, uint32_t opcode); -static void arm9_branch_link_exchange(arm7_t* cpu, uint32_t opcode); -static void arm7_half_word_transfer(arm7_t* cpu, uint32_t opcode); -static void arm7_single_word_transfer(arm7_t* cpu, uint32_t opcode); -static void arm7_undefined(arm7_t* cpu, uint32_t opcode); -static void arm7_block_transfer(arm7_t* cpu, uint32_t opcode); -static void arm7_branch(arm7_t* cpu, uint32_t opcode); -static void arm9_branch(arm7_t* cpu, uint32_t opcode); - -static void arm7_coproc_data_transfer(arm7_t* cpu, uint32_t opcode); -static void arm7_coproc_data_op(arm7_t* cpu, uint32_t opcode); -static void arm7_coproc_reg_transfer(arm7_t* cpu, uint32_t opcode); -static void arm7_software_interrupt(arm7_t* cpu, uint32_t opcode); - -static void arm7_mrs(arm7_t* cpu, uint32_t opcode); -static void arm7_msr(arm7_t* cpu, uint32_t opcode); - -static void arm9_clz(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9_qadd_qsub(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9_signed_halfword_multiply(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9_single_word_transfer(arm7_t* cpu, uint32_t opcode); -static void arm9_double_word_transfer(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9_block_transfer(arm7_t* cpu, uint32_t opcode); +static void arm7_data_processing(arm7_t *cpu, uint32_t opcode); +static void arm7_multiply(arm7_t *cpu, uint32_t opcode); +static void arm7_multiply_long(arm7_t *cpu, uint32_t opcode); +static void arm7_single_data_swap(arm7_t *cpu, uint32_t opcode); +static void arm7_branch_exchange(arm7_t *cpu, uint32_t opcode); +static void arm9_branch_link_exchange(arm7_t *cpu, uint32_t opcode); +static void arm7_half_word_transfer(arm7_t *cpu, uint32_t opcode); +static void arm7_single_word_transfer(arm7_t *cpu, uint32_t opcode); +static void arm7_undefined(arm7_t *cpu, uint32_t opcode); +static void arm7_block_transfer(arm7_t *cpu, uint32_t opcode); +static void arm7_branch(arm7_t *cpu, uint32_t opcode); +static void arm9_branch(arm7_t *cpu, uint32_t opcode); + +static void arm7_coproc_data_transfer(arm7_t *cpu, uint32_t opcode); +static void arm7_coproc_data_op(arm7_t *cpu, uint32_t opcode); +static void arm7_coproc_reg_transfer(arm7_t *cpu, uint32_t opcode); +static void arm7_software_interrupt(arm7_t *cpu, uint32_t opcode); + +static void arm7_mrs(arm7_t *cpu, uint32_t opcode); +static void arm7_msr(arm7_t *cpu, uint32_t opcode); + +static void arm9_clz(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9_qadd_qsub(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9_signed_halfword_multiply(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9_single_word_transfer(arm7_t *cpu, uint32_t opcode); +static void arm9_double_word_transfer(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9_block_transfer(arm7_t *cpu, uint32_t opcode); // Thumb Instruction Implementations -static void arm7t_mov_shift_reg(arm7_t* cpu, uint32_t opcode); -static void arm7t_add_sub(arm7_t* cpu, uint32_t opcode); -static void arm7t_mov_cmp_add_sub_imm(arm7_t* cpu, uint32_t opcode); -static void arm7t_alu_op(arm7_t* cpu, uint32_t opcode); -static void arm7t_hi_reg_op(arm7_t* cpu, uint32_t opcode); -static void arm9t_hi_reg_op(arm7_t* cpu, uint32_t opcode); -static void arm7t_pc_rel_ldst(arm7_t* cpu, uint32_t opcode); -static void arm7t_reg_off_ldst(arm7_t* cpu, uint32_t opcode); -static void arm7t_ldst_bh(arm7_t* cpu, uint32_t opcode); -static void arm7t_imm_off_ldst(arm7_t* cpu, uint32_t opcode); -static void arm7t_imm_off_ldst_bh(arm7_t* cpu, uint32_t opcode); -static void arm7t_stack_off_ldst(arm7_t* cpu, uint32_t opcode); -static void arm7t_load_addr(arm7_t* cpu, uint32_t opcode); -static void arm7t_add_off_sp(arm7_t* cpu, uint32_t opcode); -static void arm7t_push_pop_reg(arm7_t* cpu, uint32_t opcode); -static void arm7t_mult_ldst(arm7_t* cpu, uint32_t opcode); -static void arm7t_cond_branch(arm7_t* cpu, uint32_t opcode); -static void arm7t_soft_interrupt(arm7_t* cpu, uint32_t opcode); -static void arm7t_branch(arm7_t* cpu, uint32_t opcode); -static void arm7t_long_branch_link(arm7_t* cpu, uint32_t opcode); -static void arm7t_unknown(arm7_t* cpu, uint32_t opcode); - -static FORCE_INLINE void arm9t_mult_ldst(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9t_push_pop_reg(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9t_stack_off_ldst(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9t_imm_off_ldst(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9t_reg_off_ldst(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE void arm9t_pc_rel_ldst(arm7_t* cpu, uint32_t opcode); +static void arm7t_mov_shift_reg(arm7_t *cpu, uint32_t opcode); +static void arm7t_add_sub(arm7_t *cpu, uint32_t opcode); +static void arm7t_mov_cmp_add_sub_imm(arm7_t *cpu, uint32_t opcode); +static void arm7t_alu_op(arm7_t *cpu, uint32_t opcode); +static void arm7t_hi_reg_op(arm7_t *cpu, uint32_t opcode); +static void arm9t_hi_reg_op(arm7_t *cpu, uint32_t opcode); +static void arm7t_pc_rel_ldst(arm7_t *cpu, uint32_t opcode); +static void arm7t_reg_off_ldst(arm7_t *cpu, uint32_t opcode); +static void arm7t_ldst_bh(arm7_t *cpu, uint32_t opcode); +static void arm7t_imm_off_ldst(arm7_t *cpu, uint32_t opcode); +static void arm7t_imm_off_ldst_bh(arm7_t *cpu, uint32_t opcode); +static void arm7t_stack_off_ldst(arm7_t *cpu, uint32_t opcode); +static void arm7t_load_addr(arm7_t *cpu, uint32_t opcode); +static void arm7t_add_off_sp(arm7_t *cpu, uint32_t opcode); +static void arm7t_push_pop_reg(arm7_t *cpu, uint32_t opcode); +static void arm7t_mult_ldst(arm7_t *cpu, uint32_t opcode); +static void arm7t_cond_branch(arm7_t *cpu, uint32_t opcode); +static void arm7t_soft_interrupt(arm7_t *cpu, uint32_t opcode); +static void arm7t_branch(arm7_t *cpu, uint32_t opcode); +static void arm7t_long_branch_link(arm7_t *cpu, uint32_t opcode); +static void arm7t_unknown(arm7_t *cpu, uint32_t opcode); + +static FORCE_INLINE void arm9t_mult_ldst(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9t_push_pop_reg(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9t_stack_off_ldst(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9t_imm_off_ldst(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9t_reg_off_ldst(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE void arm9t_pc_rel_ldst(arm7_t *cpu, uint32_t opcode); // Internal functions -static FORCE_INLINE bool arm7_check_cond_code(arm7_t* cpu, uint32_t opcode); -static FORCE_INLINE uint32_t arm7_reg_read(arm7_t*cpu, unsigned reg); -static FORCE_INLINE uint32_t arm7_reg_read_r15_adj(arm7_t*cpu, unsigned reg, int r15_off); -static FORCE_INLINE void arm7_reg_write(arm7_t*cpu, unsigned reg, uint32_t value); -static FORCE_INLINE unsigned arm7_reg_index(arm7_t* cpu, unsigned reg); -static int arm_lookup_arm_instruction_class(const arm7_instruction_t*instruction_table, uint32_t opcode_key); -static int arm_lookup_thumb_instruction_class(const arm7_instruction_t*instruction_table,uint32_t opcode_key); -static FORCE_INLINE uint32_t arm7_shift(arm7_t* arm, uint32_t opcode, uint64_t value, uint32_t shift_value, int* carry); -static FORCE_INLINE uint32_t arm7_load_shift_reg(arm7_t* arm, uint32_t opcode, int* carry); +static FORCE_INLINE bool arm7_check_cond_code(arm7_t *cpu, uint32_t opcode); +static FORCE_INLINE uint32_t arm7_reg_read(arm7_t *cpu, unsigned reg); +static FORCE_INLINE uint32_t arm7_reg_read_r15_adj(arm7_t *cpu, unsigned reg, int r15_off); +static FORCE_INLINE void arm7_reg_write(arm7_t *cpu, unsigned reg, uint32_t value); +static FORCE_INLINE unsigned arm7_reg_index(arm7_t *cpu, unsigned reg); +static int arm_lookup_arm_instruction_class(const arm7_instruction_t *instruction_table, uint32_t opcode_key); +static int arm_lookup_thumb_instruction_class(const arm7_instruction_t *instruction_table, uint32_t opcode_key); +static FORCE_INLINE uint32_t arm7_shift(arm7_t *arm, uint32_t opcode, uint64_t value, uint32_t shift_value, int *carry); +static FORCE_INLINE uint32_t arm7_load_shift_reg(arm7_t *arm, uint32_t opcode, int *carry); static FORCE_INLINE uint32_t arm7_rotr(uint32_t value, uint32_t rotate); -static FORCE_INLINE bool arm7_get_thumb_bit(arm7_t* cpu); -static FORCE_INLINE void arm7_set_thumb_bit(arm7_t* cpu, bool value); +static FORCE_INLINE bool arm7_get_thumb_bit(arm7_t *cpu); +static FORCE_INLINE void arm7_set_thumb_bit(arm7_t *cpu, bool value); #define ARM7_BFE(VALUE, BITOFFSET, SIZE) (((VALUE) >> (BITOFFSET)) & ((1u << (SIZE)) - 1)) @@ -410,23 +410,23 @@ const static arm7_instruction_t arm9t_instruction_classes[]={ {arm7t_unknown, "UNKNOWN2", "10110001--------"}, {arm7t_unknown, "UNKNOWN3", "1011100---------"}, {NULL}, -}; +}; // clang-format on -static arm7_handler_t arm7_lookup_table[4096] = { 0 }; -static arm7_handler_t arm9_lookup_table[4096] = { 0 }; -static arm7_handler_t arm7t_lookup_table[256] = { 0 }; -static arm7_handler_t arm9t_lookup_table[256] = { 0 }; +static arm7_handler_t arm7_lookup_table[4096] = {0}; +static arm7_handler_t arm9_lookup_table[4096] = {0}; +static arm7_handler_t arm7t_lookup_table[256] = {0}; +static arm7_handler_t arm9t_lookup_table[256] = {0}; -static const char* arm7_disasm_lookup_table[4096] = { 0 }; -static const char* arm9_disasm_lookup_table[4096] = { 0 }; -static const char* arm7t_disasm_lookup_table[256] = { 0 }; -static const char* arm9t_disasm_lookup_table[256] = { 0 }; +static const char *arm7_disasm_lookup_table[4096] = {0}; +static const char *arm9_disasm_lookup_table[4096] = {0}; +static const char *arm7t_disasm_lookup_table[256] = {0}; +static const char *arm9t_disasm_lookup_table[256] = {0}; -static FORCE_INLINE unsigned arm7_reg_index(arm7_t* cpu, unsigned reg){ - if(SB_LIKELY(reg<8))return reg; - int mode = cpu->registers[CPSR]&0xf; +static FORCE_INLINE unsigned arm7_reg_index(arm7_t *cpu, unsigned reg) { + if(SB_LIKELY(reg < 8)) return reg; + int mode = cpu->registers[CPSR] & 0xf; // clang-format off @@ -451,1056 +451,1154 @@ static FORCE_INLINE unsigned arm7_reg_index(arm7_t* cpu, unsigned reg){ }; // clang-format on - - int8_t r = lookup[mode*10+reg]; - if(SB_LIKELY(r!=-1))return r; - cpu->trigger_breakpoint=true; - printf("Undefined ARM mode: %d\n",mode); + + int8_t r = lookup[mode * 10 + reg]; + if(SB_LIKELY(r != -1)) return r; + cpu->trigger_breakpoint = true; + printf("Undefined ARM mode: %d\n", mode); return 0; } -static FORCE_INLINE void arm7_reg_write(arm7_t*cpu, unsigned reg, uint32_t value){ - cpu->registers[arm7_reg_index(cpu,reg)] = value; -} -static FORCE_INLINE void arm9_reg_write_r15_thumb(arm7_t*cpu, unsigned reg, uint32_t value){ - cpu->registers[arm7_reg_index(cpu,reg)] = value; - if(SB_UNLIKELY(reg==PC))arm7_set_thumb_bit(cpu,value&1); -} -static FORCE_INLINE uint32_t arm7_reg_read(arm7_t*cpu, unsigned reg){ - return cpu->registers[arm7_reg_index(cpu,reg)]; -} -static FORCE_INLINE uint32_t arm7_reg_read_r15_adj(arm7_t*cpu, unsigned reg, int r15_off){ - uint32_t v = arm7_reg_read(cpu,reg); - if(SB_UNLIKELY(reg==PC)){ - v+=r15_off; - if(arm7_get_thumb_bit(cpu))v-=2; - } - return v; -} -static void arm7_print_binary(int number, int bits){ - for(int i=0;i>(bits-i-1))&1; - printf("%d",v); - } -} - -static int arm_lookup_arm_instruction_class(const arm7_instruction_t*instruction_table, uint32_t opcode_key){ - int key_bits[] = {4,5,6,7, 20,21,22,23,24,25,26,27}; - int matched_class = -1; - for(int c = 0; instruction_table[c].handler;++c){ - bool matches = true; - for(int bit = 0; bit< sizeof(key_bits)/sizeof(key_bits[0]); ++bit){ - bool bit_value = (opcode_key>>bit)&1; - int b_off = key_bits[bit]; - matches &= instruction_table[c].bitfield[31-b_off] != '1' || bit_value == true; - matches &= instruction_table[c].bitfield[31-b_off] != '0' || bit_value == false; - if(!matches)break; +static FORCE_INLINE void arm7_reg_write(arm7_t *cpu, unsigned reg, uint32_t value) { + cpu->registers[arm7_reg_index(cpu, reg)] = value; +} +static FORCE_INLINE void arm9_reg_write_r15_thumb(arm7_t *cpu, unsigned reg, uint32_t value) { + cpu->registers[arm7_reg_index(cpu, reg)] = value; + if(SB_UNLIKELY(reg == PC)) arm7_set_thumb_bit(cpu, value & 1); +} +static FORCE_INLINE uint32_t arm7_reg_read(arm7_t *cpu, unsigned reg) { + return cpu->registers[arm7_reg_index(cpu, reg)]; +} +static FORCE_INLINE uint32_t arm7_reg_read_r15_adj(arm7_t *cpu, unsigned reg, int r15_off) { + uint32_t v = arm7_reg_read(cpu, reg); + if(SB_UNLIKELY(reg == PC)) { + v += r15_off; + if(arm7_get_thumb_bit(cpu)) v -= 2; + } + return v; +} +static void arm7_print_binary(int number, int bits) { + for(int i = 0; i < bits; ++i) { + bool v = (number >> (bits - i - 1)) & 1; + printf("%d", v); + } +} + +static int arm_lookup_arm_instruction_class(const arm7_instruction_t *instruction_table, uint32_t opcode_key) { + int key_bits[] = {4, 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27}; + int matched_class = -1; + for(int c = 0; instruction_table[c].handler; ++c) { + bool matches = true; + for(int bit = 0; bit < sizeof(key_bits) / sizeof(key_bits[0]); ++bit) { + bool bit_value = (opcode_key >> bit) & 1; + int b_off = key_bits[bit]; + matches &= instruction_table[c].bitfield[31 - b_off] != '1' || bit_value == true; + matches &= instruction_table[c].bitfield[31 - b_off] != '0' || bit_value == false; + if(!matches) break; } - if(matches){ - if(matched_class!=-1){ - int32_t op_value = 0; - char opcode[33]="00000000000000000000000000000000"; - for(int bit = 0; bit< sizeof(key_bits)/sizeof(key_bits[0]); ++bit){ - bool bit_value = (opcode_key>>bit)&1; - if(bit_value){ - opcode[31-key_bits[bit]]='1'; - op_value|= 1<> bit) & 1; + if(bit_value) { + opcode[31 - key_bits[bit]] = '1'; + op_value |= 1 << key_bits[bit]; } } - printf("ARM7: Class %s and %s have ambiguous encodings for: %s %08x %d\n", - instruction_table[c].name, - instruction_table[matched_class].name, - opcode, op_value,opcode_key); + printf("ARM7: Class %s and %s have ambiguous encodings for: %s %08x %d\n", + instruction_table[c].name, + instruction_table[matched_class].name, + opcode, op_value, opcode_key); } - matched_class = c; + matched_class = c; } } - if(matched_class==-1){ - uint32_t op_value = 0; - char opcode[33]="00000000000000000000000000000000"; - for(int bit = 0; bit< sizeof(key_bits)/sizeof(key_bits[0]); ++bit){ - bool bit_value = (opcode_key>>bit)&1; - if(bit_value){ - opcode[31-key_bits[bit]]='1'; - op_value|= 1<> bit) & 1; + if(bit_value) { + opcode[31 - key_bits[bit]] = '1'; + op_value |= 1 << key_bits[bit]; } } - printf("ARM: No matching instruction class for key: %s %08x\n", opcode,op_value); - } - return matched_class; -} -static int arm_lookup_thumb_instruction_class(const arm7_instruction_t*instruction_table, uint32_t opcode_key){ - int key_bits[] = {8,9,10,11,12,13,14,15}; - int matched_class = -1; - for(int c = 0; instruction_table[c].handler;++c){ - bool matches = true; - for(int bit = 0; bit< sizeof(key_bits)/sizeof(key_bits[0]); ++bit){ - bool bit_value = (opcode_key>>bit)&1; - int b_off = key_bits[bit]; - matches &= instruction_table[c].bitfield[15-b_off] != '1' || bit_value == true; - matches &= instruction_table[c].bitfield[15-b_off] != '0' || bit_value == false; - if(!matches)break; + printf("ARM: No matching instruction class for key: %s %08x\n", opcode, op_value); + } + return matched_class; +} +static int arm_lookup_thumb_instruction_class(const arm7_instruction_t *instruction_table, uint32_t opcode_key) { + int key_bits[] = {8, 9, 10, 11, 12, 13, 14, 15}; + int matched_class = -1; + for(int c = 0; instruction_table[c].handler; ++c) { + bool matches = true; + for(int bit = 0; bit < sizeof(key_bits) / sizeof(key_bits[0]); ++bit) { + bool bit_value = (opcode_key >> bit) & 1; + int b_off = key_bits[bit]; + matches &= instruction_table[c].bitfield[15 - b_off] != '1' || bit_value == true; + matches &= instruction_table[c].bitfield[15 - b_off] != '0' || bit_value == false; + if(!matches) break; } - if(matches){ - if(matched_class!=-1){ - printf("ARM7t: Class %s and %s have ambiguous encodings\n", - instruction_table[c].name, - instruction_table[matched_class].name); + if(matches) { + if(matched_class != -1) { + printf("ARM7t: Class %s and %s have ambiguous encodings\n", + instruction_table[c].name, + instruction_table[matched_class].name); } - matched_class = c; + matched_class = c; } } - if(matched_class==-1){ - uint32_t op_value = 0; - char opcode[17]="0000000000000000"; - for(int bit = 0; bit< sizeof(key_bits)/sizeof(key_bits[0]); ++bit){ - bool bit_value = (opcode_key>>bit)&1; - if(bit_value){ - opcode[15-key_bits[bit]]='1'; - op_value|= 1<> bit) & 1; + if(bit_value) { + opcode[15 - key_bits[bit]] = '1'; + op_value |= 1 << key_bits[bit]; } } - printf("ARM7T: No matching instruction class for key: %s %04x\n", opcode,op_value); - } - return matched_class; + printf("ARM7T: No matching instruction class for key: %s %04x\n", opcode, op_value); + } + return matched_class; } -static arm7_t arm7_init(void* user_data){ +static arm7_t arm7_init(void *user_data) { // Generate ARM lookup table - for(int i=0;i<4096;++i){ - int inst_class = arm_lookup_arm_instruction_class(arm7_instruction_classes,i); - arm7_lookup_table[i]=inst_class==-1? NULL: arm7_instruction_classes[inst_class].handler; - arm7_disasm_lookup_table[i]=inst_class==-1? NULL: arm7_instruction_classes[inst_class].name; - } - for(int i=0;i<4096;++i){ - int inst_class = arm_lookup_arm_instruction_class(arm9_instruction_classes,i); - arm9_lookup_table[i]=inst_class==-1? NULL: arm9_instruction_classes[inst_class].handler; - arm9_disasm_lookup_table[i]=inst_class==-1? NULL: arm9_instruction_classes[inst_class].name; + for(int i = 0; i < 4096; ++i) { + int inst_class = arm_lookup_arm_instruction_class(arm7_instruction_classes, i); + arm7_lookup_table[i] = inst_class == -1 ? NULL : arm7_instruction_classes[inst_class].handler; + arm7_disasm_lookup_table[i] = inst_class == -1 ? NULL : arm7_instruction_classes[inst_class].name; + } + for(int i = 0; i < 4096; ++i) { + int inst_class = arm_lookup_arm_instruction_class(arm9_instruction_classes, i); + arm9_lookup_table[i] = inst_class == -1 ? NULL : arm9_instruction_classes[inst_class].handler; + arm9_disasm_lookup_table[i] = inst_class == -1 ? NULL : arm9_instruction_classes[inst_class].name; } // Generate Thumb Lookup Table - for(int i=0;i<256;++i){ - int inst_class = arm_lookup_thumb_instruction_class(arm7t_instruction_classes,i); - arm7t_lookup_table[i]=inst_class==-1 ? NULL: arm7t_instruction_classes[inst_class].handler; - arm7t_disasm_lookup_table[i]=inst_class==-1? NULL: arm7t_instruction_classes[inst_class].name; + for(int i = 0; i < 256; ++i) { + int inst_class = arm_lookup_thumb_instruction_class(arm7t_instruction_classes, i); + arm7t_lookup_table[i] = inst_class == -1 ? NULL : arm7t_instruction_classes[inst_class].handler; + arm7t_disasm_lookup_table[i] = inst_class == -1 ? NULL : arm7t_instruction_classes[inst_class].name; } // Generate Thumb Lookup Table - for(int i=0;i<256;++i){ - int inst_class = arm_lookup_thumb_instruction_class(arm9t_instruction_classes,i); - arm9t_lookup_table[i]=inst_class==-1 ? NULL: arm9t_instruction_classes[inst_class].handler; - arm9t_disasm_lookup_table[i]=inst_class==-1? NULL: arm9t_instruction_classes[inst_class].name; + for(int i = 0; i < 256; ++i) { + int inst_class = arm_lookup_thumb_instruction_class(arm9t_instruction_classes, i); + arm9t_lookup_table[i] = inst_class == -1 ? NULL : arm9t_instruction_classes[inst_class].handler; + arm9t_disasm_lookup_table[i] = inst_class == -1 ? NULL : arm9t_instruction_classes[inst_class].name; } arm7_t arm = {.user_data = user_data}; - arm.prefetch_pc=-1; - arm.phase=0; + arm.prefetch_pc = -1; + arm.phase = 0; arm.phased_op_id = ARM_PHASED_FILL_PIPE; return arm; - } -static FORCE_INLINE bool arm7_get_thumb_bit(arm7_t* cpu){return ARM7_BFE(cpu->registers[CPSR],5,1);} -static FORCE_INLINE void arm7_set_thumb_bit(arm7_t* cpu, bool value){ - cpu->registers[CPSR] &= ~(1<<5); - if(value)cpu->registers[CPSR]|= 1<<5; +static FORCE_INLINE bool arm7_get_thumb_bit(arm7_t *cpu) { return ARM7_BFE(cpu->registers[CPSR], 5, 1); } +static FORCE_INLINE void arm7_set_thumb_bit(arm7_t *cpu, bool value) { + cpu->registers[CPSR] &= ~(1 << 5); + if(value) cpu->registers[CPSR] |= 1 << 5; } -static FORCE_INLINE void arm7_process_interrupts(arm7_t* cpu, uint32_t interrupts){ - cpu->wait_for_interrupt=false; +static FORCE_INLINE void arm7_process_interrupts(arm7_t *cpu, uint32_t interrupts) { + cpu->wait_for_interrupt = false; uint32_t cpsr = cpu->registers[CPSR]; - bool I = ARM7_BFE(cpsr,7,1); - if(I==0&&cpu->phased_op_id==0){ - if(SB_UNLIKELY(cpu->log_cmp_file||interrupts==0))return; //Log drives interrupts when enabled - //Interrupts are enabled when I ==0 + bool I = ARM7_BFE(cpsr, 7, 1); + if(I == 0 && cpu->phased_op_id == 0) { + if(SB_UNLIKELY(cpu->log_cmp_file || interrupts == 0)) return; // Log drives interrupts when enabled + // Interrupts are enabled when I ==0 bool thumb = arm7_get_thumb_bit(cpu); - cpu->registers[R14_irq] = cpu->registers[PC]+4; - cpu->registers[PC] = cpu->irq_table_address+ 0x18; + cpu->registers[R14_irq] = cpu->registers[PC] + 4; + cpu->registers[PC] = cpu->irq_table_address + 0x18; cpu->registers[SPSR_irq] = cpsr; - //Update mode to IRQ - cpu->registers[CPSR] = (cpsr&0xffffffE0)| 0x12; - //Disable interrupts(set I bit) - cpu->registers[CPSR] |= 1<<7; - cpu->i_cycles+=1; - arm7_set_thumb_bit(cpu,false); + // Update mode to IRQ + cpu->registers[CPSR] = (cpsr & 0xffffffE0) | 0x12; + // Disable interrupts(set I bit) + cpu->registers[CPSR] |= 1 << 7; + cpu->i_cycles += 1; + arm7_set_thumb_bit(cpu, false); cpu->phased_op_id = ARM_PHASED_FILL_PIPE; - cpu->phase=0; - } -} -static void arm9_get_disasm(arm7_t * cpu, uint32_t mem_address, char* out_disasm, size_t out_size){ - out_disasm[0]='\0'; - const char * cond_code = ""; - const char * name = "INVALID"; - const char * key_str = NULL; - uint32_t opcode=0; - if(arm7_get_thumb_bit(cpu)==false){ - opcode = cpu->read32(cpu->user_data,mem_address); - - const char* cond_code_table[16]= - {"EQ","NE","CS","CC","MI","PL","VS","VC","HI","LS","GE","LT","GT","LE","","INV"}; - cond_code= cond_code_table[ARM7_BFE(opcode,28,4)]; - - uint32_t key = ((opcode>>4)&0xf)| ((opcode>>16)&0xff0); - int instr_class = arm_lookup_arm_instruction_class(arm9_instruction_classes,key); - name = instr_class==-1? "INVALID" : arm9_instruction_classes[instr_class].name; - key_str = instr_class==-1? "" : arm9_instruction_classes[instr_class].bitfield; + cpu->phase = 0; + } +} +static void arm9_get_disasm(arm7_t *cpu, uint32_t mem_address, char *out_disasm, size_t out_size) { + out_disasm[0] = '\0'; + const char *cond_code = ""; + const char *name = "INVALID"; + const char *key_str = NULL; + uint32_t opcode = 0; + if(arm7_get_thumb_bit(cpu) == false) { + opcode = cpu->read32(cpu->user_data, mem_address); + + const char *cond_code_table[16] = + {"EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "INV"}; + cond_code = cond_code_table[ARM7_BFE(opcode, 28, 4)]; + + uint32_t key = ((opcode >> 4) & 0xf) | ((opcode >> 16) & 0xff0); + int instr_class = arm_lookup_arm_instruction_class(arm9_instruction_classes, key); + name = instr_class == -1 ? "INVALID" : arm9_instruction_classes[instr_class].name; + key_str = instr_class == -1 ? "" : arm9_instruction_classes[instr_class].bitfield; // Get more information for the DP class instruction - if(strcmp(name,"DP")==0){ - const char* op_name[]={"AND", "EOR", "SUB", "RSB", - "ADD", "ADC", "SBC", "RSC", - "TST", "TEQ", "CMP", "CMN", - "ORR", "MOV", "BIC", "MVN"}; - name = op_name[ARM7_BFE(opcode,21,4)]; + if(strcmp(name, "DP") == 0) { + const char *op_name[] = {"AND", "EOR", "SUB", "RSB", + "ADD", "ADC", "SBC", "RSC", + "TST", "TEQ", "CMP", "CMN", + "ORR", "MOV", "BIC", "MVN"}; + name = op_name[ARM7_BFE(opcode, 21, 4)]; } - }else{ - opcode = cpu->read16(cpu->user_data,mem_address); - uint32_t key = ((opcode>>8)&0xff); - int instr_class = arm_lookup_thumb_instruction_class(arm9t_instruction_classes,key); - name = instr_class==-1? "INVALID" : arm9t_instruction_classes[instr_class].name; - key_str = instr_class==-1? "" : arm9t_instruction_classes[instr_class].bitfield; - } - int offset = snprintf(out_disasm,out_size,"%s%s ",name,cond_code); + } else { + opcode = cpu->read16(cpu->user_data, mem_address); + uint32_t key = ((opcode >> 8) & 0xff); + int instr_class = arm_lookup_thumb_instruction_class(arm9t_instruction_classes, key); + name = instr_class == -1 ? "INVALID" : arm9t_instruction_classes[instr_class].name; + key_str = instr_class == -1 ? "" : arm9t_instruction_classes[instr_class].bitfield; + } + int offset = snprintf(out_disasm, out_size, "%s%s ", name, cond_code); bool letter_handled[256]; - for(int i=0;i<256;++i)letter_handled[i]=false; - letter_handled['1']=true; - letter_handled['0']=true; - letter_handled['c']=true; - int key_len = strlen(key_str); - int key_off=0; - while(key_str[key_off]){ + for(int i = 0; i < 256; ++i) + letter_handled[i] = false; + letter_handled['1'] = true; + letter_handled['0'] = true; + letter_handled['c'] = true; + int key_len = strlen(key_str); + int key_off = 0; + while(key_str[key_off]) { char letter = key_str[key_off]; - int value =0; - int key_off2 = key_off; - if(letter_handled[letter]==false){ - while(key_str[key_off2]){ - if(key_str[key_off2]==letter){ - value<<=1; - value|= SB_BFE(opcode,key_len-1-key_off2,1); + int value = 0; + int key_off2 = key_off; + if(letter_handled[letter] == false) { + while(key_str[key_off2]) { + if(key_str[key_off2] == letter) { + value <<= 1; + value |= SB_BFE(opcode, key_len - 1 - key_off2, 1); } ++key_off2; } - letter_handled[letter]=true; - offset+=snprintf(out_disasm+offset,out_size-offset,"%c:%d ",letter,value); + letter_handled[letter] = true; + offset += snprintf(out_disasm + offset, out_size - offset, "%c:%d ", letter, value); } ++key_off; } - out_disasm[out_size-1]=0; - return; + out_disasm[out_size - 1] = 0; + return; } -static FORCE_INLINE bool arm7_check_cond_code(arm7_t *cpu, uint32_t opcode){ - uint32_t cond_code = ARM7_BFE(opcode,28,4); - if(SB_LIKELY(cond_code==0xE))return true; +static FORCE_INLINE bool arm7_check_cond_code(arm7_t *cpu, uint32_t opcode) { + uint32_t cond_code = ARM7_BFE(opcode, 28, 4); + if(SB_LIKELY(cond_code == 0xE)) return true; uint32_t cpsr = cpu->registers[CPSR]; - bool N = ARM7_BFE(cpsr,31,1); - bool Z = ARM7_BFE(cpsr,30,1); - bool C = ARM7_BFE(cpsr,29,1); - bool V = ARM7_BFE(cpsr,28,1); - switch(cond_code){ - case 0x0: return Z; //EQ: Equal - case 0x1: return !Z; //NE: !Equal - case 0x2: return C; //CS: Unsigned >= - case 0x3: return !C; //CC: Unsigned < - case 0x4: return N; //MI: Negative - case 0x5: return !N; //PL: Positive or Zero - case 0x6: return V; //VS: Overflow - case 0x7: return !V; //VC: No Overflow - case 0x8: return C && !Z; //HI: Unsigned > - case 0x9: return !C || Z; //LS: Unsigned <= - case 0xA: return N==V; //GE: Signed >= - case 0xB: return N!=V; //LT: Signed < - case 0xC: return !Z&&(N==V); //GT: Signed > - case 0xD: return Z||(N!=V); //LE: Signed <= - case 0xE: return true; - case 0xF: return true; + bool N = ARM7_BFE(cpsr, 31, 1); + bool Z = ARM7_BFE(cpsr, 30, 1); + bool C = ARM7_BFE(cpsr, 29, 1); + bool V = ARM7_BFE(cpsr, 28, 1); + switch(cond_code) { + case 0x0: return Z; // EQ: Equal + case 0x1: return !Z; // NE: !Equal + case 0x2: return C; // CS: Unsigned >= + case 0x3: return !C; // CC: Unsigned < + case 0x4: return N; // MI: Negative + case 0x5: return !N; // PL: Positive or Zero + case 0x6: return V; // VS: Overflow + case 0x7: return !V; // VC: No Overflow + case 0x8: return C && !Z; // HI: Unsigned > + case 0x9: return !C || Z; // LS: Unsigned <= + case 0xA: return N == V; // GE: Signed >= + case 0xB: return N != V; // LT: Signed < + case 0xC: return !Z && (N == V); // GT: Signed > + case 0xD: return Z || (N != V); // LE: Signed <= + case 0xE: return true; + case 0xF: return true; }; - return false; + return false; } -static void arm_check_log_file(arm7_t*cpu){ +static void arm_check_log_file(arm7_t *cpu) { bool thumb = arm7_get_thumb_bit(cpu); - fseek(cpu->log_cmp_file,(cpu->executed_instructions)*18*4,SEEK_SET); + fseek(cpu->log_cmp_file, (cpu->executed_instructions) * 18 * 4, SEEK_SET); uint32_t cmp_regs[18]; - if(fread(cmp_regs,18*4,1,cpu->log_cmp_file)==1){ + if(fread(cmp_regs, 18 * 4, 1, cpu->log_cmp_file) == 1) { uint32_t regs[18]; - for(int i=0;i<18;++i)regs[i]=arm7_reg_read(cpu,i); - if(arm7_get_thumb_bit(cpu)==false){ - unsigned oldpc = cpu->registers[PC]; - cmp_regs[15]-=8; - }else{ - unsigned oldpc = cpu->registers[PC]; - cmp_regs[15]-=4; + for(int i = 0; i < 18; ++i) + regs[i] = arm7_reg_read(cpu, i); + if(arm7_get_thumb_bit(cpu) == false) { + unsigned oldpc = cpu->registers[PC]; + cmp_regs[15] -= 8; + } else { + unsigned oldpc = cpu->registers[PC]; + cmp_regs[15] -= 4; } uint32_t cpsr = cmp_regs[16]; - bool has_spsr = arm7_reg_index(cpu,SPSR)!=CPSR; - if(!has_spsr){ - cmp_regs[SPSR]=arm7_reg_read(cpu,SPSR); + bool has_spsr = arm7_reg_index(cpu, SPSR) != CPSR; + if(!has_spsr) { + cmp_regs[SPSR] = arm7_reg_read(cpu, SPSR); } bool matches = true; - for(int i=0;i<18;++i)matches &= cmp_regs[i]==regs[i]; - if(!matches){ - static int last_pc_break =0; - if(last_pc_break!=cpu->registers[PC])cpu->trigger_breakpoint =true; + for(int i = 0; i < 18; ++i) + matches &= cmp_regs[i] == regs[i]; + if(!matches) { + static int last_pc_break = 0; + if(last_pc_break != cpu->registers[PC]) cpu->trigger_breakpoint = true; last_pc_break = cpu->registers[PC]; printf("Log mismatch detected\n"); printf("=====================\n"); - printf("After %llu executed_instructions\n",cpu->executed_instructions); + printf("After %llu executed_instructions\n", cpu->executed_instructions); - char * rnames[18]={ - "R0","R1","R2","R3","R4","R5","R6","R7", - "R8","R9","R10","R11","R12","R13","R14","R15", - "CPSR","SPSR" - }; - int last_instruction = cpu->executed_instructions-1; - if(last_instruction<0)last_instruction=0; - fseek(cpu->log_cmp_file,(last_instruction)*18*4,SEEK_SET); + char *rnames[18] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "CPSR", "SPSR"}; + int last_instruction = cpu->executed_instructions - 1; + if(last_instruction < 0) last_instruction = 0; + fseek(cpu->log_cmp_file, (last_instruction)*18 * 4, SEEK_SET); uint32_t prev_regs[18]; - fread(prev_regs,18*4,1,cpu->log_cmp_file); - - for(int i=0;i<18;++i){ - if(regs[i]!=cmp_regs[i])printf("%s %d (%08x) Log Value = %d (%08x) Prev Value =%d (%08x)\n", rnames[i],regs[i],regs[i],cmp_regs[i],cmp_regs[i],prev_regs[i],prev_regs[i]); - else printf("Matches %s %d (%08x) Prev Value =%d (%08x)\n", rnames[i],regs[i],regs[i],prev_regs[i],prev_regs[i]); + fread(prev_regs, 18 * 4, 1, cpu->log_cmp_file); + + for(int i = 0; i < 18; ++i) { + if(regs[i] != cmp_regs[i]) + printf("%s %d (%08x) Log Value = %d (%08x) Prev Value =%d (%08x)\n", rnames[i], regs[i], regs[i], cmp_regs[i], cmp_regs[i], prev_regs[i], prev_regs[i]); + else + printf("Matches %s %d (%08x) Prev Value =%d (%08x)\n", rnames[i], regs[i], regs[i], prev_regs[i], prev_regs[i]); } uint32_t log_cpsr = cmp_regs[16]; uint32_t prev_cpsr = prev_regs[16]; printf("N:%d LogN:%d PrevN:%d Z:%d LogZ:%d PrevZ:%d C:%d LogC:%d PrevC:%d V:%d LogV:%d PrevV:%d\n", - ARM7_BFE(cpsr,31,1), ARM7_BFE(log_cpsr,31,1), ARM7_BFE(prev_cpsr,31,1), - ARM7_BFE(cpsr,30,1), ARM7_BFE(log_cpsr,30,1), ARM7_BFE(prev_cpsr,30,1), - ARM7_BFE(cpsr,29,1), ARM7_BFE(log_cpsr,29,1), ARM7_BFE(prev_cpsr,29,1), - ARM7_BFE(cpsr,28,1), ARM7_BFE(log_cpsr,28,1), ARM7_BFE(prev_cpsr,28,1) - ); + ARM7_BFE(cpsr, 31, 1), ARM7_BFE(log_cpsr, 31, 1), ARM7_BFE(prev_cpsr, 31, 1), + ARM7_BFE(cpsr, 30, 1), ARM7_BFE(log_cpsr, 30, 1), ARM7_BFE(prev_cpsr, 30, 1), + ARM7_BFE(cpsr, 29, 1), ARM7_BFE(log_cpsr, 29, 1), ARM7_BFE(prev_cpsr, 29, 1), + ARM7_BFE(cpsr, 28, 1), ARM7_BFE(log_cpsr, 28, 1), ARM7_BFE(prev_cpsr, 28, 1)); // Set CPSR first - arm7_reg_write(cpu,CPSR,cmp_regs[CPSR]); - for(int i=0;i<18;++i){ - arm7_reg_write(cpu,i,cmp_regs[i]); + arm7_reg_write(cpu, CPSR, cmp_regs[CPSR]); + for(int i = 0; i < 18; ++i) { + arm7_reg_write(cpu, i, cmp_regs[i]); } - int log_mode = log_cpsr&0x1f; - int prev_mode = prev_cpsr&0x1f; - if(log_mode==0x12&&prev_mode!=0x12){ + int log_mode = log_cpsr & 0x1f; + int prev_mode = prev_cpsr & 0x1f; + if(log_mode == 0x12 && prev_mode != 0x12) { printf("Interrupt!\n"); - cpu->trigger_breakpoint=false; + cpu->trigger_breakpoint = false; } thumb = arm7_get_thumb_bit(cpu); - if(thumb){ - cpu->registers[PC]&=~1; - cpu->prefetch_opcode[0]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+0,false); - cpu->prefetch_opcode[1]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+2,true); - cpu->prefetch_opcode[2]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+4,true); - }else{ - cpu->registers[PC]&=~3; - cpu->prefetch_opcode[0]=cpu->read32_seq(cpu->user_data,cpu->registers[PC]+0,false); - cpu->prefetch_opcode[1]=cpu->read32_seq(cpu->user_data,cpu->registers[PC]+4,true); - cpu->prefetch_opcode[2]=cpu->read32_seq(cpu->user_data,cpu->registers[PC]+8,true); + if(thumb) { + cpu->registers[PC] &= ~1; + cpu->prefetch_opcode[0] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 0, false); + cpu->prefetch_opcode[1] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 2, true); + cpu->prefetch_opcode[2] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 4, true); + } else { + cpu->registers[PC] &= ~3; + cpu->prefetch_opcode[0] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 0, false); + cpu->prefetch_opcode[1] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 4, true); + cpu->prefetch_opcode[2] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 8, true); } } - }else{ + } else { printf("Log finished!\n"); fclose(cpu->log_cmp_file); - cpu->log_cmp_file=NULL; + cpu->log_cmp_file = NULL; } uint32_t opcode = cpu->prefetch_opcode[0]; - char disasm[128]; - arm9_get_disasm(cpu,cpu->registers[PC],disasm,128); - if(thumb==false){ - uint32_t key = ((opcode>>4)&0xf)| ((opcode>>16)&0xff0); - printf("ARM OP: %08x PC: %08x %s Binary: ",opcode,cpu->registers[PC],disasm); - arm7_print_binary(opcode,32); + char disasm[128]; + arm9_get_disasm(cpu, cpu->registers[PC], disasm, 128); + if(thumb == false) { + uint32_t key = ((opcode >> 4) & 0xf) | ((opcode >> 16) & 0xff0); + printf("ARM OP: %08x PC: %08x %s Binary: ", opcode, cpu->registers[PC], disasm); + arm7_print_binary(opcode, 32); printf("\n"); - }else{ - uint32_t key = ((opcode>>8)&0xff); - printf("THUMB OP: %04x PC: %08x %s Binary: ",opcode,cpu->registers[PC],disasm); - arm7_print_binary(opcode,16); + } else { + uint32_t key = ((opcode >> 8) & 0xff); + printf("THUMB OP: %04x PC: %08x %s Binary: ", opcode, cpu->registers[PC], disasm); + arm7_print_binary(opcode, 16); printf("\n"); } cpu->executed_instructions++; } -static FORCE_INLINE void arm7_fill_pipeline(arm7_t*cpu){ +static FORCE_INLINE void arm7_fill_pipeline(arm7_t *cpu) { bool thumb = arm7_get_thumb_bit(cpu); - if(thumb){ - cpu->registers[PC]&=~1; - cpu->prefetch_opcode[cpu->phase]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+2*cpu->phase,cpu->phase!=0); - }else{ - cpu->registers[PC]&=~3; - cpu->prefetch_opcode[cpu->phase]=cpu->read32_seq(cpu->user_data,cpu->registers[PC]+4*cpu->phase,cpu->phase!=0); + if(thumb) { + cpu->registers[PC] &= ~1; + cpu->prefetch_opcode[cpu->phase] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 2 * cpu->phase, cpu->phase != 0); + } else { + cpu->registers[PC] &= ~3; + cpu->prefetch_opcode[cpu->phase] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 4 * cpu->phase, cpu->phase != 0); } ++cpu->phase; - if(cpu->phase!=2)return; - cpu->debug_branch_ring[(cpu->debug_branch_ring_offset++)%ARM_DEBUG_BRANCH_RING_SIZE]=cpu->registers[PC]; - cpu->phase = 0; + if(cpu->phase != 2) return; + cpu->debug_branch_ring[(cpu->debug_branch_ring_offset++) % ARM_DEBUG_BRANCH_RING_SIZE] = cpu->registers[PC]; + cpu->phase = 0; cpu->phased_op_id = 0; - cpu->prefetch_pc=cpu->registers[PC]; - cpu->next_fetch_sequential=true; -} -static FORCE_INLINE bool arm7_run_phased_opcode(arm7_t* cpu){ - switch(cpu->phased_op_id){ - case ARM_PHASED_NONE: return true; - case ARM_PHASED_FILL_PIPE: arm7_fill_pipeline(cpu);break; - case ARM_PHASED_BLOCK_TRANSFER: arm7_block_transfer(cpu,cpu->phased_opcode);break; - default: cpu->phased_op_id=0;return true; + cpu->prefetch_pc = cpu->registers[PC]; + cpu->next_fetch_sequential = true; +} +static FORCE_INLINE bool arm7_run_phased_opcode(arm7_t *cpu) { + switch(cpu->phased_op_id) { + case ARM_PHASED_NONE: return true; + case ARM_PHASED_FILL_PIPE: arm7_fill_pipeline(cpu); break; + case ARM_PHASED_BLOCK_TRANSFER: arm7_block_transfer(cpu, cpu->phased_opcode); break; + default: cpu->phased_op_id = 0; return true; } - return false; + return false; } -static FORCE_INLINE void arm7_exec_instruction(arm7_t* cpu){ +static FORCE_INLINE void arm7_exec_instruction(arm7_t *cpu) { bool thumb = arm7_get_thumb_bit(cpu); - if(SB_LIKELY(arm7_run_phased_opcode(cpu))){ - if(SB_UNLIKELY(cpu->wait_for_interrupt)){ - cpu->i_cycles+=1; + if(SB_LIKELY(arm7_run_phased_opcode(cpu))) { + if(SB_UNLIKELY(cpu->wait_for_interrupt)) { + cpu->i_cycles += 1; return; } - if(SB_UNLIKELY(cpu->log_cmp_file)){ + if(SB_UNLIKELY(cpu->log_cmp_file)) { arm_check_log_file(cpu); } - cpu->next_fetch_sequential=true; + cpu->next_fetch_sequential = true; uint32_t opcode = cpu->prefetch_opcode[0]; cpu->prefetch_opcode[0] = cpu->prefetch_opcode[1]; cpu->prefetch_opcode[1] = cpu->prefetch_opcode[2]; - if(thumb==false){ + if(thumb == false) { cpu->registers[PC] += 4; cpu->prefetch_pc = cpu->registers[PC]; - if(SB_LIKELY(arm7_check_cond_code(cpu,opcode))){ - uint32_t key = ((opcode>>4)&0xf)| ((opcode>>16)&0xff0); - arm7_lookup_table[key](cpu,opcode); + if(SB_LIKELY(arm7_check_cond_code(cpu, opcode))) { + uint32_t key = ((opcode >> 4) & 0xf) | ((opcode >> 16) & 0xff0); + arm7_lookup_table[key](cpu, opcode); } - }else{ + } else { cpu->registers[PC] += 2; cpu->prefetch_pc = cpu->registers[PC]; - uint32_t key = ((opcode>>8)&0xff); - arm7t_lookup_table[key](cpu,opcode); + uint32_t key = ((opcode >> 8) & 0xff); + arm7t_lookup_table[key](cpu, opcode); } } - if(SB_UNLIKELY(cpu->phased_op_id))return; - if(thumb==false){ - if(SB_LIKELY(cpu->prefetch_pc==cpu->registers[PC]))cpu->prefetch_opcode[2] =cpu->read32_seq(cpu->user_data,cpu->registers[PC]+8,cpu->next_fetch_sequential); - else cpu->phased_op_id=ARM_PHASED_FILL_PIPE; - }else{ - if(SB_LIKELY(cpu->prefetch_pc==cpu->registers[PC]))cpu->prefetch_opcode[2]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+4,cpu->next_fetch_sequential); - else cpu->phased_op_id=ARM_PHASED_FILL_PIPE; + if(SB_UNLIKELY(cpu->phased_op_id)) return; + if(thumb == false) { + if(SB_LIKELY(cpu->prefetch_pc == cpu->registers[PC])) + cpu->prefetch_opcode[2] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 8, cpu->next_fetch_sequential); + else + cpu->phased_op_id = ARM_PHASED_FILL_PIPE; + } else { + if(SB_LIKELY(cpu->prefetch_pc == cpu->registers[PC])) + cpu->prefetch_opcode[2] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 4, cpu->next_fetch_sequential); + else + cpu->phased_op_id = ARM_PHASED_FILL_PIPE; } - if(SB_UNLIKELY(cpu->step_instructions)){ + if(SB_UNLIKELY(cpu->step_instructions)) { --cpu->step_instructions; - if(cpu->step_instructions==0)cpu->trigger_breakpoint =true; + if(cpu->step_instructions == 0) cpu->trigger_breakpoint = true; } } -static FORCE_INLINE void arm9_fill_pipeline(arm7_t*cpu){ +static FORCE_INLINE void arm9_fill_pipeline(arm7_t *cpu) { bool thumb = arm7_get_thumb_bit(cpu); - if(thumb){ - cpu->registers[PC]&=~1; - cpu->prefetch_opcode[cpu->phase]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+2*cpu->phase,cpu->phase!=0); - }else{ - cpu->registers[PC]&=~3; - cpu->prefetch_opcode[cpu->phase]=cpu->read32_seq(cpu->user_data,cpu->registers[PC]+4*cpu->phase,cpu->phase!=0); + if(thumb) { + cpu->registers[PC] &= ~1; + cpu->prefetch_opcode[cpu->phase] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 2 * cpu->phase, cpu->phase != 0); + } else { + cpu->registers[PC] &= ~3; + cpu->prefetch_opcode[cpu->phase] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 4 * cpu->phase, cpu->phase != 0); } ++cpu->phase; - if(cpu->phase!=4)return; - cpu->debug_branch_ring[(cpu->debug_branch_ring_offset++)%ARM_DEBUG_BRANCH_RING_SIZE]=cpu->registers[PC]; - cpu->phase = 0; + if(cpu->phase != 4) return; + cpu->debug_branch_ring[(cpu->debug_branch_ring_offset++) % ARM_DEBUG_BRANCH_RING_SIZE] = cpu->registers[PC]; + cpu->phase = 0; cpu->phased_op_id = 0; - cpu->prefetch_pc=cpu->registers[PC]; - cpu->next_fetch_sequential=true; -} -static FORCE_INLINE bool arm9_run_phased_opcode(arm7_t* cpu){ - switch(cpu->phased_op_id){ - case ARM_PHASED_NONE: return true; - case ARM_PHASED_FILL_PIPE: arm9_fill_pipeline(cpu);break; - case ARM_PHASED_BLOCK_TRANSFER: arm9_block_transfer(cpu,cpu->phased_opcode);break; - default: cpu->phased_op_id=0;return true; + cpu->prefetch_pc = cpu->registers[PC]; + cpu->next_fetch_sequential = true; +} +static FORCE_INLINE bool arm9_run_phased_opcode(arm7_t *cpu) { + switch(cpu->phased_op_id) { + case ARM_PHASED_NONE: return true; + case ARM_PHASED_FILL_PIPE: arm9_fill_pipeline(cpu); break; + case ARM_PHASED_BLOCK_TRANSFER: arm9_block_transfer(cpu, cpu->phased_opcode); break; + default: cpu->phased_op_id = 0; return true; } - return false; + return false; } -static void arm9_exec_instruction(arm7_t* cpu){ +static void arm9_exec_instruction(arm7_t *cpu) { bool thumb = arm7_get_thumb_bit(cpu); - if(SB_LIKELY(arm9_run_phased_opcode(cpu))){ - if(cpu->wait_for_interrupt){ - cpu->i_cycles+=1; + if(SB_LIKELY(arm9_run_phased_opcode(cpu))) { + if(cpu->wait_for_interrupt) { + cpu->i_cycles += 1; return; } - - if(SB_UNLIKELY(cpu->log_cmp_file)){ + + if(SB_UNLIKELY(cpu->log_cmp_file)) { arm_check_log_file(cpu); thumb = arm7_get_thumb_bit(cpu); } - cpu->next_fetch_sequential=true; + cpu->next_fetch_sequential = true; uint32_t opcode = cpu->prefetch_opcode[0]; cpu->prefetch_opcode[0] = cpu->prefetch_opcode[1]; cpu->prefetch_opcode[1] = cpu->prefetch_opcode[2]; cpu->prefetch_opcode[2] = cpu->prefetch_opcode[3]; cpu->prefetch_opcode[3] = cpu->prefetch_opcode[4]; - if(thumb==false){ + if(thumb == false) { cpu->registers[PC] += 4; cpu->prefetch_pc = cpu->registers[PC]; - if(arm7_check_cond_code(cpu,opcode)){ - uint32_t key = ((opcode>>4)&0xf)| ((opcode>>16)&0xff0); - arm9_lookup_table[key](cpu,opcode); + if(arm7_check_cond_code(cpu, opcode)) { + uint32_t key = ((opcode >> 4) & 0xf) | ((opcode >> 16) & 0xff0); + arm9_lookup_table[key](cpu, opcode); } - }else{ + } else { cpu->registers[PC] += 2; cpu->prefetch_pc = cpu->registers[PC]; - uint32_t key = ((opcode>>8)&0xff); - arm9t_lookup_table[key](cpu,opcode); + uint32_t key = ((opcode >> 8) & 0xff); + arm9t_lookup_table[key](cpu, opcode); } } - if(SB_UNLIKELY(cpu->phased_op_id))return; - if(thumb==false){ - if(SB_LIKELY(cpu->prefetch_pc==cpu->registers[PC]))cpu->prefetch_opcode[2] =cpu->read32_seq(cpu->user_data,cpu->registers[PC]+8,cpu->next_fetch_sequential); - else cpu->phased_op_id=ARM_PHASED_FILL_PIPE; - }else{ - if(SB_LIKELY(cpu->prefetch_pc==cpu->registers[PC]))cpu->prefetch_opcode[2]=cpu->read16_seq(cpu->user_data,cpu->registers[PC]+4,cpu->next_fetch_sequential); - else cpu->phased_op_id=ARM_PHASED_FILL_PIPE; + if(SB_UNLIKELY(cpu->phased_op_id)) return; + if(thumb == false) { + if(SB_LIKELY(cpu->prefetch_pc == cpu->registers[PC])) + cpu->prefetch_opcode[2] = cpu->read32_seq(cpu->user_data, cpu->registers[PC] + 8, cpu->next_fetch_sequential); + else + cpu->phased_op_id = ARM_PHASED_FILL_PIPE; + } else { + if(SB_LIKELY(cpu->prefetch_pc == cpu->registers[PC])) + cpu->prefetch_opcode[2] = cpu->read16_seq(cpu->user_data, cpu->registers[PC] + 4, cpu->next_fetch_sequential); + else + cpu->phased_op_id = ARM_PHASED_FILL_PIPE; } - if(SB_UNLIKELY(cpu->step_instructions)){ + if(SB_UNLIKELY(cpu->step_instructions)) { --cpu->step_instructions; - if(cpu->step_instructions==0)cpu->trigger_breakpoint =true; + if(cpu->step_instructions == 0) cpu->trigger_breakpoint = true; } } static FORCE_INLINE uint32_t arm7_rotr(uint32_t value, uint32_t rotate) { - return ((uint64_t)value >> (rotate &31)) | ((uint64_t)value << (32-(rotate&31))); + return ((uint64_t)value >> (rotate & 31)) | ((uint64_t)value << (32 - (rotate & 31))); } -static FORCE_INLINE uint32_t arm7_load_shift_reg(arm7_t* arm, uint32_t opcode, int* carry){ - uint32_t value = arm7_reg_read(arm, ARM7_BFE(opcode,0,4)); - uint32_t shift_value = 0; - if(ARM7_BFE(opcode,4,1)==true){ - int rs = ARM7_BFE(opcode,8,4); +static FORCE_INLINE uint32_t arm7_load_shift_reg(arm7_t *arm, uint32_t opcode, int *carry) { + uint32_t value = arm7_reg_read(arm, ARM7_BFE(opcode, 0, 4)); + uint32_t shift_value = 0; + if(ARM7_BFE(opcode, 4, 1) == true) { + int rs = ARM7_BFE(opcode, 8, 4); shift_value = arm7_reg_read(arm, rs); - }else{ - shift_value = ARM7_BFE(opcode,7,5); + } else { + shift_value = ARM7_BFE(opcode, 7, 5); } - return arm7_shift(arm,opcode,value,shift_value,carry); + return arm7_shift(arm, opcode, value, shift_value, carry); } -static FORCE_INLINE uint32_t arm7_shift(arm7_t* arm, uint32_t opcode, uint64_t value, uint32_t shift_value, int* carry){ - int shift_type = ARM7_BFE(opcode,5,2); - // Shift value of 0 has special behavior from a register: +static FORCE_INLINE uint32_t arm7_shift(arm7_t *arm, uint32_t opcode, uint64_t value, uint32_t shift_value, int *carry) { + int shift_type = ARM7_BFE(opcode, 5, 2); + // Shift value of 0 has special behavior from a register: // If this byte is zero, the unchanged contents of Rm will be used as the second operand, // and the old value of the CPSR C flag will be passed on as the shifter carry output. - if(shift_value==0&&(ARM7_BFE(opcode,4,1)||shift_type==0)){*carry=-1;return value;} - switch(shift_type){ - case 0: - if(shift_value>32){ - *carry = 0; - value = 0; - }else{ - *carry = shift_value==0? -1: ARM7_BFE(value, 32-shift_value,1); - value = value<32){ - *carry = 0; - value = 0; - }else{ - if(shift_value ==0){shift_value=32;} - *carry = ARM7_BFE(value, shift_value-1,1); - value = value>>shift_value; - } - break; - case 2: - if(shift_value>32){ - bool b31 = ARM7_BFE(value,31,1); - value= b31? 0xffffffff :0; - *carry= b31; - }else{ - if(shift_value ==0){shift_value=32;} - *carry = ARM7_BFE(value, shift_value-1,1); - value = (int64_t)((int32_t)value)>>shift_value; - } - break; - case 3: - if(shift_value==0){ - uint32_t cpsr=arm->registers[CPSR]; - int C = ARM7_BFE(cpsr,29,1); - //Rotate Extended (RRX) - *carry = ARM7_BFE(value,0,1); value = (value>>1)|(C<<31); - - }else{ - //Rotate - value = arm7_rotr(value,shift_value); *carry = ARM7_BFE(value,31,1); - } - break; - } + if(shift_value == 0 && (ARM7_BFE(opcode, 4, 1) || shift_type == 0)) { + *carry = -1; + return value; + } + switch(shift_type) { + case 0: + if(shift_value > 32) { + *carry = 0; + value = 0; + } else { + *carry = shift_value == 0 ? -1 : ARM7_BFE(value, 32 - shift_value, 1); + value = value << shift_value; + } + break; + case 1: + if(shift_value > 32) { + *carry = 0; + value = 0; + } else { + if(shift_value == 0) { shift_value = 32; } + *carry = ARM7_BFE(value, shift_value - 1, 1); + value = value >> shift_value; + } + break; + case 2: + if(shift_value > 32) { + bool b31 = ARM7_BFE(value, 31, 1); + value = b31 ? 0xffffffff : 0; + *carry = b31; + } else { + if(shift_value == 0) { shift_value = 32; } + *carry = ARM7_BFE(value, shift_value - 1, 1); + value = (int64_t)((int32_t)value) >> shift_value; + } + break; + case 3: + if(shift_value == 0) { + uint32_t cpsr = arm->registers[CPSR]; + int C = ARM7_BFE(cpsr, 29, 1); + // Rotate Extended (RRX) + *carry = ARM7_BFE(value, 0, 1); + value = (value >> 1) | (C << 31); + + } else { + // Rotate + value = arm7_rotr(value, shift_value); + *carry = ARM7_BFE(value, 31, 1); + } + break; + } return value; } -static FORCE_INLINE void arm7_data_processing(arm7_t* cpu, uint32_t opcode){ +static FORCE_INLINE void arm7_data_processing(arm7_t *cpu, uint32_t opcode) { // If it's used as anything but the shift amount in an operation with a register-specified shift, r15 will be PC + 12 // I.e. add r0, r15, r15, lsl r15 would set r0 to PC + 12 + ((PC + 12) << (PC + 8)) - uint64_t Rd = ARM7_BFE(opcode,12,4); - int S = ARM7_BFE(opcode,20,1); - int op = ARM7_BFE(opcode,21,4); - int r15_off = 4; + uint64_t Rd = ARM7_BFE(opcode, 12, 4); + int S = ARM7_BFE(opcode, 20, 1); + int op = ARM7_BFE(opcode, 21, 4); + int r15_off = 4; // Load Second Operand uint64_t Rm = 0; - int barrel_shifter_carry = -1; - if(opcode&((1<<25)|(0xff0))){ - int I = ARM7_BFE(opcode,25,1); - if(I){ - uint32_t imm = ARM7_BFE(opcode,0,8); - uint32_t rot = ARM7_BFE(opcode,8,4)*2; - Rm = arm7_rotr(imm, ARM7_BFE(opcode,8,4)*2); - //C is preserved when rot ==0 - barrel_shifter_carry = rot==0?-1: ARM7_BFE(Rm,31,1); - }else{ - uint32_t shift_value = 0; - if(ARM7_BFE(opcode,4,1)){ - int rs = ARM7_BFE(opcode,8,4); + int barrel_shifter_carry = -1; + if(opcode & ((1 << 25) | (0xff0))) { + int I = ARM7_BFE(opcode, 25, 1); + if(I) { + uint32_t imm = ARM7_BFE(opcode, 0, 8); + uint32_t rot = ARM7_BFE(opcode, 8, 4) * 2; + Rm = arm7_rotr(imm, ARM7_BFE(opcode, 8, 4) * 2); + // C is preserved when rot ==0 + barrel_shifter_carry = rot == 0 ? -1 : ARM7_BFE(Rm, 31, 1); + } else { + uint32_t shift_value = 0; + if(ARM7_BFE(opcode, 4, 1)) { + int rs = ARM7_BFE(opcode, 8, 4); // Only the first byte is used - shift_value = arm7_reg_read_r15_adj(cpu, rs,r15_off)&0xff; - r15_off+=4; //Using r15 for a shift adds 4 cycles - cpu->i_cycles+=1; - }else shift_value = ARM7_BFE(opcode,7,5); - uint32_t value = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode,0,4),r15_off); - Rm = arm7_shift(cpu, opcode, value, shift_value, &barrel_shifter_carry); + shift_value = arm7_reg_read_r15_adj(cpu, rs, r15_off) & 0xff; + r15_off += 4; // Using r15 for a shift adds 4 cycles + cpu->i_cycles += 1; + } else + shift_value = ARM7_BFE(opcode, 7, 5); + uint32_t value = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 0, 4), r15_off); + Rm = arm7_shift(cpu, opcode, value, shift_value, &barrel_shifter_carry); } - }else Rm= arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode,0,4),r15_off);; - - uint64_t Rn = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode,16,4), r15_off); - - uint64_t result = 0; - // Perform main operation - switch(op){ - /*AND*/ case 0: arm7_reg_write(cpu,Rd, result = Rn&Rm); break; - /*EOR*/ case 1: arm7_reg_write(cpu,Rd, result = Rn^Rm); break; - /*SUB*/ case 2: arm7_reg_write(cpu,Rd, result = Rn-Rm); break; - /*RSB*/ case 3: arm7_reg_write(cpu,Rd, result = Rm-Rn); break; - /*ADD*/ case 4: arm7_reg_write(cpu,Rd, result = Rn+Rm); break; - /*ADC*/ case 5: arm7_reg_write(cpu,Rd, result = Rn+Rm+ARM7_BFE(cpu->registers[CPSR],29,1)); break; - /*SBC*/ case 6: arm7_reg_write(cpu,Rd, result = Rn-Rm+ARM7_BFE(cpu->registers[CPSR],29,1)-1); break; - /*RSC*/ case 7: arm7_reg_write(cpu,Rd, result = Rm-Rn+ARM7_BFE(cpu->registers[CPSR],29,1)-1); break; - /*TST*/ case 8: result = Rn&Rm; break; - /*TEQ*/ case 9: result = Rn^Rm; break; - /*CMP*/ case 10: result = Rn-Rm; break; - /*CMN*/ case 11: result = Rn+Rm; break; - /*ORR*/ case 12: arm7_reg_write(cpu,Rd, result = Rn|Rm); break; - /*MOV*/ case 13: arm7_reg_write(cpu,Rd, result = Rm); break; - /*BIC*/ case 14: arm7_reg_write(cpu,Rd, result = Rn&~Rm); break; - /*MVN*/ case 15: arm7_reg_write(cpu,Rd, result = ~Rm); break; - } - //Update flags - if(S){ - //Rd is not valid for TST, TEQ, CMP, or CMN + } else + Rm = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 0, 4), r15_off); + ; + + uint64_t Rn = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 16, 4), r15_off); + + uint64_t result = 0; + // Perform main operation + switch(op) { + /*AND*/ case 0: + arm7_reg_write(cpu, Rd, result = Rn & Rm); + break; + /*EOR*/ case 1: + arm7_reg_write(cpu, Rd, result = Rn ^ Rm); + break; + /*SUB*/ case 2: + arm7_reg_write(cpu, Rd, result = Rn - Rm); + break; + /*RSB*/ case 3: + arm7_reg_write(cpu, Rd, result = Rm - Rn); + break; + /*ADD*/ case 4: + arm7_reg_write(cpu, Rd, result = Rn + Rm); + break; + /*ADC*/ case 5: + arm7_reg_write(cpu, Rd, result = Rn + Rm + ARM7_BFE(cpu->registers[CPSR], 29, 1)); + break; + /*SBC*/ case 6: + arm7_reg_write(cpu, Rd, result = Rn - Rm + ARM7_BFE(cpu->registers[CPSR], 29, 1) - 1); + break; + /*RSC*/ case 7: + arm7_reg_write(cpu, Rd, result = Rm - Rn + ARM7_BFE(cpu->registers[CPSR], 29, 1) - 1); + break; + /*TST*/ case 8: + result = Rn & Rm; + break; + /*TEQ*/ case 9: + result = Rn ^ Rm; + break; + /*CMP*/ case 10: + result = Rn - Rm; + break; + /*CMN*/ case 11: + result = Rn + Rm; + break; + /*ORR*/ case 12: + arm7_reg_write(cpu, Rd, result = Rn | Rm); + break; + /*MOV*/ case 13: + arm7_reg_write(cpu, Rd, result = Rm); + break; + /*BIC*/ case 14: + arm7_reg_write(cpu, Rd, result = Rn & ~Rm); + break; + /*MVN*/ case 15: + arm7_reg_write(cpu, Rd, result = ~Rm); + break; + } + // Update flags + if(S) { + // Rd is not valid for TST, TEQ, CMP, or CMN { - uint32_t cpsr=cpu->registers[CPSR]; - bool C = ARM7_BFE(cpsr,29,1); - bool N = ARM7_BFE(result,31,1); - bool Z = (result&0xffffffff)==0; - bool V = ARM7_BFE(cpsr,28,1); + uint32_t cpsr = cpu->registers[CPSR]; + bool C = ARM7_BFE(cpsr, 29, 1); + bool N = ARM7_BFE(result, 31, 1); + bool Z = (result & 0xffffffff) == 0; + bool V = ARM7_BFE(cpsr, 28, 1); - switch(op){ + switch(op) { // Logical Ops flags /*AND*/ case 0: - /*EOR*/ case 1: - /*TST*/ case 8: - /*TEQ*/ case 9: + /*EOR*/ case 1: + /*TST*/ case 8: + /*TEQ*/ case 9: /*ORR*/ case 12: /*MOV*/ case 13: /*BIC*/ case 14: - /*MVN*/ case 15: C = barrel_shifter_carry==-1? C: barrel_shifter_carry; break; + /*MVN*/ case 15: + C = barrel_shifter_carry == -1 ? C : barrel_shifter_carry; + break; - /*SUB*/ case 2: - /*SBC*/ case 6: - /*CMP*/ case 10: - C = !ARM7_BFE(result,32,1); + /*SUB*/ case 2: + /*SBC*/ case 6: + /*CMP*/ case 10: + C = !ARM7_BFE(result, 32, 1); // if (Rn has a different sign as Rm and result has a differnt sign to Rn) - V = (((Rn ^ Rm) & (Rn ^ result)) >> 31)&1; + V = (((Rn ^ Rm) & (Rn ^ result)) >> 31) & 1; break; - /*RSB*/ case 3: - /*RSC*/ case 7: - C = !ARM7_BFE(result,32,1); + /*RSB*/ case 3: + /*RSC*/ case 7: + C = !ARM7_BFE(result, 32, 1); // if (Rm has a different sign as Rn and result has a differnt sign to Rm) - V = (((Rm ^ Rn) & (Rm ^ result)) >> 31)&1; + V = (((Rm ^ Rn) & (Rm ^ result)) >> 31) & 1; break; /*ADD*/ case 4: /*ADC*/ case 5: - /*CMN*/ case 11: - C = ARM7_BFE(result,32,1); + /*CMN*/ case 11: + C = ARM7_BFE(result, 32, 1); // if (Rm has the same sign as Rn and result has a different sign to Rm) - V = (((Rm ^ ~Rn) & (Rm ^ result)) >> 31)&1; + V = (((Rm ^ ~Rn) & (Rm ^ result)) >> 31) & 1; break; } - cpsr&= 0x0fffffff; - cpsr|= (N?1:0)<<31; - cpsr|= (Z?1:0)<<30; - cpsr|= (C?1:0)<<29; - cpsr|= (V?1:0)<<28; + cpsr &= 0x0fffffff; + cpsr |= (N ? 1 : 0) << 31; + cpsr |= (Z ? 1 : 0) << 30; + cpsr |= (C ? 1 : 0) << 29; + cpsr |= (V ? 1 : 0) << 28; cpu->registers[CPSR] = cpsr; } - if(Rd==15){ - // When Rd is R15 and the S flag is set the result of the operation is placed in R15 + if(Rd == 15) { + // When Rd is R15 and the S flag is set the result of the operation is placed in R15 // and the SPSR corresponding to the current mode is moved to the CPSR. This allows // state changes which atomically restore both PC and CPSR. This form of instruction // should not be used in User mode. - cpu->registers[CPSR] = arm7_reg_read(cpu,SPSR); + cpu->registers[CPSR] = arm7_reg_read(cpu, SPSR); } } } -static FORCE_INLINE void arm7_multiply(arm7_t* cpu, uint32_t opcode){ - bool A = ARM7_BFE(opcode,21,1); - bool S = ARM7_BFE(opcode,20,1); - int64_t Rd = ARM7_BFE(opcode,16,4); - int64_t Rn = arm7_reg_read(cpu,ARM7_BFE(opcode,12,4)); - int64_t Rs = arm7_reg_read(cpu,ARM7_BFE(opcode,8,4)); - int64_t Rm = arm7_reg_read(cpu,ARM7_BFE(opcode,0,4)); - - if(SB_BFE(Rs,8,24)== 0 || SB_BFE(Rs,8,24)==0x00ffffff)cpu->i_cycles += 1; - else if(SB_BFE(Rs,16,16)== 0 || SB_BFE(Rs,16,16)==0x0000ffff)cpu->i_cycles += 2; - else if(SB_BFE(Rs,24,8) == 0 || SB_BFE(Rs,24,8)== 0x000000ff)cpu->i_cycles += 3; - else cpu->i_cycles += 4; - - int64_t result = Rm*Rs; - if(A){result+=Rn;cpu->i_cycles+=1;} +static FORCE_INLINE void arm7_multiply(arm7_t *cpu, uint32_t opcode) { + bool A = ARM7_BFE(opcode, 21, 1); + bool S = ARM7_BFE(opcode, 20, 1); + int64_t Rd = ARM7_BFE(opcode, 16, 4); + int64_t Rn = arm7_reg_read(cpu, ARM7_BFE(opcode, 12, 4)); + int64_t Rs = arm7_reg_read(cpu, ARM7_BFE(opcode, 8, 4)); + int64_t Rm = arm7_reg_read(cpu, ARM7_BFE(opcode, 0, 4)); + + if(SB_BFE(Rs, 8, 24) == 0 || SB_BFE(Rs, 8, 24) == 0x00ffffff) + cpu->i_cycles += 1; + else if(SB_BFE(Rs, 16, 16) == 0 || SB_BFE(Rs, 16, 16) == 0x0000ffff) + cpu->i_cycles += 2; + else if(SB_BFE(Rs, 24, 8) == 0 || SB_BFE(Rs, 24, 8) == 0x000000ff) + cpu->i_cycles += 3; + else + cpu->i_cycles += 4; + + int64_t result = Rm * Rs; + if(A) { + result += Rn; + cpu->i_cycles += 1; + } - arm7_reg_write(cpu,Rd,result); + arm7_reg_write(cpu, Rd, result); - if(S){ + if(S) { uint32_t cpsr = cpu->registers[CPSR]; - bool N = ARM7_BFE(result,31,1); - bool Z = (result&0xffffffff)==0; - bool C = ARM7_BFE(cpsr,29,1); - bool V = ARM7_BFE(cpsr,28,1); - cpsr&= 0x0ffffff; - cpsr|= (N?1u:0u)<<31; - cpsr|= (Z?1:0)<<30; - cpsr|= (C?1:0)<<29; - cpsr|= (V?1:0)<<28; + bool N = ARM7_BFE(result, 31, 1); + bool Z = (result & 0xffffffff) == 0; + bool C = ARM7_BFE(cpsr, 29, 1); + bool V = ARM7_BFE(cpsr, 28, 1); + cpsr &= 0x0ffffff; + cpsr |= (N ? 1u : 0u) << 31; + cpsr |= (Z ? 1 : 0) << 30; + cpsr |= (C ? 1 : 0) << 29; + cpsr |= (V ? 1 : 0) << 28; cpu->registers[CPSR] = cpsr; } } -//SMULLxxx -static FORCE_INLINE void arm9_signed_halfword_multiply(arm7_t* cpu, uint32_t opcode){ - int op = ARM7_BFE(opcode,21,2); - - int64_t Rd = ARM7_BFE(opcode,16,4); - int64_t Rn = (int32_t)arm7_reg_read(cpu,ARM7_BFE(opcode,12,4)); - int64_t Rs = (int32_t)arm7_reg_read(cpu,ARM7_BFE(opcode,8,4)); - int64_t Rm = (int32_t)arm7_reg_read(cpu,ARM7_BFE(opcode,0,4)); - bool y = ARM7_BFE(opcode,6,1); - bool x = ARM7_BFE(opcode,5,1); - - int64_t result = 0; - const int64_t int32_max = (1ll<<31ll)-1; - const int64_t int32_min = -(1ll<<31ll); - bool Q =false; - switch(op){ - case 0: //SMLAxy - Rs = (int16_t)(y? ARM7_BFE(Rs,16,16) : ARM7_BFE(Rs,0,16)); - Rm = (int16_t)(x? ARM7_BFE(Rm,16,16) : ARM7_BFE(Rm,0,16)); - result = Rs*Rm+Rn; - break; - case 1: //SMLAWy or SMULWy - Rs = (int16_t)(y? ARM7_BFE(Rs,16,16) : ARM7_BFE(Rs,0,16)); - result = (Rs*Rm)>>16; - // SMLAWy only - if(!x)result+=Rn; - break; - case 2: {//SMLALxy - Rs = (int16_t)(y? ARM7_BFE(Rs,16,16) : ARM7_BFE(Rs,0,16)); - Rm = (int16_t)(x? ARM7_BFE(Rm,16,16) : ARM7_BFE(Rm,0,16)); - int64_t RdHi = arm7_reg_read(cpu,Rd); - int64_t RdLo = Rn; - int64_t RdHiLo = ((RdHi<<32)|RdLo); - result = Rs*Rm+RdHiLo; - RdHi = result>>32; - RdLo = result&0xffffffff; - arm7_reg_write(cpu,Rd,RdHi); - arm7_reg_write(cpu,ARM7_BFE(opcode,12,4),RdLo); - cpu->i_cycles+=1; - } - return; - case 3: //SMULxy - Rs = (int16_t)(y? ARM7_BFE(Rs,16,16) : ARM7_BFE(Rs,0,16)); - Rm = (int16_t)(x? ARM7_BFE(Rm,16,16) : ARM7_BFE(Rm,0,16)); - result = Rs*Rm; - break; +// SMULLxxx +static FORCE_INLINE void arm9_signed_halfword_multiply(arm7_t *cpu, uint32_t opcode) { + int op = ARM7_BFE(opcode, 21, 2); + + int64_t Rd = ARM7_BFE(opcode, 16, 4); + int64_t Rn = (int32_t)arm7_reg_read(cpu, ARM7_BFE(opcode, 12, 4)); + int64_t Rs = (int32_t)arm7_reg_read(cpu, ARM7_BFE(opcode, 8, 4)); + int64_t Rm = (int32_t)arm7_reg_read(cpu, ARM7_BFE(opcode, 0, 4)); + bool y = ARM7_BFE(opcode, 6, 1); + bool x = ARM7_BFE(opcode, 5, 1); + + int64_t result = 0; + const int64_t int32_max = (1ll << 31ll) - 1; + const int64_t int32_min = -(1ll << 31ll); + bool Q = false; + switch(op) { + case 0: // SMLAxy + Rs = (int16_t)(y ? ARM7_BFE(Rs, 16, 16) : ARM7_BFE(Rs, 0, 16)); + Rm = (int16_t)(x ? ARM7_BFE(Rm, 16, 16) : ARM7_BFE(Rm, 0, 16)); + result = Rs * Rm + Rn; + break; + case 1: // SMLAWy or SMULWy + Rs = (int16_t)(y ? ARM7_BFE(Rs, 16, 16) : ARM7_BFE(Rs, 0, 16)); + result = (Rs * Rm) >> 16; + // SMLAWy only + if(!x) result += Rn; + break; + case 2: { // SMLALxy + Rs = (int16_t)(y ? ARM7_BFE(Rs, 16, 16) : ARM7_BFE(Rs, 0, 16)); + Rm = (int16_t)(x ? ARM7_BFE(Rm, 16, 16) : ARM7_BFE(Rm, 0, 16)); + int64_t RdHi = arm7_reg_read(cpu, Rd); + int64_t RdLo = Rn; + int64_t RdHiLo = ((RdHi << 32) | RdLo); + result = Rs * Rm + RdHiLo; + RdHi = result >> 32; + RdLo = result & 0xffffffff; + arm7_reg_write(cpu, Rd, RdHi); + arm7_reg_write(cpu, ARM7_BFE(opcode, 12, 4), RdLo); + cpu->i_cycles += 1; } - Q=result>int32_max||resultregisters[CPSR]|= Q<<27; - arm7_reg_write(cpu,Rd,result); -} -static FORCE_INLINE void arm7_multiply_long(arm7_t* cpu, uint32_t opcode){ - bool U = ARM7_BFE(opcode,22,1); - bool A = ARM7_BFE(opcode,21,1); - bool S = ARM7_BFE(opcode,20,1); - int64_t RdHi = ARM7_BFE(opcode,16,4); - int64_t RdLo = ARM7_BFE(opcode,12,4); - int64_t Rs = arm7_reg_read(cpu,ARM7_BFE(opcode,8,4)); - int64_t Rm = arm7_reg_read(cpu,ARM7_BFE(opcode,0,4)); - - int64_t RdHiLo = arm7_reg_read(cpu,RdHi); - RdHiLo = (RdHiLo<<32)| arm7_reg_read(cpu,RdLo); - - if(U){ + return; + case 3: // SMULxy + Rs = (int16_t)(y ? ARM7_BFE(Rs, 16, 16) : ARM7_BFE(Rs, 0, 16)); + Rm = (int16_t)(x ? ARM7_BFE(Rm, 16, 16) : ARM7_BFE(Rm, 0, 16)); + result = Rs * Rm; + break; + } + Q = result > int32_max || result < int32_min; + cpu->registers[CPSR] |= Q << 27; + arm7_reg_write(cpu, Rd, result); +} +static FORCE_INLINE void arm7_multiply_long(arm7_t *cpu, uint32_t opcode) { + bool U = ARM7_BFE(opcode, 22, 1); + bool A = ARM7_BFE(opcode, 21, 1); + bool S = ARM7_BFE(opcode, 20, 1); + int64_t RdHi = ARM7_BFE(opcode, 16, 4); + int64_t RdLo = ARM7_BFE(opcode, 12, 4); + int64_t Rs = arm7_reg_read(cpu, ARM7_BFE(opcode, 8, 4)); + int64_t Rm = arm7_reg_read(cpu, ARM7_BFE(opcode, 0, 4)); + + int64_t RdHiLo = arm7_reg_read(cpu, RdHi); + RdHiLo = (RdHiLo << 32) | arm7_reg_read(cpu, RdLo); + + if(U) { Rm = (int32_t)Rm; Rs = (int32_t)Rs; - if(SB_BFE(Rs,8,24)== 0 || SB_BFE(Rs,8,24)==0x00ffffff)cpu->i_cycles += 2; - else if(SB_BFE(Rs,16,16)== 0 || SB_BFE(Rs,16,16)==0x0000ffff)cpu->i_cycles += 3; - else if(SB_BFE(Rs,24,8) == 0 || SB_BFE(Rs,24,8)== 0x000000ff)cpu->i_cycles += 4; - else cpu->i_cycles += 5; - }else{ - if(SB_BFE(Rs,8,24)== 0 )cpu->i_cycles += 2; - else if(SB_BFE(Rs,16,16)== 0 )cpu->i_cycles += 3; - else if(SB_BFE(Rs,24,8) == 0 )cpu->i_cycles += 4; - else cpu->i_cycles += 5; - } - - - int64_t result = Rm*Rs; - if(A){result+=RdHiLo;cpu->i_cycles+=1;} + if(SB_BFE(Rs, 8, 24) == 0 || SB_BFE(Rs, 8, 24) == 0x00ffffff) + cpu->i_cycles += 2; + else if(SB_BFE(Rs, 16, 16) == 0 || SB_BFE(Rs, 16, 16) == 0x0000ffff) + cpu->i_cycles += 3; + else if(SB_BFE(Rs, 24, 8) == 0 || SB_BFE(Rs, 24, 8) == 0x000000ff) + cpu->i_cycles += 4; + else + cpu->i_cycles += 5; + } else { + if(SB_BFE(Rs, 8, 24) == 0) + cpu->i_cycles += 2; + else if(SB_BFE(Rs, 16, 16) == 0) + cpu->i_cycles += 3; + else if(SB_BFE(Rs, 24, 8) == 0) + cpu->i_cycles += 4; + else + cpu->i_cycles += 5; + } - + int64_t result = Rm * Rs; + if(A) { + result += RdHiLo; + cpu->i_cycles += 1; + } - arm7_reg_write(cpu,RdHi,result>>32); - arm7_reg_write(cpu,RdLo,result&0xffffffff); + arm7_reg_write(cpu, RdHi, result >> 32); + arm7_reg_write(cpu, RdLo, result & 0xffffffff); - if(S){ + if(S) { uint32_t cpsr = cpu->registers[CPSR]; - bool N = ARM7_BFE(result,63,1); - bool Z = result==0; - bool C = ARM7_BFE(cpsr,29,1); - bool V = ARM7_BFE(cpsr,28,1); - cpsr&= 0x0ffffff; - cpsr|= (N?1:0)<<31; - cpsr|= (Z?1:0)<<30; - cpsr|= (C?1:0)<<29; - cpsr|= (V?1:0)<<28; + bool N = ARM7_BFE(result, 63, 1); + bool Z = result == 0; + bool C = ARM7_BFE(cpsr, 29, 1); + bool V = ARM7_BFE(cpsr, 28, 1); + cpsr &= 0x0ffffff; + cpsr |= (N ? 1 : 0) << 31; + cpsr |= (Z ? 1 : 0) << 30; + cpsr |= (C ? 1 : 0) << 29; + cpsr |= (V ? 1 : 0) << 28; cpu->registers[CPSR] = cpsr; } - } -static FORCE_INLINE void arm7_single_data_swap(arm7_t* cpu, uint32_t opcode){ - bool B = ARM7_BFE(opcode, 22,1); - uint32_t addr = arm7_reg_read_r15_adj(cpu,ARM7_BFE(opcode,16,4),4); - uint32_t Rd = ARM7_BFE(opcode,12,4); - uint32_t Rm = ARM7_BFE(opcode,0,4); +static FORCE_INLINE void arm7_single_data_swap(arm7_t *cpu, uint32_t opcode) { + bool B = ARM7_BFE(opcode, 22, 1); + uint32_t addr = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 16, 4), 4); + uint32_t Rd = ARM7_BFE(opcode, 12, 4); + uint32_t Rm = ARM7_BFE(opcode, 0, 4); // Load - uint32_t read_data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - - uint32_t store_data = arm7_reg_read_r15_adj(cpu,Rm,8); - if(B==1)cpu->write8(cpu->user_data,addr,store_data); - else cpu->write32(cpu->user_data,addr,store_data); - - arm7_reg_write(cpu,Rd,read_data); - cpu->i_cycles+=1; -} -static FORCE_INLINE void arm7_branch_exchange(arm7_t* cpu, uint32_t opcode){ - int v = arm7_reg_read_r15_adj(cpu,ARM7_BFE(opcode,0,4),4); - bool thumb = (v&1)==1; - if(thumb)cpu->registers[PC] = (v&~1); - else cpu->registers[PC] = (v&~3); - cpu->prefetch_pc=-1; - arm7_set_thumb_bit(cpu,thumb); -} -static FORCE_INLINE void arm9_branch_link_exchange(arm7_t* cpu, uint32_t opcode){ - int v = arm7_reg_read_r15_adj(cpu,ARM7_BFE(opcode,0,4),4); + uint32_t read_data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + + uint32_t store_data = arm7_reg_read_r15_adj(cpu, Rm, 8); + if(B == 1) + cpu->write8(cpu->user_data, addr, store_data); + else + cpu->write32(cpu->user_data, addr, store_data); + + arm7_reg_write(cpu, Rd, read_data); + cpu->i_cycles += 1; +} +static FORCE_INLINE void arm7_branch_exchange(arm7_t *cpu, uint32_t opcode) { + int v = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 0, 4), 4); + bool thumb = (v & 1) == 1; + if(thumb) + cpu->registers[PC] = (v & ~1); + else + cpu->registers[PC] = (v & ~3); + cpu->prefetch_pc = -1; + arm7_set_thumb_bit(cpu, thumb); +} +static FORCE_INLINE void arm9_branch_link_exchange(arm7_t *cpu, uint32_t opcode) { + int v = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 0, 4), 4); bool prev_thumb = arm7_get_thumb_bit(cpu); - arm7_reg_write(cpu, LR, cpu->registers[PC]|prev_thumb); - bool thumb = (v&1)==1; - if(thumb)cpu->registers[PC] = (v&~1); - else cpu->registers[PC] = (v&~3); - cpu->prefetch_pc=-1; - arm7_set_thumb_bit(cpu,thumb); -} -static FORCE_INLINE void arm7_half_word_transfer(arm7_t* cpu, uint32_t opcode){ - bool P = ARM7_BFE(opcode,24,1); - bool U = ARM7_BFE(opcode,23,1); - bool I = ARM7_BFE(opcode,22,1); - bool W = ARM7_BFE(opcode,21,1); - bool L = ARM7_BFE(opcode,20,1); - int Rn = ARM7_BFE(opcode,16,4); - - bool S = ARM7_BFE(opcode,6,1); - bool H = ARM7_BFE(opcode,5,1); - - int offset = I == 0 ? - arm7_reg_read(cpu,ARM7_BFE(opcode,0,4)) : - ((opcode>>4)&0xf0)|(opcode&0xf); - uint64_t Rd = ARM7_BFE(opcode,12,4); - uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn,4); - - int increment = U? offset: -offset; + arm7_reg_write(cpu, LR, cpu->registers[PC] | prev_thumb); + bool thumb = (v & 1) == 1; + if(thumb) + cpu->registers[PC] = (v & ~1); + else + cpu->registers[PC] = (v & ~3); + cpu->prefetch_pc = -1; + arm7_set_thumb_bit(cpu, thumb); +} +static FORCE_INLINE void arm7_half_word_transfer(arm7_t *cpu, uint32_t opcode) { + bool P = ARM7_BFE(opcode, 24, 1); + bool U = ARM7_BFE(opcode, 23, 1); + bool I = ARM7_BFE(opcode, 22, 1); + bool W = ARM7_BFE(opcode, 21, 1); + bool L = ARM7_BFE(opcode, 20, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + + bool S = ARM7_BFE(opcode, 6, 1); + bool H = ARM7_BFE(opcode, 5, 1); + + int offset = I == 0 ? arm7_reg_read(cpu, ARM7_BFE(opcode, 0, 4)) : ((opcode >> 4) & 0xf0) | (opcode & 0xf); + uint64_t Rd = ARM7_BFE(opcode, 12, 4); + uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn, 4); + + int increment = U ? offset : -offset; if(P) addr += increment; // Store before writeback - if(L==0){ - uint32_t data = arm7_reg_read(cpu,Rd); - if(H==1)cpu->write16(cpu->user_data,addr,data); - else cpu->write8(cpu->user_data,addr,data); + if(L == 0) { + uint32_t data = arm7_reg_read(cpu, Rd); + if(H == 1) + cpu->write16(cpu->user_data, addr, data); + else + cpu->write8(cpu->user_data, addr, data); } uint32_t write_back_addr = addr; - if(!P) {write_back_addr+=increment;W=true;} - if(W)arm7_reg_write(cpu,Rn,write_back_addr); - if(L==1){ // Load - uint32_t data = H ? arm7_rotr(cpu->read16(cpu->user_data,addr),(addr&0x1)*8): cpu->read8(cpu->user_data,addr); - if(S){ - data&=0xffff; - // Unaligned signed half words and signed byte loads sign extend the byte - if(H&& !(addr&1)) { - data|= 0xffff0000*ARM7_BFE(data,15,1); - } - else data|= 0xffffff00*ARM7_BFE(data,7,1); + if(!P) { + write_back_addr += increment; + W = true; + } + if(W) arm7_reg_write(cpu, Rn, write_back_addr); + if(L == 1) { // Load + uint32_t data = H ? arm7_rotr(cpu->read16(cpu->user_data, addr), (addr & 0x1) * 8) : cpu->read8(cpu->user_data, addr); + if(S) { + data &= 0xffff; + // Unaligned signed half words and signed byte loads sign extend the byte + if(H && !(addr & 1)) { + data |= 0xffff0000 * ARM7_BFE(data, 15, 1); + } else + data |= 0xffffff00 * ARM7_BFE(data, 7, 1); } - arm7_reg_write(cpu,Rd,data); - cpu->i_cycles+=1; - } - -} -static FORCE_INLINE void arm7_single_word_transfer(arm7_t* cpu, uint32_t opcode){ - bool I = ARM7_BFE(opcode,25,1); - bool P = ARM7_BFE(opcode,24,1); - bool U = ARM7_BFE(opcode,23,1); - bool B = ARM7_BFE(opcode,22,1); - bool W = ARM7_BFE(opcode,21,1); - bool L = ARM7_BFE(opcode,20,1); - int Rn = ARM7_BFE(opcode,16,4); - int carry; - int offset = I == 0 ? ARM7_BFE(opcode,0,12): - arm7_load_shift_reg(cpu, opcode, &carry); - - uint64_t Rd = ARM7_BFE(opcode,12,4); - uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn,4); - int increment = U? offset: -offset; + arm7_reg_write(cpu, Rd, data); + cpu->i_cycles += 1; + } +} +static FORCE_INLINE void arm7_single_word_transfer(arm7_t *cpu, uint32_t opcode) { + bool I = ARM7_BFE(opcode, 25, 1); + bool P = ARM7_BFE(opcode, 24, 1); + bool U = ARM7_BFE(opcode, 23, 1); + bool B = ARM7_BFE(opcode, 22, 1); + bool W = ARM7_BFE(opcode, 21, 1); + bool L = ARM7_BFE(opcode, 20, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + int carry; + int offset = I == 0 ? ARM7_BFE(opcode, 0, 12) : arm7_load_shift_reg(cpu, opcode, &carry); + + uint64_t Rd = ARM7_BFE(opcode, 12, 4); + uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn, 4); + int increment = U ? offset : -offset; if(P) addr += increment; // Store before write back - if(L==0){ - uint32_t data = arm7_reg_read_r15_adj(cpu,Rd,8); - if(B==1)cpu->write8(cpu->user_data,addr,data); - else cpu->write32(cpu->user_data,addr,data); - } - - //Write back address before load - uint32_t write_back_addr = addr; - if(!P) {write_back_addr+=increment;W=true;} - if(W)arm7_reg_write(cpu,Rn,write_back_addr); - - if(L==1){ // Load - uint32_t data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - arm7_reg_write(cpu,Rd,data); - cpu->i_cycles+=1; - } -} -static FORCE_INLINE void arm9_single_word_transfer(arm7_t* cpu, uint32_t opcode){ - bool I = ARM7_BFE(opcode,25,1); - bool P = ARM7_BFE(opcode,24,1); - bool U = ARM7_BFE(opcode,23,1); - bool B = ARM7_BFE(opcode,22,1); - bool W = ARM7_BFE(opcode,21,1); - bool L = ARM7_BFE(opcode,20,1); - int Rn = ARM7_BFE(opcode,16,4); - int carry; - int offset = I == 0 ? ARM7_BFE(opcode,0,12): - arm7_load_shift_reg(cpu, opcode, &carry); - - uint64_t Rd = ARM7_BFE(opcode,12,4); - uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn,4); - int increment = U? offset: -offset; + if(L == 0) { + uint32_t data = arm7_reg_read_r15_adj(cpu, Rd, 8); + if(B == 1) + cpu->write8(cpu->user_data, addr, data); + else + cpu->write32(cpu->user_data, addr, data); + } + + // Write back address before load + uint32_t write_back_addr = addr; + if(!P) { + write_back_addr += increment; + W = true; + } + if(W) arm7_reg_write(cpu, Rn, write_back_addr); + + if(L == 1) { // Load + uint32_t data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + arm7_reg_write(cpu, Rd, data); + cpu->i_cycles += 1; + } +} +static FORCE_INLINE void arm9_single_word_transfer(arm7_t *cpu, uint32_t opcode) { + bool I = ARM7_BFE(opcode, 25, 1); + bool P = ARM7_BFE(opcode, 24, 1); + bool U = ARM7_BFE(opcode, 23, 1); + bool B = ARM7_BFE(opcode, 22, 1); + bool W = ARM7_BFE(opcode, 21, 1); + bool L = ARM7_BFE(opcode, 20, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + int carry; + int offset = I == 0 ? ARM7_BFE(opcode, 0, 12) : arm7_load_shift_reg(cpu, opcode, &carry); + + uint64_t Rd = ARM7_BFE(opcode, 12, 4); + uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn, 4); + int increment = U ? offset : -offset; if(P) addr += increment; // Store before write back - if(L==0){ - uint32_t data = arm7_reg_read_r15_adj(cpu,Rd,8); - if(B==1)cpu->write8(cpu->user_data,addr,data); - else cpu->write32(cpu->user_data,addr,data); + if(L == 0) { + uint32_t data = arm7_reg_read_r15_adj(cpu, Rd, 8); + if(B == 1) + cpu->write8(cpu->user_data, addr, data); + else + cpu->write32(cpu->user_data, addr, data); } - //Write back address before load - uint32_t write_back_addr = addr; - if(!P) {write_back_addr+=increment;W=true;} - if(W)arm7_reg_write(cpu,Rn,write_back_addr); + // Write back address before load + uint32_t write_back_addr = addr; + if(!P) { + write_back_addr += increment; + W = true; + } + if(W) arm7_reg_write(cpu, Rn, write_back_addr); - if(L==1){ // Load - uint32_t data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - arm9_reg_write_r15_thumb(cpu,Rd,data); - cpu->i_cycles+=1; + if(L == 1) { // Load + uint32_t data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + arm9_reg_write_r15_thumb(cpu, Rd, data); + cpu->i_cycles += 1; } } -static FORCE_INLINE void arm9_double_word_transfer(arm7_t* cpu, uint32_t opcode){ +static FORCE_INLINE void arm9_double_word_transfer(arm7_t *cpu, uint32_t opcode) { // cccc 000P UIW0 nnnn dddd oooo 11S1 oooo - bool P = ARM7_BFE(opcode,24,1); - bool U = ARM7_BFE(opcode,23,1); - bool I = ARM7_BFE(opcode,22,1); - bool W = ARM7_BFE(opcode,21,1); - bool S = ARM7_BFE(opcode,5,1); - int Rn = ARM7_BFE(opcode,16,4); - int carry; - int offset = I == 0 ? - arm7_reg_read(cpu,ARM7_BFE(opcode,0,4)) : - ((opcode>>4)&0xf0)|(opcode&0xf); - - uint64_t Rd = ARM7_BFE(opcode,12,4); - uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn,4); - int increment = U? offset: -offset; + bool P = ARM7_BFE(opcode, 24, 1); + bool U = ARM7_BFE(opcode, 23, 1); + bool I = ARM7_BFE(opcode, 22, 1); + bool W = ARM7_BFE(opcode, 21, 1); + bool S = ARM7_BFE(opcode, 5, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + int carry; + int offset = I == 0 ? arm7_reg_read(cpu, ARM7_BFE(opcode, 0, 4)) : ((opcode >> 4) & 0xf0) | (opcode & 0xf); + + uint64_t Rd = ARM7_BFE(opcode, 12, 4); + uint32_t addr = arm7_reg_read_r15_adj(cpu, Rn, 4); + int increment = U ? offset : -offset; if(P) addr += increment; // Store before write back - if(S){ - uint32_t data0 = arm7_reg_read_r15_adj(cpu,Rd,8); - uint32_t data1 = arm7_reg_read_r15_adj(cpu,Rd+1,8); - cpu->write32(cpu->user_data,addr,data0); - cpu->write32(cpu->user_data,addr+4,data1); + if(S) { + uint32_t data0 = arm7_reg_read_r15_adj(cpu, Rd, 8); + uint32_t data1 = arm7_reg_read_r15_adj(cpu, Rd + 1, 8); + cpu->write32(cpu->user_data, addr, data0); + cpu->write32(cpu->user_data, addr + 4, data1); } - //Write back address before load - uint32_t write_back_addr = addr; - if(!P) {write_back_addr+=increment;W=true;} - if(W)arm7_reg_write(cpu,Rn,write_back_addr); - - if(S==0){ // Load - uint32_t data0 = cpu->read32(cpu->user_data,addr); - uint32_t data1 = cpu->read32(cpu->user_data,addr+4); - arm9_reg_write_r15_thumb(cpu,Rd,data0); - arm9_reg_write_r15_thumb(cpu,Rd+1,data1); - cpu->i_cycles+=1; + // Write back address before load + uint32_t write_back_addr = addr; + if(!P) { + write_back_addr += increment; + W = true; + } + if(W) arm7_reg_write(cpu, Rn, write_back_addr); + + if(S == 0) { // Load + uint32_t data0 = cpu->read32(cpu->user_data, addr); + uint32_t data1 = cpu->read32(cpu->user_data, addr + 4); + arm9_reg_write_r15_thumb(cpu, Rd, data0); + arm9_reg_write_r15_thumb(cpu, Rd + 1, data1); + cpu->i_cycles += 1; } } -static FORCE_INLINE void arm7_undefined(arm7_t* cpu, uint32_t opcode){ +static FORCE_INLINE void arm7_undefined(arm7_t *cpu, uint32_t opcode) { bool thumb = arm7_get_thumb_bit(cpu); - cpu->registers[R14_und] = cpu->registers[PC]-(thumb?0:4); - cpu->registers[PC] = cpu->irq_table_address+0x4; + cpu->registers[R14_und] = cpu->registers[PC] - (thumb ? 0 : 4); + cpu->registers[PC] = cpu->irq_table_address + 0x4; uint32_t cpsr = cpu->registers[CPSR]; cpu->registers[SPSR_und] = cpsr; - //Update mode to supervisor and block irqs - cpu->registers[CPSR] = (cpsr&0xffffffE0)| 0x1b|0x80; - arm7_set_thumb_bit(cpu,false); - printf("Unhandled Instruction Class (arm7_undefined) Opcode: %x PC:%08x\n",opcode, cpu->registers[R14_und]); - cpu->i_cycles+=1; - //cpu->trigger_breakpoint = true; -} -static FORCE_INLINE void arm9_clz(arm7_t* cpu, uint32_t opcode){ - int Rd = ARM7_BFE(opcode,12,4); - int Rs = ARM7_BFE(opcode,0,4); - uint32_t reg = arm7_reg_read_r15_adj(cpu,Rs,4); + // Update mode to supervisor and block irqs + cpu->registers[CPSR] = (cpsr & 0xffffffE0) | 0x1b | 0x80; + arm7_set_thumb_bit(cpu, false); + printf("Unhandled Instruction Class (arm7_undefined) Opcode: %x PC:%08x\n", opcode, cpu->registers[R14_und]); + cpu->i_cycles += 1; + // cpu->trigger_breakpoint = true; +} +static FORCE_INLINE void arm9_clz(arm7_t *cpu, uint32_t opcode) { + int Rd = ARM7_BFE(opcode, 12, 4); + int Rs = ARM7_BFE(opcode, 0, 4); + uint32_t reg = arm7_reg_read_r15_adj(cpu, Rs, 4); uint32_t r2 = reg; - int count = 32; - while (reg) {count--;reg>>=1;} - arm7_reg_write(cpu,Rd,count); -} -static FORCE_INLINE void arm9_qadd_qsub(arm7_t* cpu, uint32_t opcode){ - bool double_value = ARM7_BFE(opcode,22,1); - bool subtract = ARM7_BFE(opcode,21,1); - int Rn = ARM7_BFE(opcode,16,4); - int Rd = ARM7_BFE(opcode,12,4); - int Rm = ARM7_BFE(opcode,0,4); - - int64_t regA = (int32_t)arm7_reg_read_r15_adj(cpu,Rm,4); - int64_t regB = (int32_t)arm7_reg_read_r15_adj(cpu,Rn,4); - const int64_t int32_max = (1ll<<31ll)-1; - const int64_t int32_min = -(1ll<<31ll); - bool Q =false; - if(double_value){ - regB*=2; - if(regB>int32_max){regB=int32_max; Q=true;} - if(regBint32_max){result=int32_max; Q=true;} - if(resultregisters[CPSR]|= Q<<27; - arm7_reg_write(cpu,Rd,result); -} -static FORCE_INLINE void arm7_block_transfer(arm7_t* cpu, uint32_t opcode){ - int P = ARM7_BFE(opcode,24,1); - int U = ARM7_BFE(opcode,23,1); - int S = ARM7_BFE(opcode,22,1); - int w = ARM7_BFE(opcode,21,1); - int L = ARM7_BFE(opcode,20,1); - int Rn =ARM7_BFE(opcode,16,4); - int reglist = ARM7_BFE(opcode,0,16); + int count = 32; + while(reg) { + count--; + reg >>= 1; + } + arm7_reg_write(cpu, Rd, count); +} +static FORCE_INLINE void arm9_qadd_qsub(arm7_t *cpu, uint32_t opcode) { + bool double_value = ARM7_BFE(opcode, 22, 1); + bool subtract = ARM7_BFE(opcode, 21, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + int Rd = ARM7_BFE(opcode, 12, 4); + int Rm = ARM7_BFE(opcode, 0, 4); + + int64_t regA = (int32_t)arm7_reg_read_r15_adj(cpu, Rm, 4); + int64_t regB = (int32_t)arm7_reg_read_r15_adj(cpu, Rn, 4); + const int64_t int32_max = (1ll << 31ll) - 1; + const int64_t int32_min = -(1ll << 31ll); + bool Q = false; + if(double_value) { + regB *= 2; + if(regB > int32_max) { + regB = int32_max; + Q = true; + } + if(regB < int32_min) { + regB = int32_min; + Q = true; + } + } + int64_t result = subtract ? regA - regB : regA + regB; + if(result > int32_max) { + result = int32_max; + Q = true; + } + if(result < int32_min) { + result = int32_min; + Q = true; + } + cpu->registers[CPSR] |= Q << 27; + arm7_reg_write(cpu, Rd, result); +} +static FORCE_INLINE void arm7_block_transfer(arm7_t *cpu, uint32_t opcode) { + int P = ARM7_BFE(opcode, 24, 1); + int U = ARM7_BFE(opcode, 23, 1); + int S = ARM7_BFE(opcode, 22, 1); + int w = ARM7_BFE(opcode, 21, 1); + int L = ARM7_BFE(opcode, 20, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + int reglist = ARM7_BFE(opcode, 0, 16); // Examples pushing R1, R5, R7 // P= 0(post) U = 0(dec) @@ -1527,86 +1625,86 @@ static FORCE_INLINE void arm7_block_transfer(arm7_t* cpu, uint32_t opcode){ // mem[Rn+12] = R7 // Rn+=12 - if(cpu->phase==0){ + if(cpu->phase == 0) { - int addr = arm7_reg_read_r15_adj(cpu,Rn,4); - int increment = U? 4: -4; - int num_regs = 0; - for(int i=0;i<16;++i) if(ARM7_BFE(reglist,i,1)==1)num_regs+=1; + int addr = arm7_reg_read_r15_adj(cpu, Rn, 4); + int increment = U ? 4 : -4; + int num_regs = 0; + for(int i = 0; i < 16; ++i) + if(ARM7_BFE(reglist, i, 1) == 1) num_regs += 1; int base_addr = addr; - if(reglist==0){ + if(reglist == 0) { // Handle Empty Rlist case: R15 loaded/stored (ARMv4 only), and Rb=Rb+/-40h (ARMv4-v5). - reglist = 1<<15; + reglist = 1 << 15; num_regs = 16; } - if(!U)base_addr+=(num_regs)*increment; - addr = base_addr; - if(U)base_addr+= (num_regs)*increment; - cpu->block.base_addr=base_addr; - - if(!(P^U))addr+=4; - cpu->block.cycle=0; + if(!U) base_addr += (num_regs)*increment; + addr = base_addr; + if(U) base_addr += (num_regs)*increment; + cpu->block.base_addr = base_addr; + + if(!(P ^ U)) addr += 4; + cpu->block.cycle = 0; cpu->block.addr = addr; - // TODO: For some reason r15 is only offset by 4 in thumb mode. - // Check if other people do this to. - cpu->block.r15_off = arm7_get_thumb_bit(cpu)? 4:8; + // TODO: For some reason r15 is only offset by 4 in thumb mode. + // Check if other people do this to. + cpu->block.r15_off = arm7_get_thumb_bit(cpu) ? 4 : 8; // Address are word aligned - //addr&=~3; + // addr&=~3; cpu->block.last_bank = -1; - } - bool user_bank_transfer = S && (!L || !SB_BFE(reglist,15,1)); + bool user_bank_transfer = S && (!L || !SB_BFE(reglist, 15, 1)); - for(int i=cpu->phase;i<16;++i){ - //Writeback happens on second cycle - //Todo, does post increment force writeback? + for(int i = cpu->phase; i < 16; ++i) { + // Writeback happens on second cycle + // Todo, does post increment force writeback? - if(ARM7_BFE(reglist,i,1)==0)continue; + if(ARM7_BFE(reglist, i, 1) == 0) continue; // When S is set the registers are read from the user bank - int reg_index = user_bank_transfer ? i : arm7_reg_index(cpu,i); - //Store happens before writeback + int reg_index = user_bank_transfer ? i : arm7_reg_index(cpu, i); + // Store happens before writeback int a = cpu->block.addr; - //Inexplicablly SRAM accesses are not DWORD aligned. GBA suite memory test can be used to verify this. - if((a&0xfe000000)!=0x0e000000)a&=~3; - if(!L) cpu->write32(cpu->user_data, a,cpu->registers[reg_index] + (i==15?cpu->block.r15_off:0)); + // Inexplicablly SRAM accesses are not DWORD aligned. GBA suite memory test can be used to verify this. + if((a & 0xfe000000) != 0x0e000000) a &= ~3; + if(!L) cpu->write32(cpu->user_data, a, cpu->registers[reg_index] + (i == 15 ? cpu->block.r15_off : 0)); - //Writeback happens on second cycle - if(++cpu->block.cycle==1 && w){ - arm7_reg_write(cpu,Rn,cpu->block.base_addr); + // Writeback happens on second cycle + if(++cpu->block.cycle == 1 && w) { + arm7_reg_write(cpu, Rn, cpu->block.base_addr); } // R15 is stored at PC+12 - if(L){ - int bank = ARM7_BFE(a,24,8); - cpu->registers[reg_index]=cpu->read32_seq(cpu->user_data, a,bank==cpu->block.last_bank); - cpu->block.last_bank=bank; - } - - cpu->block.addr+=4; - + if(L) { + int bank = ARM7_BFE(a, 24, 8); + cpu->registers[reg_index] = cpu->read32_seq(cpu->user_data, a, bank == cpu->block.last_bank); + cpu->block.last_bank = bank; + } + + cpu->block.addr += 4; + // If the instruction is a LDM then SPSR_ is transferred to CPSR at // the same time as R15 is loaded. - if(L&& S&& i==15){ - cpu->registers[CPSR] = arm7_reg_read(cpu,SPSR); + if(L && S && i == 15) { + cpu->registers[CPSR] = arm7_reg_read(cpu, SPSR); } - cpu->phased_op_id=ARM_PHASED_BLOCK_TRANSFER; - cpu->phased_opcode=opcode; - cpu->phase = i+1; + cpu->phased_op_id = ARM_PHASED_BLOCK_TRANSFER; + cpu->phased_opcode = opcode; + cpu->phase = i + 1; return; } - if(L)cpu->i_cycles+=1; - cpu->phase=0; - cpu->phased_op_id=0; + if(L) cpu->i_cycles += 1; + cpu->phase = 0; + cpu->phased_op_id = 0; } -static FORCE_INLINE void arm9_block_transfer(arm7_t* cpu, uint32_t opcode){ - int P = ARM7_BFE(opcode,24,1); - int U = ARM7_BFE(opcode,23,1); - int S = ARM7_BFE(opcode,22,1); - int w = ARM7_BFE(opcode,21,1); - int L = ARM7_BFE(opcode,20,1); - int Rn =ARM7_BFE(opcode,16,4); - int reglist = ARM7_BFE(opcode,0,16); +static FORCE_INLINE void arm9_block_transfer(arm7_t *cpu, uint32_t opcode) { + int P = ARM7_BFE(opcode, 24, 1); + int U = ARM7_BFE(opcode, 23, 1); + int S = ARM7_BFE(opcode, 22, 1); + int w = ARM7_BFE(opcode, 21, 1); + int L = ARM7_BFE(opcode, 20, 1); + int Rn = ARM7_BFE(opcode, 16, 4); + int reglist = ARM7_BFE(opcode, 0, 16); // Examples pushing R1, R5, R7 // P= 0(post) U = 0(dec) @@ -1632,652 +1730,670 @@ static FORCE_INLINE void arm9_block_transfer(arm7_t* cpu, uint32_t opcode){ // mem[Rn+8] = R5 // mem[Rn+12] = R7 // Rn+=12 - if(cpu->phase==0){ - int addr = arm7_reg_read_r15_adj(cpu,Rn,4); - int increment = U? 4: -4; - int num_regs = 0; - for(int i=0;i<16;++i) if(ARM7_BFE(reglist,i,1)==1)num_regs+=1; + if(cpu->phase == 0) { + int addr = arm7_reg_read_r15_adj(cpu, Rn, 4); + int increment = U ? 4 : -4; + int num_regs = 0; + for(int i = 0; i < 16; ++i) + if(ARM7_BFE(reglist, i, 1) == 1) num_regs += 1; int base_addr = addr; - if(reglist==0){ + if(reglist == 0) { // Handle Empty Rlist case: R15 loaded/stored (ARMv4 only), and Rb=Rb+/-40h (ARMv4-v5). num_regs = 16; } - if(!U)base_addr+=(num_regs)*increment; - addr = base_addr; - if(U)base_addr+= (num_regs)*increment; - - if(!(P^U))addr+=4; - - cpu->block.base_addr=base_addr; - cpu->block.cycle=0; + if(!U) base_addr += (num_regs)*increment; + addr = base_addr; + if(U) base_addr += (num_regs)*increment; + + if(!(P ^ U)) addr += 4; + + cpu->block.base_addr = base_addr; + cpu->block.cycle = 0; cpu->block.addr = addr; - // TODO: For some reason r15 is only offset by 4 in thumb mode. - // Check if other people do this to. - cpu->block.r15_off = arm7_get_thumb_bit(cpu)? 4:8; + // TODO: For some reason r15 is only offset by 4 in thumb mode. + // Check if other people do this to. + cpu->block.r15_off = arm7_get_thumb_bit(cpu) ? 4 : 8; cpu->block.last_bank = -1; - cpu->block.num_regs=num_regs; + cpu->block.num_regs = num_regs; } - bool user_bank_transfer = S && (!L || !SB_BFE(reglist,15,1)); - for(int i=cpu->phase;i<16;++i){ - //Writeback happens on second cycle - //Todo, does post increment force writeback? + bool user_bank_transfer = S && (!L || !SB_BFE(reglist, 15, 1)); + for(int i = cpu->phase; i < 16; ++i) { + // Writeback happens on second cycle + // Todo, does post increment force writeback? - if(ARM7_BFE(reglist,i,1)==0)continue; + if(ARM7_BFE(reglist, i, 1) == 0) continue; // When S is set the registers are read from the user bank - int reg_index = user_bank_transfer ? i : arm7_reg_index(cpu,i); - //Store happens before writeback + int reg_index = user_bank_transfer ? i : arm7_reg_index(cpu, i); + // Store happens before writeback int a = cpu->block.addr; - if(!L) cpu->write32(cpu->user_data, a,cpu->registers[reg_index] + (i==15?cpu->block.r15_off:0)); + if(!L) cpu->write32(cpu->user_data, a, cpu->registers[reg_index] + (i == 15 ? cpu->block.r15_off : 0)); // R15 is stored at PC+12 - if(L){ - int bank = ARM7_BFE(a,24,8); - cpu->registers[reg_index]=cpu->read32_seq(cpu->user_data, a,bank==cpu->block.last_bank); - cpu->block.last_bank=bank; - if(PC==reg_index)arm7_set_thumb_bit(cpu,cpu->registers[PC]&1); - } - //Writeback happens on second cycle - if(++cpu->block.cycle==1&& w){ - arm7_reg_write(cpu,Rn,cpu->block.base_addr); + if(L) { + int bank = ARM7_BFE(a, 24, 8); + cpu->registers[reg_index] = cpu->read32_seq(cpu->user_data, a, bank == cpu->block.last_bank); + cpu->block.last_bank = bank; + if(PC == reg_index) arm7_set_thumb_bit(cpu, cpu->registers[PC] & 1); + } + // Writeback happens on second cycle + if(++cpu->block.cycle == 1 && w) { + arm7_reg_write(cpu, Rn, cpu->block.base_addr); } - cpu->block.addr+=4; - + cpu->block.addr += 4; + // If the instruction is a LDM then SPSR_ is transferred to CPSR at // the same time as R15 is loaded. - if(L&& S&& i==15){ - cpu->registers[CPSR] = arm7_reg_read(cpu,SPSR); + if(L && S && i == 15) { + cpu->registers[CPSR] = arm7_reg_read(cpu, SPSR); } - cpu->phased_op_id=ARM_PHASED_BLOCK_TRANSFER; - cpu->phased_opcode=opcode; - cpu->phase = i+1; + cpu->phased_op_id = ARM_PHASED_BLOCK_TRANSFER; + cpu->phased_opcode = opcode; + cpu->phase = i + 1; return; } - //Writeback happens on second cycle - if((reglist>= (1<<(Rn+1))||cpu->block.num_regs<=1||reglist==0)&& w){ - arm7_reg_write(cpu,Rn,cpu->block.base_addr); - } - if(L)cpu->i_cycles+=1; - cpu->phase=0; - cpu->phased_op_id=0; -} -static FORCE_INLINE void arm7_branch(arm7_t* cpu, uint32_t opcode){ - //Write Link Register if L=1 - if(ARM7_BFE(opcode,24,1)) arm7_reg_write(cpu, LR, cpu->registers[PC]); - //Decode V and sign extend - int v = ARM7_BFE(opcode,0,24); - if(ARM7_BFE(v,23,1))v|=0xff000000; - //Shift left and take into account prefetch - int32_t pc_off = (v<<2)+4; - cpu->registers[PC]+=pc_off; - cpu->prefetch_pc=-1; -} -static FORCE_INLINE void arm9_branch(arm7_t* cpu, uint32_t opcode){ - int cond = ARM7_BFE(opcode,28,4); - //Decode V and sign extend - int v = ARM7_BFE(opcode,0,24); - if(ARM7_BFE(v,23,1))v|=0xff000000; - //Shift left and take into account prefetch - int32_t pc_off = (v<<2)+4; - //printf("BLX? cond: %x\n",cond); - if(cond==0xf){ - bool H = ARM7_BFE(opcode,24,1); - pc_off+=H*2; + // Writeback happens on second cycle + if((reglist >= (1 << (Rn + 1)) || cpu->block.num_regs <= 1 || reglist == 0) && w) { + arm7_reg_write(cpu, Rn, cpu->block.base_addr); + } + if(L) cpu->i_cycles += 1; + cpu->phase = 0; + cpu->phased_op_id = 0; +} +static FORCE_INLINE void arm7_branch(arm7_t *cpu, uint32_t opcode) { + // Write Link Register if L=1 + if(ARM7_BFE(opcode, 24, 1)) arm7_reg_write(cpu, LR, cpu->registers[PC]); + // Decode V and sign extend + int v = ARM7_BFE(opcode, 0, 24); + if(ARM7_BFE(v, 23, 1)) v |= 0xff000000; + // Shift left and take into account prefetch + int32_t pc_off = (v << 2) + 4; + cpu->registers[PC] += pc_off; + cpu->prefetch_pc = -1; +} +static FORCE_INLINE void arm9_branch(arm7_t *cpu, uint32_t opcode) { + int cond = ARM7_BFE(opcode, 28, 4); + // Decode V and sign extend + int v = ARM7_BFE(opcode, 0, 24); + if(ARM7_BFE(v, 23, 1)) v |= 0xff000000; + // Shift left and take into account prefetch + int32_t pc_off = (v << 2) + 4; + // printf("BLX? cond: %x\n",cond); + if(cond == 0xf) { + bool H = ARM7_BFE(opcode, 24, 1); + pc_off += H * 2; arm7_reg_write(cpu, LR, cpu->registers[PC]); - arm7_set_thumb_bit(cpu,true); - }else{ - //Write Link Register if L=1 - if(ARM7_BFE(opcode,24,1)) arm7_reg_write(cpu, LR, cpu->registers[PC]); + arm7_set_thumb_bit(cpu, true); + } else { + // Write Link Register if L=1 + if(ARM7_BFE(opcode, 24, 1)) arm7_reg_write(cpu, LR, cpu->registers[PC]); } - cpu->registers[PC]+=pc_off; - cpu->prefetch_pc=-1; + cpu->registers[PC] += pc_off; + cpu->prefetch_pc = -1; } -static FORCE_INLINE void arm7_coproc_data_transfer(arm7_t* cpu, uint32_t opcode){ - printf("Unhandled Instruction Class (arm7_coproc_data_transfer) Opcode: %x\n",opcode); +static FORCE_INLINE void arm7_coproc_data_transfer(arm7_t *cpu, uint32_t opcode) { + printf("Unhandled Instruction Class (arm7_coproc_data_transfer) Opcode: %x\n", opcode); cpu->trigger_breakpoint = true; } -static FORCE_INLINE void arm7_coproc_data_op(arm7_t* cpu, uint32_t opcode){ - printf("Unhandled Instruction Class (arm7_coproc_data_op) Opcode: %x\n",opcode); +static FORCE_INLINE void arm7_coproc_data_op(arm7_t *cpu, uint32_t opcode) { + printf("Unhandled Instruction Class (arm7_coproc_data_op) Opcode: %x\n", opcode); cpu->trigger_breakpoint = true; } -static FORCE_INLINE void arm7_coproc_reg_transfer(arm7_t* cpu, uint32_t opcode){ - int coprocessor_opcode = SB_BFE(opcode,21,3); - bool coprocessor_read = SB_BFE(opcode,20,1); - int Cn = SB_BFE(opcode,16,4); - int Rd = SB_BFE(opcode,12,4); - int Pn = SB_BFE(opcode,8,4); - int Cp = SB_BFE(opcode,5,3); - int Cm = SB_BFE(opcode,0,4); - if(coprocessor_read){ - if(!cpu->coprocessor_read){ - printf("Coprocessor Read Issued without bound coprocessor_read handler: %x\n",opcode); +static FORCE_INLINE void arm7_coproc_reg_transfer(arm7_t *cpu, uint32_t opcode) { + int coprocessor_opcode = SB_BFE(opcode, 21, 3); + bool coprocessor_read = SB_BFE(opcode, 20, 1); + int Cn = SB_BFE(opcode, 16, 4); + int Rd = SB_BFE(opcode, 12, 4); + int Pn = SB_BFE(opcode, 8, 4); + int Cp = SB_BFE(opcode, 5, 3); + int Cm = SB_BFE(opcode, 0, 4); + if(coprocessor_read) { + if(!cpu->coprocessor_read) { + printf("Coprocessor Read Issued without bound coprocessor_read handler: %x\n", opcode); return; - } - uint32_t data = cpu->coprocessor_read(cpu->user_data,Pn,coprocessor_opcode,Cn,Cm,Cp); - arm7_reg_write(cpu,Rd,data); - }else{ - if(!cpu->coprocessor_write){ - printf("Coprocessor Write Issued without bound coprocessor_write handler: %x\n",opcode); + } + uint32_t data = cpu->coprocessor_read(cpu->user_data, Pn, coprocessor_opcode, Cn, Cm, Cp); + arm7_reg_write(cpu, Rd, data); + } else { + if(!cpu->coprocessor_write) { + printf("Coprocessor Write Issued without bound coprocessor_write handler: %x\n", opcode); return; - } - uint32_t data = arm7_reg_read_r15_adj(cpu,Rd,8); - cpu->coprocessor_write(cpu->user_data,Pn,coprocessor_opcode,Cn,Cm,Cp,data); + } + uint32_t data = arm7_reg_read_r15_adj(cpu, Rd, 8); + cpu->coprocessor_write(cpu->user_data, Pn, coprocessor_opcode, Cn, Cm, Cp, data); } } -static FORCE_INLINE void arm7_software_interrupt(arm7_t* cpu, uint32_t opcode){ +static FORCE_INLINE void arm7_software_interrupt(arm7_t *cpu, uint32_t opcode) { bool thumb = arm7_get_thumb_bit(cpu); cpu->registers[R14_svc] = cpu->registers[PC]; - cpu->registers[PC] = cpu->irq_table_address+0x8; + cpu->registers[PC] = cpu->irq_table_address + 0x8; uint32_t cpsr = cpu->registers[CPSR]; cpu->registers[SPSR_svc] = cpsr; - //Update mode to supervisor and block irqs - cpu->registers[CPSR] = (cpsr&0xffffffE0)| 0x13|0x80; - uint32_t swi_number = SB_BFE(opcode,0,24); - if(arm7_get_thumb_bit(cpu))swi_number = SB_BFE(opcode,0,8); + // Update mode to supervisor and block irqs + cpu->registers[CPSR] = (cpsr & 0xffffffE0) | 0x13 | 0x80; + uint32_t swi_number = SB_BFE(opcode, 0, 24); + if(arm7_get_thumb_bit(cpu)) swi_number = SB_BFE(opcode, 0, 8); int id = -1; - for(int i=0;idebug_swi_ring_offset;++i){ - if(cpu->debug_swi_ring[i]==swi_number){id=i;break;} + for(int i = 0; i < ARM_DEBUG_SWI_RING_SIZE && i < cpu->debug_swi_ring_offset; ++i) { + if(cpu->debug_swi_ring[i] == swi_number) { + id = i; + break; + } } - if(id==-1){ - id = (cpu->debug_swi_ring_offset++)%ARM_DEBUG_SWI_RING_SIZE; - cpu->debug_swi_ring_times[id]=0; + if(id == -1) { + id = (cpu->debug_swi_ring_offset++) % ARM_DEBUG_SWI_RING_SIZE; + cpu->debug_swi_ring_times[id] = 0; } - cpu->debug_swi_ring[id]= swi_number; - cpu->debug_swi_ring_times[id]++; - arm7_set_thumb_bit(cpu,false); + cpu->debug_swi_ring[id] = swi_number; + cpu->debug_swi_ring_times[id]++; + arm7_set_thumb_bit(cpu, false); } -static FORCE_INLINE void arm7_mrs(arm7_t* cpu, uint32_t opcode){ - int P = ARM7_BFE(opcode,22,1); - int Rd= ARM7_BFE(opcode,12,4); - int data = arm7_reg_read(cpu,P ? SPSR: CPSR); - arm7_reg_write(cpu,Rd,data); +static FORCE_INLINE void arm7_mrs(arm7_t *cpu, uint32_t opcode) { + int P = ARM7_BFE(opcode, 22, 1); + int Rd = ARM7_BFE(opcode, 12, 4); + int data = arm7_reg_read(cpu, P ? SPSR : CPSR); + arm7_reg_write(cpu, Rd, data); } -static FORCE_INLINE void arm7_msr(arm7_t* cpu, uint32_t opcode){ - int P = ARM7_BFE(opcode,22,1); - int flags_only = !ARM7_BFE(opcode,16,1); - int I = ARM7_BFE(opcode,25,1); +static FORCE_INLINE void arm7_msr(arm7_t *cpu, uint32_t opcode) { + int P = ARM7_BFE(opcode, 22, 1); + int flags_only = !ARM7_BFE(opcode, 16, 1); + int I = ARM7_BFE(opcode, 25, 1); int data = 0; - int dest_reg = P ? SPSR: CPSR; + int dest_reg = P ? SPSR : CPSR; // Mask behavior from: https://problemkaputt.de/gbatek.htm#armopcodespsrtransfermrsmsr uint32_t mask = 0; - mask|= 0xff000000*ARM7_BFE(opcode,19,1); - mask|= 0x00ff0000*ARM7_BFE(opcode,18,1); - mask|= 0x0000ff00*ARM7_BFE(opcode,17,1); - mask|= 0x000000ff*ARM7_BFE(opcode,16,1); + mask |= 0xff000000 * ARM7_BFE(opcode, 19, 1); + mask |= 0x00ff0000 * ARM7_BFE(opcode, 18, 1); + mask |= 0x0000ff00 * ARM7_BFE(opcode, 17, 1); + mask |= 0x000000ff * ARM7_BFE(opcode, 16, 1); + + int mode = cpu->registers[CPSR] & 0x1f; - int mode = cpu->registers[CPSR]&0x1f; - // There is no SPSR in user or system mode - if(P && (mode==0x10 ||mode==0x1f)) return; - //User mode can only change the flags - if(mode == 0x10)mask &=0xf0000000; - - if(I){ - int imm = ARM7_BFE(opcode,0,8); - int rot = ARM7_BFE(opcode,8,4)*2; - data = arm7_rotr(imm,rot); - }else data = arm7_reg_read(cpu,ARM7_BFE(opcode,0,4)); - - int old_data = arm7_reg_read(cpu,dest_reg); - data&=mask; - data|=old_data&~mask; - - arm7_reg_write(cpu,dest_reg,data); -} + if(P && (mode == 0x10 || mode == 0x1f)) return; + // User mode can only change the flags + if(mode == 0x10) mask &= 0xf0000000; + if(I) { + int imm = ARM7_BFE(opcode, 0, 8); + int rot = ARM7_BFE(opcode, 8, 4) * 2; + data = arm7_rotr(imm, rot); + } else + data = arm7_reg_read(cpu, ARM7_BFE(opcode, 0, 4)); + + int old_data = arm7_reg_read(cpu, dest_reg); + data &= mask; + data |= old_data & ~mask; + + arm7_reg_write(cpu, dest_reg, data); +} // Thumb Instruction Implementations -static FORCE_INLINE void arm7t_mov_shift_reg(arm7_t* cpu, uint32_t opcode){ - uint32_t op = ARM7_BFE(opcode,11,2); - uint32_t offset= ARM7_BFE(opcode,6,5); - uint32_t Rs = ARM7_BFE(opcode,3,3); - uint32_t Rd = ARM7_BFE(opcode,0,3); - - opcode = (0xD<<21)|(1<<20)|(Rd<<12)|(offset<<7)|(op<<5)|(Rs); - arm7_data_processing(cpu,opcode); -} -static FORCE_INLINE void arm7t_add_sub(arm7_t* cpu, uint32_t opcode){ - bool I = ARM7_BFE(opcode,10,1); - int op = ARM7_BFE(opcode,9,1) ? /*Sub*/ 2 : /*Add*/ 4; - int Rn = ARM7_BFE(opcode,6,3); - int Rs = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); - uint32_t arm_op = (I<<25)|(op<<21)|(1<<20)|(Rs<<16)|(Rd<<12)|(Rn); - arm7_data_processing(cpu,arm_op); -} -static FORCE_INLINE void arm7t_mov_cmp_add_sub_imm(arm7_t* cpu, uint32_t opcode){ - int op = ARM7_BFE(opcode,11,2); - int Rd = ARM7_BFE(opcode,8,3); - int imm = ARM7_BFE(opcode,0,8); - op = (0x24AD>>(op*4))&0xf;/*MOV*//*CMP*//*ADD*//*SUB*/ - uint32_t arm_op = (1<<25)|(op<<21)|(1<<20)|(Rd<<16)|(Rd<<12)|(imm); +static FORCE_INLINE void arm7t_mov_shift_reg(arm7_t *cpu, uint32_t opcode) { + uint32_t op = ARM7_BFE(opcode, 11, 2); + uint32_t offset = ARM7_BFE(opcode, 6, 5); + uint32_t Rs = ARM7_BFE(opcode, 3, 3); + uint32_t Rd = ARM7_BFE(opcode, 0, 3); + + opcode = (0xD << 21) | (1 << 20) | (Rd << 12) | (offset << 7) | (op << 5) | (Rs); + arm7_data_processing(cpu, opcode); +} +static FORCE_INLINE void arm7t_add_sub(arm7_t *cpu, uint32_t opcode) { + bool I = ARM7_BFE(opcode, 10, 1); + int op = ARM7_BFE(opcode, 9, 1) ? /*Sub*/ 2 : /*Add*/ 4; + int Rn = ARM7_BFE(opcode, 6, 3); + int Rs = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); + uint32_t arm_op = (I << 25) | (op << 21) | (1 << 20) | (Rs << 16) | (Rd << 12) | (Rn); + arm7_data_processing(cpu, arm_op); +} +static FORCE_INLINE void arm7t_mov_cmp_add_sub_imm(arm7_t *cpu, uint32_t opcode) { + int op = ARM7_BFE(opcode, 11, 2); + int Rd = ARM7_BFE(opcode, 8, 3); + int imm = ARM7_BFE(opcode, 0, 8); + op = (0x24AD >> (op * 4)) & 0xf; /*MOV*/ /*CMP*/ /*ADD*/ /*SUB*/ + uint32_t arm_op = (1 << 25) | (op << 21) | (1 << 20) | (Rd << 16) | (Rd << 12) | (imm); arm7_data_processing(cpu, arm_op); } -static FORCE_INLINE void arm7t_alu_op(arm7_t* cpu, uint32_t opcode){ - int op = ARM7_BFE(opcode,6,4); - int Rs = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); - if(op==13){ - uint32_t arm_op = (0xE<<28)|(1<<20)|(Rd<<16)|(Rd<<8)|(9<<4)|(Rs); +static FORCE_INLINE void arm7t_alu_op(arm7_t *cpu, uint32_t opcode) { + int op = ARM7_BFE(opcode, 6, 4); + int Rs = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); + if(op == 13) { + uint32_t arm_op = (0xE << 28) | (1 << 20) | (Rd << 16) | (Rd << 8) | (9 << 4) | (Rs); arm7_multiply(cpu, arm_op); - cpu->registers[CPSR]&=~(1<<29); - return; - } - - int op_mapping[16]={ - /*AND{S}*/ 0, - /*EOR{S}*/ 1, - /*LSL{S}*/ 13, - /*LSR{S}*/ 13, - /*ASR{S}*/ 13, - /*ADC{S}*/ 5, - /*SBC{S}*/ 6, - /*ROR{S}*/ 13, - /*TST */ 8, - /*NEG{S}*/ 3,/*ARM Op: RSBS Rd, Rs, #0*/ - /*CMP */ 10, - /*CMN */ 11, - /*ORR{S}*/ 12, - /*MUL{S}*/ 0, - /*BIC{S}*/ 14, - /*MVN{S}*/ 15 - }; + cpu->registers[CPSR] &= ~(1 << 29); + return; + } - int shift_mapping[16]={ - /*AND{S}*/ 0, - /*EOR{S}*/ 0, - /*LSL{S}*/ 0, - /*LSR{S}*/ 1, - /*ASR{S}*/ 2, - /*ADC{S}*/ 0, - /*SBC{S}*/ 0, - /*ROR{S}*/ 3, - /*TST */ 0, - /*NEG{S}*/ 0,/*ARM Op: RSBS Rd, Rs, #0*/ - /*CMP */ 0, - /*CMN */ 0, - /*ORR{S}*/ 0, - /*MUL{S}*/ 0, - /*BIC{S}*/ 0, - /*MVN{S}*/ 0 - }; - int alu_op = (0xfe0cba38d65ddd10ULL>>(op*4))&0xf; - int shift_op = (0x0000000030021000ULL>>(op*4))&0xf; - int Rn = (op==9)?Rs:Rd; - - uint32_t arm_op = (0xEu<<28)|(alu_op<<21)|(1<<20)|(Rn<<16)|(Rd<<12)|(shift_op<<5); - - if(alu_op==13)arm_op |= (Rs<<8)|(1<<4)|Rd; // Special case shifts - else if(op==9)arm_op |= 1<<25; // Special case NEG - else arm_op|=Rs; + int op_mapping[16] = { + /*AND{S}*/ 0, + /*EOR{S}*/ 1, + /*LSL{S}*/ 13, + /*LSR{S}*/ 13, + /*ASR{S}*/ 13, + /*ADC{S}*/ 5, + /*SBC{S}*/ 6, + /*ROR{S}*/ 13, + /*TST */ 8, + /*NEG{S}*/ 3, /*ARM Op: RSBS Rd, Rs, #0*/ + /*CMP */ 10, + /*CMN */ 11, + /*ORR{S}*/ 12, + /*MUL{S}*/ 0, + /*BIC{S}*/ 14, + /*MVN{S}*/ 15}; + + int shift_mapping[16] = { + /*AND{S}*/ 0, + /*EOR{S}*/ 0, + /*LSL{S}*/ 0, + /*LSR{S}*/ 1, + /*ASR{S}*/ 2, + /*ADC{S}*/ 0, + /*SBC{S}*/ 0, + /*ROR{S}*/ 3, + /*TST */ 0, + /*NEG{S}*/ 0, /*ARM Op: RSBS Rd, Rs, #0*/ + /*CMP */ 0, + /*CMN */ 0, + /*ORR{S}*/ 0, + /*MUL{S}*/ 0, + /*BIC{S}*/ 0, + /*MVN{S}*/ 0}; + int alu_op = (0xfe0cba38d65ddd10ULL >> (op * 4)) & 0xf; + int shift_op = (0x0000000030021000ULL >> (op * 4)) & 0xf; + int Rn = (op == 9) ? Rs : Rd; + + uint32_t arm_op = (0xEu << 28) | (alu_op << 21) | (1 << 20) | (Rn << 16) | (Rd << 12) | (shift_op << 5); + + if(alu_op == 13) + arm_op |= (Rs << 8) | (1 << 4) | Rd; // Special case shifts + else if(op == 9) + arm_op |= 1 << 25; // Special case NEG + else + arm_op |= Rs; arm7_data_processing(cpu, arm_op); } -static FORCE_INLINE void arm7t_hi_reg_op(arm7_t* cpu, uint32_t opcode){ - int op = ARM7_BFE(opcode,8,2); - int H1 = ARM7_BFE(opcode,7,1); - int H2 = ARM7_BFE(opcode,6,1); - int Rs = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); +static FORCE_INLINE void arm7t_hi_reg_op(arm7_t *cpu, uint32_t opcode) { + int op = ARM7_BFE(opcode, 8, 2); + int H1 = ARM7_BFE(opcode, 7, 1); + int H2 = ARM7_BFE(opcode, 6, 1); + int Rs = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); - Rs|= H2<<3; - Rd|= H1<<3; + Rs |= H2 << 3; + Rd |= H1 << 3; - if(op==3){ + if(op == 3) { // Only the Rs field is populated since that is all that is needed for // arm7_branch_exchange - int arm_op= Rs; - arm7_branch_exchange(cpu,arm_op); - }else{ - int S= op==1; - int op_mapping[3]={/*Add*/4, /*CMP*/10,/*MOV*/13 }; + int arm_op = Rs; + arm7_branch_exchange(cpu, arm_op); + } else { + int S = op == 1; + int op_mapping[3] = {/*Add*/ 4, /*CMP*/ 10, /*MOV*/ 13}; op = op_mapping[op]; - //cccc 001o oooS nnnn dddd rrrr OOOO OOOO - uint32_t arm_op = (op<<21)|(S<<20)|(op==13?0:(Rd<<16))|(Rd<<12)|(Rs<<0); + // cccc 001o oooS nnnn dddd rrrr OOOO OOOO + uint32_t arm_op = (op << 21) | (S << 20) | (op == 13 ? 0 : (Rd << 16)) | (Rd << 12) | (Rs << 0); arm7_data_processing(cpu, arm_op); } } -static FORCE_INLINE void arm9t_hi_reg_op(arm7_t* cpu, uint32_t opcode){ - int op = ARM7_BFE(opcode,8,2); - int H1 = ARM7_BFE(opcode,7,1); - int H2 = ARM7_BFE(opcode,6,1); - int Rs = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); +static FORCE_INLINE void arm9t_hi_reg_op(arm7_t *cpu, uint32_t opcode) { + int op = ARM7_BFE(opcode, 8, 2); + int H1 = ARM7_BFE(opcode, 7, 1); + int H2 = ARM7_BFE(opcode, 6, 1); + int Rs = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); - Rs|= H2<<3; - Rd|= H1<<3; + Rs |= H2 << 3; + Rd |= H1 << 3; - if(op==3){ + if(op == 3) { // Only the Rs field is populated since that is all that is needed for // arm7_branch_exchange - int arm_op= Rs; + int arm_op = Rs; int blx = H1; - if(blx)arm9_branch_link_exchange(cpu,arm_op); - else arm7_branch_exchange(cpu,arm_op); - }else{ - int S= op==1; - int op_mapping[3]={/*Add*/4, /*CMP*/10,/*MOV*/13 }; + if(blx) + arm9_branch_link_exchange(cpu, arm_op); + else + arm7_branch_exchange(cpu, arm_op); + } else { + int S = op == 1; + int op_mapping[3] = {/*Add*/ 4, /*CMP*/ 10, /*MOV*/ 13}; op = op_mapping[op]; - //cccc 001o oooS nnnn dddd rrrr OOOO OOOO - uint32_t arm_op = (op<<21)|(S<<20)|(op==13?0:(Rd<<16))|(Rd<<12)|(Rs<<0); + // cccc 001o oooS nnnn dddd rrrr OOOO OOOO + uint32_t arm_op = (op << 21) | (S << 20) | (op == 13 ? 0 : (Rd << 16)) | (Rd << 12) | (Rs << 0); arm7_data_processing(cpu, arm_op); } } -static FORCE_INLINE void arm9t_pc_rel_ldst(arm7_t* cpu, uint32_t opcode){ - int offset = ARM7_BFE(opcode,0,8)*4; - int Rd = ARM7_BFE(opcode,8,3); - uint32_t addr = (cpu->registers[PC]+offset+2)&(~3); - uint32_t data = cpu->read32(cpu->user_data,addr); - arm9_reg_write_r15_thumb(cpu,Rd,data); +static FORCE_INLINE void arm9t_pc_rel_ldst(arm7_t *cpu, uint32_t opcode) { + int offset = ARM7_BFE(opcode, 0, 8) * 4; + int Rd = ARM7_BFE(opcode, 8, 3); + uint32_t addr = (cpu->registers[PC] + offset + 2) & (~3); + uint32_t data = cpu->read32(cpu->user_data, addr); + arm9_reg_write_r15_thumb(cpu, Rd, data); cpu->i_cycles++; } -static FORCE_INLINE void arm7t_pc_rel_ldst(arm7_t* cpu, uint32_t opcode){ - int offset = ARM7_BFE(opcode,0,8)*4; - int Rd = ARM7_BFE(opcode,8,3); - uint32_t addr = (cpu->registers[PC]+offset+2)&(~3); - uint32_t data = cpu->read32(cpu->user_data,addr); - arm7_reg_write(cpu,Rd,data); +static FORCE_INLINE void arm7t_pc_rel_ldst(arm7_t *cpu, uint32_t opcode) { + int offset = ARM7_BFE(opcode, 0, 8) * 4; + int Rd = ARM7_BFE(opcode, 8, 3); + uint32_t addr = (cpu->registers[PC] + offset + 2) & (~3); + uint32_t data = cpu->read32(cpu->user_data, addr); + arm7_reg_write(cpu, Rd, data); cpu->i_cycles++; } -static FORCE_INLINE void arm7t_reg_off_ldst(arm7_t* cpu, uint32_t opcode){ - bool B = ARM7_BFE(opcode,10,1); - bool L = ARM7_BFE(opcode,11,1); - int Ro = ARM7_BFE(opcode,6,3); - int Rb = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); +static FORCE_INLINE void arm7t_reg_off_ldst(arm7_t *cpu, uint32_t opcode) { + bool B = ARM7_BFE(opcode, 10, 1); + bool L = ARM7_BFE(opcode, 11, 1); + int Ro = ARM7_BFE(opcode, 6, 3); + int Rb = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); - int r15_off = 2; - Ro = arm7_reg_read_r15_adj(cpu,Ro,r15_off); - Rb = arm7_reg_read_r15_adj(cpu,Rb,r15_off); + int r15_off = 2; + Ro = arm7_reg_read_r15_adj(cpu, Ro, r15_off); + Rb = arm7_reg_read_r15_adj(cpu, Rb, r15_off); - uint32_t addr = Ro+Rb; + uint32_t addr = Ro + Rb; // Store before write back - if(L==0){ - uint32_t data = arm7_reg_read_r15_adj(cpu,Rd,r15_off); - if(B==1)cpu->write8(cpu->user_data,addr,data); - else cpu->write32(cpu->user_data,addr,data); - }else{ // Load - uint32_t data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - arm7_reg_write(cpu,Rd,data); + if(L == 0) { + uint32_t data = arm7_reg_read_r15_adj(cpu, Rd, r15_off); + if(B == 1) + cpu->write8(cpu->user_data, addr, data); + else + cpu->write32(cpu->user_data, addr, data); + } else { // Load + uint32_t data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + arm7_reg_write(cpu, Rd, data); cpu->i_cycles++; } } -static FORCE_INLINE void arm9t_reg_off_ldst(arm7_t* cpu, uint32_t opcode){ - bool B = ARM7_BFE(opcode,10,1); - bool L = ARM7_BFE(opcode,11,1); - int Ro = ARM7_BFE(opcode,6,3); - int Rb = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); +static FORCE_INLINE void arm9t_reg_off_ldst(arm7_t *cpu, uint32_t opcode) { + bool B = ARM7_BFE(opcode, 10, 1); + bool L = ARM7_BFE(opcode, 11, 1); + int Ro = ARM7_BFE(opcode, 6, 3); + int Rb = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); - int r15_off = 2; - Ro = arm7_reg_read_r15_adj(cpu,Ro,r15_off); - Rb = arm7_reg_read_r15_adj(cpu,Rb,r15_off); + int r15_off = 2; + Ro = arm7_reg_read_r15_adj(cpu, Ro, r15_off); + Rb = arm7_reg_read_r15_adj(cpu, Rb, r15_off); - uint32_t addr = Ro+Rb; + uint32_t addr = Ro + Rb; // Store before write back - if(L==0){ - uint32_t data = arm7_reg_read_r15_adj(cpu,Rd,r15_off); - if(B==1)cpu->write8(cpu->user_data,addr,data); - else cpu->write32(cpu->user_data,addr,data); - }else{ // Load - uint32_t data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - arm9_reg_write_r15_thumb(cpu,Rd,data); + if(L == 0) { + uint32_t data = arm7_reg_read_r15_adj(cpu, Rd, r15_off); + if(B == 1) + cpu->write8(cpu->user_data, addr, data); + else + cpu->write32(cpu->user_data, addr, data); + } else { // Load + uint32_t data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + arm9_reg_write_r15_thumb(cpu, Rd, data); cpu->i_cycles++; } - } -static FORCE_INLINE void arm7t_ldst_bh(arm7_t* cpu, uint32_t opcode){ - int op = ARM7_BFE(opcode,10,2); - int Ro = ARM7_BFE(opcode,6,3); - int Rb = ARM7_BFE(opcode,3,3); - int Rd = ARM7_BFE(opcode,0,3); - - int r15_off = 2; - Ro = arm7_reg_read_r15_adj(cpu,Ro,r15_off); - Rb = arm7_reg_read_r15_adj(cpu,Rb,r15_off); - - uint32_t addr = Ro+Rb; - - uint32_t data; - switch(op){ - case 0: //Store Halfword - data = arm7_reg_read_r15_adj(cpu,Rd,r15_off); - break; - case 1: //Load Sign Extended Byte - data = cpu->read8(cpu->user_data,addr); - cpu->i_cycles++; - if(ARM7_BFE(data,7,1))data|=0xffffff00; - break; - case 2: //Load Halfword - data = arm7_rotr(cpu->read16(cpu->user_data,addr),(addr&0x1)*8); - cpu->i_cycles++; - break; - case 3: //Load Sign Extended Half - data = arm7_rotr(cpu->read16(cpu->user_data,addr),(addr&0x1)*8)&0xffff; - cpu->i_cycles++; - //Unaligned halfwords sign extend the byte - if((addr&1)&&ARM7_BFE(data,7,1))data|=0xffffff00; - else if(ARM7_BFE(data,15,1))data|=0xffff0000; - break; - } - if(op==0)cpu->write16(cpu->user_data,addr,data); - else arm7_reg_write(cpu,Rd,data); -} -static FORCE_INLINE void arm7t_imm_off_ldst(arm7_t* cpu, uint32_t opcode){ - bool B = ARM7_BFE(opcode,12,1); - bool L = ARM7_BFE(opcode,11,1); - int offset = ARM7_BFE(opcode,6,5); - - uint32_t Rd = ARM7_BFE(opcode,0,3); - uint32_t Rb = ARM7_BFE(opcode,3,3); - uint32_t addr = arm7_reg_read_r15_adj(cpu, Rb,4); - //Offset is in 4B increments for word loads - if(!B)offset*=4; +static FORCE_INLINE void arm7t_ldst_bh(arm7_t *cpu, uint32_t opcode) { + int op = ARM7_BFE(opcode, 10, 2); + int Ro = ARM7_BFE(opcode, 6, 3); + int Rb = ARM7_BFE(opcode, 3, 3); + int Rd = ARM7_BFE(opcode, 0, 3); + + int r15_off = 2; + Ro = arm7_reg_read_r15_adj(cpu, Ro, r15_off); + Rb = arm7_reg_read_r15_adj(cpu, Rb, r15_off); + + uint32_t addr = Ro + Rb; + + uint32_t data; + switch(op) { + case 0: // Store Halfword + data = arm7_reg_read_r15_adj(cpu, Rd, r15_off); + break; + case 1: // Load Sign Extended Byte + data = cpu->read8(cpu->user_data, addr); + cpu->i_cycles++; + if(ARM7_BFE(data, 7, 1)) data |= 0xffffff00; + break; + case 2: // Load Halfword + data = arm7_rotr(cpu->read16(cpu->user_data, addr), (addr & 0x1) * 8); + cpu->i_cycles++; + break; + case 3: // Load Sign Extended Half + data = arm7_rotr(cpu->read16(cpu->user_data, addr), (addr & 0x1) * 8) & 0xffff; + cpu->i_cycles++; + // Unaligned halfwords sign extend the byte + if((addr & 1) && ARM7_BFE(data, 7, 1)) + data |= 0xffffff00; + else if(ARM7_BFE(data, 15, 1)) + data |= 0xffff0000; + break; + } + if(op == 0) + cpu->write16(cpu->user_data, addr, data); + else + arm7_reg_write(cpu, Rd, data); +} +static FORCE_INLINE void arm7t_imm_off_ldst(arm7_t *cpu, uint32_t opcode) { + bool B = ARM7_BFE(opcode, 12, 1); + bool L = ARM7_BFE(opcode, 11, 1); + int offset = ARM7_BFE(opcode, 6, 5); + + uint32_t Rd = ARM7_BFE(opcode, 0, 3); + uint32_t Rb = ARM7_BFE(opcode, 3, 3); + uint32_t addr = arm7_reg_read_r15_adj(cpu, Rb, 4); + // Offset is in 4B increments for word loads + if(!B) offset *= 4; addr += offset; - if(L==0){ // Store - uint32_t data = arm7_reg_read(cpu,Rd); - if(B==1)cpu->write8(cpu->user_data,addr,data); - else cpu->write32(cpu->user_data,addr,data); - }else{ // Load - uint32_t data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); + if(L == 0) { // Store + uint32_t data = arm7_reg_read(cpu, Rd); + if(B == 1) + cpu->write8(cpu->user_data, addr, data); + else + cpu->write32(cpu->user_data, addr, data); + } else { // Load + uint32_t data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); cpu->i_cycles++; - arm7_reg_write(cpu,Rd,data); - } -} -static FORCE_INLINE void arm9t_imm_off_ldst(arm7_t* cpu, uint32_t opcode){ - bool B = ARM7_BFE(opcode,12,1); - bool L = ARM7_BFE(opcode,11,1); - int offset = ARM7_BFE(opcode,6,5); - - uint32_t Rd = ARM7_BFE(opcode,0,3); - uint32_t Rb = ARM7_BFE(opcode,3,3); - uint32_t addr = arm7_reg_read_r15_adj(cpu, Rb,4); - //Offset is in 4B increments for word loads - if(!B)offset*=4; + arm7_reg_write(cpu, Rd, data); + } +} +static FORCE_INLINE void arm9t_imm_off_ldst(arm7_t *cpu, uint32_t opcode) { + bool B = ARM7_BFE(opcode, 12, 1); + bool L = ARM7_BFE(opcode, 11, 1); + int offset = ARM7_BFE(opcode, 6, 5); + + uint32_t Rd = ARM7_BFE(opcode, 0, 3); + uint32_t Rb = ARM7_BFE(opcode, 3, 3); + uint32_t addr = arm7_reg_read_r15_adj(cpu, Rb, 4); + // Offset is in 4B increments for word loads + if(!B) offset *= 4; addr += offset; - if(L==0){ // Store - uint32_t data = arm7_reg_read(cpu,Rd); - if(B==1)cpu->write8(cpu->user_data,addr,data); - else cpu->write32(cpu->user_data,addr,data); - }else{ // Load - uint32_t data = B ? cpu->read8(cpu->user_data,addr): arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); + if(L == 0) { // Store + uint32_t data = arm7_reg_read(cpu, Rd); + if(B == 1) + cpu->write8(cpu->user_data, addr, data); + else + cpu->write32(cpu->user_data, addr, data); + } else { // Load + uint32_t data = B ? cpu->read8(cpu->user_data, addr) : arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); cpu->i_cycles++; - arm9_reg_write_r15_thumb(cpu,Rd,data); + arm9_reg_write_r15_thumb(cpu, Rd, data); } } -static FORCE_INLINE void arm7t_imm_off_ldst_bh(arm7_t* cpu, uint32_t opcode){ - bool L = ARM7_BFE(opcode,11,1); - int offset = ARM7_BFE(opcode,6,5); - - uint32_t Rd = ARM7_BFE(opcode,0,3); - uint32_t addr = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode,3,3),4); +static FORCE_INLINE void arm7t_imm_off_ldst_bh(arm7_t *cpu, uint32_t opcode) { + bool L = ARM7_BFE(opcode, 11, 1); + int offset = ARM7_BFE(opcode, 6, 5); + + uint32_t Rd = ARM7_BFE(opcode, 0, 3); + uint32_t addr = arm7_reg_read_r15_adj(cpu, ARM7_BFE(opcode, 3, 3), 4); - addr += offset*2; - uint32_t data=0; - if(L==0){ // Store - data = arm7_reg_read(cpu,Rd); - cpu->write16(cpu->user_data,addr,data); - }else{ // Load - data = arm7_rotr(cpu->read16(cpu->user_data,addr),(addr&0x1)*8); - arm7_reg_write(cpu,Rd,data); + addr += offset * 2; + uint32_t data = 0; + if(L == 0) { // Store + data = arm7_reg_read(cpu, Rd); + cpu->write16(cpu->user_data, addr, data); + } else { // Load + data = arm7_rotr(cpu->read16(cpu->user_data, addr), (addr & 0x1) * 8); + arm7_reg_write(cpu, Rd, data); cpu->i_cycles++; } } -static FORCE_INLINE void arm7t_stack_off_ldst(arm7_t* cpu, uint32_t opcode){ - bool L = ARM7_BFE(opcode,11,1); - uint64_t Rd = ARM7_BFE(opcode,8,3); - int offset = ARM7_BFE(opcode,0,8); - uint32_t addr = arm7_reg_read(cpu,13); - - addr += offset*4; - uint32_t data; - if(L==0){ // Store - data = arm7_reg_read(cpu,Rd); - cpu->write32(cpu->user_data,addr,data); - }else{ // Load - data = arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - arm7_reg_write(cpu,Rd,data); +static FORCE_INLINE void arm7t_stack_off_ldst(arm7_t *cpu, uint32_t opcode) { + bool L = ARM7_BFE(opcode, 11, 1); + uint64_t Rd = ARM7_BFE(opcode, 8, 3); + int offset = ARM7_BFE(opcode, 0, 8); + uint32_t addr = arm7_reg_read(cpu, 13); + + addr += offset * 4; + uint32_t data; + if(L == 0) { // Store + data = arm7_reg_read(cpu, Rd); + cpu->write32(cpu->user_data, addr, data); + } else { // Load + data = arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + arm7_reg_write(cpu, Rd, data); cpu->i_cycles++; } } -static FORCE_INLINE void arm9t_stack_off_ldst(arm7_t* cpu, uint32_t opcode){ - bool L = ARM7_BFE(opcode,11,1); - uint64_t Rd = ARM7_BFE(opcode,8,3); - int offset = ARM7_BFE(opcode,0,8); - uint32_t addr = arm7_reg_read(cpu,13); - - addr += offset*4; - uint32_t data; - if(L==0){ // Store - data = arm7_reg_read(cpu,Rd); - cpu->write32(cpu->user_data,addr,data); - }else{ // Load - data = arm7_rotr(cpu->read32(cpu->user_data,addr),(addr&0x3)*8); - arm9_reg_write_r15_thumb(cpu,Rd,data); +static FORCE_INLINE void arm9t_stack_off_ldst(arm7_t *cpu, uint32_t opcode) { + bool L = ARM7_BFE(opcode, 11, 1); + uint64_t Rd = ARM7_BFE(opcode, 8, 3); + int offset = ARM7_BFE(opcode, 0, 8); + uint32_t addr = arm7_reg_read(cpu, 13); + + addr += offset * 4; + uint32_t data; + if(L == 0) { // Store + data = arm7_reg_read(cpu, Rd); + cpu->write32(cpu->user_data, addr, data); + } else { // Load + data = arm7_rotr(cpu->read32(cpu->user_data, addr), (addr & 0x3) * 8); + arm9_reg_write_r15_thumb(cpu, Rd, data); cpu->i_cycles++; } } -static FORCE_INLINE void arm7t_load_addr(arm7_t* cpu, uint32_t opcode){ - bool SP = ARM7_BFE(opcode,11,1); - int Rd = ARM7_BFE(opcode,8,3); - int imm = ARM7_BFE(opcode,0,8)*4; - - uint32_t v = arm7_reg_read_r15_adj(cpu,SP?13:15,4); - if(!SP)v&= ~3; //Bit 1 of PC always read as 0 - v+=imm; - arm7_reg_write(cpu,Rd, v); -} -static FORCE_INLINE void arm7t_add_off_sp(arm7_t* cpu, uint32_t opcode){ - int32_t offset = ARM7_BFE(opcode,0,7)*4; - int sign = ARM7_BFE(opcode,7,1); - if(sign)offset=-offset; - uint32_t value = arm7_reg_read(cpu,13); - arm7_reg_write(cpu,13,value+offset); -} -static FORCE_INLINE void arm7t_push_pop_reg(arm7_t* cpu, uint32_t opcode){ - bool push_or_pop = ARM7_BFE(opcode,11,1); - bool include_pc_lr = ARM7_BFE(opcode,8,1); - uint32_t r_list = ARM7_BFE(opcode,0,8); - int P = !push_or_pop; - int W = 1; - int U = push_or_pop; - - uint32_t arm_op = (0xe<<28)|(4<<25)|(P<<24)|(U<<23)|(W<<21)|(push_or_pop<<20)|(13<<16)|r_list; - if(include_pc_lr)arm_op|=push_or_pop? 0x8000 : 0x4000; - arm7_block_transfer(cpu,arm_op); -} -static FORCE_INLINE void arm9t_push_pop_reg(arm7_t* cpu, uint32_t opcode){ - bool push_or_pop = ARM7_BFE(opcode,11,1); - bool include_pc_lr = ARM7_BFE(opcode,8,1); - uint32_t r_list = ARM7_BFE(opcode,0,8); - int P = !push_or_pop; - int W = 1; - int U = push_or_pop; - - uint32_t arm_op = (0xe<<28)|(4<<25)|(P<<24)|(U<<23)|(W<<21)|(push_or_pop<<20)|(13<<16)|r_list; - if(include_pc_lr)arm_op|=push_or_pop? 0x8000 : 0x4000; - arm9_block_transfer(cpu,arm_op); -} -static FORCE_INLINE void arm7t_mult_ldst(arm7_t* cpu, uint32_t opcode){ - bool write_or_read = ARM7_BFE(opcode,11,1); - int Rb = ARM7_BFE(opcode,8,3); - uint32_t r_list = ARM7_BFE(opcode,0,8); - - int P = 0; - int U = 1; +static FORCE_INLINE void arm7t_load_addr(arm7_t *cpu, uint32_t opcode) { + bool SP = ARM7_BFE(opcode, 11, 1); + int Rd = ARM7_BFE(opcode, 8, 3); + int imm = ARM7_BFE(opcode, 0, 8) * 4; + + uint32_t v = arm7_reg_read_r15_adj(cpu, SP ? 13 : 15, 4); + if(!SP) v &= ~3; // Bit 1 of PC always read as 0 + v += imm; + arm7_reg_write(cpu, Rd, v); +} +static FORCE_INLINE void arm7t_add_off_sp(arm7_t *cpu, uint32_t opcode) { + int32_t offset = ARM7_BFE(opcode, 0, 7) * 4; + int sign = ARM7_BFE(opcode, 7, 1); + if(sign) offset = -offset; + uint32_t value = arm7_reg_read(cpu, 13); + arm7_reg_write(cpu, 13, value + offset); +} +static FORCE_INLINE void arm7t_push_pop_reg(arm7_t *cpu, uint32_t opcode) { + bool push_or_pop = ARM7_BFE(opcode, 11, 1); + bool include_pc_lr = ARM7_BFE(opcode, 8, 1); + uint32_t r_list = ARM7_BFE(opcode, 0, 8); + int P = !push_or_pop; + int W = 1; + int U = push_or_pop; + + uint32_t arm_op = (0xe << 28) | (4 << 25) | (P << 24) | (U << 23) | (W << 21) | (push_or_pop << 20) | (13 << 16) | r_list; + if(include_pc_lr) arm_op |= push_or_pop ? 0x8000 : 0x4000; + arm7_block_transfer(cpu, arm_op); +} +static FORCE_INLINE void arm9t_push_pop_reg(arm7_t *cpu, uint32_t opcode) { + bool push_or_pop = ARM7_BFE(opcode, 11, 1); + bool include_pc_lr = ARM7_BFE(opcode, 8, 1); + uint32_t r_list = ARM7_BFE(opcode, 0, 8); + int P = !push_or_pop; + int W = 1; + int U = push_or_pop; + + uint32_t arm_op = (0xe << 28) | (4 << 25) | (P << 24) | (U << 23) | (W << 21) | (push_or_pop << 20) | (13 << 16) | r_list; + if(include_pc_lr) arm_op |= push_or_pop ? 0x8000 : 0x4000; + arm9_block_transfer(cpu, arm_op); +} +static FORCE_INLINE void arm7t_mult_ldst(arm7_t *cpu, uint32_t opcode) { + bool write_or_read = ARM7_BFE(opcode, 11, 1); + int Rb = ARM7_BFE(opcode, 8, 3); + uint32_t r_list = ARM7_BFE(opcode, 0, 8); + + int P = 0; + int U = 1; int W = 1; // Maps to LDMIA, STMIA opcode - uint32_t arm_op = (0xe<<28)|(4<<25)|(P<<24)|(U<<23)|(W<<21)|(write_or_read<<20)|(Rb<<16)|r_list; - arm7_block_transfer(cpu,arm_op); -} -static FORCE_INLINE void arm9t_mult_ldst(arm7_t* cpu, uint32_t opcode){ - bool write_or_read = ARM7_BFE(opcode,11,1); - int Rb = ARM7_BFE(opcode,8,3); - uint32_t r_list = ARM7_BFE(opcode,0,8); - - int P = 0; - int U = 1; + uint32_t arm_op = (0xe << 28) | (4 << 25) | (P << 24) | (U << 23) | (W << 21) | (write_or_read << 20) | (Rb << 16) | r_list; + arm7_block_transfer(cpu, arm_op); +} +static FORCE_INLINE void arm9t_mult_ldst(arm7_t *cpu, uint32_t opcode) { + bool write_or_read = ARM7_BFE(opcode, 11, 1); + int Rb = ARM7_BFE(opcode, 8, 3); + uint32_t r_list = ARM7_BFE(opcode, 0, 8); + + int P = 0; + int U = 1; int W = 1; // Maps to LDMIA, STMIA opcode - uint32_t arm_op = (0xe<<28)|(4<<25)|(P<<24)|(U<<23)|(W<<21)|(write_or_read<<20)|(Rb<<16)|r_list; - arm9_block_transfer(cpu,arm_op); -} -static FORCE_INLINE void arm7t_cond_branch(arm7_t* cpu, uint32_t opcode){ - int cond = ARM7_BFE(opcode,8,4); - int s_off = ARM7_BFE(opcode,0,8); - if(ARM7_BFE(s_off,7,1))s_off|=0xFFFFFF00; - //ARM equv: cccc 1010 OOOO OOOO OOOO OOOO OOOO OOOO - uint32_t arm_op = (cond<<28)|(0xA<<24); - if(arm7_check_cond_code(cpu,arm_op)){ - cpu->registers[PC]+=s_off*2+2; - cpu->prefetch_pc=-1; - } -} -static FORCE_INLINE void arm7t_soft_interrupt(arm7_t* cpu, uint32_t opcode){ - arm7_software_interrupt(cpu,opcode); -} -static FORCE_INLINE void arm7t_branch(arm7_t* cpu, uint32_t opcode){ - int offset = ARM7_BFE(opcode,0,11)<<1; - if(ARM7_BFE(offset,11,1))offset|=0xfffff000; - cpu->registers[PC]+=offset+2; - cpu->prefetch_pc=-1; -} -static FORCE_INLINE void arm7t_long_branch_link(arm7_t* cpu, uint32_t opcode){ - bool H = ARM7_BFE(opcode,11,1); - int offset = ARM7_BFE(opcode,0,11); - int thumb_branch = ARM7_BFE(opcode,12,1); - uint32_t link_reg = arm7_reg_read(cpu,LR); + uint32_t arm_op = (0xe << 28) | (4 << 25) | (P << 24) | (U << 23) | (W << 21) | (write_or_read << 20) | (Rb << 16) | r_list; + arm9_block_transfer(cpu, arm_op); +} +static FORCE_INLINE void arm7t_cond_branch(arm7_t *cpu, uint32_t opcode) { + int cond = ARM7_BFE(opcode, 8, 4); + int s_off = ARM7_BFE(opcode, 0, 8); + if(ARM7_BFE(s_off, 7, 1)) s_off |= 0xFFFFFF00; + // ARM equv: cccc 1010 OOOO OOOO OOOO OOOO OOOO OOOO + uint32_t arm_op = (cond << 28) | (0xA << 24); + if(arm7_check_cond_code(cpu, arm_op)) { + cpu->registers[PC] += s_off * 2 + 2; + cpu->prefetch_pc = -1; + } +} +static FORCE_INLINE void arm7t_soft_interrupt(arm7_t *cpu, uint32_t opcode) { + arm7_software_interrupt(cpu, opcode); +} +static FORCE_INLINE void arm7t_branch(arm7_t *cpu, uint32_t opcode) { + int offset = ARM7_BFE(opcode, 0, 11) << 1; + if(ARM7_BFE(offset, 11, 1)) offset |= 0xfffff000; + cpu->registers[PC] += offset + 2; + cpu->prefetch_pc = -1; +} +static FORCE_INLINE void arm7t_long_branch_link(arm7_t *cpu, uint32_t opcode) { + bool H = ARM7_BFE(opcode, 11, 1); + int offset = ARM7_BFE(opcode, 0, 11); + int thumb_branch = ARM7_BFE(opcode, 12, 1); + uint32_t link_reg = arm7_reg_read(cpu, LR); // TODO: Is this +4 supposed to be +2 ARM7TDMI page 5-40 - if(H==0){ + if(H == 0) { offset <<= 12; - if (offset& 0x400000) offset |= 0xFF800000; - arm7_reg_write(cpu,LR,cpu->registers[PC] + offset+2); - }else{ - link_reg += (offset<<1); + if(offset & 0x400000) offset |= 0xFF800000; + arm7_reg_write(cpu, LR, cpu->registers[PC] + offset + 2); + } else { + link_reg += (offset << 1); uint32_t pc = cpu->registers[PC]; - cpu->registers[PC]= link_reg; - arm7_set_thumb_bit(cpu,thumb_branch); - arm7_reg_write(cpu,LR,(pc|1)); - cpu->prefetch_pc=-1; - if(!thumb_branch)arm7_set_thumb_bit(cpu,false); + cpu->registers[PC] = link_reg; + arm7_set_thumb_bit(cpu, thumb_branch); + arm7_reg_write(cpu, LR, (pc | 1)); + cpu->prefetch_pc = -1; + if(!thumb_branch) arm7_set_thumb_bit(cpu, false); } } -static FORCE_INLINE void arm7t_unknown(arm7_t* cpu, uint32_t opcode){ +static FORCE_INLINE void arm7t_unknown(arm7_t *cpu, uint32_t opcode) { bool thumb = arm7_get_thumb_bit(cpu); - cpu->registers[R14_und] = cpu->registers[PC]-(thumb?0:4); - cpu->registers[PC] = cpu->irq_table_address+0x4; + cpu->registers[R14_und] = cpu->registers[PC] - (thumb ? 0 : 4); + cpu->registers[PC] = cpu->irq_table_address + 0x4; uint32_t cpsr = cpu->registers[CPSR]; cpu->registers[SPSR_und] = cpsr; - //Update mode to supervisor and block irqs - cpu->registers[CPSR] = (cpsr&0xffffffE0)| 0x1b|0x80; - arm7_set_thumb_bit(cpu,false); - printf("Unhandled Thumb Instruction Class: (arm7t_unknown) Opcode %x\n",opcode); - printf("PC: %08x\n",cpu->registers[PC]); - //cpu->trigger_breakpoint=true; + // Update mode to supervisor and block irqs + cpu->registers[CPSR] = (cpsr & 0xffffffE0) | 0x1b | 0x80; + arm7_set_thumb_bit(cpu, false); + printf("Unhandled Thumb Instruction Class: (arm7t_unknown) Opcode %x\n", opcode); + printf("PC: %08x\n", cpu->registers[PC]); + // cpu->trigger_breakpoint=true; } #endif diff --git a/src/gb.h b/src/gb.h index c1352cc57..b1359f91f 100644 --- a/src/gb.h +++ b/src/gb.h @@ -8,438 +8,414 @@ #define SB_IO_TMA 0xff06 #define SB_IO_TAC 0xff07 -#define SB_IO_AUD1_TONE_SWEEP 0xff10 -#define SB_IO_AUD1_LENGTH_DUTY 0xff11 -#define SB_IO_AUD1_VOL_ENV 0xff12 -#define SB_IO_AUD1_FREQ 0xff13 -#define SB_IO_AUD1_FREQ_HI 0xff14 - -#define SB_IO_AUD2_LENGTH_DUTY 0xff16 -#define SB_IO_AUD2_VOL_ENV 0xff17 -#define SB_IO_AUD2_FREQ 0xff18 -#define SB_IO_AUD2_FREQ_HI 0xff19 - -#define SB_IO_AUD3_POWER 0xff1A -#define SB_IO_AUD3_LENGTH 0xff1B -#define SB_IO_AUD3_VOL 0xff1C -#define SB_IO_AUD3_FREQ 0xff1D -#define SB_IO_AUD3_FREQ_HI 0xff1E -#define SB_IO_AUD3_WAVE_BASE 0xff30 - -#define SB_IO_AUD4_LENGTH 0xff20 -#define SB_IO_AUD4_VOL_ENV 0xff21 -#define SB_IO_AUD4_POLY 0xff22 -#define SB_IO_AUD4_COUNTER 0xff23 -#define SB_IO_MASTER_VOLUME 0xff24 -#define SB_IO_SOUND_OUTPUT_SEL 0xff25 - -#define SB_IO_SOUND_ON_OFF 0xff26 -#define SB_IO_INTER_F 0xff0f -#define SB_IO_LCD_CTRL 0xff40 -#define SB_IO_LCD_STAT 0xff41 -#define SB_IO_LCD_SY 0xff42 -#define SB_IO_LCD_SX 0xff43 -#define SB_IO_LCD_LY 0xff44 -#define SB_IO_LCD_LYC 0xff45 - -#define SB_IO_OAM_DMA 0xff46 - -#define SB_IO_PPU_BGP 0xff47 -#define SB_IO_PPU_OBP0 0xff48 -#define SB_IO_PPU_OBP1 0xff49 - -#define SB_IO_LCD_WY 0xff4A -#define SB_IO_LCD_WX 0xff4B -#define SB_IO_GBC_KEY0 0xFF4C +#define SB_IO_AUD1_TONE_SWEEP 0xff10 +#define SB_IO_AUD1_LENGTH_DUTY 0xff11 +#define SB_IO_AUD1_VOL_ENV 0xff12 +#define SB_IO_AUD1_FREQ 0xff13 +#define SB_IO_AUD1_FREQ_HI 0xff14 + +#define SB_IO_AUD2_LENGTH_DUTY 0xff16 +#define SB_IO_AUD2_VOL_ENV 0xff17 +#define SB_IO_AUD2_FREQ 0xff18 +#define SB_IO_AUD2_FREQ_HI 0xff19 + +#define SB_IO_AUD3_POWER 0xff1A +#define SB_IO_AUD3_LENGTH 0xff1B +#define SB_IO_AUD3_VOL 0xff1C +#define SB_IO_AUD3_FREQ 0xff1D +#define SB_IO_AUD3_FREQ_HI 0xff1E +#define SB_IO_AUD3_WAVE_BASE 0xff30 + +#define SB_IO_AUD4_LENGTH 0xff20 +#define SB_IO_AUD4_VOL_ENV 0xff21 +#define SB_IO_AUD4_POLY 0xff22 +#define SB_IO_AUD4_COUNTER 0xff23 +#define SB_IO_MASTER_VOLUME 0xff24 +#define SB_IO_SOUND_OUTPUT_SEL 0xff25 + +#define SB_IO_SOUND_ON_OFF 0xff26 +#define SB_IO_INTER_F 0xff0f +#define SB_IO_LCD_CTRL 0xff40 +#define SB_IO_LCD_STAT 0xff41 +#define SB_IO_LCD_SY 0xff42 +#define SB_IO_LCD_SX 0xff43 +#define SB_IO_LCD_LY 0xff44 +#define SB_IO_LCD_LYC 0xff45 + +#define SB_IO_OAM_DMA 0xff46 + +#define SB_IO_PPU_BGP 0xff47 +#define SB_IO_PPU_OBP0 0xff48 +#define SB_IO_PPU_OBP1 0xff49 + +#define SB_IO_LCD_WY 0xff4A +#define SB_IO_LCD_WX 0xff4B +#define SB_IO_GBC_KEY0 0xFF4C #define SB_IO_GBC_SPEED_SWITCH 0xff4d -#define SB_IO_GBC_VBK 0xff4f +#define SB_IO_GBC_VBK 0xff4f -#define SB_IO_BIOS_BANK 0xff50 -#define SB_IO_DMA_SRC_HI 0xff51 -#define SB_IO_DMA_SRC_LO 0xff52 -#define SB_IO_DMA_DST_HI 0xff53 -#define SB_IO_DMA_DST_LO 0xff54 +#define SB_IO_BIOS_BANK 0xff50 +#define SB_IO_DMA_SRC_HI 0xff51 +#define SB_IO_DMA_SRC_LO 0xff52 +#define SB_IO_DMA_DST_HI 0xff53 +#define SB_IO_DMA_DST_LO 0xff54 #define SB_IO_DMA_MODE_LEN 0xff55 -#define SB_IO_GBC_BCPS 0xff68 -#define SB_IO_GBC_BCPD 0xff69 +#define SB_IO_GBC_BCPS 0xff68 +#define SB_IO_GBC_BCPD 0xff69 -#define SB_IO_GBC_OCPS 0xff6A -#define SB_IO_GBC_OCPD 0xff6B +#define SB_IO_GBC_OCPS 0xff6A +#define SB_IO_GBC_OCPD 0xff6B -#define SB_IO_GBC_SVBK 0xff70 +#define SB_IO_GBC_SVBK 0xff70 -#define SB_IO_INTER_EN 0xffff +#define SB_IO_INTER_EN 0xffff #define SB_MBC_NO_MBC 0 -#define SB_MBC_MBC1 1 -#define SB_MBC_MBC2 2 -#define SB_MBC_MBC3 3 -#define SB_MBC_MBC5 5 -#define SB_MBC_MBC6 6 -#define SB_MBC_MBC7 7 +#define SB_MBC_MBC1 1 +#define SB_MBC_MBC2 2 +#define SB_MBC_MBC3 3 +#define SB_MBC_MBC5 5 +#define SB_MBC_MBC6 6 +#define SB_MBC_MBC7 7 #define SB_SPRITES_PER_SCANLINE 10 -mmio_reg_t gb_io_reg_desc[]={ - { SB_IO_JOYPAD, "JOYPAD", { - { 5, 1, "Select Action buttons (0=Select)"}, - { 4, 1, "Select Direction buttons (0=Select)"}, - { 3, 1, "Input: Down or Start (0=Pressed) (Read Only)"}, - { 2, 1, "Input: Up or Select (0=Pressed) (Read Only)"}, - { 1, 1, "Input: Left or B (0=Pressed) (Read Only)"}, - { 0, 1, "Input: Right or A (0=Pressed) (Read Only)"}, - }}, - { SB_IO_SERIAL_CTRL, "SERIAL_CTRL", { - { 7, 1, "Transfer Start Flag (0=No transfer is in progress or requested, 1=Transfer in progress, or requested)"}, - { 1, 1, "Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only **"}, - { 0, 1, "Shift Clock (0=External Clock, 1=Internal Clock)"}, - }}, - { SB_IO_DIV, "DIV", { - { 0 ,8, "Div Value"}, - }}, - { SB_IO_TIMA, "TIMA", { - { 0 ,8, "Timer Value"}, - }}, - { SB_IO_TMA, "TMA", { - { 0 ,8, "Timer Modulo"}, - }}, - { SB_IO_TAC, "TAC", { - { 2 ,1, "Timer Enable"}, - { 0, 2, "Clock Divider (0: Clk/1024 1: Clk/16 2: Clk/64 3: Clk/256)"} - }}, - { SB_IO_AUD1_TONE_SWEEP, "AUD1_TONE_SWEEP", { - { 4,3, "Sweep Time"}, - { 3,1, "Sweep Increase(0)/Decrease(1)"}, - { 0,3, "Number of sweep shift (n: 0-7)"}, - }}, - { SB_IO_AUD1_LENGTH_DUTY, "AUD1_LENGTH_DUTY", { - { 6, 2, "Wave Pattern Duty (Read/Write)"}, - { 0, 6, "Sound length data (Write Only) (t1: 0-63)"}, - }}, - { SB_IO_AUD1_VOL_ENV, "AUD1_VOL_ENV", { - { 4, 4, "Initial Volume of envelope (0-0Fh) (0=No Sound)" }, - { 3, 1, "Envelope Direction (0=Decrease, 1=Increase)" }, - { 0, 3, "Number of envelope sweep (n: 0-7)" }, - }}, - { SB_IO_AUD1_FREQ, "AUD1_FREQ", { 0 }}, - { SB_IO_AUD1_FREQ_HI, "AUD1_FREQ_HI", { - { 7,1, "Initial (1=Restart Sound) (Write Only)"}, - { 6,1, "(1=Stop output when length in NR11 expires)"}, - { 0,3, "Frequency's higher 3 bits (x) (Write Only)"}, - }}, - { SB_IO_AUD2_LENGTH_DUTY, "AUD2_LENGTH_DUTY", { - { 6, 2, "Wave Pattern Duty (Read/Write)"}, - { 0, 6, "Sound length data (Write Only) (t1: 0-63)"}, - }}, - { SB_IO_AUD2_VOL_ENV, "AUD2_VOL_ENV", { - { 4, 4, "Initial Volume of envelope (0-0Fh) (0=No Sound)" }, - { 3, 1, "Envelope Direction (0=Decrease, 1=Increase)" }, - { 0, 3, "Number of envelope sweep (n: 0-7)" }, - }}, - { SB_IO_AUD2_FREQ, "AUD2_FREQ", { 0 }}, - { SB_IO_AUD2_FREQ_HI, "AUD2_FREQ_HI", { - { 7,1, "Initial (1=Restart Sound) (Write Only)"}, - { 6,1, "(1=Stop output when length in NR11 expires)"}, - { 0,3, "Frequency's higher 3 bits (x) (Write Only)"}, - }}, - { SB_IO_AUD3_POWER, "AUD3_POWER", { - {7,1,"Sound Channel 3 Enable"} - }}, - { SB_IO_AUD3_LENGTH, "AUD3_LENGTH", { 0 }}, - { SB_IO_AUD3_VOL, "AUD3_VOL", { - {5,2, "Volume (0: Mute 1: 100% 2: 50% 3: 25%)"} - }}, - { SB_IO_AUD3_FREQ, "AUD3_FREQ", { 0 }}, - { SB_IO_AUD3_FREQ_HI, "AUD3_FREQ_HI", { - { 7,1, "Initial (1=Restart Sound) (Write Only)"}, - { 6,1, "(1=Stop output when length in NR11 expires)"}, - { 0,3, "Frequency's higher 3 bits (x) (Write Only)"}, - }}, - { SB_IO_AUD4_LENGTH, "AUD4_LENGTH", { 0 }}, - { SB_IO_AUD4_VOL_ENV, "AUD4_VOL_ENV", { - { 4, 4, "Initial Volume of envelope (0-0Fh) (0=No Sound)" }, - { 3, 1, "Envelope Direction (0=Decrease, 1=Increase)" }, - { 0, 3, "Number of envelope sweep (n: 0-7)" }, - }}, - { SB_IO_AUD4_POLY, "AUD4_POLY", { - { 4,4, "Shift Clock Frequency (s)" }, - { 3,1, "Counter Step/Width (0=15 bits, 1=7 bits)" }, - { 0,3, "Dividing Ratio of Frequencies (r)" }, - }}, - { SB_IO_AUD4_COUNTER, "AUD4_COUNTER", { - {7,1, "Initial (1=Restart Sound) (Write Only)"}, - {6,1, "Counter/consecutive selection (Read/Write)"}, - }}, - { SB_IO_SOUND_OUTPUT_SEL, "SOUND_OUTPUT_SEL", { - { 7,1, "Output sound 4 to SO2 terminal" }, - { 6,1, "Output sound 3 to SO2 terminal" }, - { 5,1, "Output sound 2 to SO2 terminal" }, - { 4,1, "Output sound 1 to SO2 terminal" }, - { 3,1, "Output sound 4 to SO1 terminal" }, - { 2,1, "Output sound 3 to SO1 terminal" }, - { 1,1, "Output sound 2 to SO1 terminal" }, - { 0,1, "Output sound 1 to SO1 terminal" }, - }}, - { SB_IO_SOUND_ON_OFF, "SOUND_ON_OFF", { - { 7,1, "All sound on/off (Read/Write)"}, - { 3,1, "Sound 4 ON flag (Read Only)"}, - { 2,1, "Sound 3 ON flag (Read Only)"}, - { 1,1, "Sound 2 ON flag (Read Only)"}, - { 0,1, "Sound 1 ON flag (Read Only)"}, - }}, - { SB_IO_INTER_F, "INTER_F", { - { 0, 1, "VBlank Interrupt" }, - { 1, 1, "LCD STAT Interrupt" }, - { 2, 1, "Timer Interrupt" }, - { 3, 1, "Serial Interrupt" }, - { 4, 1, "Joypad Interrupt" }, - }}, - { SB_IO_LCD_CTRL, "LCD_CTRL", { - { 7, 1, "LCD and PPU enable 0=Off, 1=On"}, - { 6, 1, "Window tile map area 0=9800-9BFF, 1=9C00-9FFF"}, - { 5, 1, "Window enable 0=Off, 1=On"}, - { 4, 1, "BG and Window tile data area 0=8800-97FF, 1=8000-8FFF"}, - { 3, 1, "BG tile map area 0=9800-9BFF, 1=9C00-9FFF"}, - { 2, 1, "OBJ size 0=8x8, 1=8x16"}, - { 1, 1, "OBJ enable 0=Off, 1=On"}, - { 0, 1, "BG and Window enable/priority 0=Off, 1=On"}, - }}, - { SB_IO_LCD_STAT, "LCD_STAT", { - { 6,1, "LYC=LY STAT Interrupt source" }, - { 5,1, "Mode 2 OAM STAT Interrupt source" }, - { 4,1, "Mode 1 VBlank STAT Interrupt source" }, - { 3,1, "Mode 0 HBlank STAT Interrupt source" }, - { 2,1, "LYC=LY Flag" }, - { 0,2, "Mode Flag (0:Hblank 1:Vblank 2:OAM 3:Transfer)" }, - }}, - { SB_IO_LCD_SY, "LCD_SY", { 0 }}, - { SB_IO_LCD_SX, "LCD_SX", { 0 }}, - { SB_IO_LCD_LY, "LCD_LY", { 0 }}, - { SB_IO_LCD_LYC, "LCD_LYC", { 0 }}, - { SB_IO_OAM_DMA, "OAM_DMA", { 0 }}, - { SB_IO_PPU_BGP, "PPU_BGP", { - { 6,2, "Color for index 3" }, - { 4,2, "Color for index 2" }, - { 2,2, "Color for index 1" }, - { 0,2, "Color for index 0" }, - }}, - { SB_IO_PPU_OBP0, "PPU_OBP0", { - { 6,2, "Color for index 3" }, - { 4,2, "Color for index 2" }, - { 2,2, "Color for index 1" }, - { 0,2, "Color for index 0" }, - }}, - { SB_IO_PPU_OBP1, "PPU_OBP1", { - { 6,2, "Color for index 3" }, - { 4,2, "Color for index 2" }, - { 2,2, "Color for index 1" }, - { 0,2, "Color for index 0" }, - }}, - { SB_IO_LCD_WY, "LCD_WY", { 0 }}, - { SB_IO_LCD_WX, "LCD_WX", { 0 }}, - { SB_IO_GBC_KEY0, "GBC KEY0", { - {0, 1, "DMG Mode (0=Normal, 1=DMG Compatible)"} - }}, - { SB_IO_GBC_SPEED_SWITCH, "GBC_SPEED_SWITCH", { - { 7,1, "Current Speed (0=Normal, 1=Double) (Read Only)"}, - { 0,1, "Prepare Speed Switch (0=No, 1=Prepare) (Read/Write)"}, - }}, - { SB_IO_GBC_VBK, "GBC_VBK", { - {0,1, "VRAM Bank Sel"} - }}, - { SB_IO_BIOS_BANK, "BIOS_BANK", { - {0,8, "BANK VALUE"} - }}, - { SB_IO_DMA_SRC_HI, "DMA_SRC_HI", { 0 }}, - { SB_IO_DMA_SRC_LO, "DMA_SRC_LO", { 0 }}, - { SB_IO_DMA_DST_HI, "DMA_DST_HI", { 0 }}, - { SB_IO_DMA_DST_LO, "DMA_DST_LO", { 0 }}, - { SB_IO_DMA_MODE_LEN, "DMA_MODE_LEN", { - {7, 1, "Mode (0: General 1: HDMA)"}, - {0, 6, "Length*16B"} - }}, - { SB_IO_GBC_BCPS, "GBC_BCPS", { - {7, 1, "Auto Increment (0=Disabled, 1=Increment after Writing)"}, - {0,6, "Address ($00-3F)"} - }}, - { SB_IO_GBC_BCPD, "GBC_BCPD", { 0 }}, - { SB_IO_GBC_OCPS, "GBC_OCPS", { - {7, 1, "Auto Increment (0=Disabled, 1=Increment after Writing)"}, - {0,6, "Address ($00-3F)"} - }}, - { SB_IO_GBC_OCPD, "GBC_OCPD", { 0 }}, - { SB_IO_GBC_SVBK, "GBC_SVBK", { - {0,3, "WRAM Bank Sel"} - }}, - { SB_IO_INTER_EN, "INTER_EN", { - { 0, 1, "VBlank Interrupt Enable" }, - { 1, 1, "LCD STAT Interrupt Enable" }, - { 2, 1, "Timer Interrupt Enable" }, - { 3, 1, "Serial Interrupt Enable" }, - { 4, 1, "Joypad Interrupt Enable" }, - }}, +mmio_reg_t gb_io_reg_desc[] = { + { SB_IO_JOYPAD, "JOYPAD", { + {5, 1, "Select Action buttons (0=Select)"}, + {4, 1, "Select Direction buttons (0=Select)"}, + {3, 1, "Input: Down or Start (0=Pressed) (Read Only)"}, + {2, 1, "Input: Up or Select (0=Pressed) (Read Only)"}, + {1, 1, "Input: Left or B (0=Pressed) (Read Only)"}, + {0, 1, "Input: Right or A (0=Pressed) (Read Only)"}, + } }, + { SB_IO_SERIAL_CTRL, "SERIAL_CTRL", { + {7, 1, "Transfer Start Flag (0=No transfer is in progress or requested, 1=Transfer in progress, or requested)"}, + {1, 1, "Clock Speed (0=Normal, 1=Fast) ** CGB Mode Only **"}, + {0, 1, "Shift Clock (0=External Clock, 1=Internal Clock)"}, + } }, + { SB_IO_DIV, "DIV", { + {0, 8, "Div Value"}, + } }, + { SB_IO_TIMA, "TIMA", { + {0, 8, "Timer Value"}, + } }, + { SB_IO_TMA, "TMA", { + {0, 8, "Timer Modulo"}, + } }, + { SB_IO_TAC, "TAC", {{2, 1, "Timer Enable"}, {0, 2, "Clock Divider (0: Clk/1024 1: Clk/16 2: Clk/64 3: Clk/256)"}}}, + { SB_IO_AUD1_TONE_SWEEP, "AUD1_TONE_SWEEP", { + {4, 3, "Sweep Time"}, + {3, 1, "Sweep Increase(0)/Decrease(1)"}, + {0, 3, "Number of sweep shift (n: 0-7)"}, + } }, + {SB_IO_AUD1_LENGTH_DUTY, "AUD1_LENGTH_DUTY", { + {6, 2, "Wave Pattern Duty (Read/Write)"}, + {0, 6, "Sound length data (Write Only) (t1: 0-63)"}, + } }, + { SB_IO_AUD1_VOL_ENV, "AUD1_VOL_ENV", { + {4, 4, "Initial Volume of envelope (0-0Fh) (0=No Sound)"}, + {3, 1, "Envelope Direction (0=Decrease, 1=Increase)"}, + {0, 3, "Number of envelope sweep (n: 0-7)"}, + } }, + { SB_IO_AUD1_FREQ, "AUD1_FREQ", {0}}, + { SB_IO_AUD1_FREQ_HI, "AUD1_FREQ_HI", { + {7, 1, "Initial (1=Restart Sound) (Write Only)"}, + {6, 1, "(1=Stop output when length in NR11 expires)"}, + {0, 3, "Frequency's higher 3 bits (x) (Write Only)"}, + } }, + {SB_IO_AUD2_LENGTH_DUTY, "AUD2_LENGTH_DUTY", { + {6, 2, "Wave Pattern Duty (Read/Write)"}, + {0, 6, "Sound length data (Write Only) (t1: 0-63)"}, + } }, + { SB_IO_AUD2_VOL_ENV, "AUD2_VOL_ENV", { + {4, 4, "Initial Volume of envelope (0-0Fh) (0=No Sound)"}, + {3, 1, "Envelope Direction (0=Decrease, 1=Increase)"}, + {0, 3, "Number of envelope sweep (n: 0-7)"}, + } }, + { SB_IO_AUD2_FREQ, "AUD2_FREQ", {0}}, + { SB_IO_AUD2_FREQ_HI, "AUD2_FREQ_HI", { + {7, 1, "Initial (1=Restart Sound) (Write Only)"}, + {6, 1, "(1=Stop output when length in NR11 expires)"}, + {0, 3, "Frequency's higher 3 bits (x) (Write Only)"}, + } }, + { SB_IO_AUD3_POWER, "AUD3_POWER", {{7, 1, "Sound Channel 3 Enable"}}}, + { SB_IO_AUD3_LENGTH, "AUD3_LENGTH", {0}}, + { SB_IO_AUD3_VOL, "AUD3_VOL", {{5, 2, "Volume (0: Mute 1: 100% 2: 50% 3: 25%)"}}}, + { SB_IO_AUD3_FREQ, "AUD3_FREQ", {0}}, + { SB_IO_AUD3_FREQ_HI, "AUD3_FREQ_HI", { + {7, 1, "Initial (1=Restart Sound) (Write Only)"}, + {6, 1, "(1=Stop output when length in NR11 expires)"}, + {0, 3, "Frequency's higher 3 bits (x) (Write Only)"}, + } }, + { SB_IO_AUD4_LENGTH, "AUD4_LENGTH", {0}}, + { SB_IO_AUD4_VOL_ENV, "AUD4_VOL_ENV", { + {4, 4, "Initial Volume of envelope (0-0Fh) (0=No Sound)"}, + {3, 1, "Envelope Direction (0=Decrease, 1=Increase)"}, + {0, 3, "Number of envelope sweep (n: 0-7)"}, + } }, + { SB_IO_AUD4_POLY, "AUD4_POLY", { + {4, 4, "Shift Clock Frequency (s)"}, + {3, 1, "Counter Step/Width (0=15 bits, 1=7 bits)"}, + {0, 3, "Dividing Ratio of Frequencies (r)"}, + } }, + { SB_IO_AUD4_COUNTER, "AUD4_COUNTER", { + {7, 1, "Initial (1=Restart Sound) (Write Only)"}, + {6, 1, "Counter/consecutive selection (Read/Write)"}, + } }, + {SB_IO_SOUND_OUTPUT_SEL, "SOUND_OUTPUT_SEL", { + {7, 1, "Output sound 4 to SO2 terminal"}, + {6, 1, "Output sound 3 to SO2 terminal"}, + {5, 1, "Output sound 2 to SO2 terminal"}, + {4, 1, "Output sound 1 to SO2 terminal"}, + {3, 1, "Output sound 4 to SO1 terminal"}, + {2, 1, "Output sound 3 to SO1 terminal"}, + {1, 1, "Output sound 2 to SO1 terminal"}, + {0, 1, "Output sound 1 to SO1 terminal"}, + } }, + { SB_IO_SOUND_ON_OFF, "SOUND_ON_OFF", { + {7, 1, "All sound on/off (Read/Write)"}, + {3, 1, "Sound 4 ON flag (Read Only)"}, + {2, 1, "Sound 3 ON flag (Read Only)"}, + {1, 1, "Sound 2 ON flag (Read Only)"}, + {0, 1, "Sound 1 ON flag (Read Only)"}, + } }, + { SB_IO_INTER_F, "INTER_F", { + {0, 1, "VBlank Interrupt"}, + {1, 1, "LCD STAT Interrupt"}, + {2, 1, "Timer Interrupt"}, + {3, 1, "Serial Interrupt"}, + {4, 1, "Joypad Interrupt"}, + } }, + { SB_IO_LCD_CTRL, "LCD_CTRL", { + {7, 1, "LCD and PPU enable 0=Off, 1=On"}, + {6, 1, "Window tile map area 0=9800-9BFF, 1=9C00-9FFF"}, + {5, 1, "Window enable 0=Off, 1=On"}, + {4, 1, "BG and Window tile data area 0=8800-97FF, 1=8000-8FFF"}, + {3, 1, "BG tile map area 0=9800-9BFF, 1=9C00-9FFF"}, + {2, 1, "OBJ size 0=8x8, 1=8x16"}, + {1, 1, "OBJ enable 0=Off, 1=On"}, + {0, 1, "BG and Window enable/priority 0=Off, 1=On"}, + } }, + { SB_IO_LCD_STAT, "LCD_STAT", { + {6, 1, "LYC=LY STAT Interrupt source"}, + {5, 1, "Mode 2 OAM STAT Interrupt source"}, + {4, 1, "Mode 1 VBlank STAT Interrupt source"}, + {3, 1, "Mode 0 HBlank STAT Interrupt source"}, + {2, 1, "LYC=LY Flag"}, + {0, 2, "Mode Flag (0:Hblank 1:Vblank 2:OAM 3:Transfer)"}, + } }, + { SB_IO_LCD_SY, "LCD_SY", {0}}, + { SB_IO_LCD_SX, "LCD_SX", {0}}, + { SB_IO_LCD_LY, "LCD_LY", {0}}, + { SB_IO_LCD_LYC, "LCD_LYC", {0}}, + { SB_IO_OAM_DMA, "OAM_DMA", {0}}, + { SB_IO_PPU_BGP, "PPU_BGP", { + {6, 2, "Color for index 3"}, + {4, 2, "Color for index 2"}, + {2, 2, "Color for index 1"}, + {0, 2, "Color for index 0"}, + } }, + { SB_IO_PPU_OBP0, "PPU_OBP0", { + {6, 2, "Color for index 3"}, + {4, 2, "Color for index 2"}, + {2, 2, "Color for index 1"}, + {0, 2, "Color for index 0"}, + } }, + { SB_IO_PPU_OBP1, "PPU_OBP1", { + {6, 2, "Color for index 3"}, + {4, 2, "Color for index 2"}, + {2, 2, "Color for index 1"}, + {0, 2, "Color for index 0"}, + } }, + { SB_IO_LCD_WY, "LCD_WY", {0}}, + { SB_IO_LCD_WX, "LCD_WX", {0}}, + { SB_IO_GBC_KEY0, "GBC KEY0", {{0, 1, "DMG Mode (0=Normal, 1=DMG Compatible)"}}}, + {SB_IO_GBC_SPEED_SWITCH, "GBC_SPEED_SWITCH", { + {7, 1, "Current Speed (0=Normal, 1=Double) (Read Only)"}, + {0, 1, "Prepare Speed Switch (0=No, 1=Prepare) (Read/Write)"}, + } }, + { SB_IO_GBC_VBK, "GBC_VBK", {{0, 1, "VRAM Bank Sel"}}}, + { SB_IO_BIOS_BANK, "BIOS_BANK", {{0, 8, "BANK VALUE"}}}, + { SB_IO_DMA_SRC_HI, "DMA_SRC_HI", {0}}, + { SB_IO_DMA_SRC_LO, "DMA_SRC_LO", {0}}, + { SB_IO_DMA_DST_HI, "DMA_DST_HI", {0}}, + { SB_IO_DMA_DST_LO, "DMA_DST_LO", {0}}, + { SB_IO_DMA_MODE_LEN, "DMA_MODE_LEN", {{7, 1, "Mode (0: General 1: HDMA)"}, {0, 6, "Length*16B"}}}, + { SB_IO_GBC_BCPS, "GBC_BCPS", {{7, 1, "Auto Increment (0=Disabled, 1=Increment after Writing)"}, {0, 6, "Address ($00-3F)"}}}, + { SB_IO_GBC_BCPD, "GBC_BCPD", {0}}, + { SB_IO_GBC_OCPS, "GBC_OCPS", {{7, 1, "Auto Increment (0=Disabled, 1=Increment after Writing)"}, {0, 6, "Address ($00-3F)"}}}, + { SB_IO_GBC_OCPD, "GBC_OCPD", {0}}, + { SB_IO_GBC_SVBK, "GBC_SVBK", {{0, 3, "WRAM Bank Sel"}}}, + { SB_IO_INTER_EN, "INTER_EN", { + {0, 1, "VBlank Interrupt Enable"}, + {1, 1, "LCD STAT Interrupt Enable"}, + {2, 1, "Timer Interrupt Enable"}, + {3, 1, "Serial Interrupt Enable"}, + {4, 1, "Joypad Interrupt Enable"}, + } }, }; typedef struct { // Registers uint16_t af, bc, de, hl, sp, pc; - bool interrupt_enable; - bool deferred_interrupt_enable; - bool wait_for_interrupt; - bool prefix_op; - bool trigger_breakpoint; - int last_inter_f; - bool branch_taken; - bool halt_bug; + bool interrupt_enable; + bool deferred_interrupt_enable; + bool wait_for_interrupt; + bool prefix_op; + bool trigger_breakpoint; + int last_inter_f; + bool branch_taken; + bool halt_bug; } sb_gb_cpu_t; typedef struct { uint8_t data[65536]; - uint8_t wram[SB_WRAM_NUM_BANKS*SB_WRAM_BANK_SIZE]; + uint8_t wram[SB_WRAM_NUM_BANKS * SB_WRAM_BANK_SIZE]; } sb_gb_mem_t; typedef struct { uint8_t *data; - uint8_t ram_data[MAX_CARTRIDGE_RAM]; - char title[17]; - bool game_boy_color; - bool ram_write_enable; - bool ram_is_dirty; - uint8_t type; - uint8_t mbc_type; - uint8_t mapped_ram_bank; + uint8_t ram_data[MAX_CARTRIDGE_RAM]; + char title[17]; + bool game_boy_color; + bool ram_write_enable; + bool ram_is_dirty; + uint8_t type; + uint8_t mbc_type; + uint8_t mapped_ram_bank; unsigned mapped_rom_bank; - int rom_size; - int ram_size; - bool rumble; - bool has_rumble; - bool bank_mode; //MBC1 + int rom_size; + int ram_size; + bool rumble; + bool has_rumble; + bool bank_mode; // MBC1 } sb_gb_cartridge_t; -typedef struct{ +typedef struct { unsigned int scanline_cycles; unsigned int curr_scanline; unsigned int curr_window_scanline; - uint8_t *framebuffer; - uint8_t vram[SB_VRAM_BANK_SIZE*SB_VRAM_NUM_BANKS]; - uint8_t color_palettes[SB_PPU_BG_COLOR_PALETTES+SB_PPU_SPRITE_COLOR_PALETTES]; - bool in_hblank; //Used for HDMA - bool wy_eq_ly; - bool window_active; - bool latched_window_enable; - bool last_stat_interrupt; - int render_sprites[SB_SPRITES_PER_SCANLINE]; - uint8_t render_sprites_data[SB_SPRITES_PER_SCANLINE][4]; - bool finished_frame; - int sprite_index; - bool render_frame; + uint8_t *framebuffer; + uint8_t vram[SB_VRAM_BANK_SIZE * SB_VRAM_NUM_BANKS]; + uint8_t color_palettes[SB_PPU_BG_COLOR_PALETTES + SB_PPU_SPRITE_COLOR_PALETTES]; + bool in_hblank; // Used for HDMA + bool wy_eq_ly; + bool window_active; + bool latched_window_enable; + bool last_stat_interrupt; + int render_sprites[SB_SPRITES_PER_SCANLINE]; + uint8_t render_sprites_data[SB_SPRITES_PER_SCANLINE][4]; + bool finished_frame; + int sprite_index; + bool render_frame; } sb_lcd_ppu_t; -typedef struct{ - bool in_hblank; - bool active; - int bytes_transferred; - bool oam_dma_active; - int oam_bytes_transferred; +typedef struct { + bool in_hblank; + bool active; + int bytes_transferred; + bool oam_dma_active; + int oam_bytes_transferred; uint32_t oam_dma_activate_fifo; - bool hdma; + bool hdma; } sb_dma_t; -typedef struct{ - uint32_t total_clock_ticks; - bool tima_written; - bool last_tick_tima; - bool last_tick_seq; +typedef struct { + uint32_t total_clock_ticks; + bool tima_written; + bool last_tick_tima; + bool last_tick_seq; } sb_timer_t; -typedef struct{ +typedef struct { uint32_t step_counter; - int32_t length[4]; + int32_t length[4]; uint32_t volume[4]; uint32_t frequency[4]; - int32_t env_direction[4]; //1: increase 0: nochange -1: decrease + int32_t env_direction[4]; // 1: increase 0: nochange -1: decrease uint32_t env_period[4]; uint32_t env_period_timer[4]; - bool env_overflow[4]; - //Only channel 1 + bool env_overflow[4]; + // Only channel 1 uint32_t sweep_period; uint32_t sweep_timer; - int32_t sweep_direction; + int32_t sweep_direction; uint32_t sweep_shift; bool sweep_enable; bool sweep_subtracted; - bool use_length[4]; - bool active[4]; - bool powered[4]; - float chan_t[4]; + bool use_length[4]; + bool active[4]; + bool powered[4]; + float chan_t[4]; uint16_t lfsr4; -}sb_frame_sequencer_t; -typedef struct{ - double current_sim_time; - double current_sample_generated_time; - float capacitor_r; - float capacitor_l; - bool regs_written; - uint8_t curr_wave_data; - uint8_t curr_wave_sample; +} sb_frame_sequencer_t; +typedef struct { + double current_sim_time; + double current_sample_generated_time; + float capacitor_r; + float capacitor_l; + bool regs_written; + uint8_t curr_wave_data; + uint8_t curr_wave_sample; sb_frame_sequencer_t sequencer; - uint32_t wave_sample_offset; - uint32_t wave_freq_timer; -}sb_audio_t; -typedef struct{ - uint32_t ticks_to_complete; - bool last_active; -}sb_serial_t; -typedef struct{ - uint32_t bess_version; + uint32_t wave_sample_offset; + uint32_t wave_freq_timer; +} sb_audio_t; +typedef struct { + uint32_t ticks_to_complete; + bool last_active; +} sb_serial_t; +typedef struct { + uint32_t bess_version; uint16_t af, bc, de, hl, sp, pc; uint16_t interrupt_enable; - uint16_t cart_bank_mode; - uint32_t data_seg; + uint16_t cart_bank_mode; + uint32_t data_seg; uint32_t wram_seg; uint32_t vram_seg; - uint32_t palette_seg; + uint32_t palette_seg; uint32_t mapped_rom_bank; uint32_t mapped_ram_bank; -}sb_gb_bess_info_t; -typedef struct{ - uint8_t sec; - uint8_t min; - uint8_t hour; - uint16_t day; - - uint8_t latched_sec; - uint8_t latched_min; - uint8_t latched_hour; - uint16_t latched_day; - bool has_rtc; -}sb_rtc_t; +} sb_gb_bess_info_t; +typedef struct { + uint8_t sec; + uint8_t min; + uint8_t hour; + uint16_t day; + + uint8_t latched_sec; + uint8_t latched_min; + uint8_t latched_hour; + uint16_t latched_day; + bool has_rtc; +} sb_rtc_t; typedef struct { sb_gb_cartridge_t cart; - sb_gb_cpu_t cpu; - sb_gb_mem_t mem; - sb_lcd_ppu_t lcd; - sb_timer_t timers; - sb_dma_t dma; - sb_audio_t audio; - sb_serial_t serial; - sb_rtc_t rtc; + sb_gb_cpu_t cpu; + sb_gb_mem_t mem; + sb_lcd_ppu_t lcd; + sb_timer_t timers; + sb_dma_t dma; + sb_audio_t audio; + sb_serial_t serial; + sb_rtc_t rtc; sb_gb_bess_info_t bess; - int model; - uint8_t dmg_palette[4*3]; - uint8_t* bios; -} sb_gb_t; + int model; + uint8_t dmg_palette[4 * 3]; + uint8_t *bios; +} sb_gb_t; -typedef struct{ - uint8_t framebuffer[SB_LCD_H*SB_LCD_W*4]; +typedef struct { + uint8_t framebuffer[SB_LCD_H * SB_LCD_W * 4]; uint8_t bios[2304]; - } gb_scratch_t; +} gb_scratch_t; // Return offset to bess structure -static uint32_t sb_save_best_effort_state(sb_gb_t* gb){ +static uint32_t sb_save_best_effort_state(sb_gb_t *gb) { sb_gb_bess_info_t bess; - gb->bess.bess_version = 1; + gb->bess.bess_version = 1; gb->bess.af = gb->cpu.af; gb->bess.bc = gb->cpu.bc; gb->bess.de = gb->cpu.de; @@ -448,370 +424,390 @@ static uint32_t sb_save_best_effort_state(sb_gb_t* gb){ gb->bess.pc = gb->cpu.pc; gb->bess.interrupt_enable = gb->cpu.interrupt_enable; - gb->bess.data_seg = ((uint8_t*)gb->mem.data)-(uint8_t*)gb; - gb->bess.wram_seg = ((uint8_t*)gb->mem.wram)-(uint8_t*)gb; - gb->bess.vram_seg = ((uint8_t*)gb->lcd.vram)-(uint8_t*)gb; - gb->bess.palette_seg = ((uint8_t*)gb->lcd.color_palettes)-(uint8_t*)gb; + gb->bess.data_seg = ((uint8_t *)gb->mem.data) - (uint8_t *)gb; + gb->bess.wram_seg = ((uint8_t *)gb->mem.wram) - (uint8_t *)gb; + gb->bess.vram_seg = ((uint8_t *)gb->lcd.vram) - (uint8_t *)gb; + gb->bess.palette_seg = ((uint8_t *)gb->lcd.color_palettes) - (uint8_t *)gb; gb->bess.mapped_ram_bank = gb->cart.mapped_ram_bank; gb->bess.mapped_rom_bank = gb->cart.mapped_rom_bank; gb->bess.cart_bank_mode = gb->cart.bank_mode; - return ((uint8_t*)&gb->bess)-(uint8_t*)gb; + return ((uint8_t *)&gb->bess) - (uint8_t *)gb; } -static bool sb_load_best_effort_state(sb_gb_t* gb, uint8_t *save_state_data, uint32_t size, uint32_t bess_offset){ - if(bess_offset+sizeof(sb_gb_bess_info_t)>size)return false; - sb_gb_bess_info_t * bess = (sb_gb_bess_info_t*)(save_state_data+bess_offset); - - if(bess->bess_version!=1)return false; - if(bess->data_seg+sizeof(gb->mem.data) > size) return false; - if(bess->wram_seg+sizeof(gb->mem.wram) > size) return false; - if(bess->vram_seg+sizeof(gb->lcd.vram) > size) return false; - if(bess->palette_seg+sizeof(gb->lcd.color_palettes) > size) return false; - - gb->cpu.af = bess->af; - gb->cpu.bc = bess->bc; - gb->cpu.de = bess->de; - gb->cpu.hl = bess->hl; - gb->cpu.sp = bess->sp; - gb->cpu.pc = bess->pc; +static bool sb_load_best_effort_state(sb_gb_t *gb, uint8_t *save_state_data, uint32_t size, uint32_t bess_offset) { + if(bess_offset + sizeof(sb_gb_bess_info_t) > size) return false; + sb_gb_bess_info_t *bess = (sb_gb_bess_info_t *)(save_state_data + bess_offset); + + if(bess->bess_version != 1) return false; + if(bess->data_seg + sizeof(gb->mem.data) > size) return false; + if(bess->wram_seg + sizeof(gb->mem.wram) > size) return false; + if(bess->vram_seg + sizeof(gb->lcd.vram) > size) return false; + if(bess->palette_seg + sizeof(gb->lcd.color_palettes) > size) return false; + + gb->cpu.af = bess->af; + gb->cpu.bc = bess->bc; + gb->cpu.de = bess->de; + gb->cpu.hl = bess->hl; + gb->cpu.sp = bess->sp; + gb->cpu.pc = bess->pc; gb->cpu.interrupt_enable = bess->interrupt_enable; - memcpy(gb->mem.data,save_state_data+bess->data_seg,sizeof(gb->mem.data)); - memcpy(gb->mem.wram,save_state_data+bess->wram_seg,sizeof(gb->mem.wram)); - memcpy(gb->lcd.vram,save_state_data+bess->vram_seg,sizeof(gb->lcd.vram)); - memcpy(gb->lcd.color_palettes,save_state_data+bess->palette_seg,sizeof(gb->lcd.color_palettes)); + memcpy(gb->mem.data, save_state_data + bess->data_seg, sizeof(gb->mem.data)); + memcpy(gb->mem.wram, save_state_data + bess->wram_seg, sizeof(gb->mem.wram)); + memcpy(gb->lcd.vram, save_state_data + bess->vram_seg, sizeof(gb->lcd.vram)); + memcpy(gb->lcd.color_palettes, save_state_data + bess->palette_seg, sizeof(gb->lcd.color_palettes)); gb->cart.mapped_ram_bank = bess->mapped_ram_bank; gb->cart.mapped_rom_bank = bess->mapped_rom_bank; gb->cart.bank_mode = bess->cart_bank_mode; - return true; + return true; } -typedef void (*sb_opcode_impl_t)(sb_gb_t*,int op1,int op2, int op1_enum, int op2_enum, const uint8_t * flag_mask); +typedef void (*sb_opcode_impl_t)(sb_gb_t *, int op1, int op2, int op1_enum, int op2_enum, const uint8_t *flag_mask); -//Include down here because of dependence on sb_gb_t /*TODO: refactor this*/ +// Include down here because of dependence on sb_gb_t /*TODO: refactor this*/ #include "sb_instr_tables.h" -uint32_t sb_lookup_tile(sb_gb_t* gb, int px, int py, int tile_base, int data_mode); -void sb_lookup_palette_color(sb_gb_t*gb,int color_id, int*r, int *g, int *b); -static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t*emu, double delta_time,int cycles); -static void sb_tick_frame_seq(sb_gb_t*gb,sb_frame_sequencer_t* seq); -static void sb_process_audio_writes(sb_gb_t* gb); -static bool sb_run_ar_cheat(sb_gb_t* gb, const uint32_t* buffer, uint32_t size); -void sb_draw_pixel(sb_emu_state_t*emu,sb_gb_t* gb, int x, int y); +uint32_t sb_lookup_tile(sb_gb_t *gb, int px, int py, int tile_base, int data_mode); +void sb_lookup_palette_color(sb_gb_t *gb, int color_id, int *r, int *g, int *b); +static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t *emu, double delta_time, int cycles); +static void sb_tick_frame_seq(sb_gb_t *gb, sb_frame_sequencer_t *seq); +static void sb_process_audio_writes(sb_gb_t *gb); +static bool sb_run_ar_cheat(sb_gb_t *gb, const uint32_t *buffer, uint32_t size); +void sb_draw_pixel(sb_emu_state_t *emu, sb_gb_t *gb, int x, int y); -static FORCE_INLINE uint8_t sb_read8_io(sb_gb_t*gb, int addr){return gb->mem.data[addr];} -static FORCE_INLINE void sb_store8_io(sb_gb_t*gb, int addr, int value){gb->mem.data[addr]=value;} +static FORCE_INLINE uint8_t sb_read8_io(sb_gb_t *gb, int addr) { return gb->mem.data[addr]; } +static FORCE_INLINE void sb_store8_io(sb_gb_t *gb, int addr, int value) { gb->mem.data[addr] = value; } static FORCE_INLINE uint8_t sb_read8_direct(sb_gb_t *gb, int addr) { - if(addr>=0x0000&&addr<=0x3fff){ - if(addr<256||(addr>=512&&addr<2304)){ - if(!sb_read8_io(gb,SB_IO_BIOS_BANK))return gb->bios[addr]; + if(addr >= 0x0000 && addr <= 0x3fff) { + if(addr < 256 || (addr >= 512 && addr < 2304)) { + if(!sb_read8_io(gb, SB_IO_BIOS_BANK)) return gb->bios[addr]; } - int cart_addr = SB_BFE(addr,0,14); - if(gb->cart.bank_mode&&gb->cart.mbc_type==SB_MBC_MBC1){ - cart_addr|=SB_BFE(gb->cart.mapped_ram_bank,0,2)<<19; + int cart_addr = SB_BFE(addr, 0, 14); + if(gb->cart.bank_mode && gb->cart.mbc_type == SB_MBC_MBC1) { + cart_addr |= SB_BFE(gb->cart.mapped_ram_bank, 0, 2) << 19; } - cart_addr%= (gb->cart.rom_size); + cart_addr %= (gb->cart.rom_size); return gb->cart.data[cart_addr]; - }else if(addr>=0x4000&&addr<=0x7fff){ - int cart_addr = SB_BFE(addr,0,14); - cart_addr|=(gb->cart.mapped_rom_bank)<<14; - if(gb->cart.mbc_type==SB_MBC_MBC1){ - cart_addr|=SB_BFE(gb->cart.mapped_ram_bank,0,2)<<19; + } else if(addr >= 0x4000 && addr <= 0x7fff) { + int cart_addr = SB_BFE(addr, 0, 14); + cart_addr |= (gb->cart.mapped_rom_bank) << 14; + if(gb->cart.mbc_type == SB_MBC_MBC1) { + cart_addr |= SB_BFE(gb->cart.mapped_ram_bank, 0, 2) << 19; } - cart_addr%= (gb->cart.rom_size); + cart_addr %= (gb->cart.rom_size); return gb->cart.data[cart_addr]; - }else if(addr>=0x8000&&addr<=0x9fff){ - uint8_t vbank =sb_read8_io(gb,SB_IO_GBC_VBK)%SB_VRAM_NUM_BANKS; - uint8_t data =gb->lcd.vram[vbank*SB_VRAM_BANK_SIZE+addr-0x8000]; + } else if(addr >= 0x8000 && addr <= 0x9fff) { + uint8_t vbank = sb_read8_io(gb, SB_IO_GBC_VBK) % SB_VRAM_NUM_BANKS; + uint8_t data = gb->lcd.vram[vbank * SB_VRAM_BANK_SIZE + addr - 0x8000]; return data; - } else if(addr>=0xA000&&addr<=0xBfff){ - if(!gb->cart.ram_write_enable)return 0xff; - if(gb->rtc.has_rtc&&gb->cart.mbc_type==SB_MBC_MBC3){ - switch(gb->cart.mapped_ram_bank){ - case 0x08: return gb->rtc.latched_sec; - case 0x09: return gb->rtc.latched_min; - case 0x0A: return gb->rtc.latched_hour; - case 0x0B: return gb->rtc.latched_day&0xff; - case 0x0C: return SB_BFE(gb->rtc.latched_day,8,1); + } else if(addr >= 0xA000 && addr <= 0xBfff) { + if(!gb->cart.ram_write_enable) return 0xff; + if(gb->rtc.has_rtc && gb->cart.mbc_type == SB_MBC_MBC3) { + switch(gb->cart.mapped_ram_bank) { + case 0x08: return gb->rtc.latched_sec; + case 0x09: return gb->rtc.latched_min; + case 0x0A: return gb->rtc.latched_hour; + case 0x0B: return gb->rtc.latched_day & 0xff; + case 0x0C: return SB_BFE(gb->rtc.latched_day, 8, 1); } } - if(gb->cart.ram_size==0)return 0xff; - int ram_addr_off = 0x2000*gb->cart.mapped_ram_bank+(addr-0xA000); - if(gb->cart.mbc_type==SB_MBC_MBC1){ - ram_addr_off = SB_BFE(addr,0,13); - if(gb->cart.bank_mode)ram_addr_off|= SB_BFE(gb->cart.mapped_ram_bank,0,2)<<13; + if(gb->cart.ram_size == 0) return 0xff; + int ram_addr_off = 0x2000 * gb->cart.mapped_ram_bank + (addr - 0xA000); + if(gb->cart.mbc_type == SB_MBC_MBC1) { + ram_addr_off = SB_BFE(addr, 0, 13); + if(gb->cart.bank_mode) ram_addr_off |= SB_BFE(gb->cart.mapped_ram_bank, 0, 2) << 13; } - ram_addr_off%=gb->cart.ram_size; + ram_addr_off %= gb->cart.ram_size; return gb->cart.ram_data[ram_addr_off]; - }else if(addr>=0xD000&&addr<=0xDfff){ - int bank =gb->mem.data[SB_IO_GBC_SVBK]%SB_WRAM_NUM_BANKS; - if(bank==0)bank = 1; - int ram_addr_off = 0x1000*bank+(addr-0xd000); + } else if(addr >= 0xD000 && addr <= 0xDfff) { + int bank = gb->mem.data[SB_IO_GBC_SVBK] % SB_WRAM_NUM_BANKS; + if(bank == 0) bank = 1; + int ram_addr_off = 0x1000 * bank + (addr - 0xd000); return gb->mem.wram[ram_addr_off]; - }else if(addr>=0xe000 && addr<=0xfdff){ - //Echo Ram - addr =addr - 0xe000 + 0xc000; - }else if(addr>=0xfe00&&addr<=0xfe9f){ - //OAM not accessible during OAM DMA. - if(gb->dma.oam_dma_active)return 0xff; + } else if(addr >= 0xe000 && addr <= 0xfdff) { + // Echo Ram + addr = addr - 0xe000 + 0xc000; + } else if(addr >= 0xfe00 && addr <= 0xfe9f) { + // OAM not accessible during OAM DMA. + if(gb->dma.oam_dma_active) return 0xff; } return gb->mem.data[addr]; } -bool sb_gbc_enable(sb_gb_t*gb){ - return (gb->mem.data[SB_IO_GBC_KEY0]!=0x4||!gb->mem.data[SB_IO_BIOS_BANK])&&gb->model==SB_GBC; +bool sb_gbc_enable(sb_gb_t *gb) { + return (gb->mem.data[SB_IO_GBC_KEY0] != 0x4 || !gb->mem.data[SB_IO_BIOS_BANK]) && gb->model == SB_GBC; } -uint8_t sb_io_or_mask(sb_gb_t* gb, int addr){ +uint8_t sb_io_or_mask(sb_gb_t *gb, int addr) { bool gbc_en = sb_gbc_enable(gb); - if(addr>=SB_IO_AUD1_TONE_SWEEP&&addr=0xff4c&&addr<=0xff7f&&!gbc_en)|| - (addr>=0xff71&&addr<=0xff7f&&gbc_en)){ + if(addr >= SB_IO_AUD1_TONE_SWEEP && addr < SB_IO_AUD3_WAVE_BASE + 16) { + uint8_t audio_reg_mask_table[] = { + 0x80, 0x3F, 0x00, 0xFF, 0xBF, // NR10-NR15 + 0xFF, 0x3F, 0x00, 0xFF, 0xBF, // NR20-NR25 + 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, // NR30-NR35 + 0xFF, 0xFF, 0x00, 0x00, 0xBF, // NR40-NR45 + 0x00, 0x00, 0x70, // NR50-NR52 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Wave RAM + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return audio_reg_mask_table[addr - SB_IO_AUD1_TONE_SWEEP]; + } else if(addr == SB_IO_INTER_F) + return 0xE0; + else if(addr == SB_IO_LCD_STAT) + return 0x80; + else if(addr == SB_IO_TAC) + return 0xf8; + else if(addr == SB_IO_SERIAL_CTRL) + return 0x7e; + else if(addr == SB_IO_JOYPAD) + return 0xc0; + else if(addr == 0xFF03 || addr == 0xFF08 || addr == 0xFF09 || addr == 0xFF0A || + addr == 0xFF0B || addr == 0xFF0C || addr == 0xFF0D || addr == 0xFF0E || + addr == 0xFF15 || addr == 0xFF1F || addr == 0xFF27 || addr == 0xFF28 || + addr == 0xFF29 || + (addr >= 0xff4c && addr <= 0xff7f && !gbc_en) || + (addr >= 0xff71 && addr <= 0xff7f && gbc_en)) { return 0xff; } - return 0; + return 0; } uint8_t sb_read8(sb_gb_t *gb, int addr) { - //if(addr == 0xff44)return 0x90; - //if(addr == 0xff80)gb->cpu.trigger_breakpoint=true; - //Only high ram is accessible during oam_dma - if(addr >=0xff00){ - if(addr == SB_IO_GBC_BCPS){ + // if(addr == 0xff44)return 0x90; + // if(addr == 0xff80)gb->cpu.trigger_breakpoint=true; + // Only high ram is accessible during oam_dma + if(addr >= 0xff00) { + if(addr == SB_IO_GBC_BCPS) { uint8_t bcps = sb_read8_io(gb, SB_IO_GBC_BCPS); - return bcps|(1<<6)|sb_io_or_mask(gb,addr); - }else if(addr == SB_IO_GBC_BCPD){ + return bcps | (1 << 6) | sb_io_or_mask(gb, addr); + } else if(addr == SB_IO_GBC_BCPD) { uint8_t bcps = sb_read8_io(gb, SB_IO_GBC_BCPS); - uint8_t index = SB_BFE(bcps,0,6); - return gb->lcd.color_palettes[index]|sb_io_or_mask(gb,addr); - }else if(addr == SB_IO_GBC_OCPD){ + uint8_t index = SB_BFE(bcps, 0, 6); + return gb->lcd.color_palettes[index] | sb_io_or_mask(gb, addr); + } else if(addr == SB_IO_GBC_OCPD) { uint8_t ocps = sb_read8_io(gb, SB_IO_GBC_OCPS); - uint8_t index = SB_BFE(ocps,0,6); - return gb->lcd.color_palettes[index+SB_PPU_BG_COLOR_PALETTES]|sb_io_or_mask(gb,addr); - }else if (addr == SB_IO_GBC_VBK){ - uint8_t d= sb_read8_direct(gb,addr); - return d|0xfe|sb_io_or_mask(gb,addr); - }else if(addr>=SB_IO_AUD3_WAVE_BASE&&addrlcd.color_palettes[index + SB_PPU_BG_COLOR_PALETTES] | sb_io_or_mask(gb, addr); + } else if(addr == SB_IO_GBC_VBK) { + uint8_t d = sb_read8_direct(gb, addr); + return d | 0xfe | sb_io_or_mask(gb, addr); + } else if(addr >= SB_IO_AUD3_WAVE_BASE && addr < SB_IO_AUD3_WAVE_BASE + 16) { + bool wave_active = SB_BFE(sb_read8_io(gb, SB_IO_SOUND_ON_OFF), 2, 1); + if(wave_active) { return gb->audio.curr_wave_data; } } - return sb_read8_direct(gb,addr)|sb_io_or_mask(gb,addr); + return sb_read8_direct(gb, addr) | sb_io_or_mask(gb, addr); } - return sb_read8_direct(gb,addr); + return sb_read8_direct(gb, addr); } static FORCE_INLINE void sb_store8_direct(sb_gb_t *gb, int addr, int value) { - if(addr>=0x8000&&addr<=0x9fff){ - uint8_t vbank =sb_read8_io(gb, SB_IO_GBC_VBK)%SB_VRAM_NUM_BANKS;; - gb->lcd.vram[vbank*SB_VRAM_BANK_SIZE+addr-0x8000]=value; + if(addr >= 0x8000 && addr <= 0x9fff) { + uint8_t vbank = sb_read8_io(gb, SB_IO_GBC_VBK) % SB_VRAM_NUM_BANKS; + ; + gb->lcd.vram[vbank * SB_VRAM_BANK_SIZE + addr - 0x8000] = value; return; - }else if(addr>=0xA000&&addr<=0xBfff){ - if(gb->cart.ram_write_enable&&gb->cart.ram_size){ - int ram_addr_off = SB_BFE(addr,0,13); - if(gb->cart.mbc_type==SB_MBC_MBC1){ - if(gb->cart.bank_mode)ram_addr_off|= SB_BFE(gb->cart.mapped_ram_bank,0,2)<<13; - }else ram_addr_off|= gb->cart.mapped_ram_bank<<13; - ram_addr_off%=gb->cart.ram_size; - gb->cart.ram_data[ram_addr_off]=value; + } else if(addr >= 0xA000 && addr <= 0xBfff) { + if(gb->cart.ram_write_enable && gb->cart.ram_size) { + int ram_addr_off = SB_BFE(addr, 0, 13); + if(gb->cart.mbc_type == SB_MBC_MBC1) { + if(gb->cart.bank_mode) ram_addr_off |= SB_BFE(gb->cart.mapped_ram_bank, 0, 2) << 13; + } else + ram_addr_off |= gb->cart.mapped_ram_bank << 13; + ram_addr_off %= gb->cart.ram_size; + gb->cart.ram_data[ram_addr_off] = value; gb->cart.ram_is_dirty = true; - //printf("RAM WRITE: MEM[%04x, %04x] = %02x B:%d BM:%d\n",addr,ram_addr_off,value, gb->cart.mapped_ram_bank,gb->cart.bank_mode); + // printf("RAM WRITE: MEM[%04x, %04x] = %02x B:%d BM:%d\n",addr,ram_addr_off,value, gb->cart.mapped_ram_bank,gb->cart.bank_mode); } return; - }else if(addr>=0xD000&&addr<=0xDfff){ - int bank =gb->mem.data[SB_IO_GBC_SVBK]%SB_WRAM_NUM_BANKS; - if(bank==0)bank = 1; - int ram_addr_off = 0x1000*bank+(addr-0xd000); - gb->mem.wram[ram_addr_off]=value; + } else if(addr >= 0xD000 && addr <= 0xDfff) { + int bank = gb->mem.data[SB_IO_GBC_SVBK] % SB_WRAM_NUM_BANKS; + if(bank == 0) bank = 1; + int ram_addr_off = 0x1000 * bank + (addr - 0xd000); + gb->mem.wram[ram_addr_off] = value; return; - }else if(addr>=0xe000 && addr<=0xfdff){ - //Echo Ram - addr =addr - 0xe000 + 0xc000; + } else if(addr >= 0xe000 && addr <= 0xfdff) { + // Echo Ram + addr = addr - 0xe000 + 0xc000; } - if(addr<=0x7fff){ - //printf("Attempt to write to rom address %x\n",addr); - //gb->cpu.trigger_breakpoint=true; + if(addr <= 0x7fff) { + // printf("Attempt to write to rom address %x\n",addr); + // gb->cpu.trigger_breakpoint=true; return; } - gb->mem.data[addr]=value; + gb->mem.data[addr] = value; } void sb_store8(sb_gb_t *gb, int addr, int value) { - if(addr>=0xff00){ - if(!sb_gbc_enable(gb) &&addr>=0xff4C&&addr<=0xff7f&&addr!=SB_IO_BIOS_BANK)return; - if(addr == SB_IO_DMA_SRC_LO ||addr == SB_IO_DMA_DST_LO){ - value&=~0xf; - } else if(addr == SB_IO_DMA_MODE_LEN){ - if(gb->dma.active){ + if(addr >= 0xff00) { + if(!sb_gbc_enable(gb) && addr >= 0xff4C && addr <= 0xff7f && addr != SB_IO_BIOS_BANK) return; + if(addr == SB_IO_DMA_SRC_LO || addr == SB_IO_DMA_DST_LO) { + value &= ~0xf; + } else if(addr == SB_IO_DMA_MODE_LEN) { + if(gb->dma.active) { // Writing bit 7 to 0 for a running transfer halts HDMA - if(!(value&0x80)){ + if(!(value & 0x80)) { gb->dma.active = false; - value|=0x80; + value |= 0x80; } - }else{ - gb->dma.active =true; - gb->dma.bytes_transferred=0; - gb->dma.hdma = (value&0x80)!=0; + } else { + gb->dma.active = true; + gb->dma.bytes_transferred = 0; + gb->dma.hdma = (value & 0x80) != 0; gb->dma.in_hblank = false; - value&=0x7f; - uint16_t dma_src = sb_read8_io(gb,SB_IO_DMA_SRC_LO)| - ((int)sb_read8_io(gb,SB_IO_DMA_SRC_HI)<<8u); - uint16_t dma_dst = sb_read8_io(gb,SB_IO_DMA_DST_LO)| - ((int)sb_read8_io(gb,SB_IO_DMA_DST_HI)<<8u); + value &= 0x7f; + uint16_t dma_src = sb_read8_io(gb, SB_IO_DMA_SRC_LO) | + ((int)sb_read8_io(gb, SB_IO_DMA_SRC_HI) << 8u); + uint16_t dma_dst = sb_read8_io(gb, SB_IO_DMA_DST_LO) | + ((int)sb_read8_io(gb, SB_IO_DMA_DST_HI) << 8u); } } - if(addr == SB_IO_OAM_DMA){ - gb->dma.oam_dma_activate_fifo|=1<<(2); - }else if(addr == SB_IO_GBC_BCPD){ + if(addr == SB_IO_OAM_DMA) { + gb->dma.oam_dma_activate_fifo |= 1 << (2); + } else if(addr == SB_IO_GBC_BCPD) { uint8_t bcps = sb_read8_io(gb, SB_IO_GBC_BCPS); - uint8_t index = SB_BFE(bcps,0,6); - bool autoindex = SB_BFE(bcps,7,1); - //Palette cannot be written to in mode 2 or 3 - int stat = sb_read8_io(gb, SB_IO_LCD_STAT)&0x3; - if(stat!=3) gb->lcd.color_palettes[index] = value; - if(autoindex){ + uint8_t index = SB_BFE(bcps, 0, 6); + bool autoindex = SB_BFE(bcps, 7, 1); + // Palette cannot be written to in mode 2 or 3 + int stat = sb_read8_io(gb, SB_IO_LCD_STAT) & 0x3; + if(stat != 3) gb->lcd.color_palettes[index] = value; + if(autoindex) { index++; - sb_store8_io(gb,SB_IO_GBC_BCPS,(index&0x3f)|0xC0); + sb_store8_io(gb, SB_IO_GBC_BCPS, (index & 0x3f) | 0xC0); } - }else if(addr == SB_IO_GBC_OCPD){ + } else if(addr == SB_IO_GBC_OCPD) { uint8_t ocps = sb_read8_io(gb, SB_IO_GBC_OCPS); - uint8_t index = SB_BFE(ocps,0,6); - bool autoindex = SB_BFE(ocps,7,1); - int stat = sb_read8_io(gb, SB_IO_LCD_STAT)&0x3; - if(stat!=3) gb->lcd.color_palettes[index+SB_PPU_BG_COLOR_PALETTES] = value; - if(autoindex){ + uint8_t index = SB_BFE(ocps, 0, 6); + bool autoindex = SB_BFE(ocps, 7, 1); + int stat = sb_read8_io(gb, SB_IO_LCD_STAT) & 0x3; + if(stat != 3) gb->lcd.color_palettes[index + SB_PPU_BG_COLOR_PALETTES] = value; + if(autoindex) { index++; - sb_store8_io(gb,SB_IO_GBC_OCPS,(index&0x3f)|0x80); + sb_store8_io(gb, SB_IO_GBC_OCPS, (index & 0x3f) | 0x80); } - }else if(addr == SB_IO_DIV){ + } else if(addr == SB_IO_DIV) { gb->timers.total_clock_ticks = 4; - }else if(addr == SB_IO_SERIAL_BYTE){ - printf("%c",(char)value); - }else if(addr>=SB_IO_AUD1_TONE_SWEEP&&addr= SB_IO_AUD1_TONE_SWEEP && addr < SB_IO_AUD3_WAVE_BASE + 16) { sb_frame_sequencer_t *seq = &gb->audio.sequencer; - int i = (addr-SB_IO_AUD1_LENGTH_DUTY)/5; - if(addr==SB_IO_SOUND_ON_OFF){ - value&=0xf0; - value|=sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf; + int i = (addr - SB_IO_AUD1_LENGTH_DUTY) / 5; + if(addr == SB_IO_SOUND_ON_OFF) { + value &= 0xf0; + value |= sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf; } - if(addr>=SB_IO_AUD3_WAVE_BASE&&addraudio.wave_sample_offset)%32)/2; + if(addr >= SB_IO_AUD3_WAVE_BASE && addr < SB_IO_AUD3_WAVE_BASE + 16) { + bool wave_active = SB_BFE(sb_read8_io(gb, SB_IO_SOUND_ON_OFF), 2, 1); + if(wave_active) { + // Addr locked to the read pointer when the wave channel is active + addr = SB_IO_AUD3_WAVE_BASE + ((gb->audio.wave_sample_offset) % 32) / 2; } } - if(addr==SB_IO_AUD1_LENGTH_DUTY||addr==SB_IO_AUD2_LENGTH_DUTY||addr==SB_IO_AUD3_LENGTH||addr==SB_IO_AUD4_LENGTH){ + if(addr == SB_IO_AUD1_LENGTH_DUTY || addr == SB_IO_AUD2_LENGTH_DUTY || addr == SB_IO_AUD3_LENGTH || addr == SB_IO_AUD4_LENGTH) { uint8_t length_duty = value; - if(i==2) gb->audio.sequencer.length[i] = 256-SB_BFE(length_duty,0,8); - else gb->audio.sequencer.length[i] = 64-SB_BFE(length_duty,0,6); - }else if(addr==SB_IO_AUD1_VOL_ENV||addr==SB_IO_AUD2_VOL_ENV||addr==SB_IO_AUD4_VOL_ENV){ - bool power = SB_BFE(value,3,5)!=0; - gb->audio.sequencer.powered[i]= power; - gb->audio.sequencer.active[i]&=power; - gb->audio.sequencer.env_direction[i] = (SB_BFE(value,3,1)?1:-1); - gb->audio.sequencer.env_period[i] = SB_BFE(value,0,3); - if (gb->audio.sequencer.env_period[i]== 0 &&!gb->audio.sequencer.env_overflow[i]) { + if(i == 2) + gb->audio.sequencer.length[i] = 256 - SB_BFE(length_duty, 0, 8); + else + gb->audio.sequencer.length[i] = 64 - SB_BFE(length_duty, 0, 6); + } else if(addr == SB_IO_AUD1_VOL_ENV || addr == SB_IO_AUD2_VOL_ENV || addr == SB_IO_AUD4_VOL_ENV) { + bool power = SB_BFE(value, 3, 5) != 0; + gb->audio.sequencer.powered[i] = power; + gb->audio.sequencer.active[i] &= power; + gb->audio.sequencer.env_direction[i] = (SB_BFE(value, 3, 1) ? 1 : -1); + gb->audio.sequencer.env_period[i] = SB_BFE(value, 0, 3); + if(gb->audio.sequencer.env_period[i] == 0 && !gb->audio.sequencer.env_overflow[i]) { gb->audio.sequencer.volume[i] = (gb->audio.sequencer.volume[i] + 1) & 0xf; } - }else if( addr==SB_IO_AUD1_FREQ||addr==SB_IO_AUD1_FREQ_HI|| - addr==SB_IO_AUD2_FREQ||addr==SB_IO_AUD2_FREQ_HI|| - addr==SB_IO_AUD3_FREQ||addr==SB_IO_AUD3_FREQ_HI - ){ - sb_store8_direct(gb,addr,value); - uint8_t freq_lo = sb_read8_io(gb,SB_IO_AUD1_FREQ+i*5); - uint8_t freq_hi = sb_read8_io(gb,SB_IO_AUD1_FREQ_HI+i*5); - seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi,0,3))<<8u); + } else if(addr == SB_IO_AUD1_FREQ || addr == SB_IO_AUD1_FREQ_HI || + addr == SB_IO_AUD2_FREQ || addr == SB_IO_AUD2_FREQ_HI || + addr == SB_IO_AUD3_FREQ || addr == SB_IO_AUD3_FREQ_HI) { + sb_store8_direct(gb, addr, value); + uint8_t freq_lo = sb_read8_io(gb, SB_IO_AUD1_FREQ + i * 5); + uint8_t freq_hi = sb_read8_io(gb, SB_IO_AUD1_FREQ_HI + i * 5); + seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi, 0, 3)) << 8u); } - sb_store8_direct(gb,addr,value); + sb_store8_direct(gb, addr, value); sb_process_audio_writes(gb); return; - }else if(addr==SB_IO_BIOS_BANK){value|= sb_read8_io(gb,SB_IO_BIOS_BANK); - }else if(addr==SB_IO_GBC_KEY0){if(sb_read8_io(gb,SB_IO_BIOS_BANK))return; - }else if(addr==SB_IO_GBC_SPEED_SWITCH){ - value&=0x1; - value|=sb_read8_io(gb,SB_IO_GBC_SPEED_SWITCH)&0xfe; + } else if(addr == SB_IO_BIOS_BANK) { + value |= sb_read8_io(gb, SB_IO_BIOS_BANK); + } else if(addr == SB_IO_GBC_KEY0) { + if(sb_read8_io(gb, SB_IO_BIOS_BANK)) return; + } else if(addr == SB_IO_GBC_SPEED_SWITCH) { + value &= 0x1; + value |= sb_read8_io(gb, SB_IO_GBC_SPEED_SWITCH) & 0xfe; } - }else if(addr >= 0x0000 && addr <=0x1fff){ - gb->cart.ram_write_enable = (value&0xf)==0xA; + } else if(addr >= 0x0000 && addr <= 0x1fff) { + gb->cart.ram_write_enable = (value & 0xf) == 0xA; return; - }else if(addr >= 0x2000 && addr <=0x3fff){ - //MBC3 rombank select - switch(gb->cart.mbc_type){ - case SB_MBC_MBC1: gb->cart.mapped_rom_bank=value%32; if(!gb->cart.mapped_rom_bank)gb->cart.mapped_rom_bank=1;break; - case SB_MBC_MBC2: gb->cart.mapped_rom_bank=value%16; if(!gb->cart.mapped_rom_bank)gb->cart.mapped_rom_bank=1;break; - case SB_MBC_MBC3: gb->cart.mapped_rom_bank=value%256;if(!gb->cart.mapped_rom_bank)gb->cart.mapped_rom_bank=1;break; - case SB_MBC_MBC5: - case SB_MBC_MBC7: - if(addr>=0x3000){ - gb->cart.mapped_rom_bank&=0xff; - gb->cart.mapped_rom_bank|= (int)(value&1)<<8; - }else gb->cart.mapped_rom_bank=(gb->cart.mapped_rom_bank&0x100)|value; + } else if(addr >= 0x2000 && addr <= 0x3fff) { + // MBC3 rombank select + switch(gb->cart.mbc_type) { + case SB_MBC_MBC1: + gb->cart.mapped_rom_bank = value % 32; + if(!gb->cart.mapped_rom_bank) gb->cart.mapped_rom_bank = 1; + break; + case SB_MBC_MBC2: + gb->cart.mapped_rom_bank = value % 16; + if(!gb->cart.mapped_rom_bank) gb->cart.mapped_rom_bank = 1; + break; + case SB_MBC_MBC3: + gb->cart.mapped_rom_bank = value % 256; + if(!gb->cart.mapped_rom_bank) gb->cart.mapped_rom_bank = 1; + break; + case SB_MBC_MBC5: + case SB_MBC_MBC7: + if(addr >= 0x3000) { + gb->cart.mapped_rom_bank &= 0xff; + gb->cart.mapped_rom_bank |= (int)(value & 1) << 8; + } else + gb->cart.mapped_rom_bank = (gb->cart.mapped_rom_bank & 0x100) | value; break; - } + } return; - }else if(addr >= 0x4000 && addr <=0x5fff){ + } else if(addr >= 0x4000 && addr <= 0x5fff) { gb->cart.rumble = false; - if((value&(1<<3))&&gb->cart.has_rumble)gb->cart.rumble=true; - //MBC3 rombank select - //TODO implement other mappers - if(gb->cart.mbc_type!=SB_MBC_MBC1&&gb->cart.ram_size){ - if(gb->cart.mbc_type!=SB_MBC_MBC3)value %= (gb->cart.ram_size/0x2000); - }else value%=4; + if((value & (1 << 3)) && gb->cart.has_rumble) gb->cart.rumble = true; + // MBC3 rombank select + // TODO implement other mappers + if(gb->cart.mbc_type != SB_MBC_MBC1 && gb->cart.ram_size) { + if(gb->cart.mbc_type != SB_MBC_MBC3) value %= (gb->cart.ram_size / 0x2000); + } else + value %= 4; gb->cart.mapped_ram_bank = value; return; - }else if (addr>=0xfe00 && addr<=0xfe9f ){ - //OAM cannot be written to in mode 2 and 3 - int stat = sb_read8_io(gb, SB_IO_LCD_STAT)&0x3; - if(stat>=2) return; - } else if(addr>=0x6000&&addr<=0x7fff){ - if(gb->cart.mbc_type==SB_MBC_MBC1){ - gb->cart.bank_mode = SB_BFE(value,0,1); + } else if(addr >= 0xfe00 && addr <= 0xfe9f) { + // OAM cannot be written to in mode 2 and 3 + int stat = sb_read8_io(gb, SB_IO_LCD_STAT) & 0x3; + if(stat >= 2) return; + } else if(addr >= 0x6000 && addr <= 0x7fff) { + if(gb->cart.mbc_type == SB_MBC_MBC1) { + gb->cart.bank_mode = SB_BFE(value, 0, 1); } - if(gb->cart.mbc_type==SB_MBC_MBC3&&gb->rtc.has_rtc&&SB_BFE(value,0,1)){ + if(gb->cart.mbc_type == SB_MBC_MBC3 && gb->rtc.has_rtc && SB_BFE(value, 0, 1)) { gb->rtc.latched_sec = gb->rtc.sec; gb->rtc.latched_min = gb->rtc.min; - gb->rtc.latched_hour= gb->rtc.hour; + gb->rtc.latched_hour = gb->rtc.hour; gb->rtc.latched_day = gb->rtc.day; } - }else if (addr>=0x8000 && addr <=0x9fff){ - //VRAM cannot be writen to in mode 3 - int stat = sb_read8_io(gb, SB_IO_LCD_STAT)&0x3; - if(stat>=3) return; + } else if(addr >= 0x8000 && addr <= 0x9fff) { + // VRAM cannot be writen to in mode 3 + int stat = sb_read8_io(gb, SB_IO_LCD_STAT) & 0x3; + if(stat >= 3) return; } - sb_store8_direct(gb,addr,value); + sb_store8_direct(gb, addr, value); } void sb_store16(sb_gb_t *gb, int addr, unsigned int value) { - sb_store8(gb,addr,value&0xff); - sb_store8(gb,addr+1,((value>>8u)&0xff)); + sb_store8(gb, addr, value & 0xff); + sb_store8(gb, addr + 1, ((value >> 8u) & 0xff)); } uint16_t sb_read16(sb_gb_t *gb, int addr) { - uint16_t g = sb_read8(gb,addr+1); - g<<=8; - g|= sb_read8(gb,addr+0); + uint16_t g = sb_read8(gb, addr + 1); + g <<= 8; + g |= sb_read8(gb, addr + 0); return g; } -void sb_update_joypad_io_reg(sb_emu_state_t* state, sb_gb_t*gb){ +void sb_update_joypad_io_reg(sb_emu_state_t *state, sb_gb_t *gb) { // FF00 - P1/JOYP - Joypad (R/W) // // Bit 7 - Not used @@ -823,797 +819,825 @@ void sb_update_joypad_io_reg(sb_emu_state_t* state, sb_gb_t*gb){ // Bit 1 - P11 Input: Left or B (0=Pressed) (Read Only) // Bit 0 - P10 Input: Right or A (0=Pressed) (Read Only) - uint8_t data_dir = ((!(state->joy.inputs[SE_KEY_DOWN]>0.3))<<3)| - ((!(state->joy.inputs[SE_KEY_UP]>0.3))<<2) | - ((!(state->joy.inputs[SE_KEY_LEFT]>0.3))<<1)| - ((!(state->joy.inputs[SE_KEY_RIGHT]>0.3))); - uint8_t data_action = ((!(state->joy.inputs[SE_KEY_START]>0.3))<<3)| - ((!(state->joy.inputs[SE_KEY_SELECT]>0.3))<<2)| - ((!(state->joy.inputs[SE_KEY_B]>0.3))<<1)| - (!(state->joy.inputs[SE_KEY_A]>0.3)); + uint8_t data_dir = ((!(state->joy.inputs[SE_KEY_DOWN] > 0.3)) << 3) | + ((!(state->joy.inputs[SE_KEY_UP] > 0.3)) << 2) | + ((!(state->joy.inputs[SE_KEY_LEFT] > 0.3)) << 1) | + ((!(state->joy.inputs[SE_KEY_RIGHT] > 0.3))); + uint8_t data_action = ((!(state->joy.inputs[SE_KEY_START] > 0.3)) << 3) | + ((!(state->joy.inputs[SE_KEY_SELECT] > 0.3)) << 2) | + ((!(state->joy.inputs[SE_KEY_B] > 0.3)) << 1) | + (!(state->joy.inputs[SE_KEY_A] > 0.3)); uint8_t data = gb->mem.data[SB_IO_JOYPAD]; - data&=0xf0; + data &= 0xf0; - if(0 == (data & (1<<4))) data |= data_dir; - if(0 == (data & (1<<5))) data |= data_action; + if(0 == (data & (1 << 4))) data |= data_dir; + if(0 == (data & (1 << 5))) data |= data_action; - switch(SB_BFE(data,4,2)){ - case 0: data|=data_dir|data_action; break; - case 1: data|=data_action; break; - case 2: data|=data_dir; break; - case 3: data|=0xf; break; + switch(SB_BFE(data, 4, 2)) { + case 0: data |= data_dir | data_action; break; + case 1: data |= data_action; break; + case 2: data |= data_dir; break; + case 3: data |= 0xf; break; } gb->mem.data[SB_IO_JOYPAD] = data; - } -static FORCE_INLINE void sb_update_lcd(sb_emu_state_t*emu,sb_gb_t* gb){ +static FORCE_INLINE void sb_update_lcd(sb_emu_state_t *emu, sb_gb_t *gb) { uint8_t stat = sb_read8_io(gb, SB_IO_LCD_STAT); uint8_t ctrl = sb_read8_io(gb, SB_IO_LCD_CTRL); - uint8_t ly = gb->lcd.curr_scanline; + uint8_t ly = gb->lcd.curr_scanline; uint8_t old_ly = ly; uint8_t lyc = sb_read8_io(gb, SB_IO_LCD_LYC); - bool enable = SB_BFE(ctrl,7,1)==1; - bool window_enable = SB_BFE(ctrl,5,1)==1; + bool enable = SB_BFE(ctrl, 7, 1) == 1; + bool window_enable = SB_BFE(ctrl, 5, 1) == 1; - int mode = stat&0x7; + int mode = stat & 0x7; bool new_scanline = false; - if(!enable){ - //TODO: Starting at 4 here, may indicate a CPU timing bug. But is needed to pass 1-lcd_sync.gb + if(!enable) { + // TODO: Starting at 4 here, may indicate a CPU timing bug. But is needed to pass 1-lcd_sync.gb gb->lcd.scanline_cycles = 4; gb->lcd.curr_scanline = 0; gb->lcd.curr_window_scanline = 0; gb->lcd.wy_eq_ly = false; - gb->lcd.in_hblank=true; - gb->lcd.window_active=false; - sb_store8_io(gb, SB_IO_LCD_STAT,stat&~3); + gb->lcd.in_hblank = true; + gb->lcd.window_active = false; + sb_store8_io(gb, SB_IO_LCD_STAT, stat & ~3); ly = 0; - }else{ - const int mode2_clks= 80; + } else { + const int mode2_clks = 80; // TODO: mode 3 is 10 cycles longer for every sprite intersected const int mode3_clks = SB_LCD_W; const int scanline_dots = 456; - const int mode0_clks = scanline_dots-mode2_clks-mode3_clks; + const int mode0_clks = scanline_dots - mode2_clks - mode3_clks; - gb->lcd.scanline_cycles +=1; - if(gb->lcd.scanline_cycles>=scanline_dots){ - gb->lcd.scanline_cycles=0; - new_scanline=true; + gb->lcd.scanline_cycles += 1; + if(gb->lcd.scanline_cycles >= scanline_dots) { + gb->lcd.scanline_cycles = 0; + new_scanline = true; } - if(gb->lcd.scanline_cycleslcd.scanline_cycleslcd.scanline_cycles < mode2_clks) + mode = 2; + else if(gb->lcd.scanline_cycles < mode3_clks + mode2_clks) + mode = 3; + else + mode = 0; + int old_mode = stat & 0x7; + int wy = sb_read8_io(gb, SB_IO_LCD_WY); - if(new_scanline){ + if(new_scanline) { - if(gb->lcd.window_active)gb->lcd.curr_window_scanline+=1; - gb->lcd.window_active=false; + if(gb->lcd.window_active) gb->lcd.curr_window_scanline += 1; + gb->lcd.window_active = false; int old_ly = ly; - ly+=1; + ly += 1; gb->lcd.curr_scanline += 1; - if(ly>153){ + if(ly > 153) { ly = 0; - old_ly=0; - gb->lcd.curr_scanline=0; - gb->lcd.wy_eq_ly=false; + old_ly = 0; + gb->lcd.curr_scanline = 0; + gb->lcd.wy_eq_ly = false; gb->lcd.curr_window_scanline = 0; } - gb->lcd.latched_window_enable=window_enable; - if(ly==SB_LCD_H)gb->lcd.finished_frame=true; + gb->lcd.latched_window_enable = window_enable; + if(ly == SB_LCD_H) gb->lcd.finished_frame = true; } - if(ly >= SB_LCD_H) {mode = 1;} - if(gb->lcd.render_frame){ - if(mode==2){ + if(ly >= SB_LCD_H) { mode = 1; } + if(gb->lcd.render_frame) { + if(mode == 2) { int clock_num = gb->lcd.scanline_cycles; - if(clock_num==0){ - for(int i=0;ilcd.render_sprites[i]=-1; - gb->lcd.sprite_index = 0; + if(clock_num == 0) { + for(int i = 0; i < SB_SPRITES_PER_SCANLINE; ++i) + gb->lcd.render_sprites[i] = -1; + gb->lcd.sprite_index = 0; } - if(clock_num%2){ - uint8_t y = gb->lcd.curr_scanline; - const int num_sprites= 40; - int oam_table_offset = 0xfe00; - uint8_t ctrl = sb_read8_io(gb, SB_IO_LCD_CTRL); - bool draw_sprite = SB_BFE(ctrl,1,1)==1; - bool sprite8x16 = SB_BFE(ctrl,2,1)==1; - int sprite_h = sprite8x16 ? 16: 8; - int sprite_id = clock_num/2; - int sprite_base = oam_table_offset+sprite_id*4; - int yc = (int)sb_read8_io(gb, sprite_base+0)-16; - int xc = (int)sb_read8_io(gb, sprite_base+1)-16; - if(yc<=y && yc+sprite_h>y&& gb->lcd.sprite_indexlcd.render_sprites[gb->lcd.sprite_index]=sprite_id; - for(int i=0;i<4;++i){ - gb->lcd.render_sprites_data[gb->lcd.sprite_index][i]=sb_read8_io(gb, sprite_base+i); + if(clock_num % 2) { + uint8_t y = gb->lcd.curr_scanline; + const int num_sprites = 40; + int oam_table_offset = 0xfe00; + uint8_t ctrl = sb_read8_io(gb, SB_IO_LCD_CTRL); + bool draw_sprite = SB_BFE(ctrl, 1, 1) == 1; + bool sprite8x16 = SB_BFE(ctrl, 2, 1) == 1; + int sprite_h = sprite8x16 ? 16 : 8; + int sprite_id = clock_num / 2; + int sprite_base = oam_table_offset + sprite_id * 4; + int yc = (int)sb_read8_io(gb, sprite_base + 0) - 16; + int xc = (int)sb_read8_io(gb, sprite_base + 1) - 16; + if(yc <= y && yc + sprite_h > y && gb->lcd.sprite_index < SB_SPRITES_PER_SCANLINE && sprite_id < num_sprites && draw_sprite) { + gb->lcd.render_sprites[gb->lcd.sprite_index] = sprite_id; + for(int i = 0; i < 4; ++i) { + gb->lcd.render_sprites_data[gb->lcd.sprite_index][i] = sb_read8_io(gb, sprite_base + i); } gb->lcd.sprite_index++; } } } - if(gb->lcd.curr_scanlinelcd.scanline_cycles-mode2_clks-8; - //This is intenentionally not latched for: 007 - The World is Not Enough's hud. - //Zen Intergalactic Ninja, Speedy Gonzales, and the Warriors of Might and Magic are also very sensitive - //to the behavior of this window. - if(ly==wy&&window_enable) gb->lcd.wy_eq_ly = true; - if(x=0){ - sb_draw_pixel(emu,gb,x,gb->lcd.curr_scanline); + if(gb->lcd.curr_scanline < SB_LCD_H) { + int x = gb->lcd.scanline_cycles - mode2_clks - 8; + // This is intenentionally not latched for: 007 - The World is Not Enough's hud. + // Zen Intergalactic Ninja, Speedy Gonzales, and the Warriors of Might and Magic are also very sensitive + // to the behavior of this window. + if(ly == wy && window_enable) gb->lcd.wy_eq_ly = true; + if(x < SB_LCD_W && x >= 0) { + sb_draw_pixel(emu, gb, x, gb->lcd.curr_scanline); } } } - if(ly==153&& gb->lcd.scanline_cycles>=4){ly = 0;} + if(ly == 153 && gb->lcd.scanline_cycles >= 4) { ly = 0; } - bool lyc_eq_ly_interrupt = SB_BFE(stat, 6,1); - bool oam_interrupt = SB_BFE(stat, 5,1); - bool vblank_interrupt = SB_BFE(stat, 4,1); - bool hblank_interrupt = SB_BFE(stat, 3,1); + bool lyc_eq_ly_interrupt = SB_BFE(stat, 6, 1); + bool oam_interrupt = SB_BFE(stat, 5, 1); + bool vblank_interrupt = SB_BFE(stat, 4, 1); + bool hblank_interrupt = SB_BFE(stat, 3, 1); - bool curr_stat_interrupt = false; - if(ly>=SB_LCD_H&&old_ly= SB_LCD_H && old_ly < SB_LCD_H) { uint8_t inter_flag = sb_read8_io(gb, SB_IO_INTER_F); - //V-BLANK Interrupt - sb_store8_io(gb, SB_IO_INTER_F, inter_flag| (1<<0)); + // V-BLANK Interrupt + sb_store8_io(gb, SB_IO_INTER_F, inter_flag | (1 << 0)); } - if(ly == lyc) mode|=0x4; + if(ly == lyc) mode |= 0x4; - if(ly>=SB_LCD_H && vblank_interrupt) curr_stat_interrupt=true; - if((mode&0x4)==4 && lyc_eq_ly_interrupt) curr_stat_interrupt=true; - if((mode&0x3)==2 && oam_interrupt) curr_stat_interrupt=true; - if((mode&0x3)==0 && hblank_interrupt) curr_stat_interrupt=true; - if(curr_stat_interrupt&&!gb->lcd.last_stat_interrupt){ + if(ly >= SB_LCD_H && vblank_interrupt) curr_stat_interrupt = true; + if((mode & 0x4) == 4 && lyc_eq_ly_interrupt) curr_stat_interrupt = true; + if((mode & 0x3) == 2 && oam_interrupt) curr_stat_interrupt = true; + if((mode & 0x3) == 0 && hblank_interrupt) curr_stat_interrupt = true; + if(curr_stat_interrupt && !gb->lcd.last_stat_interrupt) { uint8_t inter_flag = sb_read8_io(gb, SB_IO_INTER_F); - sb_store8_io(gb, SB_IO_INTER_F, inter_flag| (1<<1)); + sb_store8_io(gb, SB_IO_INTER_F, inter_flag | (1 << 1)); } gb->lcd.last_stat_interrupt = curr_stat_interrupt; - stat = (stat&0xf8) | mode|0x80; + stat = (stat & 0xf8) | mode | 0x80; sb_store8_io(gb, SB_IO_LCD_STAT, stat); } - gb->lcd.in_hblank = (mode&0x3)==0; - sb_store8_io(gb, SB_IO_LCD_LY, ly);; + gb->lcd.in_hblank = (mode & 0x3) == 0; + sb_store8_io(gb, SB_IO_LCD_LY, ly); + ; } -uint8_t sb_read_vram(sb_gb_t*gb, int cpu_address, int bank){ - return gb->lcd.vram[bank*SB_VRAM_BANK_SIZE+cpu_address-0x8000]; +uint8_t sb_read_vram(sb_gb_t *gb, int cpu_address, int bank) { + return gb->lcd.vram[bank * SB_VRAM_BANK_SIZE + cpu_address - 0x8000]; } // Returns info about the pixel in the tile map packed into a 32bit integer // ret[1:0] = color_id // ret[7:2] = palette_id // ret[8] = backgroud_priority #define SB_BACKG_PALETTE 0 -#define SB_OBJ0_PALETTE 1 -#define SB_OBJ1_PALETTE 2 -uint32_t sb_lookup_tile(sb_gb_t* gb, int px, int py, int tile_base, int data_mode){ +#define SB_OBJ0_PALETTE 1 +#define SB_OBJ1_PALETTE 2 +uint32_t sb_lookup_tile(sb_gb_t *gb, int px, int py, int tile_base, int data_mode) { const int tile_size = 8; const int tiles_per_row = 32; - int tile_offset = (((px&0xff)/tile_size)+((py&0xff)/tile_size)*tiles_per_row)&0x3ff; + int tile_offset = (((px & 0xff) / tile_size) + ((py & 0xff) / tile_size) * tiles_per_row) & 0x3ff; - int tile_id = sb_read_vram(gb, tile_base+tile_offset,0); + int tile_id = sb_read_vram(gb, tile_base + tile_offset, 0); - int pixel_in_tile_x = 7-(px%8); - int pixel_in_tile_y = (py%8); + int pixel_in_tile_x = 7 - (px % 8); + int pixel_in_tile_y = (py % 8); int byte_tile_data_off = 0; int tile_d_vram_bank = 0; int tile_bg_palette = 0; - bool bg_to_oam_priority=false; + bool bg_to_oam_priority = false; tile_bg_palette = SB_BACKG_PALETTE; - //Only enable GB functionality if in GBC mode - if(sb_gbc_enable(gb)){ - uint8_t attr = sb_read_vram(gb, tile_base+tile_offset,1); - - bg_to_oam_priority = SB_BFE(attr,7,1); - bool v_flip = SB_BFE(attr,6,1); - bool h_flip = SB_BFE(attr,5,1); - tile_d_vram_bank = SB_BFE(attr,3,1); - tile_bg_palette = SB_BFE(attr,0,3); - - if(v_flip)pixel_in_tile_y = 7-pixel_in_tile_y; - if(h_flip)pixel_in_tile_x = 7-pixel_in_tile_x; + // Only enable GB functionality if in GBC mode + if(sb_gbc_enable(gb)) { + uint8_t attr = sb_read_vram(gb, tile_base + tile_offset, 1); + + bg_to_oam_priority = SB_BFE(attr, 7, 1); + bool v_flip = SB_BFE(attr, 6, 1); + bool h_flip = SB_BFE(attr, 5, 1); + tile_d_vram_bank = SB_BFE(attr, 3, 1); + tile_bg_palette = SB_BFE(attr, 0, 3); + + if(v_flip) pixel_in_tile_y = 7 - pixel_in_tile_y; + if(h_flip) pixel_in_tile_x = 7 - pixel_in_tile_x; } - const int bytes_per_tile = 2*8; - if(data_mode==0){ - byte_tile_data_off = 0x8000 + 0x1000 + ((int)((int8_t)(tile_id)))*bytes_per_tile; - }else{ - byte_tile_data_off = 0x8000 + ((int)((uint8_t)(tile_id)))*bytes_per_tile; + const int bytes_per_tile = 2 * 8; + if(data_mode == 0) { + byte_tile_data_off = 0x8000 + 0x1000 + ((int)((int8_t)(tile_id))) * bytes_per_tile; + } else { + byte_tile_data_off = 0x8000 + ((int)((uint8_t)(tile_id))) * bytes_per_tile; } - byte_tile_data_off+=pixel_in_tile_y*2; - uint8_t data1 = sb_read_vram(gb, byte_tile_data_off,tile_d_vram_bank); - uint8_t data2 = sb_read_vram(gb, byte_tile_data_off+1,tile_d_vram_bank); - int color_id = (SB_BFE(data1,pixel_in_tile_x,1)+SB_BFE(data2,pixel_in_tile_x,1)*2); - color_id |= (tile_bg_palette&0x3f)<<2; - if(bg_to_oam_priority)color_id|= 1<<8; + byte_tile_data_off += pixel_in_tile_y * 2; + uint8_t data1 = sb_read_vram(gb, byte_tile_data_off, tile_d_vram_bank); + uint8_t data2 = sb_read_vram(gb, byte_tile_data_off + 1, tile_d_vram_bank); + int color_id = (SB_BFE(data1, pixel_in_tile_x, 1) + SB_BFE(data2, pixel_in_tile_x, 1) * 2); + color_id |= (tile_bg_palette & 0x3f) << 2; + if(bg_to_oam_priority) color_id |= 1 << 8; return color_id; } -void sb_lookup_palette_color(sb_gb_t*gb,int color_id, int*r, int *g, int *b){ +void sb_lookup_palette_color(sb_gb_t *gb, int color_id, int *r, int *g, int *b) { uint8_t palette = 0; - if(gb->model == SB_GB){ - int pal_id = SB_BFE(color_id,2,6); - if(pal_id==SB_BACKG_PALETTE)palette = sb_read8_io(gb, SB_IO_PPU_BGP); - else if(pal_id==SB_OBJ1_PALETTE)palette = sb_read8_io(gb, SB_IO_PPU_OBP1); - else palette = color_id ==0 ? 0 : sb_read8_io(gb, SB_IO_PPU_OBP0); - color_id = SB_BFE(palette,2*(color_id&0x3),2); - - *r = gb->dmg_palette[color_id*3+0]; - *g = gb->dmg_palette[color_id*3+1]; - *b = gb->dmg_palette[color_id*3+2]; - }else if(gb->model == SB_GBC){ - - int palette = SB_BFE(color_id,2,6); - if(!sb_gbc_enable(gb)){ - uint8_t pal_map= 0; - int pal_id = SB_BFE(color_id,2,6); - if(pal_id==SB_BACKG_PALETTE)pal_map = sb_read8_io(gb, SB_IO_PPU_BGP); - else if(pal_id==SB_OBJ1_PALETTE)pal_map = sb_read8_io(gb, SB_IO_PPU_OBP1); - else pal_map = color_id ==0 ? 0 : sb_read8_io(gb, SB_IO_PPU_OBP0); - color_id = SB_BFE(pal_map,2*(color_id&0x3),2); - palette=pal_id==SB_BACKG_PALETTE?0:8; + if(gb->model == SB_GB) { + int pal_id = SB_BFE(color_id, 2, 6); + if(pal_id == SB_BACKG_PALETTE) + palette = sb_read8_io(gb, SB_IO_PPU_BGP); + else if(pal_id == SB_OBJ1_PALETTE) + palette = sb_read8_io(gb, SB_IO_PPU_OBP1); + else + palette = color_id == 0 ? 0 : sb_read8_io(gb, SB_IO_PPU_OBP0); + color_id = SB_BFE(palette, 2 * (color_id & 0x3), 2); + + *r = gb->dmg_palette[color_id * 3 + 0]; + *g = gb->dmg_palette[color_id * 3 + 1]; + *b = gb->dmg_palette[color_id * 3 + 2]; + } else if(gb->model == SB_GBC) { + + int palette = SB_BFE(color_id, 2, 6); + if(!sb_gbc_enable(gb)) { + uint8_t pal_map = 0; + int pal_id = SB_BFE(color_id, 2, 6); + if(pal_id == SB_BACKG_PALETTE) + pal_map = sb_read8_io(gb, SB_IO_PPU_BGP); + else if(pal_id == SB_OBJ1_PALETTE) + pal_map = sb_read8_io(gb, SB_IO_PPU_OBP1); + else + pal_map = color_id == 0 ? 0 : sb_read8_io(gb, SB_IO_PPU_OBP0); + color_id = SB_BFE(pal_map, 2 * (color_id & 0x3), 2); + palette = pal_id == SB_BACKG_PALETTE ? 0 : 8; } - int entry= palette*8+(color_id&0x3)*2; - uint16_t color = gb->lcd.color_palettes[entry+0]; - color |= ((int)gb->lcd.color_palettes[entry+1])<<8; + int entry = palette * 8 + (color_id & 0x3) * 2; + uint16_t color = gb->lcd.color_palettes[entry + 0]; + color |= ((int)gb->lcd.color_palettes[entry + 1]) << 8; - int tr = SB_BFE(color,0,5); - int tg = SB_BFE(color,5,5); - int tb = SB_BFE(color,10,5); + int tr = SB_BFE(color, 0, 5); + int tg = SB_BFE(color, 5, 5); + int tb = SB_BFE(color, 10, 5); - *r = tr*8; - *g = tg*8; - *b = tb*8; + *r = tr * 8; + *g = tg * 8; + *b = tb * 8; } } -void sb_draw_pixel(sb_emu_state_t*emu,sb_gb_t* gb, int x, int y){ +void sb_draw_pixel(sb_emu_state_t *emu, sb_gb_t *gb, int x, int y) { uint8_t ctrl = sb_read8_io(gb, SB_IO_LCD_CTRL); - bool draw_bg_win = SB_BFE(ctrl,0,1)==1; - bool master_priority = true; - bool gbc_mode = sb_gbc_enable(gb); - if(gbc_mode){ + bool draw_bg_win = SB_BFE(ctrl, 0, 1) == 1; + bool master_priority = true; + bool gbc_mode = sb_gbc_enable(gb); + if(gbc_mode) { // This bit has a different meaning in GBC mode master_priority = draw_bg_win; draw_bg_win = true; } - bool draw_sprite = SB_BFE(ctrl,1,1)==1; - bool sprite8x16 = SB_BFE(ctrl,2,1)==1; - int bg_tile_map_base = SB_BFE(ctrl,3,1)==1 ? 0x9c00 : 0x9800; - int bg_win_tile_data_mode = SB_BFE(ctrl,4,1)==1; - bool window_enable = SB_BFE(ctrl,5,1)==1; - int win_tile_map_base = SB_BFE(ctrl,6,1)==1 ? 0x9c00 : 0x9800; + bool draw_sprite = SB_BFE(ctrl, 1, 1) == 1; + bool sprite8x16 = SB_BFE(ctrl, 2, 1) == 1; + int bg_tile_map_base = SB_BFE(ctrl, 3, 1) == 1 ? 0x9c00 : 0x9800; + int bg_win_tile_data_mode = SB_BFE(ctrl, 4, 1) == 1; + bool window_enable = SB_BFE(ctrl, 5, 1) == 1; + int win_tile_map_base = SB_BFE(ctrl, 6, 1) == 1 ? 0x9c00 : 0x9800; int oam_table_offset = 0xfe00; - int wx = sb_read8_io(gb, SB_IO_LCD_WX)-7; + int wx = sb_read8_io(gb, SB_IO_LCD_WX) - 7; int wy = sb_read8_io(gb, SB_IO_LCD_WY); int sx = sb_read8_io(gb, SB_IO_LCD_SX); int sy = sb_read8_io(gb, SB_IO_LCD_SY); // HW only draws first 10 sprites that touch a scanline - const int bytes_per_tile = 2*8; - int color_id=0; - - bool background_priority= false; - gb->lcd.window_active|= gb->lcd.latched_window_enable&&gb->lcd.wy_eq_ly&&x>=wx; - if(draw_bg_win){ - if(gb->lcd.window_active){ - int px = x-wx; - if(px>=0){ + const int bytes_per_tile = 2 * 8; + int color_id = 0; + + bool background_priority = false; + gb->lcd.window_active |= gb->lcd.latched_window_enable && gb->lcd.wy_eq_ly && x >= wx; + if(draw_bg_win) { + if(gb->lcd.window_active) { + int px = x - wx; + if(px >= 0) { int py = gb->lcd.curr_window_scanline; - color_id = sb_lookup_tile(gb,px,py,win_tile_map_base,bg_win_tile_data_mode); + color_id = sb_lookup_tile(gb, px, py, win_tile_map_base, bg_win_tile_data_mode); } - }else{ - int px = x+ sx; - int py = y+ sy; - color_id = sb_lookup_tile(gb,px,py,bg_tile_map_base,bg_win_tile_data_mode); + } else { + int px = x + sx; + int py = y + sy; + color_id = sb_lookup_tile(gb, px, py, bg_tile_map_base, bg_win_tile_data_mode); } } - if(draw_sprite){ + if(draw_sprite) { int prior_sprite = 256; - for(int i=0;ilcd.sprite_index;++i){ + for(int i = 0; i < gb->lcd.sprite_index; ++i) { int sprite = gb->lcd.render_sprites[i]; - int xc = gb->lcd.render_sprites_data[i][1]-8; + int xc = gb->lcd.render_sprites_data[i][1] - 8; - int x_sprite = 7-(x-xc); - int prior = sb_gbc_enable(gb)?0 : xc; - //Check if the sprite is hit - if(prior_sprite<=prior||x_sprite>=8 || x_sprite<0) continue; + int x_sprite = 7 - (x - xc); + int prior = sb_gbc_enable(gb) ? 0 : xc; + // Check if the sprite is hit + if(prior_sprite <= prior || x_sprite >= 8 || x_sprite < 0) continue; - int yc = gb->lcd.render_sprites_data[i][0]-16; - int y_sprite = y-yc; + int yc = gb->lcd.render_sprites_data[i][0] - 16; + int y_sprite = y - yc; int tile = gb->lcd.render_sprites_data[i][2]; int attr = gb->lcd.render_sprites_data[i][3]; int tile_d_vram_bank = 0; - int tile_sprite_palette =0; + int tile_sprite_palette = 0; - int palette = SB_BFE(attr,4,1)!=0?SB_OBJ1_PALETTE:SB_OBJ0_PALETTE; - if(gbc_mode){ - tile_d_vram_bank = SB_BFE(attr, 3,1); - palette = SB_BFE(attr, 0,3)+8; + int palette = SB_BFE(attr, 4, 1) != 0 ? SB_OBJ1_PALETTE : SB_OBJ0_PALETTE; + if(gbc_mode) { + tile_d_vram_bank = SB_BFE(attr, 3, 1); + palette = SB_BFE(attr, 0, 3) + 8; } - if(sprite8x16)tile &=0xfe; + if(sprite8x16) tile &= 0xfe; - bool x_flip = SB_BFE(attr,5,1); - bool y_flip = SB_BFE(attr,6,1); - bool bg_win_on_top = SB_BFE(attr,7,1); + bool x_flip = SB_BFE(attr, 5, 1); + bool y_flip = SB_BFE(attr, 6, 1); + bool bg_win_on_top = SB_BFE(attr, 7, 1); - if(x_flip)x_sprite = 7-x_sprite; - if(y_flip)y_sprite = (sprite8x16? 15 : 7)-y_sprite; + if(x_flip) x_sprite = 7 - x_sprite; + if(y_flip) y_sprite = (sprite8x16 ? 15 : 7) - y_sprite; - int byte_tile_data_off = 0x8000 + (((uint8_t)(tile))*bytes_per_tile); - byte_tile_data_off+=y_sprite*2; + int byte_tile_data_off = 0x8000 + (((uint8_t)(tile)) * bytes_per_tile); + byte_tile_data_off += y_sprite * 2; - uint8_t data1 = sb_read_vram(gb, byte_tile_data_off,tile_d_vram_bank); - uint8_t data2 = sb_read_vram(gb, byte_tile_data_off+1,tile_d_vram_bank); + uint8_t data1 = sb_read_vram(gb, byte_tile_data_off, tile_d_vram_bank); + uint8_t data2 = sb_read_vram(gb, byte_tile_data_off + 1, tile_d_vram_bank); - int cid = (SB_BFE(data1,x_sprite,1)+SB_BFE(data2,x_sprite,1)*2); - if((bg_win_on_top||(SB_BFE(color_id,8,1)))&&master_priority){ - if((color_id&0x3)==0&&cid!=0){color_id = cid | (palette<<2); prior_sprite =prior;} - }else if(cid!=0){color_id = cid | (palette<<2); prior_sprite=prior;} + int cid = (SB_BFE(data1, x_sprite, 1) + SB_BFE(data2, x_sprite, 1) * 2); + if((bg_win_on_top || (SB_BFE(color_id, 8, 1))) && master_priority) { + if((color_id & 0x3) == 0 && cid != 0) { + color_id = cid | (palette << 2); + prior_sprite = prior; + } + } else if(cid != 0) { + color_id = cid | (palette << 2); + prior_sprite = prior; + } } } - int r=0,g=0,b=0; - sb_lookup_palette_color(gb,color_id,&r,&g,&b); + int r = 0, g = 0, b = 0; + sb_lookup_palette_color(gb, color_id, &r, &g, &b); float ghost_coef = 0.5; - if(gb->model != SB_GB)ghost_coef= 0.2; - ghost_coef*=emu->screen_ghosting_strength; - int p =(x+(y)*SB_LCD_W)*4; - gb->lcd.framebuffer[p+0] = r*(1.0-ghost_coef)+gb->lcd.framebuffer[p+0]*ghost_coef+0.5; - gb->lcd.framebuffer[p+1] = g*(1.0-ghost_coef)+gb->lcd.framebuffer[p+1]*ghost_coef+0.5; - gb->lcd.framebuffer[p+2] = b*(1.0-ghost_coef)+gb->lcd.framebuffer[p+2]*ghost_coef+0.5; - + if(gb->model != SB_GB) ghost_coef = 0.2; + ghost_coef *= emu->screen_ghosting_strength; + int p = (x + (y)*SB_LCD_W) * 4; + gb->lcd.framebuffer[p + 0] = r * (1.0 - ghost_coef) + gb->lcd.framebuffer[p + 0] * ghost_coef + 0.5; + gb->lcd.framebuffer[p + 1] = g * (1.0 - ghost_coef) + gb->lcd.framebuffer[p + 1] * ghost_coef + 0.5; + gb->lcd.framebuffer[p + 2] = b * (1.0 - ghost_coef) + gb->lcd.framebuffer[p + 2] * ghost_coef + 0.5; } -void sb_update_timers(sb_gb_t* gb, int delta_clocks, bool double_speed){ +void sb_update_timers(sb_gb_t *gb, int delta_clocks, bool double_speed) { uint8_t tac = sb_read8_io(gb, SB_IO_TAC); - bool tima_enable = SB_BFE(tac, 2, 1); - int clk_sel = SB_BFE(tac, 0, 2); - - int tma_bit = 0; - switch(clk_sel){ - case 0: tma_bit = 9;break; //4khz - case 1: tma_bit = 3;break; //256khz - case 2: tma_bit = 5;break; //64Khz - case 3: tma_bit = 7;break; //16Khz + bool tima_enable = SB_BFE(tac, 2, 1); + int clk_sel = SB_BFE(tac, 0, 2); + + int tma_bit = 0; + switch(clk_sel) { + case 0: tma_bit = 9; break; // 4khz + case 1: tma_bit = 3; break; // 256khz + case 2: tma_bit = 5; break; // 64Khz + case 3: tma_bit = 7; break; // 16Khz } - int seq_bit = double_speed?13:12; - for(int i=0;itimers.total_clock_ticks; - uint16_t next = curr+1; - gb->timers.total_clock_ticks=next; - bool tick_tima = SB_BFE(curr,tma_bit,1)&tima_enable; - bool tick_seq = SB_BFE(curr,seq_bit,1); - if(tick_tima==false&&gb->timers.last_tick_tima==true){ + uint16_t next = curr + 1; + gb->timers.total_clock_ticks = next; + bool tick_tima = SB_BFE(curr, tma_bit, 1) & tima_enable; + bool tick_seq = SB_BFE(curr, seq_bit, 1); + if(tick_tima == false && gb->timers.last_tick_tima == true) { uint8_t d = sb_read8_io(gb, SB_IO_TIMA); // Trigger timer interrupt - if(d == 255){ + if(d == 255) { uint8_t i_flag = sb_read8_io(gb, SB_IO_INTER_F); - i_flag |= 1<<2; + i_flag |= 1 << 2; sb_store8_io(gb, SB_IO_INTER_F, i_flag); - d = sb_read8_io(gb,SB_IO_TMA); - }else d +=1; + d = sb_read8_io(gb, SB_IO_TMA); + } else + d += 1; sb_store8_io(gb, SB_IO_TIMA, d); } - if(tick_seq&&!gb->timers.last_tick_seq){ - sb_tick_frame_seq(gb,&gb->audio.sequencer); + if(tick_seq && !gb->timers.last_tick_seq) { + sb_tick_frame_seq(gb, &gb->audio.sequencer); } gb->timers.last_tick_seq = tick_seq; gb->timers.last_tick_tima = tick_tima; } - sb_store8_io(gb, SB_IO_DIV, SB_BFE(gb->timers.total_clock_ticks,8,8)); + sb_store8_io(gb, SB_IO_DIV, SB_BFE(gb->timers.total_clock_ticks, 8, 8)); } -int sb_update_dma(sb_gb_t *gb){ +int sb_update_dma(sb_gb_t *gb) { int delta_cycles = 0; - if(gb->dma.active){ + if(gb->dma.active) { unsigned bytes_transferred = 0; - uint16_t dma_src = sb_read8_io(gb,SB_IO_DMA_SRC_LO)| - ((int)sb_read8_io(gb,SB_IO_DMA_SRC_HI)<<8u); - uint16_t dma_dst = sb_read8_io(gb,SB_IO_DMA_DST_LO)| - ((int)sb_read8_io(gb,SB_IO_DMA_DST_HI)<<8u); - dma_src&=0xfff0; - dma_dst&=0x1ff0; - dma_dst|=0x8000; - uint8_t dma_mode_length = sb_read8_io(gb,SB_IO_DMA_MODE_LEN); - - int len = (SB_BFE(dma_mode_length, 0,7)); + uint16_t dma_src = sb_read8_io(gb, SB_IO_DMA_SRC_LO) | + ((int)sb_read8_io(gb, SB_IO_DMA_SRC_HI) << 8u); + uint16_t dma_dst = sb_read8_io(gb, SB_IO_DMA_DST_LO) | + ((int)sb_read8_io(gb, SB_IO_DMA_DST_HI) << 8u); + dma_src &= 0xfff0; + dma_dst &= 0x1ff0; + dma_dst |= 0x8000; + uint8_t dma_mode_length = sb_read8_io(gb, SB_IO_DMA_MODE_LEN); + + int len = (SB_BFE(dma_mode_length, 0, 7)); bool hdma_mode = gb->dma.hdma; - if(!hdma_mode||(gb->dma.in_hblank==false&&gb->lcd.in_hblank==true&&gb->lcd.curr_scanline=0){ - for(int i=0;i<16;++i){ + if(!hdma_mode || (gb->dma.in_hblank == false && gb->lcd.in_hblank == true && gb->lcd.curr_scanline < SB_LCD_H - 1)) { + while(len >= 0) { + for(int i = 0; i < 16; ++i) { int off = gb->dma.bytes_transferred++; - if(dma_src>0xffff){len=0;break;} - uint8_t data = sb_read8(gb,dma_src); - sb_store8(gb,dma_dst,data); + if(dma_src > 0xffff) { + len = 0; + break; + } + uint8_t data = sb_read8(gb, dma_src); + sb_store8(gb, dma_dst, data); dma_src++; dma_dst++; - bytes_transferred+=1; + bytes_transferred += 1; } - sb_store8_io(gb,SB_IO_DMA_SRC_LO,SB_BFE(dma_src,0,8)); - sb_store8_io(gb,SB_IO_DMA_SRC_HI,SB_BFE(dma_src,8,8)); - sb_store8_io(gb,SB_IO_DMA_DST_LO,SB_BFE(dma_dst,0,8)); - sb_store8_io(gb,SB_IO_DMA_DST_HI,SB_BFE(dma_dst,8,8)); - len--; - if(hdma_mode)break; + sb_store8_io(gb, SB_IO_DMA_SRC_LO, SB_BFE(dma_src, 0, 8)); + sb_store8_io(gb, SB_IO_DMA_SRC_HI, SB_BFE(dma_src, 8, 8)); + sb_store8_io(gb, SB_IO_DMA_DST_LO, SB_BFE(dma_dst, 0, 8)); + sb_store8_io(gb, SB_IO_DMA_DST_HI, SB_BFE(dma_dst, 8, 8)); + len--; + if(hdma_mode) break; } - uint8_t new_mode = (len&0x7f); - if(len<0){ + uint8_t new_mode = (len & 0x7f); + if(len < 0) { gb->dma.active = false; - gb->dma.hdma = false; + gb->dma.hdma = false; len = 0; hdma_mode = 0; new_mode = 0xff; } - if(!gb->dma.active)new_mode|=0x80; - sb_store8_io(gb,SB_IO_DMA_MODE_LEN,new_mode); + if(!gb->dma.active) new_mode |= 0x80; + sb_store8_io(gb, SB_IO_DMA_MODE_LEN, new_mode); } gb->dma.in_hblank = gb->lcd.in_hblank; - delta_cycles+= bytes_transferred/2; + delta_cycles += bytes_transferred / 2; } return delta_cycles; } -void sb_update_oam_dma(sb_gb_t* gb, int delta_cycles){ - delta_cycles/=4; - uint16_t dma_src = ((int)sb_read8_io(gb,SB_IO_OAM_DMA))<<8u; +void sb_update_oam_dma(sb_gb_t *gb, int delta_cycles) { + delta_cycles /= 4; + uint16_t dma_src = ((int)sb_read8_io(gb, SB_IO_OAM_DMA)) << 8u; uint16_t dma_dst = 0xfe00; // From CasualPokePlayer: - // in most cases echo ram is only E000-FDFF. + // in most cases echo ram is only E000-FDFF. // oam dma is one of the exceptions here which have the entire E000-FFFF // region as echo ram for dma source - if(dma_src==0xfe00)dma_src=0xde00; - else if(dma_src==0xff00)dma_src=0xdf00; - for(int i=0;idma.oam_dma_activate_fifo){ - if(gb->dma.oam_dma_activate_fifo&1){ - gb->dma.oam_dma_active=true; - gb->dma.oam_bytes_transferred=0; + if(dma_src == 0xfe00) + dma_src = 0xde00; + else if(dma_src == 0xff00) + dma_src = 0xdf00; + for(int i = 0; i < delta_cycles; i++) { + if(gb->dma.oam_dma_activate_fifo) { + if(gb->dma.oam_dma_activate_fifo & 1) { + gb->dma.oam_dma_active = true; + gb->dma.oam_bytes_transferred = 0; } - gb->dma.oam_dma_activate_fifo>>=1; + gb->dma.oam_dma_activate_fifo >>= 1; } - if(gb->dma.oam_dma_active){ - if(gb->dma.oam_bytes_transferred<0xA0){ - uint8_t data = sb_read8_direct(gb,dma_src+gb->dma.oam_bytes_transferred); - sb_store8_direct(gb,dma_dst+gb->dma.oam_bytes_transferred,data); + if(gb->dma.oam_dma_active) { + if(gb->dma.oam_bytes_transferred < 0xA0) { + uint8_t data = sb_read8_direct(gb, dma_src + gb->dma.oam_bytes_transferred); + sb_store8_direct(gb, dma_dst + gb->dma.oam_bytes_transferred, data); gb->dma.oam_bytes_transferred++; } - if(gb->dma.oam_bytes_transferred>=0xA0)gb->dma.oam_dma_active=false; + if(gb->dma.oam_bytes_transferred >= 0xA0) gb->dma.oam_dma_active = false; } } - } -static FORCE_INLINE void sb_tick_sio(sb_gb_t* gb, int delta_cycles){ - //Just a stub for now; - uint8_t siocnt= sb_read8_io(gb,SB_IO_SERIAL_CTRL); - bool active = SB_BFE(siocnt,7,1); - if(active){ - if(gb->serial.last_active==false){ - gb->serial.last_active =true; - gb->serial.ticks_to_complete=4*1024*1024/1024; - bool fast_clock = SB_BFE(siocnt,1,1)&&sb_gbc_enable(gb); - if(fast_clock)gb->serial.ticks_to_complete/=2; +static FORCE_INLINE void sb_tick_sio(sb_gb_t *gb, int delta_cycles) { + // Just a stub for now; + uint8_t siocnt = sb_read8_io(gb, SB_IO_SERIAL_CTRL); + bool active = SB_BFE(siocnt, 7, 1); + if(active) { + if(gb->serial.last_active == false) { + gb->serial.last_active = true; + gb->serial.ticks_to_complete = 4 * 1024 * 1024 / 1024; + bool fast_clock = SB_BFE(siocnt, 1, 1) && sb_gbc_enable(gb); + if(fast_clock) gb->serial.ticks_to_complete /= 2; } - bool internal_clock = SB_BFE(siocnt,0,1); - if(internal_clock)gb->serial.ticks_to_complete-=delta_cycles; - if(gb->serial.ticks_to_complete<=0){ - siocnt&=0x7f; - sb_store8_io(gb,SB_IO_SERIAL_CTRL,siocnt); - sb_store8_io(gb,SB_IO_SERIAL_BYTE,0xff); - uint8_t i_flag = sb_read8_io(gb,SB_IO_INTER_F); - i_flag |= (1<<3); - sb_store8_io(gb,SB_IO_INTER_F,i_flag); - active =false; + bool internal_clock = SB_BFE(siocnt, 0, 1); + if(internal_clock) gb->serial.ticks_to_complete -= delta_cycles; + if(gb->serial.ticks_to_complete <= 0) { + siocnt &= 0x7f; + sb_store8_io(gb, SB_IO_SERIAL_CTRL, siocnt); + sb_store8_io(gb, SB_IO_SERIAL_BYTE, 0xff); + uint8_t i_flag = sb_read8_io(gb, SB_IO_INTER_F); + i_flag |= (1 << 3); + sb_store8_io(gb, SB_IO_INTER_F, i_flag); + active = false; } } - gb->serial.last_active =active; + gb->serial.last_active = active; } -void sb_tick_components(sb_emu_state_t* emu, sb_gb_t* gb, int cycles){ - unsigned speed = sb_read8_io(gb,SB_IO_GBC_SPEED_SWITCH); - bool double_speed = SB_BFE(speed, 7, 1)&&sb_gbc_enable(gb); - sb_update_oam_dma(gb,(double_speed?2:1)*cycles); - for(int i=0;irtc.sec = tm->tm_sec; gb->rtc.min = tm->tm_min; - gb->rtc.hour= tm->tm_hour; - gb->rtc.day = (tm->tm_wday-1)%7; + gb->rtc.hour = tm->tm_hour; + gb->rtc.day = (tm->tm_wday - 1) % 7; } -void sb_tick(sb_emu_state_t* emu, sb_gb_t* gb,gb_scratch_t* scratch){ - gb->lcd.framebuffer = scratch->framebuffer; - gb->cart.data = emu->rom_data; +void sb_tick(sb_emu_state_t *emu, sb_gb_t *gb, gb_scratch_t *scratch) { + gb->lcd.framebuffer = scratch->framebuffer; + gb->cart.data = emu->rom_data; gb->bios = scratch->bios; int instructions_to_execute = emu->step_instructions; - if(instructions_to_execute==0)instructions_to_execute=70224/2; + if(instructions_to_execute == 0) instructions_to_execute = 70224 / 2; int frames_to_draw = 1; - int total_cylces = 0; - int rumble_cycles= 0; - gb->lcd.finished_frame =false; + int total_cylces = 0; + int rumble_cycles = 0; + gb->lcd.finished_frame = false; gb->lcd.render_frame = emu->render_frame; gb_tick_rtc(gb); - for(int i=0;icpu.pc; - unsigned op = sb_read8(gb,gb->cpu.pc); - bool request_speed_switch= false; - if(sb_gbc_enable(gb)){ - unsigned speed = sb_read8_io(gb,SB_IO_GBC_SPEED_SWITCH); + if(dma_delta_cycles == 0) { + cpu_delta_cycles = 4; + int pc = gb->cpu.pc; + unsigned op = sb_read8(gb, gb->cpu.pc); + bool request_speed_switch = false; + if(sb_gbc_enable(gb)) { + unsigned speed = sb_read8_io(gb, SB_IO_GBC_SPEED_SWITCH); double_speed = SB_BFE(speed, 7, 1); request_speed_switch = SB_BFE(speed, 0, 1); } - if(gb->cpu.prefix_op)op+=256; - + if(gb->cpu.prefix_op) op += 256; + int trigger_interrupt = -1; // TODO: Can interrupts trigger between prefix ops and the second byte? - if(gb->cpu.prefix_op==false){ - uint8_t ie = sb_read8_io(gb,SB_IO_INTER_EN); + if(gb->cpu.prefix_op == false) { + uint8_t ie = sb_read8_io(gb, SB_IO_INTER_EN); uint8_t i_flag = gb->cpu.last_inter_f; - uint8_t masked_interupt = ie&i_flag&0x1f; - for(int i=0;i<5;++i){ - if(masked_interupt & (1<cpu.interrupt_enable){ + if(trigger_interrupt != -1 && request_speed_switch == false) { + if(gb->cpu.interrupt_enable) { gb->cpu.interrupt_enable = false; gb->cpu.deferred_interrupt_enable = false; - int interrupt_address = (trigger_interrupt*0x8)+0x40; - sb_call_impl(gb, interrupt_address, 0, 0, 0, (const uint8_t*)"----"); - cpu_delta_cycles = 5*4; - call_interrupt=true; + int interrupt_address = (trigger_interrupt * 0x8) + 0x40; + sb_call_impl(gb, interrupt_address, 0, 0, 0, (const uint8_t *)"----"); + cpu_delta_cycles = 5 * 4; + call_interrupt = true; } - if(call_interrupt){ - uint8_t i_flag = sb_read8_io(gb,SB_IO_INTER_F); - i_flag &= ~(1<cpu.wait_for_interrupt = false; } - if(gb->cpu.deferred_interrupt_enable){ + if(gb->cpu.deferred_interrupt_enable) { gb->cpu.deferred_interrupt_enable = false; gb->cpu.interrupt_enable = true; } - - if(call_interrupt==false&&gb->cpu.wait_for_interrupt==false){ + + if(call_interrupt == false && gb->cpu.wait_for_interrupt == false) { sb_instr_t inst = sb_decode_table[op]; - gb->cpu.pc+=inst.length; - if(gb->cpu.halt_bug)gb->cpu.pc--; + gb->cpu.pc += inst.length; + if(gb->cpu.halt_bug) gb->cpu.pc--; gb->cpu.halt_bug = false; - int operand1 = sb_load_operand(gb,inst.op_src1); - int operand2 = sb_load_operand(gb,inst.op_src2); + int operand1 = sb_load_operand(gb, inst.op_src1); + int operand2 = sb_load_operand(gb, inst.op_src2); unsigned pc_before_inst = gb->cpu.pc; gb->cpu.prefix_op = false; - inst.impl(gb, operand1, operand2,inst.op_src1,inst.op_src2, inst.flag_mask); - if(gb->cpu.prefix_op==true)i--; + inst.impl(gb, operand1, operand2, inst.op_src1, inst.op_src2, inst.flag_mask); + if(gb->cpu.prefix_op == true) i--; - if(gb->cpu.wait_for_interrupt){ - uint8_t ie = sb_read8_io(gb,SB_IO_INTER_EN); + if(gb->cpu.wait_for_interrupt) { + uint8_t ie = sb_read8_io(gb, SB_IO_INTER_EN); uint8_t i_flag = gb->cpu.last_inter_f; - uint8_t masked_interupt = ie&i_flag&0x1f; - if(masked_interupt&&!gb->cpu.interrupt_enable){ - gb->cpu.wait_for_interrupt=false; - gb->cpu.halt_bug =true; + uint8_t masked_interupt = ie & i_flag & 0x1f; + if(masked_interupt && !gb->cpu.interrupt_enable) { + gb->cpu.wait_for_interrupt = false; + gb->cpu.halt_bug = true; } } - cpu_delta_cycles = 4*((gb->cpu.branch_taken? (inst.mcycles_branch_taken-(inst.mcycles-1)) : 1)); - gb->cpu.branch_taken=false; - }else if(call_interrupt==false&&gb->cpu.wait_for_interrupt==true && request_speed_switch){ + cpu_delta_cycles = 4 * ((gb->cpu.branch_taken ? (inst.mcycles_branch_taken - (inst.mcycles - 1)) : 1)); + gb->cpu.branch_taken = false; + } else if(call_interrupt == false && gb->cpu.wait_for_interrupt == true && request_speed_switch) { gb->cpu.wait_for_interrupt = false; - sb_store8_io(gb,SB_IO_GBC_SPEED_SWITCH,double_speed? 0x00: 0x80); - cpu_delta_cycles=0; + sb_store8_io(gb, SB_IO_GBC_SPEED_SWITCH, double_speed ? 0x00 : 0x80); + cpu_delta_cycles = 0; } - if(trigger_interrupt!=-1)gb->cpu.wait_for_interrupt=false; - if(!gb->cpu.wait_for_interrupt){ - unsigned next_op = sb_read8(gb,gb->cpu.pc); - if(gb->cpu.prefix_op)next_op+=256; + if(trigger_interrupt != -1) gb->cpu.wait_for_interrupt = false; + if(!gb->cpu.wait_for_interrupt) { + unsigned next_op = sb_read8(gb, gb->cpu.pc); + if(gb->cpu.prefix_op) next_op += 256; sb_instr_t next_inst = sb_decode_table[next_op]; - cpu_delta_cycles+= (next_inst.mcycles-1)*4; - if(gb->cpu.prefix_op){ - cpu_delta_cycles -=4; + cpu_delta_cycles += (next_inst.mcycles - 1) * 4; + if(gb->cpu.prefix_op) { + cpu_delta_cycles -= 4; } } - gb->cpu.last_inter_f = sb_read8_io(gb,SB_IO_INTER_F); + gb->cpu.last_inter_f = sb_read8_io(gb, SB_IO_INTER_F); } - int delta_cycles_after_speed = double_speed ? cpu_delta_cycles/2 : cpu_delta_cycles; - delta_cycles_after_speed+= dma_delta_cycles; - rumble_cycles+=delta_cycles_after_speed*gb->cart.rumble; - total_cylces+=delta_cycles_after_speed; - sb_tick_components(emu,gb,delta_cycles_after_speed); + int delta_cycles_after_speed = double_speed ? cpu_delta_cycles / 2 : cpu_delta_cycles; + delta_cycles_after_speed += dma_delta_cycles; + rumble_cycles += delta_cycles_after_speed * gb->cart.rumble; + total_cylces += delta_cycles_after_speed; + sb_tick_components(emu, gb, delta_cycles_after_speed); - if (gb->cpu.pc == emu->pc_breakpoint||gb->cpu.trigger_breakpoint){ + if(gb->cpu.pc == emu->pc_breakpoint || gb->cpu.trigger_breakpoint) { gb->cpu.trigger_breakpoint = false; emu->run_mode = SB_MODE_PAUSE; break; } - if(gb->lcd.finished_frame){break;} - if(total_cylces>=70224&&emu->step_instructions==0)break; - emu->step_instructions=0; + if(gb->lcd.finished_frame) { break; } + if(total_cylces >= 70224 && emu->step_instructions == 0) break; + emu->step_instructions = 0; } - emu->joy.rumble = (double)rumble_cycles/(double)total_cylces; + emu->joy.rumble = (double)rumble_cycles / (double)total_cylces; } -float compute_vol_env_slope(uint8_t d){ - int dir = SB_BFE(d,3,1); - int length_of_step = SB_BFE(d,0,3); - - float step_time = length_of_step/64.0; - float slope = 1./step_time; - if(dir==0)slope*=-1; - if(length_of_step==0)slope=0; - return slope/16.; -} -float sb_polyblep(float t,float dt){ - if(t<=dt){ - t = t/dt; - return t+t-t*t-1.0;; - }else if (t >= 1-dt){ - t=(t-1.0)/dt; - return t*t+t+t+1.0; - }else return 0; +float compute_vol_env_slope(uint8_t d) { + int dir = SB_BFE(d, 3, 1); + int length_of_step = SB_BFE(d, 0, 3); + + float step_time = length_of_step / 64.0; + float slope = 1. / step_time; + if(dir == 0) slope *= -1; + if(length_of_step == 0) slope = 0; + return slope / 16.; } -float sb_bandlimited_square(float t, float duty_cycle,float dt){ +float sb_polyblep(float t, float dt) { + if(t <= dt) { + t = t / dt; + return t + t - t * t - 1.0; + ; + } else if(t >= 1 - dt) { + t = (t - 1.0) / dt; + return t * t + t + t + 1.0; + } else + return 0; +} +float sb_bandlimited_square(float t, float duty_cycle, float dt) { float t2 = t - duty_cycle; - if(t2< 0.0)t2 +=1.0; + if(t2 < 0.0) t2 += 1.0; float y = t < duty_cycle ? -1 : 1; - y -= sb_polyblep(t,dt); - y += sb_polyblep(t2,dt); + y -= sb_polyblep(t, dt); + y += sb_polyblep(t2, dt); return y; } -static bool sb_load_rom(sb_emu_state_t* emu,sb_gb_t* gb, gb_scratch_t* scratch){ - if(!sb_path_has_file_ext(emu->rom_path,".gb") && - !sb_path_has_file_ext(emu->rom_path,".gbc")) return false; - if(emu->rom_size>MAX_CARTRIDGE_SIZE)return false; +static bool sb_load_rom(sb_emu_state_t *emu, sb_gb_t *gb, gb_scratch_t *scratch) { + if(!sb_path_has_file_ext(emu->rom_path, ".gb") && + !sb_path_has_file_ext(emu->rom_path, ".gbc")) return false; + if(emu->rom_size > MAX_CARTRIDGE_SIZE) return false; memset(gb, 0, sizeof(sb_gb_t)); memset(scratch, 0, sizeof(gb_scratch_t)); gb->cart.data = emu->rom_data; - for(size_t i = 0; i< 32*1024;++i)gb->mem.data[i] = gb->cart.data[i]; + for(size_t i = 0; i < 32 * 1024; ++i) + gb->mem.data[i] = gb->cart.data[i]; // Copy Header - for (int i = 0; i < 11; ++i) { + for(int i = 0; i < 11; ++i) { gb->cart.title[i] = gb->cart.data[i + 0x134]; } - gb->cart.title[12] ='\0'; + gb->cart.title[12] = '\0'; // TODO PGB Mode(Values with Bit 7 set, and either Bit 2 or 3 set) gb->cart.game_boy_color = SB_BFE(gb->cart.data[0x143], 7, 1) == 1; gb->cart.type = gb->cart.data[0x147]; - for(int i=0;ilcd.color_palettes);++i)gb->lcd.color_palettes[i]=0xff; - - switch(gb->cart.type){ - case 0: gb->cart.mbc_type = SB_MBC_NO_MBC; break; - - case 1: - case 2: - case 3: gb->cart.mbc_type = SB_MBC_MBC1; break; - - case 5: - case 6: gb->cart.mbc_type = SB_MBC_MBC2; break; - - case 0x0f: - case 0x10: gb->rtc.has_rtc =true; gb->cart.mbc_type = SB_MBC_MBC3; break; - case 0x11: - case 0x12: - case 0x13: gb->cart.mbc_type = SB_MBC_MBC3; break; - - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E:gb->cart.mbc_type = SB_MBC_MBC5; break; - - case 0x20:gb->cart.mbc_type = SB_MBC_MBC6; break; - case 0x22:gb->cart.mbc_type = SB_MBC_MBC7; break; - + for(int i = 0; i < sizeof(gb->lcd.color_palettes); ++i) + gb->lcd.color_palettes[i] = 0xff; + + switch(gb->cart.type) { + case 0: gb->cart.mbc_type = SB_MBC_NO_MBC; break; + + case 1: + case 2: + case 3: gb->cart.mbc_type = SB_MBC_MBC1; break; + + case 5: + case 6: gb->cart.mbc_type = SB_MBC_MBC2; break; + + case 0x0f: + case 0x10: + gb->rtc.has_rtc = true; + gb->cart.mbc_type = SB_MBC_MBC3; + break; + case 0x11: + case 0x12: + case 0x13: gb->cart.mbc_type = SB_MBC_MBC3; break; + + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: gb->cart.mbc_type = SB_MBC_MBC5; break; + + case 0x20: gb->cart.mbc_type = SB_MBC_MBC6; break; + case 0x22: gb->cart.mbc_type = SB_MBC_MBC7; break; } - gb->cart.has_rumble=false; - switch(gb->cart.type){ - case 0x1C: - case 0x1D: - case 0x1E: - case 0x22: gb->cart.has_rumble=true; break; + gb->cart.has_rumble = false; + switch(gb->cart.type) { + case 0x1C: + case 0x1D: + case 0x1E: + case 0x22: gb->cart.has_rumble = true; break; } - switch (gb->cart.data[0x148]) { - case 0x0: gb->cart.rom_size = 32 * 1024; break; - case 0x1: gb->cart.rom_size = 64 * 1024; break; - case 0x2: gb->cart.rom_size = 128 * 1024; break; - case 0x3: gb->cart.rom_size = 256 * 1024; break; - case 0x4: gb->cart.rom_size = 512 * 1024; break; - case 0x5: gb->cart.rom_size = 1024 * 1024; break; - case 0x6: gb->cart.rom_size = 2 * 1024 * 1024; break; - case 0x7: gb->cart.rom_size = 4 * 1024 * 1024; break; - case 0x8: gb->cart.rom_size = 8 * 1024 * 1024; break; - case 0x52: gb->cart.rom_size = 1.1 * 1024 * 1024; break; - case 0x53: gb->cart.rom_size = 1.2 * 1024 * 1024; break; - case 0x54: gb->cart.rom_size = 1.5 * 1024 * 1024; break; - default: gb->cart.rom_size = 32 * 1024; break; + switch(gb->cart.data[0x148]) { + case 0x0: gb->cart.rom_size = 32 * 1024; break; + case 0x1: gb->cart.rom_size = 64 * 1024; break; + case 0x2: gb->cart.rom_size = 128 * 1024; break; + case 0x3: gb->cart.rom_size = 256 * 1024; break; + case 0x4: gb->cart.rom_size = 512 * 1024; break; + case 0x5: gb->cart.rom_size = 1024 * 1024; break; + case 0x6: gb->cart.rom_size = 2 * 1024 * 1024; break; + case 0x7: gb->cart.rom_size = 4 * 1024 * 1024; break; + case 0x8: gb->cart.rom_size = 8 * 1024 * 1024; break; + case 0x52: gb->cart.rom_size = 1.1 * 1024 * 1024; break; + case 0x53: gb->cart.rom_size = 1.2 * 1024 * 1024; break; + case 0x54: gb->cart.rom_size = 1.5 * 1024 * 1024; break; + default: gb->cart.rom_size = 32 * 1024; break; } - switch (gb->cart.data[0x149]) { - case 0x0: gb->cart.ram_size = 0; break; - case 0x1: gb->cart.ram_size = 2*1024; break; - case 0x2: gb->cart.ram_size = 8 * 1024; break; - case 0x3: gb->cart.ram_size = 32 * 1024; break; - case 0x4: gb->cart.ram_size = 128 * 1024; break; - case 0x5: gb->cart.ram_size = 64 * 1024; break; - default: gb->cart.ram_size = 0; break; + switch(gb->cart.data[0x149]) { + case 0x0: gb->cart.ram_size = 0; break; + case 0x1: gb->cart.ram_size = 2 * 1024; break; + case 0x2: gb->cart.ram_size = 8 * 1024; break; + case 0x3: gb->cart.ram_size = 32 * 1024; break; + case 0x4: gb->cart.ram_size = 128 * 1024; break; + case 0x5: gb->cart.ram_size = 64 * 1024; break; + default: gb->cart.ram_size = 0; break; } gb->model = SB_GB; - if(gb->cart.game_boy_color&&!emu->force_dmg_mode){ + if(gb->cart.game_boy_color && !emu->force_dmg_mode) { gb->model = SB_GBC; } - gb->cart.mapped_rom_bank=1; - size_t bytes =0; - uint8_t*data = sb_load_file_data(emu->save_file_path, &bytes); - if(data){ - if(bytes!=gb->cart.ram_size){ + gb->cart.mapped_rom_bank = 1; + size_t bytes = 0; + uint8_t *data = sb_load_file_data(emu->save_file_path, &bytes); + if(data) { + if(bytes != gb->cart.ram_size) { printf("Warning save file size(%zu) doesn't match size expected(%d) for the cartridge type", bytes, gb->cart.ram_size); } - if(bytes>gb->cart.ram_size){ + if(bytes > gb->cart.ram_size) { bytes = gb->cart.ram_size; } memcpy(gb->cart.ram_data, data, bytes); sb_free_file_data(data); - }else{ - printf("Could not find save file: %s\n",emu->save_file_path); - memset(gb->cart.ram_data,0,MAX_CARTRIDGE_RAM); + } else { + printf("Could not find save file: %s\n", emu->save_file_path); + memset(gb->cart.ram_data, 0, MAX_CARTRIDGE_RAM); } - bool loaded_bios = false; - if(gb->model==SB_GB){ - if(!emu->force_dmg_mode){ - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_boot.bin", scratch->bios,2304); - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "gbc_bios.bin", scratch->bios,2304); - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb0_boot.bin", scratch->bios,2304); - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_agb_boot.bin", scratch->bios,2304); - if(loaded_bios){ - gb->model=SB_GBC; + bool loaded_bios = false; + if(gb->model == SB_GB) { + if(!emu->force_dmg_mode) { + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_boot.bin", scratch->bios, 2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "gbc_bios.bin", scratch->bios, 2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb0_boot.bin", scratch->bios, 2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_agb_boot.bin", scratch->bios, 2304); + if(loaded_bios) { + gb->model = SB_GBC; } } - if(!loaded_bios) loaded_bios= se_load_bios_file("DMG BOOT", emu->save_file_path, "dmg_rom.bin", scratch->bios,256); - if(!loaded_bios) loaded_bios= se_load_bios_file("DMG BOOT", emu->save_file_path, "dmg0_rom.bin", scratch->bios,256); - if(!loaded_bios) loaded_bios= se_load_bios_file("DMG BOOT", emu->save_file_path, "gb_bios.bin", scratch->bios,256); - }else if(gb->model==SB_GBC){ - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_boot.bin", scratch->bios,2304); - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "gbc_bios.bin", scratch->bios,2304); - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb0_boot.bin", scratch->bios,2304); - if(!loaded_bios)loaded_bios= se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_agb_boot.bin", scratch->bios,2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("DMG BOOT", emu->save_file_path, "dmg_rom.bin", scratch->bios, 256); + if(!loaded_bios) loaded_bios = se_load_bios_file("DMG BOOT", emu->save_file_path, "dmg0_rom.bin", scratch->bios, 256); + if(!loaded_bios) loaded_bios = se_load_bios_file("DMG BOOT", emu->save_file_path, "gb_bios.bin", scratch->bios, 256); + } else if(gb->model == SB_GBC) { + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_boot.bin", scratch->bios, 2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "gbc_bios.bin", scratch->bios, 2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb0_boot.bin", scratch->bios, 2304); + if(!loaded_bios) loaded_bios = se_load_bios_file("GBC BOOT", emu->save_file_path, "cgb_agb_boot.bin", scratch->bios, 2304); } - if(loaded_bios){ - gb->cpu.pc = 0; - }else{ - sb_store8_io(gb,SB_IO_BIOS_BANK,1); + if(loaded_bios) { + gb->cpu.pc = 0; + } else { + sb_store8_io(gb, SB_IO_BIOS_BANK, 1); gb->cpu.pc = 0x100; - gb->cpu.af=0x01B0; - gb->cpu.bc=0x0013; - gb->cpu.de=0x00D8; - gb->cpu.hl=0x014D; - gb->cpu.sp=0xFFFE; - if(gb->model == SB_GBC){ - gb->cpu.af|=0x11<<8; + gb->cpu.af = 0x01B0; + gb->cpu.bc = 0x0013; + gb->cpu.de = 0x00D8; + gb->cpu.hl = 0x014D; + gb->cpu.sp = 0xFFFE; + if(gb->model == SB_GBC) { + gb->cpu.af |= 0x11 << 8; } gb->mem.data[0xFF05] = 0x00; // TIMA @@ -1653,287 +1677,298 @@ static bool sb_load_rom(sb_emu_state_t* emu,sb_gb_t* gb, gb_scratch_t* scratch){ gb->mem.data[0xFF4B] = 0x00; // WX gb->mem.data[0xFFFF] = 0x00; // IE } - - return true; + + return true; } -static uint8_t sb_read_wave_ram(sb_gb_t*gb, int index){ - return sb_read8_io(gb,SB_IO_AUD3_WAVE_BASE+index); +static uint8_t sb_read_wave_ram(sb_gb_t *gb, int index) { + return sb_read8_io(gb, SB_IO_AUD3_WAVE_BASE + index); } -static int sb_compute_next_sweep_freq(sb_frame_sequencer_t*seq){ - int shift = seq->sweep_shift?seq->sweep_shift:8; - int32_t increment = (seq->frequency[0] >> shift)*seq->sweep_direction; - int32_t new_frequency = seq->frequency[0]+increment; - seq->sweep_subtracted|=seq->sweep_direction==-1; +static int sb_compute_next_sweep_freq(sb_frame_sequencer_t *seq) { + int shift = seq->sweep_shift ? seq->sweep_shift : 8; + int32_t increment = (seq->frequency[0] >> shift) * seq->sweep_direction; + int32_t new_frequency = seq->frequency[0] + increment; + seq->sweep_subtracted |= seq->sweep_direction == -1; return new_frequency; } -static void sb_tick_frame_sweep(sb_frame_sequencer_t*seq){ +static void sb_tick_frame_sweep(sb_frame_sequencer_t *seq) { int32_t new_frequency = sb_compute_next_sweep_freq(seq); - if(new_frequency>2047){ - seq->active[0]=false; - new_frequency = 2047; - }else if(new_frequency<0)new_frequency=0; - if(seq->sweep_shift){ - seq->frequency[0]= new_frequency; + if(new_frequency > 2047) { + seq->active[0] = false; + new_frequency = 2047; + } else if(new_frequency < 0) + new_frequency = 0; + if(seq->sweep_shift) { + seq->frequency[0] = new_frequency; new_frequency = sb_compute_next_sweep_freq(seq); - if(new_frequency>2047){ - seq->active[0]=false; - new_frequency = 2047; + if(new_frequency > 2047) { + seq->active[0] = false; + new_frequency = 2047; } } } -static void sb_tick_frame_seq(sb_gb_t*gb,sb_frame_sequencer_t* seq){ - int step = (seq->step_counter++)%8; - //Tick sweep - if(step==2||step==6){ - if(seq->active[0]&&seq->sweep_enable){ - if(seq->sweep_timer>0)seq->sweep_timer--; - if(seq->sweep_timer == 0){ - if(seq->sweep_period > 0){ +static void sb_tick_frame_seq(sb_gb_t *gb, sb_frame_sequencer_t *seq) { + int step = (seq->step_counter++) % 8; + // Tick sweep + if(step == 2 || step == 6) { + if(seq->active[0] && seq->sweep_enable) { + if(seq->sweep_timer > 0) seq->sweep_timer--; + if(seq->sweep_timer == 0) { + if(seq->sweep_period > 0) { seq->sweep_timer = seq->sweep_period; sb_tick_frame_sweep(seq); - }else seq->sweep_timer = 8; + } else + seq->sweep_timer = 8; } } } - //Tick envelope - if(step==7){ - for(int i=0;i<4;++i){ - if(i==2)continue; - if(seq->env_period[i]){ - if(seq->env_period_timer[i]>0)seq->env_period_timer[i]--; - if(seq->env_period_timer[i]==0){ - seq->env_period_timer[i]=seq->env_period[i]; + // Tick envelope + if(step == 7) { + for(int i = 0; i < 4; ++i) { + if(i == 2) continue; + if(seq->env_period[i]) { + if(seq->env_period_timer[i] > 0) seq->env_period_timer[i]--; + if(seq->env_period_timer[i] == 0) { + seq->env_period_timer[i] = seq->env_period[i]; int volume = seq->volume[i]; - volume+=seq->env_direction[i]; - if(volume<=0){volume=0;seq->env_overflow[i]=true;} - if(volume>0xF){volume=0xF;seq->env_overflow[i]=true;}; - seq->volume[i]=volume; + volume += seq->env_direction[i]; + if(volume <= 0) { + volume = 0; + seq->env_overflow[i] = true; + } + if(volume > 0xF) { + volume = 0xF; + seq->env_overflow[i] = true; + }; + seq->volume[i] = volume; } } } } - if((step%2)==0){ - //Tick length - for(int i=0;i<4;++i){ - if(!seq->use_length[i])continue; - if(seq->length[i]>0)seq->length[i]--; - if(seq->length[i]==0){ - seq->active[i]=false; - seq->length[i] = i==2?256:64; + if((step % 2) == 0) { + // Tick length + for(int i = 0; i < 4; ++i) { + if(!seq->use_length[i]) continue; + if(seq->length[i] > 0) seq->length[i]--; + if(seq->length[i] == 0) { + seq->active[i] = false; + seq->length[i] = i == 2 ? 256 : 64; seq->use_length[i] = false; } } } - int nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - for(int i=0;i<4;++i){ - seq->active[i]&=seq->powered[i]; + int nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + for(int i = 0; i < 4; ++i) { + seq->active[i] &= seq->powered[i]; bool active = seq->active[i]; - nrf_52|=active<audio; - sb_frame_sequencer_t* seq = &audio->sequencer; - int nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - bool master_enable = SB_BFE(nrf_52,7,1); - if(!master_enable){ - for(int i=SB_IO_AUD1_TONE_SWEEP;iaudio; + sb_frame_sequencer_t *seq = &audio->sequencer; + int nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + bool master_enable = SB_BFE(nrf_52, 7, 1); + if(!master_enable) { + for(int i = SB_IO_AUD1_TONE_SWEEP; i < SB_IO_SOUND_ON_OFF; ++i) { + sb_store8_io(gb, i, 0); } - for(int i=0;i<4;++i){ - if(sb_gbc_enable(gb)||i!=3){ - seq->active[i]=false; - seq->powered[i]=false; - seq->length[i]=0; + for(int i = 0; i < 4; ++i) { + if(sb_gbc_enable(gb) || i != 3) { + seq->active[i] = false; + seq->powered[i] = false; + seq->length[i] = 0; } - seq->use_length[i]=false; + seq->use_length[i] = false; } - - }else{ + + } else { uint8_t freq_sweep1 = sb_read8_io(gb, SB_IO_AUD1_TONE_SWEEP); - seq->sweep_period=SB_BFE(freq_sweep1, 4, 3); - seq->sweep_shift=SB_BFE(freq_sweep1, 0, 3); - seq->sweep_direction= SB_BFE(freq_sweep1, 3,1)? -1. : 1; - for(int i=0;i<4;++i){ - bool prev_length_en = seq->use_length[i]; - uint8_t freq_hi = sb_read8_io(gb,SB_IO_AUD1_FREQ_HI+i*5); - seq->use_length[i]= SB_BFE(freq_hi,6,1); - uint8_t vol_env = sb_read8_io(gb,SB_IO_AUD1_VOL_ENV+i*5); - if(i==2){ - bool power = SB_BFE(sb_read8_io(gb,SB_IO_AUD3_POWER),7,1); - seq->powered[i]=power; + seq->sweep_period = SB_BFE(freq_sweep1, 4, 3); + seq->sweep_shift = SB_BFE(freq_sweep1, 0, 3); + seq->sweep_direction = SB_BFE(freq_sweep1, 3, 1) ? -1. : 1; + for(int i = 0; i < 4; ++i) { + bool prev_length_en = seq->use_length[i]; + uint8_t freq_hi = sb_read8_io(gb, SB_IO_AUD1_FREQ_HI + i * 5); + seq->use_length[i] = SB_BFE(freq_hi, 6, 1); + uint8_t vol_env = sb_read8_io(gb, SB_IO_AUD1_VOL_ENV + i * 5); + if(i == 2) { + bool power = SB_BFE(sb_read8_io(gb, SB_IO_AUD3_POWER), 7, 1); + seq->powered[i] = power; } - if(i!=0){ - uint8_t freq_lo = sb_read8_io(gb,SB_IO_AUD1_FREQ+i*5); - seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi,0,3))<<8u); + if(i != 0) { + uint8_t freq_lo = sb_read8_io(gb, SB_IO_AUD1_FREQ + i * 5); + seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi, 0, 3)) << 8u); } - if(i==2){ + if(i == 2) { seq->env_direction[i] = 0; seq->env_period[i] = 0; - }else{ - seq->env_direction[i] = (SB_BFE(vol_env,3,1)?1:-1); - seq->env_period[i] = SB_BFE(vol_env,0,3); + } else { + seq->env_direction[i] = (SB_BFE(vol_env, 3, 1) ? 1 : -1); + seq->env_period[i] = SB_BFE(vol_env, 0, 3); } - bool triggered = SB_BFE(freq_hi,7,1); - if(triggered){ - uint8_t length_duty = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY+i*5); - uint8_t freq_lo = sb_read8_io(gb,SB_IO_AUD1_FREQ+i*5); - seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi,0,3))<<8u); - seq->volume[i] = SB_BFE(vol_env,4,4); - - if(seq->length[i]==0)seq->length[i]=i==2?256:64; - if(i==3)seq->lfsr4 = 0x7FFF; - if(i==2){ - audio->wave_sample_offset=31; - audio->wave_freq_timer=4; + bool triggered = SB_BFE(freq_hi, 7, 1); + if(triggered) { + uint8_t length_duty = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY + i * 5); + uint8_t freq_lo = sb_read8_io(gb, SB_IO_AUD1_FREQ + i * 5); + seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi, 0, 3)) << 8u); + seq->volume[i] = SB_BFE(vol_env, 4, 4); + + if(seq->length[i] == 0) seq->length[i] = i == 2 ? 256 : 64; + if(i == 3) seq->lfsr4 = 0x7FFF; + if(i == 2) { + audio->wave_sample_offset = 31; + audio->wave_freq_timer = 4; } - seq->env_period_timer[i]=0; - seq->env_overflow[i]=false; - seq->chan_t[i]=0; - seq->active[i]=true; - if(i==0){ - seq->sweep_subtracted=false; - seq->sweep_enable = seq->sweep_period||seq->sweep_shift; - seq->sweep_timer=seq->sweep_period; - if(seq->sweep_timer==0)seq->sweep_timer=8; - if (seq->sweep_shift && sb_compute_next_sweep_freq(seq) > 2047) { + seq->env_period_timer[i] = 0; + seq->env_overflow[i] = false; + seq->chan_t[i] = 0; + seq->active[i] = true; + if(i == 0) { + seq->sweep_subtracted = false; + seq->sweep_enable = seq->sweep_period || seq->sweep_shift; + seq->sweep_timer = seq->sweep_period; + if(seq->sweep_timer == 0) seq->sweep_timer = 8; + if(seq->sweep_shift && sb_compute_next_sweep_freq(seq) > 2047) { seq->active[0] = false; - } - seq->sweep_enable = seq->sweep_period>0||seq->sweep_shift>0; + } + seq->sweep_enable = seq->sweep_period > 0 || seq->sweep_shift > 0; } } - if(i==0&&seq->sweep_subtracted&&seq->sweep_direction!=-1){ - seq->active[0]= false; + if(i == 0 && seq->sweep_subtracted && seq->sweep_direction != -1) { + seq->active[0] = false; seq->sweep_enable = false; } - if(seq->use_length[i]&&!prev_length_en){ - bool second_half_of_length_period = (seq->step_counter&1); - if(second_half_of_length_period){ - if(seq->length[i])seq->length[i]--; - if(seq->length[i]==0){ - if(triggered) seq->length[i]=i==2?255:63; - else{ - seq->active[i]=false; - seq->use_length[i]=triggered&&seq->use_length[i]; + if(seq->use_length[i] && !prev_length_en) { + bool second_half_of_length_period = (seq->step_counter & 1); + if(second_half_of_length_period) { + if(seq->length[i]) seq->length[i]--; + if(seq->length[i] == 0) { + if(triggered) + seq->length[i] = i == 2 ? 255 : 63; + else { + seq->active[i] = false; + seq->use_length[i] = triggered && seq->use_length[i]; } } } } - sb_store8_io(gb, SB_IO_AUD1_FREQ_HI+i*5,freq_hi&0x7f); + sb_store8_io(gb, SB_IO_AUD1_FREQ_HI + i * 5, freq_hi & 0x7f); } } - nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - for(int i=0;i<4;++i){ - seq->active[i]&=seq->powered[i]; + nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + for(int i = 0; i < 4; ++i) { + seq->active[i] &= seq->powered[i]; bool active = seq->active[i]; - nrf_52|=active<>8|addr<<8; - if (addr < 0xA000 || addr > 0xDFFF)return false; - uint8_t data=(cheat>>16)&0xff; - uint8_t bank=cheat>>24; - - uint8_t previous_bank=gb->cart.mapped_ram_bank; - - if(addr>=0xA000&&addr<=0xBFFF){ - gb->cart.mapped_ram_bank=bank; + for(int i = 0; i < size; i++) { + uint32_t cheat = buffer[i]; + uint16_t addr = cheat & 0xffff; + addr = addr >> 8 | addr << 8; + if(addr < 0xA000 || addr > 0xDFFF) return false; + uint8_t data = (cheat >> 16) & 0xff; + uint8_t bank = cheat >> 24; + + uint8_t previous_bank = gb->cart.mapped_ram_bank; + + if(addr >= 0xA000 && addr <= 0xBFFF) { + gb->cart.mapped_ram_bank = bank; } - sb_store8_direct(gb,addr,data); + sb_store8_direct(gb, addr, data); - if(addr>=0xA000&&addr<=0xBFFF){ - gb->cart.mapped_ram_bank=previous_bank; + if(addr >= 0xA000 && addr <= 0xBFFF) { + gb->cart.mapped_ram_bank = previous_bank; } } return true; } -static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t*emu, double delta_time, int cycles){ - - sb_audio_t* audio = &gb->audio; - sb_frame_sequencer_t* seq = &audio->sequencer; - - if(delta_time>1.0/60.)delta_time = 1.0/60.; - audio->current_sim_time +=delta_time; - #ifdef GBA_AUDIO - uint32_t prev_audio_clock = audio->audio_clock; - audio->audio_clock+=cycles; - cycles = (audio->audio_clock-(prev_audio_clock&~3))/4; - uint32_t frame_cycles = (audio->audio_clock-(prev_audio_clock&~32767))/32768; - while(frame_cycles--)gba_tick_frame_seq(gb,seq); - #endif +static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t *emu, double delta_time, int cycles) { + + sb_audio_t *audio = &gb->audio; + sb_frame_sequencer_t *seq = &audio->sequencer; + + if(delta_time > 1.0 / 60.) delta_time = 1.0 / 60.; + audio->current_sim_time += delta_time; +#ifdef GBA_AUDIO + uint32_t prev_audio_clock = audio->audio_clock; + audio->audio_clock += cycles; + cycles = (audio->audio_clock - (prev_audio_clock & ~3)) / 4; + uint32_t frame_cycles = (audio->audio_clock - (prev_audio_clock & ~32767)) / 32768; + while(frame_cycles--) + gba_tick_frame_seq(gb, seq); +#endif int freq_tim = audio->wave_freq_timer; - freq_tim-=cycles; - if(freq_tim<0){ - int wave_inc_count = (-freq_tim-1)/((2048-seq->frequency[2])*2)+1; - audio->wave_sample_offset+= wave_inc_count; - freq_tim +=(2048-seq->frequency[2])*2*wave_inc_count; - unsigned wav_samp = (audio->wave_sample_offset)%32; - int dat =sb_read_wave_ram(gb,wav_samp/2); + freq_tim -= cycles; + if(freq_tim < 0) { + int wave_inc_count = (-freq_tim - 1) / ((2048 - seq->frequency[2]) * 2) + 1; + audio->wave_sample_offset += wave_inc_count; + freq_tim += (2048 - seq->frequency[2]) * 2 * wave_inc_count; + unsigned wav_samp = (audio->wave_sample_offset) % 32; + int dat = sb_read_wave_ram(gb, wav_samp / 2); audio->curr_wave_data = dat; - int offset = (wav_samp&1)? 0:4; - audio->curr_wave_sample = ((dat>>offset)&0xf); + int offset = (wav_samp & 1) ? 0 : 4; + audio->curr_wave_sample = ((dat >> offset) & 0xf); } - audio->wave_freq_timer=freq_tim; + audio->wave_freq_timer = freq_tim; audio->current_sample_generated_time -= (int)(audio->current_sim_time); audio->current_sim_time -= (int)(audio->current_sim_time); - if(audio->current_sample_generated_time >audio->current_sim_time)return; - - int nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - - bool master_enable = SB_BFE(nrf_52,7,1); - if(!master_enable)return; - float sample_delta_t = 1.0/SE_AUDIO_SAMPLE_RATE; - - const static float duty_lookup[]={0.125,0.25,0.5,0.75}; - uint8_t length_duty1 = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY); - float duty1 = duty_lookup[SB_BFE(length_duty1,6,2)]; - uint8_t length_duty2 = sb_read8_io(gb, SB_IO_AUD2_LENGTH_DUTY); - float duty2 = duty_lookup[SB_BFE(length_duty2,6,2)]; - - uint8_t power3 = sb_read8_io(gb,SB_IO_AUD3_POWER); - uint8_t vol_env3 = sb_read8_io(gb,SB_IO_AUD3_VOL); - int channel3_shift = SB_BFE(vol_env3,5,2)-1; - if(SB_BFE(power3,7,1)==0||channel3_shift==-1)channel3_shift=4; - - uint8_t poly4 = sb_read8_io(gb,SB_IO_AUD4_POLY); - float r4 = SB_BFE(poly4,0,3); - uint8_t s4 = SB_BFE(poly4,4,4); - bool sevenBit4 = SB_BFE(poly4,3,1); - if(r4==0)r4=0.5; - - uint8_t master_vol = sb_read8_io(gb,SB_IO_MASTER_VOLUME); - float master_left = SB_BFE(master_vol,4,3)/7.; - float master_right = SB_BFE(master_vol,0,3)/7.; - - uint8_t chan_sel = sb_read8_io(gb,SB_IO_SOUND_OUTPUT_SEL); - //These are type int to allow them to be multiplied to enable/disable - float chan_l[6]={0};float chan_r[6]={0}; - for(int i=0;i<4;++i){ - chan_l[i] = SB_BFE(chan_sel,i,1); - chan_r[i] = SB_BFE(chan_sel,i+4,1); + if(audio->current_sample_generated_time > audio->current_sim_time) return; + + int nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + + bool master_enable = SB_BFE(nrf_52, 7, 1); + if(!master_enable) return; + float sample_delta_t = 1.0 / SE_AUDIO_SAMPLE_RATE; + + const static float duty_lookup[] = {0.125, 0.25, 0.5, 0.75}; + uint8_t length_duty1 = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY); + float duty1 = duty_lookup[SB_BFE(length_duty1, 6, 2)]; + uint8_t length_duty2 = sb_read8_io(gb, SB_IO_AUD2_LENGTH_DUTY); + float duty2 = duty_lookup[SB_BFE(length_duty2, 6, 2)]; + + uint8_t power3 = sb_read8_io(gb, SB_IO_AUD3_POWER); + uint8_t vol_env3 = sb_read8_io(gb, SB_IO_AUD3_VOL); + int channel3_shift = SB_BFE(vol_env3, 5, 2) - 1; + if(SB_BFE(power3, 7, 1) == 0 || channel3_shift == -1) channel3_shift = 4; + + uint8_t poly4 = sb_read8_io(gb, SB_IO_AUD4_POLY); + float r4 = SB_BFE(poly4, 0, 3); + uint8_t s4 = SB_BFE(poly4, 4, 4); + bool sevenBit4 = SB_BFE(poly4, 3, 1); + if(r4 == 0) r4 = 0.5; + + uint8_t master_vol = sb_read8_io(gb, SB_IO_MASTER_VOLUME); + float master_left = SB_BFE(master_vol, 4, 3) / 7.; + float master_right = SB_BFE(master_vol, 0, 3) / 7.; + + uint8_t chan_sel = sb_read8_io(gb, SB_IO_SOUND_OUTPUT_SEL); + // These are type int to allow them to be multiplied to enable/disable + float chan_l[6] = {0}; + float chan_r[6] = {0}; + for(int i = 0; i < 4; ++i) { + chan_l[i] = SB_BFE(chan_sel, i, 1); + chan_r[i] = SB_BFE(chan_sel, i + 4, 1); } - #ifdef GBA_AUDIO +#ifdef GBA_AUDIO { - uint16_t soundcnt_h = gba_io_read16(gb,GBA_SOUNDCNT_H); - //These are type int to allow them to be multiplied to enable/disable - uint16_t chan_sel = gba_io_read16(gb,GBA_SOUNDCNT_L); - /* soundcnth + uint16_t soundcnt_h = gba_io_read16(gb, GBA_SOUNDCNT_H); + // These are type int to allow them to be multiplied to enable/disable + uint16_t chan_sel = gba_io_read16(gb, GBA_SOUNDCNT_L); + /* soundcnth 0-1 R/W Sound # 1-4 Volume (0=25%, 1=50%, 2=100%, 3=Prohibited) 2 R/W DMA Sound A Volume (0=50%, 1=100%) 3 R/W DMA Sound B Volume (0=50%, 1=100%) @@ -1945,113 +1980,119 @@ static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t*emu, doubl 12 R/W DMA Sound B Enable RIGHT (0=Disable, 1=Enable) 13 R/W DMA Sound B Enable LEFT (0=Disable, 1=Enable) 14 R/W DMA Sound B Timer Select (0=Timer 0, 1=Timer 1) - 15 W? DMA Sound B Reset FIFO (1=Reset)*/ - float psg_volume_lookup[4]={0.25,0.5,1.0,0.}; - float psg_volume = psg_volume_lookup[SB_BFE(soundcnt_h,0,2)]*0.25; + 15 W? DMA Sound B Reset FIFO (1=Reset)*/ + float psg_volume_lookup[4] = {0.25, 0.5, 1.0, 0.}; + float psg_volume = psg_volume_lookup[SB_BFE(soundcnt_h, 0, 2)] * 0.25; - float r_vol = SB_BFE(chan_sel,0,3)/7.*psg_volume; - float l_vol = SB_BFE(chan_sel,4,3)/7.*psg_volume; - for(int i=0;i<4;++i){ + float r_vol = SB_BFE(chan_sel, 0, 3) / 7. * psg_volume; + float l_vol = SB_BFE(chan_sel, 4, 3) / 7. * psg_volume; + for(int i = 0; i < 4; ++i) { chan_r[i] *= r_vol; chan_l[i] *= l_vol; } // Channel volume for each FIFO - for(int i=0;i<2;++i){ + for(int i = 0; i < 2; ++i) { // Volume - chan_r[i+4]=chan_l[i+4]= SB_BFE(soundcnt_h,2+i,1)? 1.0: 0.5; - chan_r[i+4]*= SB_BFE(soundcnt_h,8+i*4,1); - chan_l[i+4]*= SB_BFE(soundcnt_h,9+i*4,1); + chan_r[i + 4] = chan_l[i + 4] = SB_BFE(soundcnt_h, 2 + i, 1) ? 1.0 : 0.5; + chan_r[i + 4] *= SB_BFE(soundcnt_h, 8 + i * 4, 1); + chan_l[i + 4] *= SB_BFE(soundcnt_h, 9 + i * 4, 1); } - gba_io_store16(gb,GBA_SOUNDCNT_H,soundcnt_h&~((1<<11)|(1<<15))); - master_left=master_right=1; + gba_io_store16(gb, GBA_SOUNDCNT_H, soundcnt_h & ~((1 << 11) | (1 << 15))); + master_left = master_right = 1; } - #endif +#endif float freq_hz[4]; - for(int i=0;i<2;++i){freq_hz[i]= 131072./(2048-seq->frequency[i]);} - freq_hz[2]= (65536.)/(2048-seq->frequency[2]); - freq_hz[3] = 524288.0/r4/pow(2.0,s4+1); - while(audio->current_sample_generated_time < audio->current_sim_time){ - - audio->current_sample_generated_time+=sample_delta_t; - - if((sb_ring_buffer_size(&emu->audio_ring_buff)+3>SB_AUDIO_RING_BUFFER_SIZE)) continue; - - //Advance each channel - for(int i=0;i<4;++i)seq->chan_t[i] +=sample_delta_t*freq_hz[i]; - //Generate new noise value if needed - if(seq->chan_t[3]>=1.0) { + for(int i = 0; i < 2; ++i) { + freq_hz[i] = 131072. / (2048 - seq->frequency[i]); + } + freq_hz[2] = (65536.) / (2048 - seq->frequency[2]); + freq_hz[3] = 524288.0 / r4 / pow(2.0, s4 + 1); + while(audio->current_sample_generated_time < audio->current_sim_time) { + + audio->current_sample_generated_time += sample_delta_t; + + if((sb_ring_buffer_size(&emu->audio_ring_buff) + 3 > SB_AUDIO_RING_BUFFER_SIZE)) continue; + + // Advance each channel + for(int i = 0; i < 4; ++i) + seq->chan_t[i] += sample_delta_t * freq_hz[i]; + // Generate new noise value if needed + if(seq->chan_t[3] >= 1.0) { int bit = (seq->lfsr4 ^ (seq->lfsr4 >> 1)) & 1; seq->lfsr4 >>= 1; seq->lfsr4 |= bit << 14; - if (sevenBit4) { + if(sevenBit4) { seq->lfsr4 &= ~(1 << 7); seq->lfsr4 |= bit << 6; } } - - //Loopback - for(int i=0;i<4;++i) seq->chan_t[i]-=(int)seq->chan_t[i]; - - //Compute and clamp Volume Envelopes + + // Loopback + for(int i = 0; i < 4; ++i) + seq->chan_t[i] -= (int)seq->chan_t[i]; + + // Compute and clamp Volume Envelopes float v[4]; - for(int i=0;i<4;++i)v[i] = seq->active[i]?seq->volume[i]/15.:0; + for(int i = 0; i < 4; ++i) + v[i] = seq->active[i] ? seq->volume[i] / 15. : 0; v[2] = 1.0; - int dat = audio->curr_wave_sample >>channel3_shift; - int wav_offset = 8>>channel3_shift; - + int dat = audio->curr_wave_sample >> channel3_shift; + int wav_offset = 8 >> channel3_shift; + float channels[6]; - channels[0] = sb_bandlimited_square(seq->chan_t[0],duty1,sample_delta_t*freq_hz[0])*v[0]; - channels[1] = sb_bandlimited_square(seq->chan_t[1],duty2,sample_delta_t*freq_hz[1])*v[1]; - channels[2] = (dat-wav_offset)/8.; - channels[3] = ((seq->lfsr4 & 1) * 2.-1.)*v[3]; - - #ifdef GBA_AUDIO - for(int i=0;i<2;++i)channels[4+i] = audio->fifo[i].data[audio->fifo[i].read_ptr&0x1f]/128.; - #else - for(int i=0;i<2;++i)channels[4+i] =0; - #endif - - //Mix channels + channels[0] = sb_bandlimited_square(seq->chan_t[0], duty1, sample_delta_t * freq_hz[0]) * v[0]; + channels[1] = sb_bandlimited_square(seq->chan_t[1], duty2, sample_delta_t * freq_hz[1]) * v[1]; + channels[2] = (dat - wav_offset) / 8.; + channels[3] = ((seq->lfsr4 & 1) * 2. - 1.) * v[3]; + +#ifdef GBA_AUDIO + for(int i = 0; i < 2; ++i) + channels[4 + i] = audio->fifo[i].data[audio->fifo[i].read_ptr & 0x1f] / 128.; +#else + for(int i = 0; i < 2; ++i) + channels[4 + i] = 0; +#endif + + // Mix channels float sample_volume_l = 0; float sample_volume_r = 0; - for(int i=0;i<6;++i){ - float l = channels[i]*chan_l[i]; - float r = channels[i]*chan_r[i]; - if(l>=-2.&&l<=2)sample_volume_l+=l; - if(r>=-2.&&r<=2)sample_volume_r+=r; + for(int i = 0; i < 6; ++i) { + float l = channels[i] * chan_l[i]; + float r = channels[i] * chan_r[i]; + if(l >= -2. && l <= 2) sample_volume_l += l; + if(r >= -2. && r <= 2) sample_volume_r += r; } - - sample_volume_l*=0.25; - sample_volume_r*=0.25; - sample_volume_l*=master_left; - sample_volume_r*=master_right; + + sample_volume_l *= 0.25; + sample_volume_r *= 0.25; + sample_volume_l *= master_left; + sample_volume_r *= master_right; const float lowpass_coef = 0.999; - emu->mix_l_volume = emu->mix_l_volume*lowpass_coef + fabs(sample_volume_l)*(1.0-lowpass_coef); - emu->mix_r_volume = emu->mix_r_volume*lowpass_coef + fabs(sample_volume_r)*(1.0-lowpass_coef); - - for(int i=0;i<6;++i){ - emu->audio_channel_output[i] = emu->audio_channel_output[i]*lowpass_coef - + fabs(channels[i])*(1.0-lowpass_coef); + emu->mix_l_volume = emu->mix_l_volume * lowpass_coef + fabs(sample_volume_l) * (1.0 - lowpass_coef); + emu->mix_r_volume = emu->mix_r_volume * lowpass_coef + fabs(sample_volume_r) * (1.0 - lowpass_coef); + + for(int i = 0; i < 6; ++i) { + emu->audio_channel_output[i] = emu->audio_channel_output[i] * lowpass_coef + fabs(channels[i]) * (1.0 - lowpass_coef); } // Clipping - if(sample_volume_l>1.0)sample_volume_l=1; - if(sample_volume_r>1.0)sample_volume_r=1; - if(sample_volume_l<-1.0)sample_volume_l=-1; - if(sample_volume_r<-1.0)sample_volume_r=-1; - if(!(audio->capacitor_l<2&&audio->capacitor_l>-2))audio->capacitor_l=0; - if(!(audio->capacitor_r<2&&audio->capacitor_r>-2))audio->capacitor_r=0; - float out_l = sample_volume_l-audio->capacitor_l; - float out_r = sample_volume_r-audio->capacitor_r; - audio->capacitor_l = (sample_volume_l-out_l)*0.996; - audio->capacitor_r = (sample_volume_r-out_r)*0.996; + if(sample_volume_l > 1.0) sample_volume_l = 1; + if(sample_volume_r > 1.0) sample_volume_r = 1; + if(sample_volume_l < -1.0) sample_volume_l = -1; + if(sample_volume_r < -1.0) sample_volume_r = -1; + if(!(audio->capacitor_l < 2 && audio->capacitor_l > -2)) audio->capacitor_l = 0; + if(!(audio->capacitor_r < 2 && audio->capacitor_r > -2)) audio->capacitor_r = 0; + float out_l = sample_volume_l - audio->capacitor_l; + float out_r = sample_volume_r - audio->capacitor_r; + audio->capacitor_l = (sample_volume_l - out_l) * 0.996; + audio->capacitor_r = (sample_volume_r - out_r) * 0.996; // Quantization - unsigned write_entry0 = (emu->audio_ring_buff.write_ptr++)%SB_AUDIO_RING_BUFFER_SIZE; - unsigned write_entry1 = (emu->audio_ring_buff.write_ptr++)%SB_AUDIO_RING_BUFFER_SIZE; + unsigned write_entry0 = (emu->audio_ring_buff.write_ptr++) % SB_AUDIO_RING_BUFFER_SIZE; + unsigned write_entry1 = (emu->audio_ring_buff.write_ptr++) % SB_AUDIO_RING_BUFFER_SIZE; - emu->audio_ring_buff.data[write_entry0] = out_l*32760; - emu->audio_ring_buff.data[write_entry1] = out_r*32760; + emu->audio_ring_buff.data[write_entry0] = out_l * 32760; + emu->audio_ring_buff.data[write_entry1] = out_r * 32760; } } \ No newline at end of file diff --git a/src/gba.h b/src/gba.h index 240a869b0..1b271d734 100644 --- a/src/gba.h +++ b/src/gba.h @@ -7,612 +7,648 @@ #include "arm7.h" #include "gba_bios.h" #include -//Should be power of 2 for perf, 8192 samples gives ~85ms maximal latency for 48kHz -#define LR 14 -#define PC 15 -#define CPSR 16 -#define SPSR 17 -#define GBA_LCD_W 240 -#define GBA_LCD_H 160 -#define GBA_SWAPCHAIN_SIZE 4 +// Should be power of 2 for perf, 8192 samples gives ~85ms maximal latency for 48kHz +#define LR 14 +#define PC 15 +#define CPSR 16 +#define SPSR 17 +#define GBA_LCD_W 240 +#define GBA_LCD_H 160 +#define GBA_SWAPCHAIN_SIZE 4 #define GBA_AUDIO_DMA_ACTIVATE_THRESHOLD 12 ////////////////////////////////////////////////////////////////////////////////////////// // MMIO Register listing from GBATEK (https://problemkaputt.de/gbatek.htm#gbamemorymap) // ////////////////////////////////////////////////////////////////////////////////////////// // LCD MMIO Registers -#define GBA_DISPCNT 0x4000000 /* R/W LCD Control */ -#define GBA_GREENSWP 0x4000002 /* R/W Undocumented - Green Swap */ -#define GBA_DISPSTAT 0x4000004 /* R/W General LCD Status (STAT,LYC) */ -#define GBA_VCOUNT 0x4000006 /* R Vertical Counter (LY) */ -#define GBA_BG0CNT 0x4000008 /* R/W BG0 Control */ -#define GBA_BG1CNT 0x400000A /* R/W BG1 Control */ -#define GBA_BG2CNT 0x400000C /* R/W BG2 Control */ -#define GBA_BG3CNT 0x400000E /* R/W BG3 Control */ -#define GBA_BG0HOFS 0x4000010 /* W BG0 X-Offset */ -#define GBA_BG0VOFS 0x4000012 /* W BG0 Y-Offset */ -#define GBA_BG1HOFS 0x4000014 /* W BG1 X-Offset */ -#define GBA_BG1VOFS 0x4000016 /* W BG1 Y-Offset */ -#define GBA_BG2HOFS 0x4000018 /* W BG2 X-Offset */ -#define GBA_BG2VOFS 0x400001A /* W BG2 Y-Offset */ -#define GBA_BG3HOFS 0x400001C /* W BG3 X-Offset */ -#define GBA_BG3VOFS 0x400001E /* W BG3 Y-Offset */ -#define GBA_BG2PA 0x4000020 /* W BG2 Rotation/Scaling Parameter A (dx) */ -#define GBA_BG2PB 0x4000022 /* W BG2 Rotation/Scaling Parameter B (dmx) */ -#define GBA_BG2PC 0x4000024 /* W BG2 Rotation/Scaling Parameter C (dy) */ -#define GBA_BG2PD 0x4000026 /* W BG2 Rotation/Scaling Parameter D (dmy) */ -#define GBA_BG2X 0x4000028 /* W BG2 Reference Point X-Coordinate */ -#define GBA_BG2Y 0x400002C /* W BG2 Reference Point Y-Coordinate */ -#define GBA_BG3PA 0x4000030 /* W BG3 Rotation/Scaling Parameter A (dx) */ -#define GBA_BG3PB 0x4000032 /* W BG3 Rotation/Scaling Parameter B (dmx) */ -#define GBA_BG3PC 0x4000034 /* W BG3 Rotation/Scaling Parameter C (dy) */ -#define GBA_BG3PD 0x4000036 /* W BG3 Rotation/Scaling Parameter D (dmy) */ -#define GBA_BG3X 0x4000038 /* W BG3 Reference Point X-Coordinate */ -#define GBA_BG3Y 0x400003C /* W BG3 Reference Point Y-Coordinate */ -#define GBA_WIN0H 0x4000040 /* W Window 0 Horizontal Dimensions */ -#define GBA_WIN1H 0x4000042 /* W Window 1 Horizontal Dimensions */ -#define GBA_WIN0V 0x4000044 /* W Window 0 Vertical Dimensions */ -#define GBA_WIN1V 0x4000046 /* W Window 1 Vertical Dimensions */ -#define GBA_WININ 0x4000048 /* R/W Inside of Window 0 and 1 */ -#define GBA_WINOUT 0x400004A /* R/W Inside of OBJ Window & Outside of Windows */ -#define GBA_MOSAIC 0x400004C /* W Mosaic Size */ -#define GBA_BLDCNT 0x4000050 /* R/W Color Special Effects Selection */ -#define GBA_BLDALPHA 0x4000052 /* R/W Alpha Blending Coefficients */ -#define GBA_BLDY 0x4000054 /* W Brightness (Fade-In/Out) Coefficient */ +#define GBA_DISPCNT 0x4000000 /* R/W LCD Control */ +#define GBA_GREENSWP 0x4000002 /* R/W Undocumented - Green Swap */ +#define GBA_DISPSTAT 0x4000004 /* R/W General LCD Status (STAT,LYC) */ +#define GBA_VCOUNT 0x4000006 /* R Vertical Counter (LY) */ +#define GBA_BG0CNT 0x4000008 /* R/W BG0 Control */ +#define GBA_BG1CNT 0x400000A /* R/W BG1 Control */ +#define GBA_BG2CNT 0x400000C /* R/W BG2 Control */ +#define GBA_BG3CNT 0x400000E /* R/W BG3 Control */ +#define GBA_BG0HOFS 0x4000010 /* W BG0 X-Offset */ +#define GBA_BG0VOFS 0x4000012 /* W BG0 Y-Offset */ +#define GBA_BG1HOFS 0x4000014 /* W BG1 X-Offset */ +#define GBA_BG1VOFS 0x4000016 /* W BG1 Y-Offset */ +#define GBA_BG2HOFS 0x4000018 /* W BG2 X-Offset */ +#define GBA_BG2VOFS 0x400001A /* W BG2 Y-Offset */ +#define GBA_BG3HOFS 0x400001C /* W BG3 X-Offset */ +#define GBA_BG3VOFS 0x400001E /* W BG3 Y-Offset */ +#define GBA_BG2PA 0x4000020 /* W BG2 Rotation/Scaling Parameter A (dx) */ +#define GBA_BG2PB 0x4000022 /* W BG2 Rotation/Scaling Parameter B (dmx) */ +#define GBA_BG2PC 0x4000024 /* W BG2 Rotation/Scaling Parameter C (dy) */ +#define GBA_BG2PD 0x4000026 /* W BG2 Rotation/Scaling Parameter D (dmy) */ +#define GBA_BG2X 0x4000028 /* W BG2 Reference Point X-Coordinate */ +#define GBA_BG2Y 0x400002C /* W BG2 Reference Point Y-Coordinate */ +#define GBA_BG3PA 0x4000030 /* W BG3 Rotation/Scaling Parameter A (dx) */ +#define GBA_BG3PB 0x4000032 /* W BG3 Rotation/Scaling Parameter B (dmx) */ +#define GBA_BG3PC 0x4000034 /* W BG3 Rotation/Scaling Parameter C (dy) */ +#define GBA_BG3PD 0x4000036 /* W BG3 Rotation/Scaling Parameter D (dmy) */ +#define GBA_BG3X 0x4000038 /* W BG3 Reference Point X-Coordinate */ +#define GBA_BG3Y 0x400003C /* W BG3 Reference Point Y-Coordinate */ +#define GBA_WIN0H 0x4000040 /* W Window 0 Horizontal Dimensions */ +#define GBA_WIN1H 0x4000042 /* W Window 1 Horizontal Dimensions */ +#define GBA_WIN0V 0x4000044 /* W Window 0 Vertical Dimensions */ +#define GBA_WIN1V 0x4000046 /* W Window 1 Vertical Dimensions */ +#define GBA_WININ 0x4000048 /* R/W Inside of Window 0 and 1 */ +#define GBA_WINOUT 0x400004A /* R/W Inside of OBJ Window & Outside of Windows */ +#define GBA_MOSAIC 0x400004C /* W Mosaic Size */ +#define GBA_BLDCNT 0x4000050 /* R/W Color Special Effects Selection */ +#define GBA_BLDALPHA 0x4000052 /* R/W Alpha Blending Coefficients */ +#define GBA_BLDY 0x4000054 /* W Brightness (Fade-In/Out) Coefficient */ // Sound Registers -#define GBA_SOUND1CNT_L 0x4000060 /* R/W Channel 1 Sweep register (NR10) */ -#define GBA_SOUND1CNT_H 0x4000062 /* R/W Channel 1 Duty/Length/Envelope (NR11, NR12) */ -#define GBA_SOUND1CNT_X 0x4000064 /* R/W Channel 1 Frequency/Control (NR13, NR14) */ -#define GBA_SOUND2CNT_L 0x4000068 /* R/W Channel 2 Duty/Length/Envelope (NR21, NR22) */ -#define GBA_SOUND2CNT_H 0x400006C /* R/W Channel 2 Frequency/Control (NR23, NR24) */ -#define GBA_SOUND3CNT_L 0x4000070 /* R/W Channel 3 Stop/Wave RAM select (NR30) */ -#define GBA_SOUND3CNT_H 0x4000072 /* R/W Channel 3 Length/Volume (NR31, NR32) */ -#define GBA_SOUND3CNT_X 0x4000074 /* R/W Channel 3 Frequency/Control (NR33, NR34) */ -#define GBA_SOUND4CNT_L 0x4000078 /* R/W Channel 4 Length/Envelope (NR41, NR42) */ -#define GBA_SOUND4CNT_H 0x400007C /* R/W Channel 4 Frequency/Control (NR43, NR44) */ -#define GBA_SOUNDCNT_L 0x4000080 /* R/W Control Stereo/Volume/Enable (NR50, NR51) */ -#define GBA_SOUNDCNT_H 0x4000082 /* R/W Control Mixing/DMA Control */ -#define GBA_SOUNDCNT_X 0x4000084 /* R/W Control Sound on/off (NR52) */ -#define GBA_SOUNDBIAS 0x4000088 /* BIOS Sound PWM Control */ -#define GBA_WAVE_RAM 0x4000090 /* R/W Channel 3 Wave Pattern RAM (2 banks!!) */ -#define GBA_FIFO_A 0x40000A0 /* W Channel A FIFO, Data 0-3 */ -#define GBA_FIFO_B 0x40000A4 /* W Channel B FIFO, Data 0-3 */ +#define GBA_SOUND1CNT_L 0x4000060 /* R/W Channel 1 Sweep register (NR10) */ +#define GBA_SOUND1CNT_H 0x4000062 /* R/W Channel 1 Duty/Length/Envelope (NR11, NR12) */ +#define GBA_SOUND1CNT_X 0x4000064 /* R/W Channel 1 Frequency/Control (NR13, NR14) */ +#define GBA_SOUND2CNT_L 0x4000068 /* R/W Channel 2 Duty/Length/Envelope (NR21, NR22) */ +#define GBA_SOUND2CNT_H 0x400006C /* R/W Channel 2 Frequency/Control (NR23, NR24) */ +#define GBA_SOUND3CNT_L 0x4000070 /* R/W Channel 3 Stop/Wave RAM select (NR30) */ +#define GBA_SOUND3CNT_H 0x4000072 /* R/W Channel 3 Length/Volume (NR31, NR32) */ +#define GBA_SOUND3CNT_X 0x4000074 /* R/W Channel 3 Frequency/Control (NR33, NR34) */ +#define GBA_SOUND4CNT_L 0x4000078 /* R/W Channel 4 Length/Envelope (NR41, NR42) */ +#define GBA_SOUND4CNT_H 0x400007C /* R/W Channel 4 Frequency/Control (NR43, NR44) */ +#define GBA_SOUNDCNT_L 0x4000080 /* R/W Control Stereo/Volume/Enable (NR50, NR51) */ +#define GBA_SOUNDCNT_H 0x4000082 /* R/W Control Mixing/DMA Control */ +#define GBA_SOUNDCNT_X 0x4000084 /* R/W Control Sound on/off (NR52) */ +#define GBA_SOUNDBIAS 0x4000088 /* BIOS Sound PWM Control */ +#define GBA_WAVE_RAM 0x4000090 /* R/W Channel 3 Wave Pattern RAM (2 banks!!) */ +#define GBA_FIFO_A 0x40000A0 /* W Channel A FIFO, Data 0-3 */ +#define GBA_FIFO_B 0x40000A4 /* W Channel B FIFO, Data 0-3 */ // DMA Transfer Channels -#define GBA_DMA0SAD 0x40000B0 /* W DMA 0 Source Address */ -#define GBA_DMA0DAD 0x40000B4 /* W DMA 0 Destination Address */ -#define GBA_DMA0CNT_L 0x40000B8 /* W DMA 0 Word Count */ -#define GBA_DMA0CNT_H 0x40000BA /* R/W DMA 0 Control */ -#define GBA_DMA1SAD 0x40000BC /* W DMA 1 Source Address */ -#define GBA_DMA1DAD 0x40000C0 /* W DMA 1 Destination Address */ -#define GBA_DMA1CNT_L 0x40000C4 /* W DMA 1 Word Count */ -#define GBA_DMA1CNT_H 0x40000C6 /* R/W DMA 1 Control */ -#define GBA_DMA2SAD 0x40000C8 /* W DMA 2 Source Address */ -#define GBA_DMA2DAD 0x40000CC /* W DMA 2 Destination Address */ -#define GBA_DMA2CNT_L 0x40000D0 /* W DMA 2 Word Count */ -#define GBA_DMA2CNT_H 0x40000D2 /* R/W DMA 2 Control */ -#define GBA_DMA3SAD 0x40000D4 /* W DMA 3 Source Address */ -#define GBA_DMA3DAD 0x40000D8 /* W DMA 3 Destination Address */ -#define GBA_DMA3CNT_L 0x40000DC /* W DMA 3 Word Count */ -#define GBA_DMA3CNT_H 0x40000DE /* R/W DMA 3 Control */ +#define GBA_DMA0SAD 0x40000B0 /* W DMA 0 Source Address */ +#define GBA_DMA0DAD 0x40000B4 /* W DMA 0 Destination Address */ +#define GBA_DMA0CNT_L 0x40000B8 /* W DMA 0 Word Count */ +#define GBA_DMA0CNT_H 0x40000BA /* R/W DMA 0 Control */ +#define GBA_DMA1SAD 0x40000BC /* W DMA 1 Source Address */ +#define GBA_DMA1DAD 0x40000C0 /* W DMA 1 Destination Address */ +#define GBA_DMA1CNT_L 0x40000C4 /* W DMA 1 Word Count */ +#define GBA_DMA1CNT_H 0x40000C6 /* R/W DMA 1 Control */ +#define GBA_DMA2SAD 0x40000C8 /* W DMA 2 Source Address */ +#define GBA_DMA2DAD 0x40000CC /* W DMA 2 Destination Address */ +#define GBA_DMA2CNT_L 0x40000D0 /* W DMA 2 Word Count */ +#define GBA_DMA2CNT_H 0x40000D2 /* R/W DMA 2 Control */ +#define GBA_DMA3SAD 0x40000D4 /* W DMA 3 Source Address */ +#define GBA_DMA3DAD 0x40000D8 /* W DMA 3 Destination Address */ +#define GBA_DMA3CNT_L 0x40000DC /* W DMA 3 Word Count */ +#define GBA_DMA3CNT_H 0x40000DE /* R/W DMA 3 Control */ // Timer Registers -#define GBA_TM0CNT_L 0x4000100 /* R/W Timer 0 Counter/Reload */ -#define GBA_TM0CNT_H 0x4000102 /* R/W Timer 0 Control */ -#define GBA_TM1CNT_L 0x4000104 /* R/W Timer 1 Counter/Reload */ -#define GBA_TM1CNT_H 0x4000106 /* R/W Timer 1 Control */ -#define GBA_TM2CNT_L 0x4000108 /* R/W Timer 2 Counter/Reload */ -#define GBA_TM2CNT_H 0x400010A /* R/W Timer 2 Control */ -#define GBA_TM3CNT_L 0x400010C /* R/W Timer 3 Counter/Reload */ -#define GBA_TM3CNT_H 0x400010E /* R/W Timer 3 Control */ +#define GBA_TM0CNT_L 0x4000100 /* R/W Timer 0 Counter/Reload */ +#define GBA_TM0CNT_H 0x4000102 /* R/W Timer 0 Control */ +#define GBA_TM1CNT_L 0x4000104 /* R/W Timer 1 Counter/Reload */ +#define GBA_TM1CNT_H 0x4000106 /* R/W Timer 1 Control */ +#define GBA_TM2CNT_L 0x4000108 /* R/W Timer 2 Counter/Reload */ +#define GBA_TM2CNT_H 0x400010A /* R/W Timer 2 Control */ +#define GBA_TM3CNT_L 0x400010C /* R/W Timer 3 Counter/Reload */ +#define GBA_TM3CNT_H 0x400010E /* R/W Timer 3 Control */ // Serial Communication (1) -#define GBA_SIODATA32 0x4000120 /*R/W SIO Data (Normal-32bit Mode; shared with below) */ -#define GBA_SIOMULTI0 0x4000120 /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ -#define GBA_SIOMULTI1 0x4000122 /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ -#define GBA_SIOMULTI2 0x4000124 /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ -#define GBA_SIOMULTI3 0x4000126 /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ -#define GBA_SIOCNT 0x4000128 /*R/W SIO Control Register */ -#define GBA_SIOMLT_SEND 0x400012A /*R/W SIO Data (Local of MultiPlayer; shared below) */ -#define GBA_SIODATA8 0x400012A /*R/W SIO Data (Normal-8bit and UART Mode) */ +#define GBA_SIODATA32 0x4000120 /*R/W SIO Data (Normal-32bit Mode; shared with below) */ +#define GBA_SIOMULTI0 0x4000120 /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ +#define GBA_SIOMULTI1 0x4000122 /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ +#define GBA_SIOMULTI2 0x4000124 /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ +#define GBA_SIOMULTI3 0x4000126 /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ +#define GBA_SIOCNT 0x4000128 /*R/W SIO Control Register */ +#define GBA_SIOMLT_SEND 0x400012A /*R/W SIO Data (Local of MultiPlayer; shared below) */ +#define GBA_SIODATA8 0x400012A /*R/W SIO Data (Normal-8bit and UART Mode) */ // Keypad Input -#define GBA_KEYINPUT 0x4000130 /* R Key Status */ -#define GBA_KEYCNT 0x4000132 /* R/W Key Interrupt Control */ +#define GBA_KEYINPUT 0x4000130 /* R Key Status */ +#define GBA_KEYCNT 0x4000132 /* R/W Key Interrupt Control */ // Serial Communication (2) -#define GBA_RCNT 0x4000134 /* R/W SIO Mode Select/General Purpose Data */ -#define GBA_IR 0x4000136 /* - Ancient - Infrared Register (Prototypes only) */ -#define GBA_JOYCNT 0x4000140 /* R/W SIO JOY Bus Control */ -#define GBA_JOY_RECV 0x4000150 /* R/W SIO JOY Bus Receive Data */ -#define GBA_JOY_TRANS 0x4000154 /* R/W SIO JOY Bus Transmit Data */ -#define GBA_JOYSTAT 0x4000158 /* R/? SIO JOY Bus Receive Status */ +#define GBA_RCNT 0x4000134 /* R/W SIO Mode Select/General Purpose Data */ +#define GBA_IR 0x4000136 /* - Ancient - Infrared Register (Prototypes only) */ +#define GBA_JOYCNT 0x4000140 /* R/W SIO JOY Bus Control */ +#define GBA_JOY_RECV 0x4000150 /* R/W SIO JOY Bus Receive Data */ +#define GBA_JOY_TRANS 0x4000154 /* R/W SIO JOY Bus Transmit Data */ +#define GBA_JOYSTAT 0x4000158 /* R/? SIO JOY Bus Receive Status */ // Interrupt, Waitstate, and Power-Down Control -#define GBA_IE 0x4000200 /* R/W IE Interrupt Enable Register */ -#define GBA_IF 0x4000202 /* R/W IF Interrupt Request Flags / IRQ Acknowledge */ -#define GBA_WAITCNT 0x4000204 /* R/W WAITCNT Game Pak Waitstate Control */ -#define GBA_IME 0x4000208 /* R/W IME Interrupt Master Enable Register */ -#define GBA_POSTFLG 0x4000300 /* R/W POSTFLG Undocumented - Post Boot Flag */ -#define GBA_HALTCNT 0x4000301 /* W HALTCNT Undocumented - Power Down Control */ +#define GBA_IE 0x4000200 /* R/W IE Interrupt Enable Register */ +#define GBA_IF 0x4000202 /* R/W IF Interrupt Request Flags / IRQ Acknowledge */ +#define GBA_WAITCNT 0x4000204 /* R/W WAITCNT Game Pak Waitstate Control */ +#define GBA_IME 0x4000208 /* R/W IME Interrupt Master Enable Register */ +#define GBA_POSTFLG 0x4000300 /* R/W POSTFLG Undocumented - Post Boot Flag */ +#define GBA_HALTCNT 0x4000301 /* W HALTCNT Undocumented - Power Down Control */ // #define GBA_? 0x4000410 /* ? ? Undocumented - Purpose Unknown / Bug ??? 0FFh */ // #define GBA_? 0x4000800 /* R/W ? Undocumented - Internal Memory Control (R/W) */ // #define GBA_? 0x4xx0800 /* R/W ? Mirrors of 4000800h (repeated each 64K) */ // #define GBA_(3DS) 0x4700000 /* W (3DS) Disable ARM7 bootrom overlay (3DS only) */ -mmio_reg_t gba_io_reg_desc[]={ +mmio_reg_t gba_io_reg_desc[] = { // Interrupt, Waitstate, and Power-Down Control - { GBA_IE , "IE", { - { 0 , 1, "LCD V-Blank" }, - { 1 , 1, "LCD H-Blank" }, - { 2 , 1, "LCD V-Counter Match" }, - { 3 , 1, "Timer 0 Overflow" }, - { 4 , 1, "Timer 1 Overflow" }, - { 5 , 1, "Timer 2 Overflow" }, - { 6 , 1, "Timer 3 Overflow" }, - { 7 , 1, "Serial Communication" }, - { 8 , 1, "DMA 0" }, - { 9 , 1, "DMA 1" }, - { 10, 1, "DMA 2" }, - { 11, 1, "DMA 3" }, - { 12, 1, "Keypad" }, - { 13, 1, "Game Pak (ext)" }, - } }, /* R/W IE Interrupt Enable Register */ - { GBA_IF , "IF", { - { 0 , 1, "LCD V-Blank" }, - { 1 , 1, "LCD H-Blank" }, - { 2 , 1, "LCD V-Counter Match" }, - { 3 , 1, "Timer 0 Overflow" }, - { 4 , 1, "Timer 1 Overflow" }, - { 5 , 1, "Timer 2 Overflow" }, - { 6 , 1, "Timer 3 Overflow" }, - { 7 , 1, "Serial Communication" }, - { 8 , 1, "DMA 0" }, - { 9 , 1, "DMA 1" }, - { 10, 1, "DMA 2" }, - { 11, 1, "DMA 3" }, - { 12, 1, "Keypad" }, - { 13, 1, "Game Pak (ext)" }, - } }, /* R/W IF Interrupt Request Flags / IRQ Acknowledge */ - { GBA_WAITCNT, "WAITCNT", { - { 0,2, "SRAM Wait Control (0..3 = 4,3,2,8 cycles)" }, - { 2,2, "Wait State 0 First Access (0..3 = 4,3,2,8 cycles)" }, - { 4,1, "Wait State 0 Second Access (0..1 = 2,1 cycles)" }, - { 5,2, "Wait State 1 First Access (0..3 = 4,3,2,8 cycles)" }, - { 7,1, "Wait State 1 Second Access (0..1 = 4,1 cycles)" }, - { 8,2, "Wait State 2 First Access (0..3 = 4,3,2,8 cycles)" }, - { 10,1, "Wait State 2 Second Access (0..1 = 8,1 cycles)" }, - { 11,2, "PHI Terminal Output (0..3 = Disable, 4.19MHz, 8.38MHz, 16.78MHz)" }, - { 14,1, "Game Pak Prefetch Buffer (0=Disable, 1=Enable)" }, - { 15,1, "Game Pak Type Flag (0=GBA, 1=CGB) (IN35 signal)" }, - } }, /* R/W WAITCNT Game Pak Waitstate Control */ - { GBA_IME , "IME", {0} }, /* R/W IME Interrupt Master Enable Register */ - { GBA_POSTFLG, "POSTFLG", {0} }, /* R/W POSTFLG Undocumented - Post Boot Flag */ - { GBA_HALTCNT, "HALTCNT", {0} }, - - { GBA_DISPCNT , "DISPCNT ", { - { 0, 3, "BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)"}, - { 3 ,1, "Reserved / CGB Mode (0=GBA, 1=CGB)"}, - { 4 ,1, "Display Frame Select (0-1=Frame 0-1)"}, - { 5 ,1, "H-Blank Interval Free (1=Allow access to OAM during H-Blank)"}, - { 6 ,1, "OBJ Character VRAM Mapping (0=2D, 1=1D"}, - { 7 ,1, "Forced Blank (1=Allow FAST VRAM,Palette,OAM)"}, - { 8 ,1, "Screen Display BG0 (0=Off, 1=On)"}, - { 9 ,1, "Screen Display BG1 (0=Off, 1=On)"}, - { 10,1, "Screen Display BG2 (0=Off, 1=On)"}, - { 11,1, "Screen Display BG3 (0=Off, 1=On)"}, - { 12,1, "Screen Display OBJ (0=Off, 1=On)"}, - { 13,1, "Window 0 Display Flag (0=Off, 1=On)"}, - { 14,1, "Window 1 Display Flag (0=Off, 1=On)"}, - { 15,1, "OBJ Window Display Flag (0=Off, 1=On)"}, - } }, - { GBA_GREENSWP, "GREENSWP", { {0, 1, "Green Swap (0=Normal, 1=Swap)" }} }, /* R/W Undocumented - Green Swap */ - { GBA_DISPSTAT, "DISPSTAT", { - { 0,1, "V-Blank flag (1=VBlank) (set in line 160..226; not 227",}, - { 1,1, "H-Blank flag (1=HBlank) (toggled in all lines, 0..227",}, - { 2,1, "V-Counter flag (1=Match) (set in selected line)",}, - { 3,1, "V-Blank IRQ Enable (1=Enable)",}, - { 4,1, "H-Blank IRQ Enable (1=Enable)",}, - { 5,1, "V-Counter IRQ Enable (1=Enable)",}, - { 6,1, "DSi: LCD Initialization Ready (0=Busy, 1=Ready",}, - { 7,1, "NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262",}, - { 8,8, "V-Count Setting (LYC) (0..227)",}, - - } }, /* R/W General LCD Status (STAT,LYC) */ - { GBA_VCOUNT , "VCOUNT ", { 0 } }, /* R Vertical Counter (LY) */ - { GBA_BG0CNT , "BG0CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,2 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 4,2 , "NDS: MSBs of char base"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG0 Control */ - { GBA_BG1CNT , "BG1CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,2 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 4,2 , "NDS: MSBs of char base"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG1 Control */ - { GBA_BG2CNT , "BG2CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,2 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 4,2 , "NDS: MSBs of char base"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG2 Control */ - { GBA_BG3CNT , "BG3CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,2 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 4,2 , "NDS: MSBs of char base"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG3 Control */ - { GBA_BG0HOFS , "BG0HOFS", { 0 } }, /* W BG0 X-Offset */ - { GBA_BG0VOFS , "BG0VOFS", { 0 } }, /* W BG0 Y-Offset */ - { GBA_BG1HOFS , "BG1HOFS", { 0 } }, /* W BG1 X-Offset */ - { GBA_BG1VOFS , "BG1VOFS", { 0 } }, /* W BG1 Y-Offset */ - { GBA_BG2HOFS , "BG2HOFS", { 0 } }, /* W BG2 X-Offset */ - { GBA_BG2VOFS , "BG2VOFS", { 0 } }, /* W BG2 Y-Offset */ - { GBA_BG3HOFS , "BG3HOFS", { 0 } }, /* W BG3 X-Offset */ - { GBA_BG3VOFS , "BG3VOFS", { 0 } }, /* W BG3 Y-Offset */ - { GBA_BG2PA , "BG2PA", { 0 } }, /* W BG2 Rotation/Scaling Parameter A (dx) */ - { GBA_BG2PB , "BG2PB", { 0 } }, /* W BG2 Rotation/Scaling Parameter B (dmx) */ - { GBA_BG2PC , "BG2PC", { 0 } }, /* W BG2 Rotation/Scaling Parameter C (dy) */ - { GBA_BG2PD , "BG2PD", { 0 } }, /* W BG2 Rotation/Scaling Parameter D (dmy) */ - { GBA_BG2X , "BG2X", { 0 } }, /* W BG2 Reference Point X-Coordinate */ - { GBA_BG2Y , "BG2Y", { 0 } }, /* W BG2 Reference Point Y-Coordinate */ - { GBA_BG3PA , "BG3PA", { 0 } }, /* W BG3 Rotation/Scaling Parameter A (dx) */ - { GBA_BG3PB , "BG3PB", { 0 } }, /* W BG3 Rotation/Scaling Parameter B (dmx) */ - { GBA_BG3PC , "BG3PC", { 0 } }, /* W BG3 Rotation/Scaling Parameter C (dy) */ - { GBA_BG3PD , "BG3PD", { 0 } }, /* W BG3 Rotation/Scaling Parameter D (dmy) */ - { GBA_BG3X , "BG3X", { 0 } }, /* W BG3 Reference Point X-Coordinate */ - { GBA_BG3Y , "BG3Y", { 0 } }, /* W BG3 Reference Point Y-Coordinate */ - { GBA_WIN0H , "WIN0H", { - { 0, 8, "X2, Rightmost coordinate of window, plus 1 " }, - { 8, 8, "X1, Leftmost coordinate of window"}, - } }, /* W Window 0 Horizontal Dimensions */ - { GBA_WIN1H , "WIN1H", { - { 0, 8, "X2, Rightmost coordinate of window, plus 1 " }, - { 8, 8, "X1, Leftmost coordinate of window"}, - } }, /* W Window 1 Horizontal Dimensions */ - { GBA_WIN0V , "WIN0V", { - {0, 8, "Y2, Bottom-most coordinate of window, plus 1" }, - {8, 8, "Y1, Top-most coordinate of window" }, - } }, /* W Window 0 Vertical Dimensions */ - { GBA_WIN1V , "WIN1V", { - {0, 8, "Y2, Bottom-most coordinate of window, plus 1" }, - {8, 8, "Y1, Top-most coordinate of window" }, - } }, /* W Window 1 Vertical Dimensions */ - { GBA_WININ , "WININ", { - { 0 , 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 1 , 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 2 , 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 3 , 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 4 , 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 5 , 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, - { 8 , 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 9 , 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, - } }, /* R/W Inside of Window 0 and 1 */ - { GBA_WINOUT , "WINOUT", { - { 0 , 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 1 , 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 2 , 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 3 , 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 4 , 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 5 , 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, - { 8 , 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 9 , 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, - } }, /* R/W Inside of OBJ Window & Outside of Windows */ - { GBA_MOSAIC , "MOSAIC", { - { 0, 4, "BG Mosaic H-Size (minus 1)" }, - { 4, 4, "BG Mosaic V-Size (minus 1)" }, - { 8, 4, "OBJ Mosaic H-Size (minus 1)" }, - { 12,4, "OBJ Mosaic V-Size (minus 1)" }, - } }, /* W Mosaic Size */ - { GBA_BLDCNT , "BLDCNT", { - { 0 , 1, "BG0 1st Target Pixel (Background 0)" }, - { 1 , 1, "BG1 1st Target Pixel (Background 1)" }, - { 2 , 1, "BG2 1st Target Pixel (Background 2)" }, - { 3 , 1, "BG3 1st Target Pixel (Background 3)" }, - { 4 , 1, "OBJ 1st Target Pixel (Top-most OBJ pixel)" }, - { 5 , 1, "BD 1st Target Pixel (Backdrop)" }, - { 6 , 2, "Color Effect (0: None 1: Alpha 2: Lighten 3: Darken)" }, - { 8 , 1, "BG0 2nd Target Pixel (Background 0)" }, - { 9 , 1, "BG1 2nd Target Pixel (Background 1)" }, - { 10, 1, "BG2 2nd Target Pixel (Background 2)" }, - { 11, 1, "BG3 2nd Target Pixel (Background 3)" }, - { 12, 1, "OBJ 2nd Target Pixel (Top-most OBJ pixel)" }, - { 13, 1, "BD 2nd Target Pixel (Backdrop)" }, - } }, /* R/W Color Special Effects Selection */ - { GBA_BLDALPHA, "BLDALPHA", { - {0, 4, "EVA Coef. (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, - {8, 4, "EVB Coef. (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, - } }, /* R/W Alpha Blending Coefficients */ - { GBA_BLDY , "BLDY", { 0 } }, /* W Brightness (Fade-In/Out) Coefficient */ + { GBA_IE, "IE", { + {0, 1, "LCD V-Blank"}, + {1, 1, "LCD H-Blank"}, + {2, 1, "LCD V-Counter Match"}, + {3, 1, "Timer 0 Overflow"}, + {4, 1, "Timer 1 Overflow"}, + {5, 1, "Timer 2 Overflow"}, + {6, 1, "Timer 3 Overflow"}, + {7, 1, "Serial Communication"}, + {8, 1, "DMA 0"}, + {9, 1, "DMA 1"}, + {10, 1, "DMA 2"}, + {11, 1, "DMA 3"}, + {12, 1, "Keypad"}, + {13, 1, "Game Pak (ext)"}, + } }, /* R/W IE Interrupt Enable Register */ + { GBA_IF, "IF", { + {0, 1, "LCD V-Blank"}, + {1, 1, "LCD H-Blank"}, + {2, 1, "LCD V-Counter Match"}, + {3, 1, "Timer 0 Overflow"}, + {4, 1, "Timer 1 Overflow"}, + {5, 1, "Timer 2 Overflow"}, + {6, 1, "Timer 3 Overflow"}, + {7, 1, "Serial Communication"}, + {8, 1, "DMA 0"}, + {9, 1, "DMA 1"}, + {10, 1, "DMA 2"}, + {11, 1, "DMA 3"}, + {12, 1, "Keypad"}, + {13, 1, "Game Pak (ext)"}, + } }, /* R/W IF Interrupt Request Flags / IRQ Acknowledge */ + { GBA_WAITCNT, "WAITCNT", { + {0, 2, "SRAM Wait Control (0..3 = 4,3,2,8 cycles)"}, + {2, 2, "Wait State 0 First Access (0..3 = 4,3,2,8 cycles)"}, + {4, 1, "Wait State 0 Second Access (0..1 = 2,1 cycles)"}, + {5, 2, "Wait State 1 First Access (0..3 = 4,3,2,8 cycles)"}, + {7, 1, "Wait State 1 Second Access (0..1 = 4,1 cycles)"}, + {8, 2, "Wait State 2 First Access (0..3 = 4,3,2,8 cycles)"}, + {10, 1, "Wait State 2 Second Access (0..1 = 8,1 cycles)"}, + {11, 2, "PHI Terminal Output (0..3 = Disable, 4.19MHz, 8.38MHz, 16.78MHz)"}, + {14, 1, "Game Pak Prefetch Buffer (0=Disable, 1=Enable)"}, + {15, 1, "Game Pak Type Flag (0=GBA, 1=CGB) (IN35 signal)"}, + } }, /* R/W WAITCNT Game Pak Waitstate Control */ + { GBA_IME, "IME", {0}}, /* R/W IME Interrupt Master Enable Register */ + { GBA_POSTFLG, "POSTFLG", {0}}, /* R/W POSTFLG Undocumented - Post Boot Flag */ + { GBA_HALTCNT, "HALTCNT", {0}}, + + { GBA_DISPCNT, "DISPCNT ", { + {0, 3, "BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)"}, + {3, 1, "Reserved / CGB Mode (0=GBA, 1=CGB)"}, + {4, 1, "Display Frame Select (0-1=Frame 0-1)"}, + {5, 1, "H-Blank Interval Free (1=Allow access to OAM during H-Blank)"}, + {6, 1, "OBJ Character VRAM Mapping (0=2D, 1=1D"}, + {7, 1, "Forced Blank (1=Allow FAST VRAM,Palette,OAM)"}, + {8, 1, "Screen Display BG0 (0=Off, 1=On)"}, + {9, 1, "Screen Display BG1 (0=Off, 1=On)"}, + {10, 1, "Screen Display BG2 (0=Off, 1=On)"}, + {11, 1, "Screen Display BG3 (0=Off, 1=On)"}, + {12, 1, "Screen Display OBJ (0=Off, 1=On)"}, + {13, 1, "Window 0 Display Flag (0=Off, 1=On)"}, + {14, 1, "Window 1 Display Flag (0=Off, 1=On)"}, + {15, 1, "OBJ Window Display Flag (0=Off, 1=On)"}, + } }, + { GBA_GREENSWP, "GREENSWP", {{0, 1, "Green Swap (0=Normal, 1=Swap)"}}}, /* R/W Undocumented - Green Swap */ + { GBA_DISPSTAT, "DISPSTAT", { + { + 0, + 1, + "V-Blank flag (1=VBlank) (set in line 160..226; not 227", + }, + { + 1, + 1, + "H-Blank flag (1=HBlank) (toggled in all lines, 0..227", + }, + { + 2, + 1, + "V-Counter flag (1=Match) (set in selected line)", + }, + { + 3, + 1, + "V-Blank IRQ Enable (1=Enable)", + }, + { + 4, + 1, + "H-Blank IRQ Enable (1=Enable)", + }, + { + 5, + 1, + "V-Counter IRQ Enable (1=Enable)", + }, + { + 6, + 1, + "DSi: LCD Initialization Ready (0=Busy, 1=Ready", + }, + { + 7, + 1, + "NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262", + }, + { + 8, + 8, + "V-Count Setting (LYC) (0..227)", + }, + + } }, /* R/W General LCD Status (STAT,LYC) */ + { GBA_VCOUNT, "VCOUNT ", {0}}, /* R Vertical Counter (LY) */ + { GBA_BG0CNT, "BG0CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 2, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {4, 2, "NDS: MSBs of char base"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG0 Control */ + { GBA_BG1CNT, "BG1CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 2, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {4, 2, "NDS: MSBs of char base"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG1 Control */ + { GBA_BG2CNT, "BG2CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 2, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {4, 2, "NDS: MSBs of char base"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG2 Control */ + { GBA_BG3CNT, "BG3CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 2, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {4, 2, "NDS: MSBs of char base"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG3 Control */ + { GBA_BG0HOFS, "BG0HOFS", {0}}, /* W BG0 X-Offset */ + { GBA_BG0VOFS, "BG0VOFS", {0}}, /* W BG0 Y-Offset */ + { GBA_BG1HOFS, "BG1HOFS", {0}}, /* W BG1 X-Offset */ + { GBA_BG1VOFS, "BG1VOFS", {0}}, /* W BG1 Y-Offset */ + { GBA_BG2HOFS, "BG2HOFS", {0}}, /* W BG2 X-Offset */ + { GBA_BG2VOFS, "BG2VOFS", {0}}, /* W BG2 Y-Offset */ + { GBA_BG3HOFS, "BG3HOFS", {0}}, /* W BG3 X-Offset */ + { GBA_BG3VOFS, "BG3VOFS", {0}}, /* W BG3 Y-Offset */ + { GBA_BG2PA, "BG2PA", {0}}, /* W BG2 Rotation/Scaling Parameter A (dx) */ + { GBA_BG2PB, "BG2PB", {0}}, /* W BG2 Rotation/Scaling Parameter B (dmx) */ + { GBA_BG2PC, "BG2PC", {0}}, /* W BG2 Rotation/Scaling Parameter C (dy) */ + { GBA_BG2PD, "BG2PD", {0}}, /* W BG2 Rotation/Scaling Parameter D (dmy) */ + { GBA_BG2X, "BG2X", {0}}, /* W BG2 Reference Point X-Coordinate */ + { GBA_BG2Y, "BG2Y", {0}}, /* W BG2 Reference Point Y-Coordinate */ + { GBA_BG3PA, "BG3PA", {0}}, /* W BG3 Rotation/Scaling Parameter A (dx) */ + { GBA_BG3PB, "BG3PB", {0}}, /* W BG3 Rotation/Scaling Parameter B (dmx) */ + { GBA_BG3PC, "BG3PC", {0}}, /* W BG3 Rotation/Scaling Parameter C (dy) */ + { GBA_BG3PD, "BG3PD", {0}}, /* W BG3 Rotation/Scaling Parameter D (dmy) */ + { GBA_BG3X, "BG3X", {0}}, /* W BG3 Reference Point X-Coordinate */ + { GBA_BG3Y, "BG3Y", {0}}, /* W BG3 Reference Point Y-Coordinate */ + { GBA_WIN0H, "WIN0H", { + {0, 8, "X2, Rightmost coordinate of window, plus 1 "}, + {8, 8, "X1, Leftmost coordinate of window"}, + } }, /* W Window 0 Horizontal Dimensions */ + { GBA_WIN1H, "WIN1H", { + {0, 8, "X2, Rightmost coordinate of window, plus 1 "}, + {8, 8, "X1, Leftmost coordinate of window"}, + } }, /* W Window 1 Horizontal Dimensions */ + { GBA_WIN0V, "WIN0V", { + {0, 8, "Y2, Bottom-most coordinate of window, plus 1"}, + {8, 8, "Y1, Top-most coordinate of window"}, + } }, /* W Window 0 Vertical Dimensions */ + { GBA_WIN1V, "WIN1V", { + {0, 8, "Y2, Bottom-most coordinate of window, plus 1"}, + {8, 8, "Y1, Top-most coordinate of window"}, + } }, /* W Window 1 Vertical Dimensions */ + { GBA_WININ, "WININ", { + {0, 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, + {1, 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, + {2, 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, + {3, 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, + {4, 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, + {5, 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, + {8, 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, + {9, 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, + {10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, + {11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, + {12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, + {13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, + } }, /* R/W Inside of Window 0 and 1 */ + { GBA_WINOUT, "WINOUT", { + {0, 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, + {1, 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, + {2, 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, + {3, 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, + {4, 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, + {5, 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, + {8, 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, + {9, 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, + {10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, + {11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, + {12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, + {13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, + } }, /* R/W Inside of OBJ Window & Outside of Windows */ + { GBA_MOSAIC, "MOSAIC", { + {0, 4, "BG Mosaic H-Size (minus 1)"}, + {4, 4, "BG Mosaic V-Size (minus 1)"}, + {8, 4, "OBJ Mosaic H-Size (minus 1)"}, + {12, 4, "OBJ Mosaic V-Size (minus 1)"}, + } }, /* W Mosaic Size */ + { GBA_BLDCNT, "BLDCNT", { + {0, 1, "BG0 1st Target Pixel (Background 0)"}, + {1, 1, "BG1 1st Target Pixel (Background 1)"}, + {2, 1, "BG2 1st Target Pixel (Background 2)"}, + {3, 1, "BG3 1st Target Pixel (Background 3)"}, + {4, 1, "OBJ 1st Target Pixel (Top-most OBJ pixel)"}, + {5, 1, "BD 1st Target Pixel (Backdrop)"}, + {6, 2, "Color Effect (0: None 1: Alpha 2: Lighten 3: Darken)"}, + {8, 1, "BG0 2nd Target Pixel (Background 0)"}, + {9, 1, "BG1 2nd Target Pixel (Background 1)"}, + {10, 1, "BG2 2nd Target Pixel (Background 2)"}, + {11, 1, "BG3 2nd Target Pixel (Background 3)"}, + {12, 1, "OBJ 2nd Target Pixel (Top-most OBJ pixel)"}, + {13, 1, "BD 2nd Target Pixel (Backdrop)"}, + } }, /* R/W Color Special Effects Selection */ + { GBA_BLDALPHA, "BLDALPHA", { + {0, 4, "EVA Coef. (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, + {8, 4, "EVB Coef. (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, + } }, /* R/W Alpha Blending Coefficients */ + { GBA_BLDY, "BLDY", {0}}, /* W Brightness (Fade-In/Out) Coefficient */ // Sound Registers - { GBA_SOUND1CNT_L, "SOUND1CNT_L", { - {0,3, "Number of sweep shift (n=0-7)"}, - {3,1, "Sweep Frequency Direction (0=Increase, 1=Decrease)"}, - {4,3, "Sweep Time; units of 7.8ms (0-7, min=7.8ms, max=54.7ms)"}, - } }, /* R/W Channel 1 Sweep register (NR10) */ - { GBA_SOUND1CNT_H, "SOUND1CNT_H", { - { 0,6, "Sound length; units of (64-n)/256s (0-63)"}, - { 6,2, "Wave Pattern Duty (0-3, see below)"}, - { 8,3, "Envelope Step-Time; units of n/64s (1-7, 0=No Envelope)"}, - { 11,1, "Envelope Direction (0=Decrease, 1=Increase)"}, - { 12,4, "Initial Volume of envelope (1-15, 0=No Sound)"}, - } }, /* R/W Channel 1 Duty/Length/Envelope (NR11, NR12) */ - { GBA_SOUND1CNT_X, "SOUND1CNT_X", { - { 0,11, "Frequency; 131072/(2048-n)Hz (0-2047)"}, - { 14,1, "Length Flag (1=Stop output when length in NR11 expires)"}, - { 15,1, "Initial (1=Restart Sound)"}, - } }, /* R/W Channel 1 Frequency/Control (NR13, NR14) */ - { GBA_SOUND2CNT_L, "SOUND2CNT_L", { - { 0,6, "Sound length; units of (64-n)/256s (0-63)"}, - { 6,2, "Wave Pattern Duty (0-3, see below)"}, - { 8,3, "Envelope Step-Time; units of n/64s (1-7, 0=No Envelope)"}, - { 11,1, "Envelope Direction (0=Decrease, 1=Increase)"}, - { 12,4, "Initial Volume of envelope (1-15, 0=No Sound)"}, - } }, /* R/W Channel 2 Duty/Length/Envelope (NR21, NR22) */ - { GBA_SOUND2CNT_H, "SOUND2CNT_H", { - { 0 ,11, "Frequency; 131072/(2048-n)Hz (0-2047)"}, - { 14,1, "Length Flag (1=Stop output when length in NR11 expires)"}, - { 15,1, "Initial (1=Restart Sound)"}, - } }, /* R/W Channel 2 Frequency/Control (NR23, NR24) */ - { GBA_SOUND3CNT_L, "SOUND3CNT_L", { - { 5, 1, "Wave RAM Dimension (0=One bank, 1=Two banks)" }, - { 6, 1, "Wave RAM Bank Number (0-1, see below)" }, - { 7, 1, "Sound Channel 3 Off (0=Stop, 1=Playback)" }, - } }, /* R/W Channel 3 Stop/Wave RAM select (NR30) */ - { GBA_SOUND3CNT_H, "SOUND3CNT_H", { - { 0,8, "Sound length; units of (256-n)/256s (0-255)"}, - { 13,2, "Sound Volume (0=Mute/Zero, 1=100%, 2=50%, 3=25%)"}, - { 15,1, "Force Volume (0=Use above, 1=Force 75% regardless of above)"}, - } }, /* R/W Channel 3 Length/Volume (NR31, NR32) */ - { GBA_SOUND3CNT_X, "SOUND3CNT_X", { - { 0,11, "Sample Rate; 2097152/(2048-n) Hz (0-2047)" }, - { 14,1, "Length Flag (1=Stop output when length in NR31 expires)" }, - { 15,1, "Initial (1=Restart Sound)" }, - } }, /* R/W Channel 3 Frequency/Control (NR33, NR34) */ - { GBA_SOUND4CNT_L, "SOUND4CNT_L", { - { 0, 6, "Sound length; units of (64-n)/256s (0-63)" }, - { 8, 3, "Envelope Step-Time; units of n/64s (1-7, 0=No Envelope)" }, - { 11, 1, "Envelope Direction (0=Decrease, 1=Increase)" }, - { 12, 4, "Initial Volume of envelope (1-15, 0=No Sound)" }, - } }, /* R/W Channel 4 Length/Envelope (NR41, NR42) */ - { GBA_SOUND4CNT_H, "SOUND4CNT_H", { - { 0, 1, "Dividing Ratio of Frequencies (r)"}, - { 3, 1, "Counter Step/Width (0=15 bits, 1=7 bits)"}, - { 4, 1, "Shift Clock Frequency (s)"}, - { 14, 1, "Length Flag (1=Stop output when length in NR41 expires)"}, - { 15, 1, "Initial (1=Restart Sound)"}, - } }, /* R/W Channel 4 Frequency/Control (NR43, NR44) */ - { GBA_SOUNDCNT_L , "SOUNDCNT_L", { - { 0,1, "Sound 1 Master Volume RIGHT" }, - { 1,1, "Sound 2 Master Volume RIGHT" }, - { 2,1, "Sound 3 Master Volume RIGHT" }, - { 3,1, "Sound 4 Master Volume RIGHT" }, - { 4,1, "Sound 1 Master Volume LEFT" }, - { 5,1, "Sound 2 Master Volume LEFT" }, - { 6,1, "Sound 3 Master Volume LEFT" }, - { 7,1, "Sound 4 Master Volume LEFT" }, - - { 8,1, "Sound 1 Enable RIGHT" }, - { 9,1, "Sound 2 Enable RIGHT" }, - { 10,1, "Sound 3 Enable RIGHT" }, - { 11,1, "Sound 4 Enable RIGHT" }, - { 12,1, "Sound 1 Enable LEFT" }, - { 13,1, "Sound 2 Enable LEFT" }, - { 14,1, "Sound 3 Enable LEFT" }, - { 15,1, "Sound 4 Enable LEFT" }, - } }, /* R/W Control Stereo/Volume/Enable (NR50, NR51) */ - { GBA_SOUNDCNT_H , "SOUNDCNT_H", { - { 0 ,2, "Sound # 1-4 Volume (0=25%, 1=50%, 2=100%, 3=Prohibited)" }, - { 2 ,1, "DMA Sound A Volume (0=50%, 1=100%)" }, - { 3 ,1, "DMA Sound B Volume (0=50%, 1=100%)" }, - { 8 ,1, "DMA Sound A Enable RIGHT (0=Disable, 1=Enable)" }, - { 9 ,1, "DMA Sound A Enable LEFT (0=Disable, 1=Enable)" }, - { 10,1, "DMA Sound A Timer Select (0=Timer 0, 1=Timer 1)" }, - { 11,1, "DMA Sound A Reset FIFO (1=Reset)" }, - { 12,1, "DMA Sound B Enable RIGHT (0=Disable, 1=Enable)" }, - { 13,1, "DMA Sound B Enable LEFT (0=Disable, 1=Enable)" }, - { 14,1, "DMA Sound B Timer Select (0=Timer 0, 1=Timer 1)" }, - { 15,1, "DMA Sound B Reset FIFO (1=Reset)" }, - } }, /* R/W Control Mixing/DMA Control */ - { GBA_SOUNDCNT_X , "SOUNDCNT_X", { - {0, 1, "Sound 1 ON flag (Read Only)" }, - {1, 1, "Sound 2 ON flag (Read Only)" }, - {2, 1, "Sound 3 ON flag (Read Only)" }, - {3, 1, "Sound 4 ON flag (Read Only)" }, - {7, 1, "PSG/FIFO Master Enable (0=Disable, 1=Enable) (Read/Write)" }, - } }, /* R/W Control Sound on/off (NR52) */ - { GBA_SOUNDBIAS , "SOUNDBIAS", { - { 1,9,"Bias Level (Default=100h, converting signed samples into unsigned)"}, - { 14,2,"Amplitude Resolution/Sampling Cycle (Default=0, see below)"}, - } }, /* BIOS Sound PWM Control */ - { GBA_WAVE_RAM , "WAVE_RAM", { 0 } }, /* R/W Channel 3 Wave Pattern RAM (2 banks!!) */ - { GBA_FIFO_A , "FIFO_A", { 0 } }, /* W Channel A FIFO, Data 0-3 */ - { GBA_FIFO_B , "FIFO_B", { 0 } }, /* W Channel B FIFO, Data 0-3 */ + {GBA_SOUND1CNT_L, "SOUND1CNT_L", { + {0, 3, "Number of sweep shift (n=0-7)"}, + {3, 1, "Sweep Frequency Direction (0=Increase, 1=Decrease)"}, + {4, 3, "Sweep Time; units of 7.8ms (0-7, min=7.8ms, max=54.7ms)"}, + } }, /* R/W Channel 1 Sweep register (NR10) */ + {GBA_SOUND1CNT_H, "SOUND1CNT_H", { + {0, 6, "Sound length; units of (64-n)/256s (0-63)"}, + {6, 2, "Wave Pattern Duty (0-3, see below)"}, + {8, 3, "Envelope Step-Time; units of n/64s (1-7, 0=No Envelope)"}, + {11, 1, "Envelope Direction (0=Decrease, 1=Increase)"}, + {12, 4, "Initial Volume of envelope (1-15, 0=No Sound)"}, + } }, /* R/W Channel 1 Duty/Length/Envelope (NR11, NR12) */ + {GBA_SOUND1CNT_X, "SOUND1CNT_X", { + {0, 11, "Frequency; 131072/(2048-n)Hz (0-2047)"}, + {14, 1, "Length Flag (1=Stop output when length in NR11 expires)"}, + {15, 1, "Initial (1=Restart Sound)"}, + } }, /* R/W Channel 1 Frequency/Control (NR13, NR14) */ + {GBA_SOUND2CNT_L, "SOUND2CNT_L", { + {0, 6, "Sound length; units of (64-n)/256s (0-63)"}, + {6, 2, "Wave Pattern Duty (0-3, see below)"}, + {8, 3, "Envelope Step-Time; units of n/64s (1-7, 0=No Envelope)"}, + {11, 1, "Envelope Direction (0=Decrease, 1=Increase)"}, + {12, 4, "Initial Volume of envelope (1-15, 0=No Sound)"}, + } }, /* R/W Channel 2 Duty/Length/Envelope (NR21, NR22) */ + {GBA_SOUND2CNT_H, "SOUND2CNT_H", { + {0, 11, "Frequency; 131072/(2048-n)Hz (0-2047)"}, + {14, 1, "Length Flag (1=Stop output when length in NR11 expires)"}, + {15, 1, "Initial (1=Restart Sound)"}, + } }, /* R/W Channel 2 Frequency/Control (NR23, NR24) */ + {GBA_SOUND3CNT_L, "SOUND3CNT_L", { + {5, 1, "Wave RAM Dimension (0=One bank, 1=Two banks)"}, + {6, 1, "Wave RAM Bank Number (0-1, see below)"}, + {7, 1, "Sound Channel 3 Off (0=Stop, 1=Playback)"}, + } }, /* R/W Channel 3 Stop/Wave RAM select (NR30) */ + {GBA_SOUND3CNT_H, "SOUND3CNT_H", { + {0, 8, "Sound length; units of (256-n)/256s (0-255)"}, + {13, 2, "Sound Volume (0=Mute/Zero, 1=100%, 2=50%, 3=25%)"}, + {15, 1, "Force Volume (0=Use above, 1=Force 75% regardless of above)"}, + } }, /* R/W Channel 3 Length/Volume (NR31, NR32) */ + {GBA_SOUND3CNT_X, "SOUND3CNT_X", { + {0, 11, "Sample Rate; 2097152/(2048-n) Hz (0-2047)"}, + {14, 1, "Length Flag (1=Stop output when length in NR31 expires)"}, + {15, 1, "Initial (1=Restart Sound)"}, + } }, /* R/W Channel 3 Frequency/Control (NR33, NR34) */ + {GBA_SOUND4CNT_L, "SOUND4CNT_L", { + {0, 6, "Sound length; units of (64-n)/256s (0-63)"}, + {8, 3, "Envelope Step-Time; units of n/64s (1-7, 0=No Envelope)"}, + {11, 1, "Envelope Direction (0=Decrease, 1=Increase)"}, + {12, 4, "Initial Volume of envelope (1-15, 0=No Sound)"}, + } }, /* R/W Channel 4 Length/Envelope (NR41, NR42) */ + {GBA_SOUND4CNT_H, "SOUND4CNT_H", { + {0, 1, "Dividing Ratio of Frequencies (r)"}, + {3, 1, "Counter Step/Width (0=15 bits, 1=7 bits)"}, + {4, 1, "Shift Clock Frequency (s)"}, + {14, 1, "Length Flag (1=Stop output when length in NR41 expires)"}, + {15, 1, "Initial (1=Restart Sound)"}, + } }, /* R/W Channel 4 Frequency/Control (NR43, NR44) */ + { GBA_SOUNDCNT_L, "SOUNDCNT_L", { + {0, 1, "Sound 1 Master Volume RIGHT"}, + {1, 1, "Sound 2 Master Volume RIGHT"}, + {2, 1, "Sound 3 Master Volume RIGHT"}, + {3, 1, "Sound 4 Master Volume RIGHT"}, + {4, 1, "Sound 1 Master Volume LEFT"}, + {5, 1, "Sound 2 Master Volume LEFT"}, + {6, 1, "Sound 3 Master Volume LEFT"}, + {7, 1, "Sound 4 Master Volume LEFT"}, + + {8, 1, "Sound 1 Enable RIGHT"}, + {9, 1, "Sound 2 Enable RIGHT"}, + {10, 1, "Sound 3 Enable RIGHT"}, + {11, 1, "Sound 4 Enable RIGHT"}, + {12, 1, "Sound 1 Enable LEFT"}, + {13, 1, "Sound 2 Enable LEFT"}, + {14, 1, "Sound 3 Enable LEFT"}, + {15, 1, "Sound 4 Enable LEFT"}, + } }, /* R/W Control Stereo/Volume/Enable (NR50, NR51) */ + { GBA_SOUNDCNT_H, "SOUNDCNT_H", { + {0, 2, "Sound # 1-4 Volume (0=25%, 1=50%, 2=100%, 3=Prohibited)"}, + {2, 1, "DMA Sound A Volume (0=50%, 1=100%)"}, + {3, 1, "DMA Sound B Volume (0=50%, 1=100%)"}, + {8, 1, "DMA Sound A Enable RIGHT (0=Disable, 1=Enable)"}, + {9, 1, "DMA Sound A Enable LEFT (0=Disable, 1=Enable)"}, + {10, 1, "DMA Sound A Timer Select (0=Timer 0, 1=Timer 1)"}, + {11, 1, "DMA Sound A Reset FIFO (1=Reset)"}, + {12, 1, "DMA Sound B Enable RIGHT (0=Disable, 1=Enable)"}, + {13, 1, "DMA Sound B Enable LEFT (0=Disable, 1=Enable)"}, + {14, 1, "DMA Sound B Timer Select (0=Timer 0, 1=Timer 1)"}, + {15, 1, "DMA Sound B Reset FIFO (1=Reset)"}, + } }, /* R/W Control Mixing/DMA Control */ + { GBA_SOUNDCNT_X, "SOUNDCNT_X", { + {0, 1, "Sound 1 ON flag (Read Only)"}, + {1, 1, "Sound 2 ON flag (Read Only)"}, + {2, 1, "Sound 3 ON flag (Read Only)"}, + {3, 1, "Sound 4 ON flag (Read Only)"}, + {7, 1, "PSG/FIFO Master Enable (0=Disable, 1=Enable) (Read/Write)"}, + } }, /* R/W Control Sound on/off (NR52) */ + { GBA_SOUNDBIAS, "SOUNDBIAS", { + {1, 9, "Bias Level (Default=100h, converting signed samples into unsigned)"}, + {14, 2, "Amplitude Resolution/Sampling Cycle (Default=0, see below)"}, + } }, /* BIOS Sound PWM Control */ + { GBA_WAVE_RAM, "WAVE_RAM", {0}}, /* R/W Channel 3 Wave Pattern RAM (2 banks!!) */ + { GBA_FIFO_A, "FIFO_A", {0}}, /* W Channel A FIFO, Data 0-3 */ + { GBA_FIFO_B, "FIFO_B", {0}}, /* W Channel B FIFO, Data 0-3 */ // DMA Transfer Channels - { GBA_DMA0SAD , "DMA0SAD", { 0 } }, /* W DMA 0 Source Address */ - { GBA_DMA0DAD , "DMA0DAD", { 0 } }, /* W DMA 0 Destination Address */ - { GBA_DMA0CNT_L, "DMA0CNT_L", { 0 } }, /* W DMA 0 Word Count */ - { GBA_DMA0CNT_H, "DMA0CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Prohibited)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 0 Control */ - { GBA_DMA1SAD , "DMA1SAD", { 0 } }, /* W DMA 1 Source Address */ - { GBA_DMA1DAD , "DMA1DAD", { 0 } }, /* W DMA 1 Destination Address */ - { GBA_DMA1CNT_L, "DMA1CNT_L", { 0 } }, /* W DMA 1 Word Count */ - { GBA_DMA1CNT_H, "DMA1CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Sound)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 1 Control */ - { GBA_DMA2SAD , "DMA2SAD", { 0 } }, /* W DMA 2 Source Address */ - { GBA_DMA2DAD , "DMA2DAD", { 0 } }, /* W DMA 2 Destination Address */ - { GBA_DMA2CNT_L, "DMA2CNT_L", { 0 } }, /* W DMA 2 Word Count */ - { GBA_DMA2CNT_H, "DMA2CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Sound)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 2 Control */ - { GBA_DMA3SAD , "DMA3SAD", { 0 } }, /* W DMA 3 Source Address */ - { GBA_DMA3DAD , "DMA3DAD", { 0 } }, /* W DMA 3 Destination Address */ - { GBA_DMA3CNT_L, "DMA3CNT_L", { 0 } }, /* W DMA 3 Word Count */ - { GBA_DMA3CNT_H, "DMA3CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 1, "Game Pak DRQ (0=Normal, 1=DRQ Game Pak, DMA3)" }, - { 12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video Capture)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 3 Control */ + { GBA_DMA0SAD, "DMA0SAD", {0}}, /* W DMA 0 Source Address */ + { GBA_DMA0DAD, "DMA0DAD", {0}}, /* W DMA 0 Destination Address */ + { GBA_DMA0CNT_L, "DMA0CNT_L", {0}}, /* W DMA 0 Word Count */ + { GBA_DMA0CNT_H, "DMA0CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Prohibited)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 0 Control */ + { GBA_DMA1SAD, "DMA1SAD", {0}}, /* W DMA 1 Source Address */ + { GBA_DMA1DAD, "DMA1DAD", {0}}, /* W DMA 1 Destination Address */ + { GBA_DMA1CNT_L, "DMA1CNT_L", {0}}, /* W DMA 1 Word Count */ + { GBA_DMA1CNT_H, "DMA1CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Sound)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 1 Control */ + { GBA_DMA2SAD, "DMA2SAD", {0}}, /* W DMA 2 Source Address */ + { GBA_DMA2DAD, "DMA2DAD", {0}}, /* W DMA 2 Destination Address */ + { GBA_DMA2CNT_L, "DMA2CNT_L", {0}}, /* W DMA 2 Word Count */ + { GBA_DMA2CNT_H, "DMA2CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Sound)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 2 Control */ + { GBA_DMA3SAD, "DMA3SAD", {0}}, /* W DMA 3 Source Address */ + { GBA_DMA3DAD, "DMA3DAD", {0}}, /* W DMA 3 Destination Address */ + { GBA_DMA3CNT_L, "DMA3CNT_L", {0}}, /* W DMA 3 Word Count */ + { GBA_DMA3CNT_H, "DMA3CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 1, "Game Pak DRQ (0=Normal, 1=DRQ Game Pak, DMA3)"}, + {12, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video Capture)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 3 Control */ // Timer Registers - { GBA_TM0CNT_L, "TM0CNT_L", {0} }, /* R/W Timer 0 Counter/Reload */ - { GBA_TM0CNT_H, "TM0CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 0 Control */ - { GBA_TM1CNT_L, "TM1CNT_L", {0} }, /* R/W Timer 1 Counter/Reload */ - { GBA_TM1CNT_H, "TM1CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 1 Control */ - { GBA_TM2CNT_L, "TM2CNT_L", {0} }, /* R/W Timer 2 Counter/Reload */ - { GBA_TM2CNT_H, "TM2CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 2 Control */ - { GBA_TM3CNT_L, "TM3CNT_L", {0} }, /* R/W Timer 3 Counter/Reload */ - { GBA_TM3CNT_H, "TM3CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 3 Control */ + { GBA_TM0CNT_L, "TM0CNT_L", {0}}, /* R/W Timer 0 Counter/Reload */ + { GBA_TM0CNT_H, "TM0CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 0 Control */ + { GBA_TM1CNT_L, "TM1CNT_L", {0}}, /* R/W Timer 1 Counter/Reload */ + { GBA_TM1CNT_H, "TM1CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 1 Control */ + { GBA_TM2CNT_L, "TM2CNT_L", {0}}, /* R/W Timer 2 Counter/Reload */ + { GBA_TM2CNT_H, "TM2CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 2 Control */ + { GBA_TM3CNT_L, "TM3CNT_L", {0}}, /* R/W Timer 3 Counter/Reload */ + { GBA_TM3CNT_H, "TM3CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 3 Control */ // Serial Communication (1) - { GBA_SIODATA32 , "SIODATA32", {0} }, /*R/W SIO Data (Normal-32bit Mode; shared with below) */ - { GBA_SIOMULTI0 , "SIOMULTI0", {0} }, /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ - { GBA_SIOMULTI1 , "SIOMULTI1", {0} }, /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ - { GBA_SIOMULTI2 , "SIOMULTI2", {0} }, /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ - { GBA_SIOMULTI3 , "SIOMULTI3", {0} }, /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ - { GBA_SIOCNT , "SIOCNT", {0} }, /*R/W SIO Control Register */ - { GBA_SIOMLT_SEND, "SIOMLT_SEND", {0} }, /*R/W SIO Data (Local of MultiPlayer; shared below) */ - { GBA_SIODATA8 , "SIODATA8", {0} }, /*R/W SIO Data (Normal-8bit and UART Mode) */ + { GBA_SIODATA32, "SIODATA32", {0}}, /*R/W SIO Data (Normal-32bit Mode; shared with below) */ + { GBA_SIOMULTI0, "SIOMULTI0", {0}}, /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ + { GBA_SIOMULTI1, "SIOMULTI1", {0}}, /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ + { GBA_SIOMULTI2, "SIOMULTI2", {0}}, /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ + { GBA_SIOMULTI3, "SIOMULTI3", {0}}, /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ + { GBA_SIOCNT, "SIOCNT", {0}}, /*R/W SIO Control Register */ + {GBA_SIOMLT_SEND, "SIOMLT_SEND", {0}}, /*R/W SIO Data (Local of MultiPlayer; shared below) */ + { GBA_SIODATA8, "SIODATA8", {0}}, /*R/W SIO Data (Normal-8bit and UART Mode) */ // Keypad Input - { GBA_KEYINPUT, "GBA_KEYINPUT", { - { 0, 1, "Button A" }, - { 1, 1, "Button B" }, - { 2, 1, "Select" }, - { 3, 1, "Start" }, - { 4, 1, "Right" }, - { 5, 1, "Left" }, - { 6, 1, "Up" }, - { 7, 1, "Down" }, - { 8, 1, "Button R" }, - { 9, 1, "Button L" }, - } }, /* R Key Status */ - { GBA_KEYCNT , "GBA_KEYCNT", { - { 0, 1, "Button A" }, - { 1, 1, "Button B" }, - { 2, 1, "Select" }, - { 3, 1, "Start" }, - { 4, 1, "Right" }, - { 5, 1, "Left" }, - { 6, 1, "Up" }, - { 7, 1, "Down" }, - { 8, 1, "Button R" }, - { 9, 1, "Button L" }, - { 14,1, "Button IRQ Enable (0=Disable, 1=Enable)" }, - { 15,1, "Button IRQ Condition (0=OR, 1=AND)"}, - } }, /* R/W Key Interrupt Control */ + { GBA_KEYINPUT, "GBA_KEYINPUT", { + {0, 1, "Button A"}, + {1, 1, "Button B"}, + {2, 1, "Select"}, + {3, 1, "Start"}, + {4, 1, "Right"}, + {5, 1, "Left"}, + {6, 1, "Up"}, + {7, 1, "Down"}, + {8, 1, "Button R"}, + {9, 1, "Button L"}, + } }, /* R Key Status */ + { GBA_KEYCNT, "GBA_KEYCNT", { + {0, 1, "Button A"}, + {1, 1, "Button B"}, + {2, 1, "Select"}, + {3, 1, "Start"}, + {4, 1, "Right"}, + {5, 1, "Left"}, + {6, 1, "Up"}, + {7, 1, "Down"}, + {8, 1, "Button R"}, + {9, 1, "Button L"}, + {14, 1, "Button IRQ Enable (0=Disable, 1=Enable)"}, + {15, 1, "Button IRQ Condition (0=OR, 1=AND)"}, + } }, /* R/W Key Interrupt Control */ // Serial Communication (2) - { GBA_RCNT , "RCNT", {0} }, /* R/W SIO Mode Select/General Purpose Data */ - { GBA_IR , "IR", {0} }, /* - Ancient - Infrared Register (Prototypes only) */ - { GBA_JOYCNT , "JOYCNT", {0} }, /* R/W SIO JOY Bus Control */ - { GBA_JOY_RECV , "JOY_RECV", {0} }, /* R/W SIO JOY Bus Receive Data */ - { GBA_JOY_TRANS, "JOY_TRANS", {0} }, /* R/W SIO JOY Bus Transmit Data */ - { GBA_JOYSTAT , "JOYSTAT", {0} }, /* R/? SIO JOY Bus Receive Status */ + { GBA_RCNT, "RCNT", {0}}, /* R/W SIO Mode Select/General Purpose Data */ + { GBA_IR, "IR", {0}}, /* - Ancient - Infrared Register (Prototypes only) */ + { GBA_JOYCNT, "JOYCNT", {0}}, /* R/W SIO JOY Bus Control */ + { GBA_JOY_RECV, "JOY_RECV", {0}}, /* R/W SIO JOY Bus Receive Data */ + { GBA_JOY_TRANS, "JOY_TRANS", {0}}, /* R/W SIO JOY Bus Transmit Data */ + { GBA_JOYSTAT, "JOYSTAT", {0}}, /* R/? SIO JOY Bus Receive Status */ }; // Interrupt sources -#define GBA_INT_LCD_VBLANK 0 -#define GBA_INT_LCD_HBLANK 1 -#define GBA_INT_LCD_VCOUNT 2 -#define GBA_INT_TIMER0 3 -#define GBA_INT_TIMER1 4 -#define GBA_INT_TIMER2 5 -#define GBA_INT_TIMER3 6 -#define GBA_INT_SERIAL 7 -#define GBA_INT_DMA0 8 -#define GBA_INT_DMA1 9 -#define GBA_INT_DMA2 10 -#define GBA_INT_DMA3 11 -#define GBA_INT_KEYPAD 12 -#define GBA_INT_GAMEPAK 13 -#define GBA_BG_PALETTE 0x00000000 -#define GBA_OBJ_PALETTE 0x00000200 +#define GBA_INT_LCD_VBLANK 0 +#define GBA_INT_LCD_HBLANK 1 +#define GBA_INT_LCD_VCOUNT 2 +#define GBA_INT_TIMER0 3 +#define GBA_INT_TIMER1 4 +#define GBA_INT_TIMER2 5 +#define GBA_INT_TIMER3 6 +#define GBA_INT_SERIAL 7 +#define GBA_INT_DMA0 8 +#define GBA_INT_DMA1 9 +#define GBA_INT_DMA2 10 +#define GBA_INT_DMA3 11 +#define GBA_INT_KEYPAD 12 +#define GBA_INT_GAMEPAK 13 +#define GBA_BG_PALETTE 0x00000000 +#define GBA_OBJ_PALETTE 0x00000200 #define GBA_OBJ_TILES0_2 0x00010000 #define GBA_OBJ_TILES3_5 0x00014000 -#define GBA_OAM 0x07000000 +#define GBA_OAM 0x07000000 #define GBA_BACKUP_NONE 0 #define GBA_BACKUP_EEPROM 1 #define GBA_BACKUP_EEPROM_512B 2 #define GBA_BACKUP_EEPROM_8KB 3 #define GBA_BACKUP_SRAM 4 -#define GBA_BACKUP_FLASH_64K 5 -#define GBA_BACKUP_FLASH_128K 6 +#define GBA_BACKUP_FLASH_64K 5 +#define GBA_BACKUP_FLASH_128K 6 #define GBA_REQ_1B 0x01 #define GBA_REQ_2B 0x02 @@ -621,164 +657,164 @@ mmio_reg_t gba_io_reg_desc[]={ #define GBA_REQ_READ 0x40 #define GBA_REQ_WRITE 0x80 -typedef struct { +typedef struct { uint8_t *bios; - uint8_t wram0[256*1024]; - uint8_t wram1[32*1024]; - uint8_t io[1024]; - uint8_t palette[1024]; - uint8_t vram[128*1024]; - uint8_t oam[1024]; + uint8_t wram0[256 * 1024]; + uint8_t wram1[32 * 1024]; + uint8_t io[1024]; + uint8_t palette[1024]; + uint8_t vram[128 * 1024]; + uint8_t oam[1024]; uint8_t *cart_rom; - uint8_t cart_backup[128*1024]; - uint8_t flash_chip_id[4]; + uint8_t cart_backup[128 * 1024]; + uint8_t flash_chip_id[4]; uint32_t openbus_word; - uint32_t eeprom_word; - uint32_t eeprom_addr; - uint32_t prefetch_en; - uint32_t prefetch_size; + uint32_t eeprom_word; + uint32_t eeprom_addr; + uint32_t prefetch_en; + uint32_t prefetch_size; uint32_t requests; uint32_t bios_word; uint32_t sram_word; uint32_t mmio_word; - uint8_t wait_state_table[16*4]; + uint8_t wait_state_table[16 * 4]; // Tracks the place of the squashable pipeline bubble that enters the pipeline after a single cycle data read - // Each bit represents one clock cycle in time with bit 0 meaning the current cycle of the last stage of the - // CPU pipeline and larger bits indicating future cycles. + // Each bit represents one clock cycle in time with bit 0 meaning the current cycle of the last stage of the + // CPU pipeline and larger bits indicating future cycles. - // This is shifted to the right every clock cycle to mimic the bubble traveling through the pipeline. - // Some complexity is introduced because this bubble may be squashed by upstream push back. This is modelled by - // extra shift rights for the multicycling of the various stages. + // This is shifted to the right every clock cycle to mimic the bubble traveling through the pipeline. + // Some complexity is introduced because this bubble may be squashed by upstream push back. This is modelled by + // extra shift rights for the multicycling of the various stages. uint32_t pipeline_bubble_shift_register; // Lookup tables to accelerate MMIO masking / Open bus behavior uint32_t mmio_data_mask_lookup[256]; uint8_t mmio_reg_valid_lookup[256]; - uint8_t mmio_debug_access_buffer[16*1024]; + uint8_t mmio_debug_access_buffer[16 * 1024]; } gba_mem_t; typedef struct { - unsigned rom_size; - uint8_t backup_type; - bool backup_is_dirty; - bool in_chip_id_mode; - int flash_state; - int flash_bank; + unsigned rom_size; + uint8_t backup_type; + bool backup_is_dirty; + bool in_chip_id_mode; + int flash_state; + int flash_bank; uint32_t gpio_data; } gba_cartridge_t; -typedef struct{ - int source_addr; - int dest_addr; - int length; - int current_transaction; - bool last_enable; - bool last_vblank; - bool last_hblank; +typedef struct { + int source_addr; + int dest_addr; + int length; + int current_transaction; + bool last_enable; + bool last_vblank; + bool last_hblank; uint32_t latched_transfer; - int startup_delay; - bool activate_audio_dma; - bool video_dma_active; -} gba_dma_t; -typedef struct{ - int scan_clock; + int startup_delay; + bool activate_audio_dma; + bool video_dma_active; +} gba_dma_t; +typedef struct { + int scan_clock; bool last_vblank; bool last_hblank; - int last_lcd_y; + int last_lcd_y; bool has_hit_vblank; struct { int32_t internal_bgx; int32_t internal_bgy; int32_t render_bgx; int32_t render_bgy; - bool wrote_bgx; - bool wrote_bgy; - }aff[2]; + bool wrote_bgx; + bool wrote_bgy; + } aff[2]; uint16_t dispcnt_pipeline[3]; - int fast_forward_ticks; - float ghosting_strength; + int fast_forward_ticks; + float ghosting_strength; uint32_t mosaic_y_counter; -}gba_ppu_t; -typedef struct{ - bool last_enable; - uint16_t reload_value; - uint16_t pending_reload_value; - int startup_delay; -}gba_timer_t; -typedef struct{ +} gba_ppu_t; +typedef struct { + bool last_enable; + uint16_t reload_value; + uint16_t pending_reload_value; + int startup_delay; +} gba_timer_t; +typedef struct { uint32_t step_counter; - int32_t length[4]; + int32_t length[4]; uint32_t volume[4]; uint32_t frequency[4]; - int32_t env_direction[4]; //1: increase 0: nochange -1: decrease + int32_t env_direction[4]; // 1: increase 0: nochange -1: decrease uint32_t env_period[4]; uint32_t env_period_timer[4]; - bool env_overflow[4]; - //Only channel 1 + bool env_overflow[4]; + // Only channel 1 uint32_t sweep_period; uint32_t sweep_timer; - int32_t sweep_direction; + int32_t sweep_direction; uint32_t sweep_shift; bool sweep_enable; bool sweep_subtracted; - bool use_length[4]; - bool active[4]; - bool powered[4]; - float chan_t[4]; + bool use_length[4]; + bool active[4]; + bool powered[4]; + float chan_t[4]; uint16_t lfsr4; -}gba_frame_sequencer_t; -typedef struct{ - struct{ +} gba_frame_sequencer_t; +typedef struct { + struct { int8_t data[64]; - int read_ptr; - int write_ptr; - bool request_dma_fill; - }fifo[2]; - double current_sim_time; - double current_sample_generated_time; - uint16_t wave_freq_timer; - uint16_t wave_sample_offset; - uint8_t curr_wave_sample; - uint8_t curr_wave_data; - float capacitor_l,capacitor_r; + int read_ptr; + int write_ptr; + bool request_dma_fill; + } fifo[2]; + double current_sim_time; + double current_sample_generated_time; + uint16_t wave_freq_timer; + uint16_t wave_sample_offset; + uint8_t curr_wave_sample; + uint8_t curr_wave_data; + float capacitor_l, capacitor_r; gba_frame_sequencer_t sequencer; - uint32_t audio_clock; -}gba_audio_t; -typedef struct{ + uint32_t audio_clock; +} gba_audio_t; +typedef struct { uint32_t serial_state; uint32_t serial_bits_clocked; uint64_t input_register; uint64_t output_register; uint32_t state; - uint8_t status_register; - //Used to create an RTC that is real time in the game world. + uint8_t status_register; + // Used to create an RTC that is real time in the game world. uint64_t initial_rtc_time; uint64_t total_clocks_ticked; -}gba_rtc_t; -typedef struct{ - int ticks_till_transfer_done; - bool last_active; -}gba_sio_t; - -typedef struct{ - uint32_t bess_version; //Versioning field must be 1 - /* - r0-r15 +} gba_rtc_t; +typedef struct { + int ticks_till_transfer_done; + bool last_active; +} gba_sio_t; + +typedef struct { + uint32_t bess_version; // Versioning field must be 1 + /* + r0-r15 CPSR 16 - SPSR 17 - R13_fiq 22 - R13_irq 24 - R13_svc 26 - R13_abt 28 - R13_und 30 - R14_fiq 23 - R14_irq 25 - R14_svc 27 - R14_abt 29 - R14_und 31 - SPSR_fiq 32 - SPSR_irq 33 - SPSR_svc 34 - SPSR_abt 35 - SPSR_und 36 + SPSR 17 + R13_fiq 22 + R13_irq 24 + R13_svc 26 + R13_abt 28 + R13_und 30 + R14_fiq 23 + R14_irq 25 + R14_svc 27 + R14_abt 29 + R14_und 31 + SPSR_fiq 32 + SPSR_irq 33 + SPSR_svc 34 + SPSR_abt 35 + SPSR_und 36 */ uint32_t cpu_registers[37]; uint32_t wram0_seg; @@ -790,881 +826,937 @@ typedef struct{ uint32_t cart_backup_seg; uint16_t timer_reload_values[4]; uint32_t padding[18]; -}gba_bess_info_t; -typedef struct{ +} gba_bess_info_t; +typedef struct { uint16_t dac; uint16_t value; - uint8_t last_clk; -}gba_solar_sensor_t; -typedef struct gba_t{ - gba_mem_t mem; - arm7_t cpu; + uint8_t last_clk; +} gba_solar_sensor_t; +typedef struct gba_t { + gba_mem_t mem; + arm7_t cpu; gba_cartridge_t cart; - gba_ppu_t ppu; - gba_rtc_t rtc; - gba_dma_t dma[4]; - gba_sio_t sio; + gba_ppu_t ppu; + gba_rtc_t rtc; + gba_dma_t dma[4]; + gba_sio_t sio; gba_bess_info_t bess; - //There is a 2 cycle penalty when the CPU takes over from the DMA - bool last_transaction_dma; - bool activate_dmas; - bool dma_wait_ppu; + // There is a 2 cycle penalty when the CPU takes over from the DMA + bool last_transaction_dma; + bool activate_dmas; + bool dma_wait_ppu; gba_timer_t timers[4]; - uint32_t timer_ticks_before_event; - uint32_t deferred_timer_ticks; - uint32_t global_timer; + uint32_t timer_ticks_before_event; + uint32_t deferred_timer_ticks; + uint32_t global_timer; gba_audio_t audio; - bool prev_key_interrupt; - uint32_t first_target_buffer[GBA_LCD_W]; - uint32_t second_target_buffer[GBA_LCD_W]; - uint8_t window[GBA_LCD_W]; - uint8_t *framebuffer; - // Some HW has up to a 4 cycle delay before its IF propagates. - // This array acts as a FIFO to keep track of that. - uint16_t pipelined_if[5]; - int active_if_pipe_stages; - int last_cpu_tick; - int residual_dma_ticks; - bool stop_mode; + bool prev_key_interrupt; + uint32_t first_target_buffer[GBA_LCD_W]; + uint32_t second_target_buffer[GBA_LCD_W]; + uint8_t window[GBA_LCD_W]; + uint8_t *framebuffer; + // Some HW has up to a 4 cycle delay before its IF propagates. + // This array acts as a FIFO to keep track of that. + uint16_t pipelined_if[5]; + int active_if_pipe_stages; + int last_cpu_tick; + int residual_dma_ticks; + bool stop_mode; gba_solar_sensor_t solar_sensor; -} gba_t; - -typedef struct{ - uint8_t framebuffer[GBA_LCD_W*GBA_LCD_H*4]; - uint8_t bios[16*1024]; - FILE * log_cmp_file; - bool skip_bios_intro; - char save_file_path[SB_FILE_PATH_SIZE]; -}gba_scratch_t; -static void gba_process_audio_writes(gba_t* gba); -static uint8_t gba_audio_process_byte_write(gba_t *gba, uint32_t addr, uint8_t value); -static bool gba_run_ar_cheat(gba_t* gba, const uint32_t* buffer, uint32_t size); -static FORCE_INLINE void gba_recompute_waitstate_table(gba_t* gba,uint16_t waitcnt); -static FORCE_INLINE uint32_t gba_read32(gba_t*gba, unsigned baddr); -static FORCE_INLINE void gba_store32(gba_t*gba, unsigned baddr, uint32_t data); - -//Returns offset into savestate where bess info can be found -static uint32_t gba_save_best_effort_state(gba_t* gba){ - gba->bess.bess_version = 1; - for(int i=0;i<37;++i)gba->bess.cpu_registers[i]=gba->cpu.registers[i]; - - gba->bess.wram0_seg = ((uint8_t*)gba->mem.wram0)-(uint8_t*)gba; - gba->bess.wram1_seg = ((uint8_t*)gba->mem.wram1)-(uint8_t*)gba; - gba->bess.io_seg = ((uint8_t*)gba->mem.io)-(uint8_t*)gba; - gba->bess.palette_seg = ((uint8_t*)gba->mem.palette)-(uint8_t*)gba; - gba->bess.vram_seg = ((uint8_t*)gba->mem.vram)-(uint8_t*)gba; - gba->bess.oam_seg = ((uint8_t*)gba->mem.oam)-(uint8_t*)gba; - gba->bess.cart_backup_seg = ((uint8_t*)gba->mem.cart_backup)-(uint8_t*)gba; - for(int i=0;i<4;++i)gba->bess.timer_reload_values[i]=gba->timers[i].reload_value; - return ((uint8_t*)&gba->bess)-(uint8_t*)(gba); -} -static bool gba_load_best_effort_state(gba_t* gba,uint8_t *save_state_data, uint32_t size, uint32_t bess_offset){ - if(bess_offset+sizeof(gba_bess_info_t)>size)return false; - gba_bess_info_t * bess = (gba_bess_info_t*)(save_state_data+bess_offset); - if(bess->bess_version!=1)return false; - if(bess->wram0_seg+sizeof(gba->mem.wram0) > size) return false; - if(bess->wram1_seg+sizeof(gba->mem.wram1) > size) return false; - if(bess->io_seg+sizeof(gba->mem.io) > size) return false; - if(bess->palette_seg+sizeof(gba->mem.palette) > size) return false; - if(bess->vram_seg+sizeof(gba->mem.vram) > size) return false; - if(bess->oam_seg+sizeof(gba->mem.oam) > size) return false; - if(bess->cart_backup_seg+sizeof(gba->mem.cart_backup) > size) return false; - for(int i=0;i<37;++i)gba->cpu.registers[i]=bess->cpu_registers[i]; - memcpy(gba->mem.wram0,save_state_data+bess->wram0_seg,sizeof(gba->mem.wram0)); - memcpy(gba->mem.wram1,save_state_data+bess->wram1_seg,sizeof(gba->mem.wram1)); - memcpy(gba->mem.io,save_state_data+bess->io_seg,sizeof(gba->mem.io)); - memcpy(gba->mem.palette,save_state_data+bess->palette_seg,sizeof(gba->mem.palette)); - memcpy(gba->mem.vram,save_state_data+bess->vram_seg,sizeof(gba->mem.vram)); - memcpy(gba->mem.oam,save_state_data+bess->oam_seg,sizeof(gba->mem.oam)); - memcpy(gba->mem.cart_backup,save_state_data+bess->cart_backup_seg,sizeof(gba->mem.cart_backup)); - for(int i=0;i<4;++i)gba->timers[i].pending_reload_value=gba->timers[i].reload_value=bess->timer_reload_values[i]; - - gba_recompute_waitstate_table(gba,gba_read32(gba, GBA_WAITCNT)); - return true; -} - -static FORCE_INLINE sb_debug_mmio_access_t gba_debug_mmio_access(gba_t*gba, unsigned baddr, int trigger_breakpoint){ - baddr&=0xffff; - baddr/=4; - - if(trigger_breakpoint!=-1){ - gba->mem.mmio_debug_access_buffer[baddr]&=0x7f; - if(trigger_breakpoint!=0)gba->mem.mmio_debug_access_buffer[baddr]|=0x80; +} gba_t; + +typedef struct { + uint8_t framebuffer[GBA_LCD_W * GBA_LCD_H * 4]; + uint8_t bios[16 * 1024]; + FILE *log_cmp_file; + bool skip_bios_intro; + char save_file_path[SB_FILE_PATH_SIZE]; +} gba_scratch_t; +static void gba_process_audio_writes(gba_t *gba); +static uint8_t gba_audio_process_byte_write(gba_t *gba, uint32_t addr, uint8_t value); +static bool gba_run_ar_cheat(gba_t *gba, const uint32_t *buffer, uint32_t size); +static FORCE_INLINE void gba_recompute_waitstate_table(gba_t *gba, uint16_t waitcnt); +static FORCE_INLINE uint32_t gba_read32(gba_t *gba, unsigned baddr); +static FORCE_INLINE void gba_store32(gba_t *gba, unsigned baddr, uint32_t data); + +// Returns offset into savestate where bess info can be found +static uint32_t gba_save_best_effort_state(gba_t *gba) { + gba->bess.bess_version = 1; + for(int i = 0; i < 37; ++i) + gba->bess.cpu_registers[i] = gba->cpu.registers[i]; + + gba->bess.wram0_seg = ((uint8_t *)gba->mem.wram0) - (uint8_t *)gba; + gba->bess.wram1_seg = ((uint8_t *)gba->mem.wram1) - (uint8_t *)gba; + gba->bess.io_seg = ((uint8_t *)gba->mem.io) - (uint8_t *)gba; + gba->bess.palette_seg = ((uint8_t *)gba->mem.palette) - (uint8_t *)gba; + gba->bess.vram_seg = ((uint8_t *)gba->mem.vram) - (uint8_t *)gba; + gba->bess.oam_seg = ((uint8_t *)gba->mem.oam) - (uint8_t *)gba; + gba->bess.cart_backup_seg = ((uint8_t *)gba->mem.cart_backup) - (uint8_t *)gba; + for(int i = 0; i < 4; ++i) + gba->bess.timer_reload_values[i] = gba->timers[i].reload_value; + return ((uint8_t *)&gba->bess) - (uint8_t *)(gba); +} +static bool gba_load_best_effort_state(gba_t *gba, uint8_t *save_state_data, uint32_t size, uint32_t bess_offset) { + if(bess_offset + sizeof(gba_bess_info_t) > size) return false; + gba_bess_info_t *bess = (gba_bess_info_t *)(save_state_data + bess_offset); + if(bess->bess_version != 1) return false; + if(bess->wram0_seg + sizeof(gba->mem.wram0) > size) return false; + if(bess->wram1_seg + sizeof(gba->mem.wram1) > size) return false; + if(bess->io_seg + sizeof(gba->mem.io) > size) return false; + if(bess->palette_seg + sizeof(gba->mem.palette) > size) return false; + if(bess->vram_seg + sizeof(gba->mem.vram) > size) return false; + if(bess->oam_seg + sizeof(gba->mem.oam) > size) return false; + if(bess->cart_backup_seg + sizeof(gba->mem.cart_backup) > size) return false; + for(int i = 0; i < 37; ++i) + gba->cpu.registers[i] = bess->cpu_registers[i]; + memcpy(gba->mem.wram0, save_state_data + bess->wram0_seg, sizeof(gba->mem.wram0)); + memcpy(gba->mem.wram1, save_state_data + bess->wram1_seg, sizeof(gba->mem.wram1)); + memcpy(gba->mem.io, save_state_data + bess->io_seg, sizeof(gba->mem.io)); + memcpy(gba->mem.palette, save_state_data + bess->palette_seg, sizeof(gba->mem.palette)); + memcpy(gba->mem.vram, save_state_data + bess->vram_seg, sizeof(gba->mem.vram)); + memcpy(gba->mem.oam, save_state_data + bess->oam_seg, sizeof(gba->mem.oam)); + memcpy(gba->mem.cart_backup, save_state_data + bess->cart_backup_seg, sizeof(gba->mem.cart_backup)); + for(int i = 0; i < 4; ++i) + gba->timers[i].pending_reload_value = gba->timers[i].reload_value = bess->timer_reload_values[i]; + + gba_recompute_waitstate_table(gba, gba_read32(gba, GBA_WAITCNT)); + return true; +} + +static FORCE_INLINE sb_debug_mmio_access_t gba_debug_mmio_access(gba_t *gba, unsigned baddr, int trigger_breakpoint) { + baddr &= 0xffff; + baddr /= 4; + + if(trigger_breakpoint != -1) { + gba->mem.mmio_debug_access_buffer[baddr] &= 0x7f; + if(trigger_breakpoint != 0) gba->mem.mmio_debug_access_buffer[baddr] |= 0x80; } uint8_t flag = gba->mem.mmio_debug_access_buffer[baddr]; - sb_debug_mmio_access_t access; - access.read_since_reset = flag&0x1; - access.read_in_tick = flag&0x2; + sb_debug_mmio_access_t access; + access.read_since_reset = flag & 0x1; + access.read_in_tick = flag & 0x2; - access.write_since_reset = flag&0x10; - access.write_in_tick = flag&0x20; - access.trigger_breakpoint = flag&0x80; - return access; + access.write_since_reset = flag & 0x10; + access.write_in_tick = flag & 0x20; + access.trigger_breakpoint = flag & 0x80; + return access; } -static void gba_tick_keypad(sb_joy_t*joy, gba_t* gba); -static FORCE_INLINE void gba_tick_timers(gba_t* gba); -static void gba_compute_timers(gba_t* gba); -static void FORCE_INLINE gba_send_interrupt(gba_t*gba,int delay,int if_bit); +static void gba_tick_keypad(sb_joy_t *joy, gba_t *gba); +static FORCE_INLINE void gba_tick_timers(gba_t *gba); +static void gba_compute_timers(gba_t *gba); +static void FORCE_INLINE gba_send_interrupt(gba_t *gba, int delay, int if_bit); // Returns a pointer to the data backing the baddr (when not DWORD aligned, it -// ignores the lowest 2 bits. -static FORCE_INLINE uint32_t * gba_dword_lookup(gba_t* gba,unsigned baddr, int req_type); -static FORCE_INLINE uint32_t gba_read32(gba_t*gba, unsigned baddr){return *gba_dword_lookup(gba,baddr,GBA_REQ_READ|GBA_REQ_4B);} -static FORCE_INLINE uint16_t gba_read16(gba_t*gba, unsigned baddr){ - uint32_t* val = gba_dword_lookup(gba,baddr,GBA_REQ_READ|GBA_REQ_2B); - int offset = SB_BFE(baddr,1,1); - return ((uint16_t*)val)[offset]; -} -static FORCE_INLINE uint8_t gba_read8(gba_t*gba, unsigned baddr){ - uint32_t* val = gba_dword_lookup(gba,baddr,GBA_REQ_READ|GBA_REQ_1B); - int offset = SB_BFE(baddr,0,2); - return ((uint8_t*)val)[offset]; -} -static FORCE_INLINE uint8_t gba_read8_debug(gba_t*gba, unsigned baddr){ - uint32_t* val = gba_dword_lookup(gba,baddr,GBA_REQ_READ|GBA_REQ_1B|GBA_REQ_DEBUG); - int offset = SB_BFE(baddr,0,2); - return ((uint8_t*)val)[offset]; -} -static FORCE_INLINE void gba_process_flash_state_machine(gba_t* gba, unsigned baddr, uint8_t data){ - #define FLASH_DEFAULT 0x0 - #define FLASH_RECV_AA 0x1 - #define FLASH_RECV_55 0x2 - #define FLASH_ERASE_RECV_AA 0x3 - #define FLASH_ERASE_RECV_55 0x4 - - #define FLASH_ENTER_CHIP_ID 0x90 - #define FLASH_EXIT_CHIP_ID 0xF0 - #define FLASH_PREP_ERASE 0x80 - #define FLASH_ERASE_CHIP 0x10 - #define FLASH_ERASE_4KB 0x30 - #define FLASH_WRITE_BYTE 0xA0 - #define FLASH_SET_BANK 0xB0 +// ignores the lowest 2 bits. +static FORCE_INLINE uint32_t *gba_dword_lookup(gba_t *gba, unsigned baddr, int req_type); +static FORCE_INLINE uint32_t gba_read32(gba_t *gba, unsigned baddr) { return *gba_dword_lookup(gba, baddr, GBA_REQ_READ | GBA_REQ_4B); } +static FORCE_INLINE uint16_t gba_read16(gba_t *gba, unsigned baddr) { + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_READ | GBA_REQ_2B); + int offset = SB_BFE(baddr, 1, 1); + return ((uint16_t *)val)[offset]; +} +static FORCE_INLINE uint8_t gba_read8(gba_t *gba, unsigned baddr) { + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_READ | GBA_REQ_1B); + int offset = SB_BFE(baddr, 0, 2); + return ((uint8_t *)val)[offset]; +} +static FORCE_INLINE uint8_t gba_read8_debug(gba_t *gba, unsigned baddr) { + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_READ | GBA_REQ_1B | GBA_REQ_DEBUG); + int offset = SB_BFE(baddr, 0, 2); + return ((uint8_t *)val)[offset]; +} +static FORCE_INLINE void gba_process_flash_state_machine(gba_t *gba, unsigned baddr, uint8_t data) { +#define FLASH_DEFAULT 0x0 +#define FLASH_RECV_AA 0x1 +#define FLASH_RECV_55 0x2 +#define FLASH_ERASE_RECV_AA 0x3 +#define FLASH_ERASE_RECV_55 0x4 + +#define FLASH_ENTER_CHIP_ID 0x90 +#define FLASH_EXIT_CHIP_ID 0xF0 +#define FLASH_PREP_ERASE 0x80 +#define FLASH_ERASE_CHIP 0x10 +#define FLASH_ERASE_4KB 0x30 +#define FLASH_WRITE_BYTE 0xA0 +#define FLASH_SET_BANK 0xB0 int state = gba->cart.flash_state; - gba->cart.flash_state=FLASH_DEFAULT; - baddr&=0xffff; - switch(state){ - default: - printf("Unknown flash state %02x\n",gba->cart.flash_state); - case FLASH_DEFAULT: - if(baddr==0x5555 && data == 0xAA) gba->cart.flash_state = FLASH_RECV_AA; - break; - case FLASH_RECV_AA: - if(baddr==0x2AAA && data == 0x55) gba->cart.flash_state = FLASH_RECV_55; - break; - case FLASH_RECV_55: - if(baddr==0x5555){ - // Process command - switch(data){ - case FLASH_ENTER_CHIP_ID:gba->cart.in_chip_id_mode = true; break; - case FLASH_EXIT_CHIP_ID: gba->cart.in_chip_id_mode = false; break; - case FLASH_PREP_ERASE: gba->cart.flash_state = FLASH_PREP_ERASE; break; - case FLASH_WRITE_BYTE: gba->cart.flash_state = FLASH_WRITE_BYTE; break; - case FLASH_SET_BANK: gba->cart.flash_state = FLASH_SET_BANK; break; - default: printf("Unknown flash command: %02x\n",data);break; - } + gba->cart.flash_state = FLASH_DEFAULT; + baddr &= 0xffff; + switch(state) { + default: + printf("Unknown flash state %02x\n", gba->cart.flash_state); + case FLASH_DEFAULT: + if(baddr == 0x5555 && data == 0xAA) gba->cart.flash_state = FLASH_RECV_AA; + break; + case FLASH_RECV_AA: + if(baddr == 0x2AAA && data == 0x55) gba->cart.flash_state = FLASH_RECV_55; + break; + case FLASH_RECV_55: + if(baddr == 0x5555) { + // Process command + switch(data) { + case FLASH_ENTER_CHIP_ID: gba->cart.in_chip_id_mode = true; break; + case FLASH_EXIT_CHIP_ID: gba->cart.in_chip_id_mode = false; break; + case FLASH_PREP_ERASE: gba->cart.flash_state = FLASH_PREP_ERASE; break; + case FLASH_WRITE_BYTE: gba->cart.flash_state = FLASH_WRITE_BYTE; break; + case FLASH_SET_BANK: gba->cart.flash_state = FLASH_SET_BANK; break; + default: printf("Unknown flash command: %02x\n", data); break; } - break; - case FLASH_PREP_ERASE: - if(baddr==0x5555 && data == 0xAA) gba->cart.flash_state = FLASH_ERASE_RECV_AA; - break; - case FLASH_ERASE_RECV_AA: - if(baddr==0x2AAA && data == 0x55) gba->cart.flash_state = FLASH_ERASE_RECV_55; - break; - case FLASH_ERASE_RECV_55: - if(baddr==0x5555|| data ==FLASH_ERASE_4KB){ - int size = gba->cart.backup_type == GBA_BACKUP_FLASH_64K? 64*1024 : 128*1024; - int erase_4k_off = gba->cart.flash_bank*64*1024+SB_BFE(baddr,12,4)*4096; - // Process command - switch(data){ - case FLASH_ERASE_CHIP: - printf("Erase Flash Chip %d bytes\n",size); - for(int i=0;imem.cart_backup[i]=0xff; - break; - case FLASH_ERASE_4KB:for(int i=0;i<4096;++i)gba->mem.cart_backup[erase_4k_off+i]=0xff; break; - default: printf("Unknown flash erase command: %02x\n",data);break; - } - gba->cart.backup_is_dirty=true; + } + break; + case FLASH_PREP_ERASE: + if(baddr == 0x5555 && data == 0xAA) gba->cart.flash_state = FLASH_ERASE_RECV_AA; + break; + case FLASH_ERASE_RECV_AA: + if(baddr == 0x2AAA && data == 0x55) gba->cart.flash_state = FLASH_ERASE_RECV_55; + break; + case FLASH_ERASE_RECV_55: + if(baddr == 0x5555 || data == FLASH_ERASE_4KB) { + int size = gba->cart.backup_type == GBA_BACKUP_FLASH_64K ? 64 * 1024 : 128 * 1024; + int erase_4k_off = gba->cart.flash_bank * 64 * 1024 + SB_BFE(baddr, 12, 4) * 4096; + // Process command + switch(data) { + case FLASH_ERASE_CHIP: + printf("Erase Flash Chip %d bytes\n", size); + for(int i = 0; i < size; ++i) + gba->mem.cart_backup[i] = 0xff; + break; + case FLASH_ERASE_4KB: + for(int i = 0; i < 4096; ++i) + gba->mem.cart_backup[erase_4k_off + i] = 0xff; + break; + default: printf("Unknown flash erase command: %02x\n", data); break; } - break; - case FLASH_WRITE_BYTE: - gba->mem.cart_backup[gba->cart.flash_bank*64*1024+baddr] &= data; - gba->cart.backup_is_dirty=true; - break; - case FLASH_SET_BANK: - gba->cart.flash_bank = data&1; - break; + gba->cart.backup_is_dirty = true; + } + break; + case FLASH_WRITE_BYTE: + gba->mem.cart_backup[gba->cart.flash_bank * 64 * 1024 + baddr] &= data; + gba->cart.backup_is_dirty = true; + break; + case FLASH_SET_BANK: + gba->cart.flash_bank = data & 1; + break; } } -static uint64_t gba_rev_bits(uint64_t data, int bits){ +static uint64_t gba_rev_bits(uint64_t data, int bits) { uint64_t out = 0; - for(int i=0;i>=1; + for(int i = 0; i < bits; ++i) { + out <<= 1; + out |= data & 1; + data >>= 1; } return out; } -static uint8_t gba_bin_to_bcd(uint8_t bin){ - bin%=100; - return (bin%10)|((bin/10)<<4); +static uint8_t gba_bin_to_bcd(uint8_t bin) { + bin %= 100; + return (bin % 10) | ((bin / 10) << 4); } /* Only simulates a small subset of the RTC needed to make time events work in the pokemon games. */ -static FORCE_INLINE void gba_process_rtc_state_machine(gba_t* gba){ +static FORCE_INLINE void gba_process_rtc_state_machine(gba_t *gba) { uint32_t data = gba->cart.gpio_data; - bool clk = SB_BFE(data,0,1); - bool io_dat = SB_BFE(data,1,1); - bool cs = SB_BFE(data,2,1); - #define SERIAL_INIT 0 - #define SERIAL_CLK_LOW 1 - #define SERIAL_CLK_HIGH 2 - - #define GBA_RTC_RESET 0 - #define GBA_RTC_UNUSED 1 - #define GBA_RTC_DATE_TIME 2 - #define GBA_RTC_FORCE_IRQ 3 - #define GBA_RTC_STATUS 4 - #define GBA_RTC_UNUSED2 5 - #define GBA_RTC_TIME 6 - #define GBA_RTC_UNUSED3 7 - - gba->rtc.status_register &= ~((1<<7)); + bool clk = SB_BFE(data, 0, 1); + bool io_dat = SB_BFE(data, 1, 1); + bool cs = SB_BFE(data, 2, 1); +#define SERIAL_INIT 0 +#define SERIAL_CLK_LOW 1 +#define SERIAL_CLK_HIGH 2 + +#define GBA_RTC_RESET 0 +#define GBA_RTC_UNUSED 1 +#define GBA_RTC_DATE_TIME 2 +#define GBA_RTC_FORCE_IRQ 3 +#define GBA_RTC_STATUS 4 +#define GBA_RTC_UNUSED2 5 +#define GBA_RTC_TIME 6 +#define GBA_RTC_UNUSED3 7 + + gba->rtc.status_register &= ~((1 << 7)); gba->rtc.status_register |= 0x40; - if(cs==0){ - gba->rtc.serial_state=SERIAL_INIT; - gba->rtc.serial_bits_clocked=0; + if(cs == 0) { + gba->rtc.serial_state = SERIAL_INIT; + gba->rtc.serial_bits_clocked = 0; gba->rtc.state = 0; gba->rtc.input_register = 0; gba->rtc.output_register = 0; - }else{ - time_t time_secs= gba->rtc.initial_rtc_time+(gba->rtc.total_clocks_ticked)/(16*1024*1024); - struct tm * tm = localtime(&time_secs); - uint8_t second = gba_bin_to_bcd(tm->tm_sec); - uint8_t minute = gba_bin_to_bcd(tm->tm_min); - uint8_t hour = gba_bin_to_bcd(tm->tm_hour); - uint8_t day = gba_bin_to_bcd(tm->tm_mday); - uint8_t month = gba_bin_to_bcd(tm->tm_mon+1); - uint8_t year = gba_bin_to_bcd(tm->tm_year%100); - uint8_t day_of_week=gba_bin_to_bcd(tm->tm_wday); - bool new_bit = false; - - if(gba->rtc.serial_state==SERIAL_CLK_LOW&&clk){ - gba->rtc.input_register<<=1; - gba->rtc.input_register|=((uint64_t)io_dat); + } else { + time_t time_secs = gba->rtc.initial_rtc_time + (gba->rtc.total_clocks_ticked) / (16 * 1024 * 1024); + struct tm *tm = localtime(&time_secs); + uint8_t second = gba_bin_to_bcd(tm->tm_sec); + uint8_t minute = gba_bin_to_bcd(tm->tm_min); + uint8_t hour = gba_bin_to_bcd(tm->tm_hour); + uint8_t day = gba_bin_to_bcd(tm->tm_mday); + uint8_t month = gba_bin_to_bcd(tm->tm_mon + 1); + uint8_t year = gba_bin_to_bcd(tm->tm_year % 100); + uint8_t day_of_week = gba_bin_to_bcd(tm->tm_wday); + bool new_bit = false; + + if(gba->rtc.serial_state == SERIAL_CLK_LOW && clk) { + gba->rtc.input_register <<= 1; + gba->rtc.input_register |= ((uint64_t)io_dat); new_bit = true; - - bool out_bit = (gba->rtc.output_register&1); - gba->mem.cart_rom[0x0000C4] |=(out_bit<<1); - gba->rtc.output_register>>=1; + + bool out_bit = (gba->rtc.output_register & 1); + gba->mem.cart_rom[0x0000C4] |= (out_bit << 1); + gba->rtc.output_register >>= 1; } - - gba->rtc.serial_state= clk? SERIAL_CLK_HIGH: SERIAL_CLK_LOW; - if(new_bit){ + gba->rtc.serial_state = clk ? SERIAL_CLK_HIGH : SERIAL_CLK_LOW; + + if(new_bit) { gba->rtc.serial_bits_clocked++; - if(gba->rtc.serial_bits_clocked==8) { + if(gba->rtc.serial_bits_clocked == 8) { // Check whether the command should be interpreted MSB-first or LSB-first. - gba->rtc.input_register&=0xff; + gba->rtc.input_register &= 0xff; if((gba->rtc.input_register >> 4) == 6) { gba->rtc.input_register = (gba->rtc.input_register << 4) | (gba->rtc.input_register >> 4); - gba->rtc.input_register&=0xff; + gba->rtc.input_register &= 0xff; gba->rtc.input_register = ((gba->rtc.input_register & 0x33) << 2) | ((gba->rtc.input_register & 0xCC) >> 2); - gba->rtc.input_register&=0xff; + gba->rtc.input_register &= 0xff; gba->rtc.input_register = ((gba->rtc.input_register & 0x55) << 1) | ((gba->rtc.input_register & 0xAA) >> 1); - gba->rtc.input_register&=0xff; - } - gba->rtc.state= SB_BFE(gba->rtc.input_register,0,8); - printf("RTC Command %d\n",gba->rtc.state); - } - int cmd = SB_BFE(gba->rtc.state,4,3); - bool read = SB_BFE(gba->rtc.state,7,1); - switch(cmd){ - case GBA_RTC_STATUS:{ - if(gba->rtc.serial_bits_clocked==8) gba->rtc.output_register = gba->rtc.status_register; - if(gba->rtc.serial_bits_clocked==16){ - if(!read){ - gba->rtc.status_register=SB_BFE(gba->rtc.input_register,0,8); - } - gba->rtc.serial_bits_clocked=0; - } - break; + gba->rtc.input_register &= 0xff; } - case GBA_RTC_DATE_TIME:{ - if(gba->rtc.serial_bits_clocked==8) gba->rtc.output_register = - (((uint64_t)(year&0xff) )<<(0*8ull))| - (((uint64_t)(month&0xff) )<<(1*8ull))| - (((uint64_t)(day&0xff) )<<(2*8ull))| - (((uint64_t)(day_of_week&0xff))<<(3*8ull))| - (((uint64_t)(hour&0xff) )<<(4*8ull))| - (((uint64_t)(minute&0xff) )<<(5*8ull))| - (((uint64_t)(second&0xff) )<<(6*8ull)); - if(gba->rtc.serial_bits_clocked==8*8){ - if(!read){ - year = SB_BFE(gba->rtc.input_register,6*8,8); - month = SB_BFE(gba->rtc.input_register,5*8,8); - day = SB_BFE(gba->rtc.input_register,4*8,8); - day_of_week = SB_BFE(gba->rtc.input_register,3*8,8); - hour = SB_BFE(gba->rtc.input_register,2*8,8); - minute = SB_BFE(gba->rtc.input_register,1*8,8); - second = SB_BFE(gba->rtc.input_register,0*8,8); - } - gba->rtc.serial_bits_clocked=0; + gba->rtc.state = SB_BFE(gba->rtc.input_register, 0, 8); + printf("RTC Command %d\n", gba->rtc.state); + } + int cmd = SB_BFE(gba->rtc.state, 4, 3); + bool read = SB_BFE(gba->rtc.state, 7, 1); + switch(cmd) { + case GBA_RTC_STATUS: { + if(gba->rtc.serial_bits_clocked == 8) gba->rtc.output_register = gba->rtc.status_register; + if(gba->rtc.serial_bits_clocked == 16) { + if(!read) { + gba->rtc.status_register = SB_BFE(gba->rtc.input_register, 0, 8); } - break; + gba->rtc.serial_bits_clocked = 0; } - case GBA_RTC_TIME:{ - if(gba->rtc.serial_bits_clocked==8) gba->rtc.output_register = - ((uint64_t)(hour&0xff)<<(0*8))| - ((uint64_t)(minute&0xff)<<(1*8))| - ((uint64_t)(second&0xff)<<(2*8)); - if(gba->rtc.serial_bits_clocked==4*8){ - if(!read){ - hour = SB_BFE(gba->rtc.input_register,0*8,8); - minute = SB_BFE(gba->rtc.input_register,1*8,8); - second = SB_BFE(gba->rtc.input_register,2*8,8); - } - gba->rtc.serial_bits_clocked=0; + break; + } + case GBA_RTC_DATE_TIME: { + if(gba->rtc.serial_bits_clocked == 8) gba->rtc.output_register = + (((uint64_t)(year & 0xff)) << (0 * 8ull)) | + (((uint64_t)(month & 0xff)) << (1 * 8ull)) | + (((uint64_t)(day & 0xff)) << (2 * 8ull)) | + (((uint64_t)(day_of_week & 0xff)) << (3 * 8ull)) | + (((uint64_t)(hour & 0xff)) << (4 * 8ull)) | + (((uint64_t)(minute & 0xff)) << (5 * 8ull)) | + (((uint64_t)(second & 0xff)) << (6 * 8ull)); + if(gba->rtc.serial_bits_clocked == 8 * 8) { + if(!read) { + year = SB_BFE(gba->rtc.input_register, 6 * 8, 8); + month = SB_BFE(gba->rtc.input_register, 5 * 8, 8); + day = SB_BFE(gba->rtc.input_register, 4 * 8, 8); + day_of_week = SB_BFE(gba->rtc.input_register, 3 * 8, 8); + hour = SB_BFE(gba->rtc.input_register, 2 * 8, 8); + minute = SB_BFE(gba->rtc.input_register, 1 * 8, 8); + second = SB_BFE(gba->rtc.input_register, 0 * 8, 8); } - break; + gba->rtc.serial_bits_clocked = 0; } - default: - case GBA_RTC_UNUSED: case GBA_RTC_UNUSED2: case GBA_RTC_UNUSED3: case GBA_RTC_FORCE_IRQ: - printf("Error: Unknown RTC Command %d\n",cmd); - case GBA_RTC_RESET: - if(gba->rtc.serial_bits_clocked==8){ - gba->rtc.serial_bits_clocked=0; + break; + } + case GBA_RTC_TIME: { + if(gba->rtc.serial_bits_clocked == 8) gba->rtc.output_register = + ((uint64_t)(hour & 0xff) << (0 * 8)) | + ((uint64_t)(minute & 0xff) << (1 * 8)) | + ((uint64_t)(second & 0xff) << (2 * 8)); + if(gba->rtc.serial_bits_clocked == 4 * 8) { + if(!read) { + hour = SB_BFE(gba->rtc.input_register, 0 * 8, 8); + minute = SB_BFE(gba->rtc.input_register, 1 * 8, 8); + second = SB_BFE(gba->rtc.input_register, 2 * 8, 8); } + gba->rtc.serial_bits_clocked = 0; + } + break; + } + default: + case GBA_RTC_UNUSED: + case GBA_RTC_UNUSED2: + case GBA_RTC_UNUSED3: + case GBA_RTC_FORCE_IRQ: + printf("Error: Unknown RTC Command %d\n", cmd); + case GBA_RTC_RESET: + if(gba->rtc.serial_bits_clocked == 8) { + gba->rtc.serial_bits_clocked = 0; + } break; } - - } } } -static FORCE_INLINE void gba_process_backup_write(gba_t*gba, unsigned baddr, uint32_t data){ - if(gba->cart.backup_type==GBA_BACKUP_FLASH_64K||gba->cart.backup_type==GBA_BACKUP_FLASH_128K){ - gba_process_flash_state_machine(gba,baddr,data); - }else if(gba->cart.backup_type==GBA_BACKUP_SRAM){ - if(gba->mem.cart_backup[baddr&0x7fff]!=(data&0xff)){ - gba->mem.cart_backup[baddr&0x7fff]=data&0xff; - gba->cart.backup_is_dirty=true; +static FORCE_INLINE void gba_process_backup_write(gba_t *gba, unsigned baddr, uint32_t data) { + if(gba->cart.backup_type == GBA_BACKUP_FLASH_64K || gba->cart.backup_type == GBA_BACKUP_FLASH_128K) { + gba_process_flash_state_machine(gba, baddr, data); + } else if(gba->cart.backup_type == GBA_BACKUP_SRAM) { + if(gba->mem.cart_backup[baddr & 0x7fff] != (data & 0xff)) { + gba->mem.cart_backup[baddr & 0x7fff] = data & 0xff; + gba->cart.backup_is_dirty = true; } } } -static void gba_process_solar_sensor(gba_t*gba){ - uint16_t data_and_dir = gba->cart.gpio_data&(gba->cart.gpio_data>>16); - bool clk = SB_BFE(data_and_dir,0,1); - bool rst = SB_BFE(data_and_dir,1,1); - bool cs = SB_BFE(data_and_dir,2,1); - if(!cs){ - if(rst){gba->solar_sensor.dac=0;} - else if(!clk&&gba->solar_sensor.last_clk){ +static void gba_process_solar_sensor(gba_t *gba) { + uint16_t data_and_dir = gba->cart.gpio_data & (gba->cart.gpio_data >> 16); + bool clk = SB_BFE(data_and_dir, 0, 1); + bool rst = SB_BFE(data_and_dir, 1, 1); + bool cs = SB_BFE(data_and_dir, 2, 1); + if(!cs) { + if(rst) { + gba->solar_sensor.dac = 0; + } else if(!clk && gba->solar_sensor.last_clk) { gba->solar_sensor.dac++; } - bool flag = gba->solar_sensor.dac> gba->solar_sensor.value; - gba->solar_sensor.last_clk=clk; - //printf("DAC Value: %d clk: %d rst: %d dir:%d flag:%d\n",gba->solar_sensor.dac,clk,rst,SB_BFE(gba->cart.gpio_data,16,16),flag); - if(SB_BFE(gba->cart.gpio_data,16+3,1)==0){ - gba->mem.cart_rom[0x0000C4] &=~(1<<3); - gba->mem.cart_rom[0x0000C4] |=(flag<<3); + bool flag = gba->solar_sensor.dac > gba->solar_sensor.value; + gba->solar_sensor.last_clk = clk; + // printf("DAC Value: %d clk: %d rst: %d dir:%d flag:%d\n",gba->solar_sensor.dac,clk,rst,SB_BFE(gba->cart.gpio_data,16,16),flag); + if(SB_BFE(gba->cart.gpio_data, 16 + 3, 1) == 0) { + gba->mem.cart_rom[0x0000C4] &= ~(1 << 3); + gba->mem.cart_rom[0x0000C4] |= (flag << 3); } - }else{ - gba->solar_sensor.dac=0; + } else { + gba->solar_sensor.dac = 0; } } -static FORCE_INLINE void gba_store32(gba_t*gba, unsigned baddr, uint32_t data){ - if(baddr>=0x08000000){ - //Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e - if((baddr&0xfe000000)==0xE000000){gba_process_backup_write(gba,baddr,data>>((baddr&3)*8));return;} - if(baddr>=0x080000C4&& baddr<0x080000C8){ - if(baddr==0x080000c4){ +static FORCE_INLINE void gba_store32(gba_t *gba, unsigned baddr, uint32_t data) { + if(baddr >= 0x08000000) { + // Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e + if((baddr & 0xfe000000) == 0xE000000) { + gba_process_backup_write(gba, baddr, data >> ((baddr & 3) * 8)); + return; + } + if(baddr >= 0x080000C4 && baddr < 0x080000C8) { + if(baddr == 0x080000c4) { gba->cart.gpio_data = data; - } - gba->mem.cart_rom[0x0000C4] =gba->cart.gpio_data&~SB_BFE(gba->cart.gpio_data,16,16); + } + gba->mem.cart_rom[0x0000C4] = gba->cart.gpio_data & ~SB_BFE(gba->cart.gpio_data, 16, 16); gba_process_solar_sensor(gba); gba_process_rtc_state_machine(gba); return; } } - uint32_t *val=gba_dword_lookup(gba,baddr,GBA_REQ_WRITE|GBA_REQ_4B); - *val= data; + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_WRITE | GBA_REQ_4B); + *val = data; } -static FORCE_INLINE void gba_store16(gba_t*gba, unsigned baddr, uint32_t data){ - if(baddr>=0x08000000){ - //Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e - if((baddr&0xfe000000)==0xE000000){ - gba_process_backup_write(gba,baddr,data>> ((baddr&1)*8)); +static FORCE_INLINE void gba_store16(gba_t *gba, unsigned baddr, uint32_t data) { + if(baddr >= 0x08000000) { + // Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e + if((baddr & 0xfe000000) == 0xE000000) { + gba_process_backup_write(gba, baddr, data >> ((baddr & 1) * 8)); return; } - if(baddr>=0x080000C4&& baddr<0x080000C8){ - int addr = baddr&~1; - if(addr==0x080000c4)gba->cart.gpio_data =(gba->cart.gpio_data&0xffff0000)|(data&0xffff); - if(addr==0x080000c6)gba->cart.gpio_data =(gba->cart.gpio_data&0x0000ffff)|((data&0xffff)<<16); - gba->mem.cart_rom[0x0000C4] =gba->cart.gpio_data&~SB_BFE(gba->cart.gpio_data,16,16); + if(baddr >= 0x080000C4 && baddr < 0x080000C8) { + int addr = baddr & ~1; + if(addr == 0x080000c4) gba->cart.gpio_data = (gba->cart.gpio_data & 0xffff0000) | (data & 0xffff); + if(addr == 0x080000c6) gba->cart.gpio_data = (gba->cart.gpio_data & 0x0000ffff) | ((data & 0xffff) << 16); + gba->mem.cart_rom[0x0000C4] = gba->cart.gpio_data & ~SB_BFE(gba->cart.gpio_data, 16, 16); gba_process_solar_sensor(gba); gba_process_rtc_state_machine(gba); return; } } - uint32_t* val = gba_dword_lookup(gba,baddr,GBA_REQ_WRITE|GBA_REQ_2B); - int offset = SB_BFE(baddr,1,1); - ((uint16_t*)val)[offset]=data; + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_WRITE | GBA_REQ_2B); + int offset = SB_BFE(baddr, 1, 1); + ((uint16_t *)val)[offset] = data; } -static FORCE_INLINE void gba_store8(gba_t*gba, unsigned baddr, uint32_t data){ - if(baddr>=0x05000000){ +static FORCE_INLINE void gba_store8(gba_t *gba, unsigned baddr, uint32_t data) { + if(baddr >= 0x05000000) { // 8 bit stores to palette mirror across 8 bit halves - if((baddr&0xff000000)==0x5000000){gba_store16(gba,baddr&~1,(data&0xff)*0x0101); return; } - if(((baddr&0xff000000)==0x06000000)&&((baddr&0x1ffff)<=0x0013FFF)){gba_store16(gba,baddr&~1,(data&0xff)*0x0101);return;} - //Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e - if((baddr&0xfe000000)==0xE000000){ gba_process_backup_write(gba,baddr,data); return; } + if((baddr & 0xff000000) == 0x5000000) { + gba_store16(gba, baddr & ~1, (data & 0xff) * 0x0101); + return; + } + if(((baddr & 0xff000000) == 0x06000000) && ((baddr & 0x1ffff) <= 0x0013FFF)) { + gba_store16(gba, baddr & ~1, (data & 0xff) * 0x0101); + return; + } + // Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e + if((baddr & 0xfe000000) == 0xE000000) { + gba_process_backup_write(gba, baddr, data); + return; + } // Remaining 8 bit ops are not supported on VRAM or ROM - return; - } - uint32_t *val = gba_dword_lookup(gba,baddr,GBA_REQ_WRITE|GBA_REQ_1B); - int offset = SB_BFE(baddr,0,2); - ((uint8_t*)val)[offset]=data; -} -static FORCE_INLINE void gba_store8_debug(gba_t*gba, unsigned baddr, uint32_t data){ - if(baddr>=0x05000000){ + return; + } + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_WRITE | GBA_REQ_1B); + int offset = SB_BFE(baddr, 0, 2); + ((uint8_t *)val)[offset] = data; +} +static FORCE_INLINE void gba_store8_debug(gba_t *gba, unsigned baddr, uint32_t data) { + if(baddr >= 0x05000000) { // 8 bit stores to palette mirror across 8 bit halves - if((baddr&0xff000000)==0x5000000){gba_store16(gba,baddr&~1,(data&0xff)*0x0101); return; } - if(((baddr&0xff000000)==0x06000000)&&((baddr&0x1ffff)<=0x0013FFF)){gba_store16(gba,baddr&~1,(data&0xff)*0x0101);return;} - //Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e - if((baddr&0xfe000000)==0xE000000){ gba_process_backup_write(gba,baddr,data); return; } + if((baddr & 0xff000000) == 0x5000000) { + gba_store16(gba, baddr & ~1, (data & 0xff) * 0x0101); + return; + } + if(((baddr & 0xff000000) == 0x06000000) && ((baddr & 0x1ffff) <= 0x0013FFF)) { + gba_store16(gba, baddr & ~1, (data & 0xff) * 0x0101); + return; + } + // Mask is 0xfe to catch the sram mirror at 0x0f and 0x0e + if((baddr & 0xfe000000) == 0xE000000) { + gba_process_backup_write(gba, baddr, data); + return; + } // Remaining 8 bit ops are not supported on VRAM or ROM - return; - } - uint32_t *val = gba_dword_lookup(gba,baddr,GBA_REQ_WRITE|GBA_REQ_1B|GBA_REQ_DEBUG); - int offset = SB_BFE(baddr,0,2); - ((uint8_t*)val)[offset]=data; -} -static FORCE_INLINE void gba_io_store8(gba_t*gba, unsigned baddr, uint8_t data){gba->mem.io[baddr&0xfff]=data;} -static FORCE_INLINE void gba_io_store16(gba_t*gba, unsigned baddr, uint16_t data){*(uint16_t*)(gba->mem.io+(baddr&0xfff))=data;} -static FORCE_INLINE void gba_io_store32(gba_t*gba, unsigned baddr, uint32_t data){*(uint32_t*)(gba->mem.io+(baddr&0xfff))=data;} - -static FORCE_INLINE uint8_t gba_io_read8(gba_t*gba, unsigned baddr) {return gba->mem.io[baddr&0xfff];} -static FORCE_INLINE uint16_t gba_io_read16(gba_t*gba, unsigned baddr){return *(uint16_t*)(gba->mem.io+(baddr&0xfff));} -static FORCE_INLINE uint32_t gba_io_read32(gba_t*gba, unsigned baddr){return *(uint32_t*)(gba->mem.io+(baddr&0xfff));} -static FORCE_INLINE void gba_recompute_waitstate_table(gba_t* gba,uint16_t waitcnt){ - // TODO: Make the waitstate for the ROM configureable - const int wait_state_table[16*4]={ - 1,1,1,1, //0x00 (bios) - 1,1,1,1, //0x01 (bios) - 3,3,6,6, //0x02 (256k WRAM) - 1,1,1,1, //0x03 (32k WRAM) - 1,1,1,1, //0x04 (IO) - 1,1,2,2, //0x05 (BG/OBJ Palette) - 1,1,2,2, //0x06 (VRAM) - 1,1,1,1, //0x07 (OAM) - 4,4,8,8, //0x08 (GAMEPAK ROM 0) - 4,4,8,8, //0x09 (GAMEPAK ROM 0) - 4,4,8,8, //0x0A (GAMEPAK ROM 1) - 4,4,8,8, //0x0B (GAMEPAK ROM 1) - 4,4,8,8, //0x0C (GAMEPAK ROM 2) - 4,4,8,8, //0x0D (GAMEPAK ROM 2) - 4,4,4,4, //0x0E (GAMEPAK SRAM) - 1,1,1,1, //0x0F (unused) + return; + } + uint32_t *val = gba_dword_lookup(gba, baddr, GBA_REQ_WRITE | GBA_REQ_1B | GBA_REQ_DEBUG); + int offset = SB_BFE(baddr, 0, 2); + ((uint8_t *)val)[offset] = data; +} +static FORCE_INLINE void gba_io_store8(gba_t *gba, unsigned baddr, uint8_t data) { gba->mem.io[baddr & 0xfff] = data; } +static FORCE_INLINE void gba_io_store16(gba_t *gba, unsigned baddr, uint16_t data) { *(uint16_t *)(gba->mem.io + (baddr & 0xfff)) = data; } +static FORCE_INLINE void gba_io_store32(gba_t *gba, unsigned baddr, uint32_t data) { *(uint32_t *)(gba->mem.io + (baddr & 0xfff)) = data; } + +static FORCE_INLINE uint8_t gba_io_read8(gba_t *gba, unsigned baddr) { return gba->mem.io[baddr & 0xfff]; } +static FORCE_INLINE uint16_t gba_io_read16(gba_t *gba, unsigned baddr) { return *(uint16_t *)(gba->mem.io + (baddr & 0xfff)); } +static FORCE_INLINE uint32_t gba_io_read32(gba_t *gba, unsigned baddr) { return *(uint32_t *)(gba->mem.io + (baddr & 0xfff)); } +static FORCE_INLINE void gba_recompute_waitstate_table(gba_t *gba, uint16_t waitcnt) { + // TODO: Make the waitstate for the ROM configureable + const int wait_state_table[16 * 4] = { + 1, 1, 1, 1, // 0x00 (bios) + 1, 1, 1, 1, // 0x01 (bios) + 3, 3, 6, 6, // 0x02 (256k WRAM) + 1, 1, 1, 1, // 0x03 (32k WRAM) + 1, 1, 1, 1, // 0x04 (IO) + 1, 1, 2, 2, // 0x05 (BG/OBJ Palette) + 1, 1, 2, 2, // 0x06 (VRAM) + 1, 1, 1, 1, // 0x07 (OAM) + 4, 4, 8, 8, // 0x08 (GAMEPAK ROM 0) + 4, 4, 8, 8, // 0x09 (GAMEPAK ROM 0) + 4, 4, 8, 8, // 0x0A (GAMEPAK ROM 1) + 4, 4, 8, 8, // 0x0B (GAMEPAK ROM 1) + 4, 4, 8, 8, // 0x0C (GAMEPAK ROM 2) + 4, 4, 8, 8, // 0x0D (GAMEPAK ROM 2) + 4, 4, 4, 4, // 0x0E (GAMEPAK SRAM) + 1, 1, 1, 1, // 0x0F (unused) }; - for(int i=0;i<16*4;++i){ - gba->mem.wait_state_table[i]=wait_state_table[i]; + for(int i = 0; i < 16 * 4; ++i) { + gba->mem.wait_state_table[i] = wait_state_table[i]; } - uint8_t sram_wait = SB_BFE(waitcnt,0,2); + uint8_t sram_wait = SB_BFE(waitcnt, 0, 2); uint8_t wait_first[3]; uint8_t wait_second[3]; - wait_first[0] = SB_BFE(waitcnt,2,2); - wait_second[0] = SB_BFE(waitcnt,4,1); - wait_first[1] = SB_BFE(waitcnt,5,2); - wait_second[1] = SB_BFE(waitcnt,7,1); - wait_first[2] = SB_BFE(waitcnt,8,2); - wait_second[2] = SB_BFE(waitcnt,10,1); - uint8_t prefetch_en = SB_BFE(waitcnt,14,1); + wait_first[0] = SB_BFE(waitcnt, 2, 2); + wait_second[0] = SB_BFE(waitcnt, 4, 1); + wait_first[1] = SB_BFE(waitcnt, 5, 2); + wait_second[1] = SB_BFE(waitcnt, 7, 1); + wait_first[2] = SB_BFE(waitcnt, 8, 2); + wait_second[2] = SB_BFE(waitcnt, 10, 1); + uint8_t prefetch_en = SB_BFE(waitcnt, 14, 1); - int primary_table[4]={4,3,2,8}; + int primary_table[4] = {4, 3, 2, 8}; - //Each waitstate is two entries in table - for(int ws=0;ws<3;++ws){ - for(int i=0;i<2;++i){ + // Each waitstate is two entries in table + for(int ws = 0; ws < 3; ++ws) { + for(int i = 0; i < 2; ++i) { uint8_t w_first = primary_table[wait_first[ws]]; - uint8_t w_second = wait_second[ws]?1:2; - if(ws==1)w_second = wait_second[ws]?1:4; - if(ws==2)w_second = wait_second[ws]?1:8; - w_first+=1;w_second+=1; - //Wait 0 - int wait16b = w_second; - int wait32b = w_second*2; + uint8_t w_second = wait_second[ws] ? 1 : 2; + if(ws == 1) w_second = wait_second[ws] ? 1 : 4; + if(ws == 2) w_second = wait_second[ws] ? 1 : 8; + w_first += 1; + w_second += 1; + // Wait 0 + int wait16b = w_second; + int wait32b = w_second * 2; - int wait16b_nonseq = w_first; - int wait32b_nonseq = w_first+w_second; + int wait16b_nonseq = w_first; + int wait32b_nonseq = w_first + w_second; - gba->mem.wait_state_table[(0x08+i+ws*2)*4+0] = wait16b; - gba->mem.wait_state_table[(0x08+i+ws*2)*4+1] = wait16b_nonseq; - gba->mem.wait_state_table[(0x08+i+ws*2)*4+2] = wait32b; - gba->mem.wait_state_table[(0x08+i+ws*2)*4+3] = wait32b_nonseq; + gba->mem.wait_state_table[(0x08 + i + ws * 2) * 4 + 0] = wait16b; + gba->mem.wait_state_table[(0x08 + i + ws * 2) * 4 + 1] = wait16b_nonseq; + gba->mem.wait_state_table[(0x08 + i + ws * 2) * 4 + 2] = wait32b; + gba->mem.wait_state_table[(0x08 + i + ws * 2) * 4 + 3] = wait32b_nonseq; } } gba->mem.prefetch_en = prefetch_en; gba->mem.prefetch_size = 0; - //SRAM - gba->mem.wait_state_table[(0x0E*4)+0]= 1+primary_table[sram_wait]; - gba->mem.wait_state_table[(0x0E*4)+1]= 1+primary_table[sram_wait]; - gba->mem.wait_state_table[(0x0E*4)+2]= 1+primary_table[sram_wait]; - gba->mem.wait_state_table[(0x0E*4)+3]= 1+primary_table[sram_wait]; - waitcnt&=(1<<15); // Force cartridge to report as GBA cart - gba_io_store16(gba,GBA_WAITCNT,waitcnt); -} -static FORCE_INLINE void gba_compute_access_cycles(gba_t *gba, uint32_t address,int request_size/*0: 1B,1: 2B,3: 4B*/){ - int bank = SB_BFE(address,24,4); - bool prefetch_en= gba->mem.prefetch_en; - if(SB_UNLIKELY(!prefetch_en)){ - if(gba->cpu.i_cycles)request_size|=1; - if(request_size&1)gba->cpu.next_fetch_sequential =false; + // SRAM + gba->mem.wait_state_table[(0x0E * 4) + 0] = 1 + primary_table[sram_wait]; + gba->mem.wait_state_table[(0x0E * 4) + 1] = 1 + primary_table[sram_wait]; + gba->mem.wait_state_table[(0x0E * 4) + 2] = 1 + primary_table[sram_wait]; + gba->mem.wait_state_table[(0x0E * 4) + 3] = 1 + primary_table[sram_wait]; + waitcnt &= (1 << 15); // Force cartridge to report as GBA cart + gba_io_store16(gba, GBA_WAITCNT, waitcnt); +} +static FORCE_INLINE void gba_compute_access_cycles(gba_t *gba, uint32_t address, int request_size /*0: 1B,1: 2B,3: 4B*/) { + int bank = SB_BFE(address, 24, 4); + bool prefetch_en = gba->mem.prefetch_en; + if(SB_UNLIKELY(!prefetch_en)) { + if(gba->cpu.i_cycles) request_size |= 1; + if(request_size & 1) gba->cpu.next_fetch_sequential = false; gba->mem.prefetch_size = 0; } - uint32_t wait = gba->mem.wait_state_table[bank*4+request_size]; - if(SB_LIKELY(prefetch_en)){ - gba->mem.prefetch_size+=gba->cpu.i_cycles; - if(bank>=0x08&&bank<=0x0D){ - if(SB_UNLIKELY(request_size&1)){ - uint32_t pc = gba->cpu.prefetch_pc; - if(pc>=0x08000000){ - // Check if the bubble made it to the execute stage before being squashed, - // and apply the bubble cycle if it was not squashed. - // Note, only a single pipeline bubble is tracked using this infrastructure. - int pc_bank = SB_BFE(pc,24,4); - int prefetch_cycles = gba->mem.wait_state_table[pc_bank*4]; - int prefetch_phase = (gba->mem.prefetch_size)%prefetch_cycles; - if(gba->mem.prefetch_size>gba->cpu.i_cycles&&prefetch_phase==prefetch_cycles-1)wait+=1; - } - //Non sequential->reset prefetch buffer + uint32_t wait = gba->mem.wait_state_table[bank * 4 + request_size]; + if(SB_LIKELY(prefetch_en)) { + gba->mem.prefetch_size += gba->cpu.i_cycles; + if(bank >= 0x08 && bank <= 0x0D) { + if(SB_UNLIKELY(request_size & 1)) { + uint32_t pc = gba->cpu.prefetch_pc; + if(pc >= 0x08000000) { + // Check if the bubble made it to the execute stage before being squashed, + // and apply the bubble cycle if it was not squashed. + // Note, only a single pipeline bubble is tracked using this infrastructure. + int pc_bank = SB_BFE(pc, 24, 4); + int prefetch_cycles = gba->mem.wait_state_table[pc_bank * 4]; + int prefetch_phase = (gba->mem.prefetch_size) % prefetch_cycles; + if(gba->mem.prefetch_size > gba->cpu.i_cycles && prefetch_phase == prefetch_cycles - 1) wait += 1; + } + // Non sequential->reset prefetch buffer gba->mem.prefetch_size = 0; - gba->cpu.next_fetch_sequential =false; - }else{ - //Sequential fetch from prefetch buffer based on available wait states - if(gba->mem.prefetch_size>=wait){ - gba->mem.prefetch_size-=wait-1; - wait = 1; - }else{ + gba->cpu.next_fetch_sequential = false; + } else { + // Sequential fetch from prefetch buffer based on available wait states + if(gba->mem.prefetch_size >= wait) { + gba->mem.prefetch_size -= wait - 1; + wait = 1; + } else { wait -= gba->mem.prefetch_size; - gba->mem.prefetch_size=0; + gba->mem.prefetch_size = 0; } } - }else gba->mem.prefetch_size+=wait; + } else + gba->mem.prefetch_size += wait; } - gba->mem.requests+=wait; + gba->mem.requests += wait; } -static FORCE_INLINE uint32_t gba_compute_access_cycles_dma(gba_t *gba, uint32_t address,int request_size/*0: 1B,1: 2B,3: 4B*/){ - int bank = SB_BFE(address,24,4); - uint32_t wait = gba->mem.wait_state_table[bank*4+request_size]; +static FORCE_INLINE uint32_t gba_compute_access_cycles_dma(gba_t *gba, uint32_t address, int request_size /*0: 1B,1: 2B,3: 4B*/) { + int bank = SB_BFE(address, 24, 4); + uint32_t wait = gba->mem.wait_state_table[bank * 4 + request_size]; return wait; } static FORCE_INLINE void gba_process_mmio_read(gba_t *gba, uint32_t address); -// Memory IO functions for the emulated CPU -static FORCE_INLINE uint32_t arm7_read32(void* user_data, uint32_t address){ - gba_compute_access_cycles((gba_t*)user_data,address,3); - uint32_t value = gba_read32((gba_t*)user_data,address); +// Memory IO functions for the emulated CPU +static FORCE_INLINE uint32_t arm7_read32(void *user_data, uint32_t address) { + gba_compute_access_cycles((gba_t *)user_data, address, 3); + uint32_t value = gba_read32((gba_t *)user_data, address); return value; } -static FORCE_INLINE uint32_t arm7_read16(void* user_data, uint32_t address){ - gba_compute_access_cycles((gba_t*)user_data,address,1); - uint16_t value = gba_read16((gba_t*)user_data,address); +static FORCE_INLINE uint32_t arm7_read16(void *user_data, uint32_t address) { + gba_compute_access_cycles((gba_t *)user_data, address, 1); + uint16_t value = gba_read16((gba_t *)user_data, address); return value; } -static FORCE_INLINE uint32_t arm7_read32_seq(void* user_data, uint32_t address, bool seq){ - gba_compute_access_cycles((gba_t*)user_data,address,seq?2:3); - return gba_read32((gba_t*)user_data,address); +static FORCE_INLINE uint32_t arm7_read32_seq(void *user_data, uint32_t address, bool seq) { + gba_compute_access_cycles((gba_t *)user_data, address, seq ? 2 : 3); + return gba_read32((gba_t *)user_data, address); } -static FORCE_INLINE uint32_t arm7_read16_seq(void* user_data, uint32_t address, bool seq){ - gba_compute_access_cycles((gba_t*)user_data,address,seq?0:1); - return gba_read16((gba_t*)user_data,address); +static FORCE_INLINE uint32_t arm7_read16_seq(void *user_data, uint32_t address, bool seq) { + gba_compute_access_cycles((gba_t *)user_data, address, seq ? 0 : 1); + return gba_read16((gba_t *)user_data, address); } -//Used to process special behavior triggered by MMIO write +// Used to process special behavior triggered by MMIO write static bool gba_process_mmio_write(gba_t *gba, uint32_t address, uint32_t data, int req_size_bytes); -static FORCE_INLINE uint8_t arm7_read8(void* user_data, uint32_t address){ - gba_compute_access_cycles((gba_t*)user_data,address,1); - return gba_read8((gba_t*)user_data,address); +static FORCE_INLINE uint8_t arm7_read8(void *user_data, uint32_t address) { + gba_compute_access_cycles((gba_t *)user_data, address, 1); + return gba_read8((gba_t *)user_data, address); } -static FORCE_INLINE void gba_dma_write32(gba_t* gba, uint32_t address, uint32_t data){ - if((address&0xfffffC00)==0x04000000){ - if(gba_process_mmio_write(gba,address,data,4))return; +static FORCE_INLINE void gba_dma_write32(gba_t *gba, uint32_t address, uint32_t data) { + if((address & 0xfffffC00) == 0x04000000) { + if(gba_process_mmio_write(gba, address, data, 4)) return; } - gba_store32(gba,address,data); + gba_store32(gba, address, data); } -static FORCE_INLINE void gba_dma_write16(gba_t* gba, uint32_t address, uint16_t data){ - if((address&0xfffffC00)==0x04000000){ - if(gba_process_mmio_write(gba,address,data,2))return; +static FORCE_INLINE void gba_dma_write16(gba_t *gba, uint32_t address, uint16_t data) { + if((address & 0xfffffC00) == 0x04000000) { + if(gba_process_mmio_write(gba, address, data, 2)) return; } - gba_store16(gba,address,data); + gba_store16(gba, address, data); } -static FORCE_INLINE void arm7_write32(void* user_data, uint32_t address, uint32_t data){ - gba_compute_access_cycles((gba_t*)user_data,address,3); - gba_dma_write32((gba_t*)user_data,address,data); +static FORCE_INLINE void arm7_write32(void *user_data, uint32_t address, uint32_t data) { + gba_compute_access_cycles((gba_t *)user_data, address, 3); + gba_dma_write32((gba_t *)user_data, address, data); } -static FORCE_INLINE void arm7_write16(void* user_data, uint32_t address, uint16_t data){ - gba_compute_access_cycles((gba_t*)user_data,address,1); - gba_dma_write16((gba_t*)user_data,address,data); +static FORCE_INLINE void arm7_write16(void *user_data, uint32_t address, uint16_t data) { + gba_compute_access_cycles((gba_t *)user_data, address, 1); + gba_dma_write16((gba_t *)user_data, address, data); } -static FORCE_INLINE void arm7_write8(void* user_data, uint32_t address, uint8_t data) { - gba_compute_access_cycles((gba_t*)user_data,address,1); - if((address&0xfffff000)==0x04000000){ - if(gba_process_mmio_write((gba_t*)user_data,address,data,1))return; +static FORCE_INLINE void arm7_write8(void *user_data, uint32_t address, uint8_t data) { + gba_compute_access_cycles((gba_t *)user_data, address, 1); + if((address & 0xfffff000) == 0x04000000) { + if(gba_process_mmio_write((gba_t *)user_data, address, data, 1)) return; } - gba_store8((gba_t*)user_data,address,data); + gba_store8((gba_t *)user_data, address, data); } // Try to load a GBA rom, return false on invalid rom -bool gba_load_rom(sb_emu_state_t*emu,gba_t* gba, gba_scratch_t *scratch); - -static FORCE_INLINE uint32_t * gba_dword_lookup(gba_t* gba,unsigned addr, int req_type){ +bool gba_load_rom(sb_emu_state_t *emu, gba_t *gba, gba_scratch_t *scratch); + +static FORCE_INLINE uint32_t *gba_dword_lookup(gba_t *gba, unsigned addr, int req_type) { uint32_t *ret = &gba->mem.openbus_word; - switch(addr>>24){ - case 0x0: if(addr<0x4000){ - if(gba->cpu.registers[15]<0x4000)gba->mem.bios_word = *(uint32_t*)(gba->mem.bios+(addr&~3)); - //else gba->mem.bios_word=0; - gba->mem.openbus_word=gba->mem.bios_word; - } break; - case 0x1: break; - case 0x2: - ret = (uint32_t*)(gba->mem.wram0+(addr&0x3fffc)); - gba->mem.openbus_word=*ret; - break; - case 0x3: - ret = (uint32_t*)(gba->mem.wram1+(addr&0x7ffc)); - gba->mem.openbus_word=*ret; - break; - case 0x4: - if(SB_LIKELY(addr<=0x40003FF)){ - if(req_type&GBA_REQ_READ){ - int io_reg = (addr>>2)&0xff; - if(SB_LIKELY(gba->mem.mmio_reg_valid_lookup[io_reg])){ - gba_process_mmio_read(gba,addr); - gba->mem.mmio_word = (*(uint32_t*)(gba->mem.io+(addr&0x3fc)))&gba->mem.mmio_data_mask_lookup[io_reg]; - ret = &gba->mem.mmio_word; - } - }else ret = (uint32_t*)(gba->mem.io+(addr&0x3fc)); - if(!(req_type&GBA_REQ_DEBUG)){ - gba->mem.mmio_debug_access_buffer[(addr&0xffff)/4]|=(req_type&GBA_REQ_WRITE)?0x70:0xf; - if(gba->mem.mmio_debug_access_buffer[(addr&0xffff)/4]&0x80)gba->cpu.trigger_breakpoint =true; - } + switch(addr >> 24) { + case 0x0: + if(addr < 0x4000) { + if(gba->cpu.registers[15] < 0x4000) gba->mem.bios_word = *(uint32_t *)(gba->mem.bios + (addr & ~3)); + // else gba->mem.bios_word=0; + gba->mem.openbus_word = gba->mem.bios_word; + } + break; + case 0x1: break; + case 0x2: + ret = (uint32_t *)(gba->mem.wram0 + (addr & 0x3fffc)); + gba->mem.openbus_word = *ret; + break; + case 0x3: + ret = (uint32_t *)(gba->mem.wram1 + (addr & 0x7ffc)); + gba->mem.openbus_word = *ret; + break; + case 0x4: + if(SB_LIKELY(addr <= 0x40003FF)) { + if(req_type & GBA_REQ_READ) { + int io_reg = (addr >> 2) & 0xff; + if(SB_LIKELY(gba->mem.mmio_reg_valid_lookup[io_reg])) { + gba_process_mmio_read(gba, addr); + gba->mem.mmio_word = (*(uint32_t *)(gba->mem.io + (addr & 0x3fc))) & gba->mem.mmio_data_mask_lookup[io_reg]; + ret = &gba->mem.mmio_word; + } + } else + ret = (uint32_t *)(gba->mem.io + (addr & 0x3fc)); + if(!(req_type & GBA_REQ_DEBUG)) { + gba->mem.mmio_debug_access_buffer[(addr & 0xffff) / 4] |= (req_type & GBA_REQ_WRITE) ? 0x70 : 0xf; + if(gba->mem.mmio_debug_access_buffer[(addr & 0xffff) / 4] & 0x80) gba->cpu.trigger_breakpoint = true; } - break; - case 0x5: - ret = (uint32_t*)(gba->mem.palette+(addr&0x3fc)); - gba->mem.openbus_word=*ret; - break; - case 0x6: - if(addr&0x10000){ - ret = (uint32_t*)(gba->mem.vram+(addr&0x07ffc)+0x10000); - gba->mem.openbus_word= *ret; - if(addr&0x08000){ - uint16_t dispcnt = gba_io_read16(gba, GBA_DISPCNT); - int bg_mode = SB_BFE(dispcnt,0,3); - //Don't allow writes to mirrored VRAM in bitmap mode. See also vram-mirror.gba - //Needed for Acrobat Kid. Still requires testing to verify correct behavior - if(bg_mode>2&&!(addr&0x04000)){ret = &gba->mem.openbus_word;*ret=0;} - } - }else ret = (uint32_t*)(gba->mem.vram+(addr&0x1fffc)); - gba->mem.openbus_word=*ret; - break; - case 0x7: - ret = (uint32_t*)(gba->mem.oam+(addr&0x3fc)); - gba->mem.openbus_word=*ret; - break; - case 0x8: - case 0x9: - case 0xA: - case 0xB: - case 0xC: - case 0xD:{ - int maddr = addr&0x1fffffc; - if(SB_UNLIKELY(maddr>=gba->cart.rom_size)){ - gba->mem.openbus_word = ((maddr/2)&0xffff)|(((maddr/2+1)&0xffff)<<16); - // Return ready when done writting EEPROM (required by Minish Cap) - if(gba->cart.backup_type==GBA_BACKUP_EEPROM) gba->mem.openbus_word = 1; - }else{ - gba->mem.openbus_word = *(uint32_t*)(gba->mem.cart_rom+maddr); - if(req_type&0x3){ - uint16_t res16 = gba->mem.openbus_word >> (addr&2)*8; - gba->mem.openbus_word = res16*0x10001u; - } + } + break; + case 0x5: + ret = (uint32_t *)(gba->mem.palette + (addr & 0x3fc)); + gba->mem.openbus_word = *ret; + break; + case 0x6: + if(addr & 0x10000) { + ret = (uint32_t *)(gba->mem.vram + (addr & 0x07ffc) + 0x10000); + gba->mem.openbus_word = *ret; + if(addr & 0x08000) { + uint16_t dispcnt = gba_io_read16(gba, GBA_DISPCNT); + int bg_mode = SB_BFE(dispcnt, 0, 3); + // Don't allow writes to mirrored VRAM in bitmap mode. See also vram-mirror.gba + // Needed for Acrobat Kid. Still requires testing to verify correct behavior + if(bg_mode > 2 && !(addr & 0x04000)) { + ret = &gba->mem.openbus_word; + *ret = 0; } } - break; - case 0xE: - case 0xF: - if(gba->cart.backup_type==GBA_BACKUP_SRAM){ - gba->mem.sram_word= gba->mem.cart_backup[(addr&0x7fff)]*0x01010101; - ret = &gba->mem.sram_word; - }else if(gba->cart.backup_type==GBA_BACKUP_EEPROM) ret = (uint32_t*)&gba->mem.eeprom_word; - else if(gba->cart.backup_type==GBA_BACKUP_NONE){ - gba->mem.sram_word= 0xffffffff; + } else + ret = (uint32_t *)(gba->mem.vram + (addr & 0x1fffc)); + gba->mem.openbus_word = *ret; + break; + case 0x7: + ret = (uint32_t *)(gba->mem.oam + (addr & 0x3fc)); + gba->mem.openbus_word = *ret; + break; + case 0x8: + case 0x9: + case 0xA: + case 0xB: + case 0xC: + case 0xD: { + int maddr = addr & 0x1fffffc; + if(SB_UNLIKELY(maddr >= gba->cart.rom_size)) { + gba->mem.openbus_word = ((maddr / 2) & 0xffff) | (((maddr / 2 + 1) & 0xffff) << 16); + // Return ready when done writting EEPROM (required by Minish Cap) + if(gba->cart.backup_type == GBA_BACKUP_EEPROM) gba->mem.openbus_word = 1; + } else { + gba->mem.openbus_word = *(uint32_t *)(gba->mem.cart_rom + maddr); + if(req_type & 0x3) { + uint16_t res16 = gba->mem.openbus_word >> (addr & 2) * 8; + gba->mem.openbus_word = res16 * 0x10001u; + } + } + } break; + case 0xE: + case 0xF: + if(gba->cart.backup_type == GBA_BACKUP_SRAM) { + gba->mem.sram_word = gba->mem.cart_backup[(addr & 0x7fff)] * 0x01010101; + ret = &gba->mem.sram_word; + } else if(gba->cart.backup_type == GBA_BACKUP_EEPROM) + ret = (uint32_t *)&gba->mem.eeprom_word; + else if(gba->cart.backup_type == GBA_BACKUP_NONE) { + gba->mem.sram_word = 0xffffffff; + ret = &gba->mem.sram_word; + } else { + // Flash + if(gba->cart.in_chip_id_mode && addr <= 0xE000001) { + gba->mem.openbus_word = *(uint32_t *)gba->mem.flash_chip_id; + ret = &gba->mem.openbus_word; + } else { + gba->mem.sram_word = gba->mem.cart_backup[(addr & 0xffff) + gba->cart.flash_bank * 64 * 1024] * 0x01010101; ret = &gba->mem.sram_word; - }else{ - //Flash - if(gba->cart.in_chip_id_mode&&addr<=0xE000001){ - gba->mem.openbus_word = *(uint32_t*)gba->mem.flash_chip_id; - ret = &gba->mem.openbus_word; - }else{ - gba->mem.sram_word = gba->mem.cart_backup[(addr&0xffff)+gba->cart.flash_bank*64*1024]*0x01010101; - ret = &gba->mem.sram_word; - } } - gba->mem.openbus_word=(*ret&0xffff)*0x10001; - break; + } + gba->mem.openbus_word = (*ret & 0xffff) * 0x10001; + break; } return ret; } -static FORCE_INLINE void gba_audio_fifo_push(gba_t*gba, int fifo, int8_t data){ - int size = (gba->audio.fifo[fifo].write_ptr-gba->audio.fifo[fifo].read_ptr)&0x1f; - if(size<28){ - gba->audio.fifo[fifo].write_ptr = (gba->audio.fifo[fifo].write_ptr+1)&0x1f; - gba->audio.fifo[fifo].data[gba->audio.fifo[fifo].write_ptr]= data; - }else{ - //gba->audio.fifo[fifo].write_ptr=gba->audio.fifo[fifo].read_ptr = 0; - } -} -static void gba_recompute_mmio_mask_table(gba_t* gba){ - for(int io_reg = 0; io_reg<256;io_reg++){ - uint32_t dword_address = 0x04000000+io_reg*4; - uint32_t data_mask =0xffffffff; - bool valid = true; - if(dword_address==0x4000008)data_mask&=0xdfffdfff; - else if(dword_address==0x4000048)data_mask &= 0x3f3f3f3f; - else if(dword_address==0x4000050)data_mask &= 0x1F1F3FFF; - else if(dword_address==0x4000060)data_mask &= 0xFFC0007F; - else if(dword_address==0x4000064||dword_address==0x400006C||dword_address==0x4000074)data_mask &= 0x4000; - else if(dword_address==0x4000068)data_mask &= 0xFFC0; - else if(dword_address==0x4000070)data_mask &= 0xE00000E0; - else if(dword_address==0x4000078)data_mask &= 0xff00; - else if(dword_address==0x400007C)data_mask &= 0x40FF; - else if(dword_address==0x4000080)data_mask &= 0x770FFF77; - else if(dword_address==0x4000084)data_mask &= 0x008F; - else if(dword_address==0x4000088||dword_address==0x4000134||dword_address==0x4000140||dword_address==0x4000158||dword_address==0x4000204||dword_address==0x4000208)data_mask = 0x0000ffff; - else if(dword_address==0x40000B8||dword_address==0x40000C4||dword_address==0x40000D0)data_mask&=0xf7e00000; - else if(dword_address==0x40000DC)data_mask&=0xFFE00000; - else if((dword_address>=0x4000010&& dword_address<=0x4000046) || - (dword_address==0x400004C) || - (dword_address>=0x4000054&& dword_address<=0x400005E)|| - (dword_address==0x400008C)|| - (dword_address>=0x40000A0&&dword_address<=0x40000B6)|| - (dword_address>=0x40000BC&&dword_address<=0x40000C2)|| - (dword_address>=0x40000C8&&dword_address<=0x40000CE)|| - (dword_address>=0x40000D4&&dword_address<=0x40000DA)|| - (dword_address>=0x40000E0&&dword_address<=0x40000FE)|| - (dword_address==0x400100C))valid = false; - gba->mem.mmio_data_mask_lookup[io_reg]=data_mask; - gba->mem.mmio_reg_valid_lookup[io_reg]=valid; - } -} - -static FORCE_INLINE void gba_process_mmio_read(gba_t *gba, uint32_t address){ +static FORCE_INLINE void gba_audio_fifo_push(gba_t *gba, int fifo, int8_t data) { + int size = (gba->audio.fifo[fifo].write_ptr - gba->audio.fifo[fifo].read_ptr) & 0x1f; + if(size < 28) { + gba->audio.fifo[fifo].write_ptr = (gba->audio.fifo[fifo].write_ptr + 1) & 0x1f; + gba->audio.fifo[fifo].data[gba->audio.fifo[fifo].write_ptr] = data; + } else { + // gba->audio.fifo[fifo].write_ptr=gba->audio.fifo[fifo].read_ptr = 0; + } +} +static void gba_recompute_mmio_mask_table(gba_t *gba) { + for(int io_reg = 0; io_reg < 256; io_reg++) { + uint32_t dword_address = 0x04000000 + io_reg * 4; + uint32_t data_mask = 0xffffffff; + bool valid = true; + if(dword_address == 0x4000008) + data_mask &= 0xdfffdfff; + else if(dword_address == 0x4000048) + data_mask &= 0x3f3f3f3f; + else if(dword_address == 0x4000050) + data_mask &= 0x1F1F3FFF; + else if(dword_address == 0x4000060) + data_mask &= 0xFFC0007F; + else if(dword_address == 0x4000064 || dword_address == 0x400006C || dword_address == 0x4000074) + data_mask &= 0x4000; + else if(dword_address == 0x4000068) + data_mask &= 0xFFC0; + else if(dword_address == 0x4000070) + data_mask &= 0xE00000E0; + else if(dword_address == 0x4000078) + data_mask &= 0xff00; + else if(dword_address == 0x400007C) + data_mask &= 0x40FF; + else if(dword_address == 0x4000080) + data_mask &= 0x770FFF77; + else if(dword_address == 0x4000084) + data_mask &= 0x008F; + else if(dword_address == 0x4000088 || dword_address == 0x4000134 || dword_address == 0x4000140 || dword_address == 0x4000158 || dword_address == 0x4000204 || dword_address == 0x4000208) + data_mask = 0x0000ffff; + else if(dword_address == 0x40000B8 || dword_address == 0x40000C4 || dword_address == 0x40000D0) + data_mask &= 0xf7e00000; + else if(dword_address == 0x40000DC) + data_mask &= 0xFFE00000; + else if((dword_address >= 0x4000010 && dword_address <= 0x4000046) || + (dword_address == 0x400004C) || + (dword_address >= 0x4000054 && dword_address <= 0x400005E) || + (dword_address == 0x400008C) || + (dword_address >= 0x40000A0 && dword_address <= 0x40000B6) || + (dword_address >= 0x40000BC && dword_address <= 0x40000C2) || + (dword_address >= 0x40000C8 && dword_address <= 0x40000CE) || + (dword_address >= 0x40000D4 && dword_address <= 0x40000DA) || + (dword_address >= 0x40000E0 && dword_address <= 0x40000FE) || + (dword_address == 0x400100C)) + valid = false; + gba->mem.mmio_data_mask_lookup[io_reg] = data_mask; + gba->mem.mmio_reg_valid_lookup[io_reg] = valid; + } +} + +static FORCE_INLINE void gba_process_mmio_read(gba_t *gba, uint32_t address) { // Force recomputing timers on timer read - if(address>= GBA_TM0CNT_L&&address<=GBA_TM3CNT_H)gba_compute_timers(gba); + if(address >= GBA_TM0CNT_L && address <= GBA_TM3CNT_H) gba_compute_timers(gba); } -static bool gba_process_mmio_write(gba_t *gba, uint32_t address, uint32_t data, int req_size_bytes){ - uint32_t address_u32 = address&~3; +static bool gba_process_mmio_write(gba_t *gba, uint32_t address, uint32_t data, int req_size_bytes) { + uint32_t address_u32 = address & ~3; uint32_t word_mask = 0xffffffff; - uint32_t word_data = data; - if(req_size_bytes==2){ - word_data<<= (address&2)*8; - word_mask =0x0000ffffu<< ((address&2)*8u); - }else if(req_size_bytes==1){ - word_data<<= (address&3)*8; - word_mask =0x000000ffu<< ((address&3)*8u); - } - word_data&=word_mask; - - if(address_u32== GBA_IE){ - uint16_t IE = gba_io_read16(gba,GBA_IE); - uint16_t IF = gba_io_read16(gba,GBA_IF); - - IE = ((IE&~word_mask)|(word_data&word_mask))>>0; - IF &= ~((word_data)>>16); - gba_io_store16(gba,GBA_IE,IE); - gba_io_store16(gba,GBA_IF,IF); - - return true; - }else if(address_u32==GBA_SOUNDCNT_L){ - uint16_t soundcnt_h = SB_BFE(data,16,16); + uint32_t word_data = data; + if(req_size_bytes == 2) { + word_data <<= (address & 2) * 8; + word_mask = 0x0000ffffu << ((address & 2) * 8u); + } else if(req_size_bytes == 1) { + word_data <<= (address & 3) * 8; + word_mask = 0x000000ffu << ((address & 3) * 8u); + } + word_data &= word_mask; + + if(address_u32 == GBA_IE) { + uint16_t IE = gba_io_read16(gba, GBA_IE); + uint16_t IF = gba_io_read16(gba, GBA_IF); + + IE = ((IE & ~word_mask) | (word_data & word_mask)) >> 0; + IF &= ~((word_data) >> 16); + gba_io_store16(gba, GBA_IE, IE); + gba_io_store16(gba, GBA_IF, IF); + + return true; + } else if(address_u32 == GBA_SOUNDCNT_L) { + uint16_t soundcnt_h = SB_BFE(data, 16, 16); // Channel volume for each FIFO - for(int i=0;i<2;++i){ - int timer = SB_BFE(soundcnt_h,10+i*4,1); - bool reset = SB_BFE(soundcnt_h,11+i*4,1); - if(reset){ - gba->audio.fifo[i].read_ptr=0; - gba->audio.fifo[i].write_ptr=0; - for(int d=0;d<32;++d)gba->audio.fifo[i].data[d]=0; + for(int i = 0; i < 2; ++i) { + int timer = SB_BFE(soundcnt_h, 10 + i * 4, 1); + bool reset = SB_BFE(soundcnt_h, 11 + i * 4, 1); + if(reset) { + gba->audio.fifo[i].read_ptr = 0; + gba->audio.fifo[i].write_ptr = 0; + for(int d = 0; d < 32; ++d) + gba->audio.fifo[i].data[d] = 0; } } - }else if(address_u32 == GBA_TM0CNT_L||address_u32==GBA_TM1CNT_L||address_u32==GBA_TM2CNT_L||address_u32==GBA_TM3CNT_L){ + } else if(address_u32 == GBA_TM0CNT_L || address_u32 == GBA_TM1CNT_L || address_u32 == GBA_TM2CNT_L || address_u32 == GBA_TM3CNT_L) { gba_compute_timers(gba); - int timer_off = (address_u32-GBA_TM0CNT_L)/4; - if(word_mask&0xffff){ - gba->timers[timer_off+0].pending_reload_value = word_data&(word_mask&0xffff); + int timer_off = (address_u32 - GBA_TM0CNT_L) / 4; + if(word_mask & 0xffff) { + gba->timers[timer_off + 0].pending_reload_value = word_data & (word_mask & 0xffff); } - if(word_mask&0xffff0000){ - gba_store16(gba,address_u32+2,(word_data>>16)&0xffff); - gba->timers[timer_off+0].reload_value =gba->timers[timer_off+0].pending_reload_value; + if(word_mask & 0xffff0000) { + gba_store16(gba, address_u32 + 2, (word_data >> 16) & 0xffff); + gba->timers[timer_off + 0].reload_value = gba->timers[timer_off + 0].pending_reload_value; } - gba->timer_ticks_before_event=0; + gba->timer_ticks_before_event = 0; return true; - }else if(address_u32==GBA_POSTFLG){ - //Only BIOS can update Post Flag and haltcnt - if(gba->cpu.registers[15]<0x4000){ - //Writes to haltcnt halt the CPU - if(word_mask&0xff00){ - if(word_data&0x8000)gba->stop_mode = true; + } else if(address_u32 == GBA_POSTFLG) { + // Only BIOS can update Post Flag and haltcnt + if(gba->cpu.registers[15] < 0x4000) { + // Writes to haltcnt halt the CPU + if(word_mask & 0xff00) { + if(word_data & 0x8000) gba->stop_mode = true; gba->cpu.wait_for_interrupt = true; } - uint32_t data = gba_io_read32(gba,address_u32); - //POST can only be initialized once, then other writes are dropped. - if((word_mask&0xff)&&(data&0xff))word_mask&=~0xff; - data&=~word_mask; - data|=word_data&word_mask; - gba_io_store32(gba,address_u32,data); + uint32_t data = gba_io_read32(gba, address_u32); + // POST can only be initialized once, then other writes are dropped. + if((word_mask & 0xff) && (data & 0xff)) word_mask &= ~0xff; + data &= ~word_mask; + data |= word_data & word_mask; + gba_io_store32(gba, address_u32, data); } - return true; - /* - Ignore these for now since it is causing audio pops in Metroid Zero - }else if(address_u32==GBA_FIFO_A){ - // See: https://github.com/mgba-emu/mgba/issues/1847 - for(int i=0;i<4;++i){ - if(word_mask&(0xff<<(8*i)))gba_audio_fifo_push(gba,0,SB_BFE(word_data,8*i,8)); - else gba_audio_fifo_push(gba,0,gba->audio.fifo[0].data[(gba->audio.fifo[0].write_ptr)&0x1f]); - } - }else if(address_u32==GBA_FIFO_B){ - for(int i=0;i<4;++i){ - if(word_mask&(0xff<<(8*i)))gba_audio_fifo_push(gba,1,SB_BFE(word_data,8*i,8)); - else gba_audio_fifo_push(gba,1,gba->audio.fifo[1].data[(gba->audio.fifo[1].write_ptr)&0x1f]); - } - */ - }else if(address_u32==GBA_BG2X||address_u32==GBA_BG3X){ - int aff_bg = (address_u32-GBA_BG2X)/0x10; - gba->ppu.aff[aff_bg].wrote_bgx= true; - }else if(address_u32==GBA_BG2Y||address_u32==GBA_BG3Y){ - int aff_bg = (address_u32-GBA_BG2Y)/0x10; + return true; + /* + Ignore these for now since it is causing audio pops in Metroid Zero + }else if(address_u32==GBA_FIFO_A){ + // See: https://github.com/mgba-emu/mgba/issues/1847 + for(int i=0;i<4;++i){ + if(word_mask&(0xff<<(8*i)))gba_audio_fifo_push(gba,0,SB_BFE(word_data,8*i,8)); + else gba_audio_fifo_push(gba,0,gba->audio.fifo[0].data[(gba->audio.fifo[0].write_ptr)&0x1f]); + } + }else if(address_u32==GBA_FIFO_B){ + for(int i=0;i<4;++i){ + if(word_mask&(0xff<<(8*i)))gba_audio_fifo_push(gba,1,SB_BFE(word_data,8*i,8)); + else gba_audio_fifo_push(gba,1,gba->audio.fifo[1].data[(gba->audio.fifo[1].write_ptr)&0x1f]); + } + */ + } else if(address_u32 == GBA_BG2X || address_u32 == GBA_BG3X) { + int aff_bg = (address_u32 - GBA_BG2X) / 0x10; + gba->ppu.aff[aff_bg].wrote_bgx = true; + } else if(address_u32 == GBA_BG2Y || address_u32 == GBA_BG3Y) { + int aff_bg = (address_u32 - GBA_BG2Y) / 0x10; gba->ppu.aff[aff_bg].wrote_bgy = true; - }else if(address_u32==GBA_DMA0CNT_L||address_u32==GBA_DMA1CNT_L|| - address_u32==GBA_DMA2CNT_L||address_u32==GBA_DMA3CNT_L){ - gba->activate_dmas=true; - }else if (address_u32==GBA_WAITCNT){ - uint16_t waitcnt = gba_io_read16(gba,GBA_WAITCNT); - waitcnt = ((waitcnt&~word_mask)|(word_data&word_mask)); - gba_recompute_waitstate_table(gba,waitcnt); - }else if(address_u32==GBA_KEYINPUT){ - if(word_mask&0xffff0000){ - gba_store16(gba,GBA_KEYINPUT,(word_data>>16)&0xffff); - } - gba_tick_keypad(NULL,gba); - }else if(address_u32>=GBA_SOUND1CNT_L&&address_u32activate_dmas = true; + } else if(address_u32 == GBA_WAITCNT) { + uint16_t waitcnt = gba_io_read16(gba, GBA_WAITCNT); + waitcnt = ((waitcnt & ~word_mask) | (word_data & word_mask)); + gba_recompute_waitstate_table(gba, waitcnt); + } else if(address_u32 == GBA_KEYINPUT) { + if(word_mask & 0xffff0000) { + gba_store16(gba, GBA_KEYINPUT, (word_data >> 16) & 0xffff); + } + gba_tick_keypad(NULL, gba); + } else if(address_u32 >= GBA_SOUND1CNT_L && address_u32 < GBA_WAVE_RAM) { + for(int i = 0; i < 4; ++i) { + if(word_mask & (0xff << (i * 8))) { + uint8_t data = gba_audio_process_byte_write(gba, address_u32 + i, SB_BFE(word_data, (i * 8), 8)); + gba_io_store8(gba, address_u32 + i, data); } } gba_process_audio_writes(gba); @@ -1672,22 +1764,24 @@ static bool gba_process_mmio_write(gba_t *gba, uint32_t address, uint32_t data, } return false; } -int gba_search_rom_for_backup_string(gba_t* gba){ - int btype = GBA_BACKUP_NONE; - for(int b = 0; b< gba->cart.rom_size;++b){ - const char* strings[]={"EEPROM_", "SRAM_", "FLASH_","FLASH512_","FLASH1M_"}; - int backup_type[]= {GBA_BACKUP_EEPROM,GBA_BACKUP_SRAM,GBA_BACKUP_FLASH_64K, GBA_BACKUP_FLASH_64K, GBA_BACKUP_FLASH_128K}; - for(int type = 0; type=gba->cart.rom_size)matches=false; - else if(str[str_off]!=gba->mem.cart_rom[b+str_off])matches = false; +int gba_search_rom_for_backup_string(gba_t *gba) { + int btype = GBA_BACKUP_NONE; + for(int b = 0; b < gba->cart.rom_size; ++b) { + const char *strings[] = {"EEPROM_", "SRAM_", "FLASH_", "FLASH512_", "FLASH1M_"}; + int backup_type[] = {GBA_BACKUP_EEPROM, GBA_BACKUP_SRAM, GBA_BACKUP_FLASH_64K, GBA_BACKUP_FLASH_64K, GBA_BACKUP_FLASH_128K}; + for(int type = 0; type < sizeof(strings) / sizeof(strings[0]); ++type) { + int str_off = 0; + bool matches = true; + const char *str = strings[type]; + while(str[str_off] && matches) { + if(b + str_off >= gba->cart.rom_size) + matches = false; + else if(str[str_off] != gba->mem.cart_rom[b + str_off]) + matches = false; ++str_off; } - if(matches){ - if(btype!=backup_type[type]&&btype!=GBA_BACKUP_NONE){ + if(matches) { + if(btype != backup_type[type] && btype != GBA_BACKUP_NONE) { printf("Found multiple backup types, defaulting to none\n"); return GBA_BACKUP_NONE; } @@ -1695,1158 +1789,1226 @@ int gba_search_rom_for_backup_string(gba_t* gba){ } } } - return btype; + return btype; } -void gba_unload(gba_t*gba,gba_scratch_t *scratch){ +void gba_unload(gba_t *gba, gba_scratch_t *scratch) { printf("Unloading GBA\n"); - if(scratch->log_cmp_file)fclose(scratch->log_cmp_file); - scratch->log_cmp_file=NULL; + if(scratch->log_cmp_file) fclose(scratch->log_cmp_file); + scratch->log_cmp_file = NULL; } -bool gba_load_rom(sb_emu_state_t*emu,gba_t* gba, gba_scratch_t *scratch){ - memset(gba,0,sizeof(gba_t)); - memset(scratch,0,sizeof(gba_scratch_t)); - if(!sb_path_has_file_ext(emu->rom_path, ".gba"))return false; +bool gba_load_rom(sb_emu_state_t *emu, gba_t *gba, gba_scratch_t *scratch) { + memset(gba, 0, sizeof(gba_t)); + memset(scratch, 0, sizeof(gba_scratch_t)); + if(!sb_path_has_file_ext(emu->rom_path, ".gba")) return false; - if(emu->rom_size>32*1024*1024){ - printf("ROMs with sizes >32MB (%zu bytes) are too big for the GBA\n",emu->rom_size); + if(emu->rom_size > 32 * 1024 * 1024) { + printf("ROMs with sizes >32MB (%zu bytes) are too big for the GBA\n", emu->rom_size); return false; - } + } - gba->mem.bios=scratch->bios; - bool loaded_bios= se_load_bios_file("GBA BIOS", emu->save_file_path, "gba_bios.bin", scratch->bios,16*1024); - if(!loaded_bios){ - memcpy(scratch->bios,gba_bios_bin,sizeof(gba_bios_bin)); - scratch->skip_bios_intro=true; + gba->mem.bios = scratch->bios; + bool loaded_bios = se_load_bios_file("GBA BIOS", emu->save_file_path, "gba_bios.bin", scratch->bios, 16 * 1024); + if(!loaded_bios) { + memcpy(scratch->bios, gba_bios_bin, sizeof(gba_bios_bin)); + scratch->skip_bios_intro = true; } - gba->cart.rom_size = emu->rom_size; + gba->cart.rom_size = emu->rom_size; gba->mem.cart_rom = emu->rom_data; gba->cart.backup_type = gba_search_rom_for_backup_string(gba); - size_t bytes=0; - uint8_t*data = sb_load_file_data(emu->save_file_path,&bytes); - if(data){ - printf("Loaded save file: %s, bytes: %zu\n",emu->save_file_path,bytes); - if(bytes>=128*1024)bytes=128*1024; + size_t bytes = 0; + uint8_t *data = sb_load_file_data(emu->save_file_path, &bytes); + if(data) { + printf("Loaded save file: %s, bytes: %zu\n", emu->save_file_path, bytes); + if(bytes >= 128 * 1024) bytes = 128 * 1024; memcpy(gba->mem.cart_backup, data, bytes); sb_free_file_data(data); - }else{ - printf("Could not find save file: %s\n",emu->save_file_path); - for(int i=0;imem.cart_backup);++i) gba->mem.cart_backup[i]=0xff; + } else { + printf("Could not find save file: %s\n", emu->save_file_path); + for(int i = 0; i < sizeof(gba->mem.cart_backup); ++i) + gba->mem.cart_backup[i] = 0xff; } // Setup flash chip id (this is not used if the cartridge does not have flash backup storage) - if(gba->cart.backup_type==GBA_BACKUP_FLASH_64K){ - gba->mem.flash_chip_id[1]=0xd4; - gba->mem.flash_chip_id[0]=0xbf; - }else{ - gba->mem.flash_chip_id[1]=0x13; - gba->mem.flash_chip_id[0]=0x62; + if(gba->cart.backup_type == GBA_BACKUP_FLASH_64K) { + gba->mem.flash_chip_id[1] = 0xd4; + gba->mem.flash_chip_id[0] = 0xbf; + } else { + gba->mem.flash_chip_id[1] = 0x13; + gba->mem.flash_chip_id[0] = 0x62; } gba->cpu = arm7_init(gba); - - for(int bg = 2;bg<4;++bg){ - gba_io_store16(gba,GBA_BG2PA+(bg-2)*0x10,1<<8); - gba_io_store16(gba,GBA_BG2PB+(bg-2)*0x10,0<<8); - gba_io_store16(gba,GBA_BG2PC+(bg-2)*0x10,0<<8); - gba_io_store16(gba,GBA_BG2PD+(bg-2)*0x10,1<<8); - } - gba_store16(gba,0x04000088,512); - gba_store32(gba,0x040000DC,0x84000000); - gba_recompute_waitstate_table(gba,0); + + for(int bg = 2; bg < 4; ++bg) { + gba_io_store16(gba, GBA_BG2PA + (bg - 2) * 0x10, 1 << 8); + gba_io_store16(gba, GBA_BG2PB + (bg - 2) * 0x10, 0 << 8); + gba_io_store16(gba, GBA_BG2PC + (bg - 2) * 0x10, 0 << 8); + gba_io_store16(gba, GBA_BG2PD + (bg - 2) * 0x10, 1 << 8); + } + gba_store16(gba, 0x04000088, 512); + gba_store32(gba, 0x040000DC, 0x84000000); + gba_recompute_waitstate_table(gba, 0); gba_recompute_mmio_mask_table(gba); - if(scratch->skip_bios_intro){ + if(scratch->skip_bios_intro) { printf("No GBA bios using bundled bios\n"); - memcpy(gba->mem.bios,gba_bios_bin,sizeof(gba_bios_bin)); - const uint32_t initial_regs[37]={ - 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x3007f00,0x0000000,0x8000000, - 0xdf,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x3007fa0,0x0,0x3007fe0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0, + memcpy(gba->mem.bios, gba_bios_bin, sizeof(gba_bios_bin)); + const uint32_t initial_regs[37] = { + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x3007f00, + 0x0000000, + 0x8000000, + 0xdf, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x3007fa0, + 0x0, + 0x3007fe0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, }; - for(int i=0;i<37;++i)gba->cpu.registers[i]=initial_regs[i]; - const uint32_t initial_mmio_writes[]={ - 0x4000000,0x80, - 0x4000004,0x7e0000, - 0x4000020,0x100, - 0x4000024,0x1000000, - 0x4000030,0x100, - 0x4000034,0x1000000, - 0x4000080,0xe0000, - 0x4000084,0xf, - 0x4000088,0x200, - 0x4000100,0xff8a, - 0x4000130,0x3ff, - 0x4000134,0x8000, - 0x4000300,0x1, + for(int i = 0; i < 37; ++i) + gba->cpu.registers[i] = initial_regs[i]; + const uint32_t initial_mmio_writes[] = { + 0x4000000, + 0x80, + 0x4000004, + 0x7e0000, + 0x4000020, + 0x100, + 0x4000024, + 0x1000000, + 0x4000030, + 0x100, + 0x4000034, + 0x1000000, + 0x4000080, + 0xe0000, + 0x4000084, + 0xf, + 0x4000088, + 0x200, + 0x4000100, + 0xff8a, + 0x4000130, + 0x3ff, + 0x4000134, + 0x8000, + 0x4000300, + 0x1, }; - for(int i=0;icpu.registers[PC] = 0x0000000; - gba->cpu.registers[CPSR]= 0x000000d3; - } - if(gba->cpu.log_cmp_file){fclose(gba->cpu.log_cmp_file);gba->cpu.log_cmp_file=NULL;}; - gba->cpu.log_cmp_file =se_load_log_file(scratch->save_file_path, "log.bin"); - gba->cpu.executed_instructions+=2; - gba->audio.current_sample_generated_time=gba->audio.current_sim_time=0; - gba->rtc.initial_rtc_time=time(NULL); - return true; -} - + for(int i = 0; i < sizeof(initial_mmio_writes) / sizeof(uint32_t); i += 2) { + uint32_t addr = initial_mmio_writes[i + 0]; + uint32_t data = initial_mmio_writes[i + 1]; + arm7_write32(gba, addr, data); + } + gba_store32(gba, GBA_IE, 0x1); + gba_store16(gba, GBA_DISPCNT, 0x9140); + } else { + gba->cpu.registers[PC] = 0x0000000; + gba->cpu.registers[CPSR] = 0x000000d3; + } + if(gba->cpu.log_cmp_file) { + fclose(gba->cpu.log_cmp_file); + gba->cpu.log_cmp_file = NULL; + }; + gba->cpu.log_cmp_file = se_load_log_file(scratch->save_file_path, "log.bin"); + gba->cpu.executed_instructions += 2; + gba->audio.current_sample_generated_time = gba->audio.current_sim_time = 0; + gba->rtc.initial_rtc_time = time(NULL); + return true; +} + #define GBA_LCD_HBLANK_END (295) #define GBA_LCD_HBLANK_START (GBA_LCD_W) -#define GBA_LCD_VBLANK_START (GBA_LCD_H*1232) -#define GBA_LCD_VBLANK_END (227*1232) - -//Returns true if the fast forward failed to be more efficient in main emu loop -static FORCE_INLINE int gba_ppu_compute_max_fast_forward(gba_t* gba, bool render){ - int scanline_clock = (gba->ppu.scan_clock)%1232; - //If inside hblank, can fastforward to outside of hblank - if(scanline_clock>=GBA_LCD_HBLANK_START*4&&scanline_clock<=GBA_LCD_HBLANK_END*4) return GBA_LCD_HBLANK_END*4-scanline_clock-1; - //If inside hrender, can fastforward to hblank if not the first pixel and not visible - bool not_visible = !render||gba->ppu.scan_clock>GBA_LCD_VBLANK_START; - if(not_visible&& (scanline_clock>=1 && scanline_clock<=GBA_LCD_HBLANK_START*4))return GBA_LCD_HBLANK_START*4-scanline_clock-1; - return 3-((gba->ppu.scan_clock)%4); -} -static FORCE_INLINE void gba_tick_ppu(gba_t* gba, bool render){ - if(SB_LIKELY(gba->ppu.fast_forward_ticks>0)){ +#define GBA_LCD_VBLANK_START (GBA_LCD_H * 1232) +#define GBA_LCD_VBLANK_END (227 * 1232) + +// Returns true if the fast forward failed to be more efficient in main emu loop +static FORCE_INLINE int gba_ppu_compute_max_fast_forward(gba_t *gba, bool render) { + int scanline_clock = (gba->ppu.scan_clock) % 1232; + // If inside hblank, can fastforward to outside of hblank + if(scanline_clock >= GBA_LCD_HBLANK_START * 4 && scanline_clock <= GBA_LCD_HBLANK_END * 4) return GBA_LCD_HBLANK_END * 4 - scanline_clock - 1; + // If inside hrender, can fastforward to hblank if not the first pixel and not visible + bool not_visible = !render || gba->ppu.scan_clock > GBA_LCD_VBLANK_START; + if(not_visible && (scanline_clock >= 1 && scanline_clock <= GBA_LCD_HBLANK_START * 4)) return GBA_LCD_HBLANK_START * 4 - scanline_clock - 1; + return 3 - ((gba->ppu.scan_clock) % 4); +} +static FORCE_INLINE void gba_tick_ppu(gba_t *gba, bool render) { + if(SB_LIKELY(gba->ppu.fast_forward_ticks > 0)) { gba->ppu.fast_forward_ticks--; - return; + return; } - if(gba->ppu.scan_clock>=280896)gba->ppu.scan_clock-=280896; - int lcd_y = (gba->ppu.scan_clock)/1232; - int lcd_x = ((gba->ppu.scan_clock)%1232)/4; + if(gba->ppu.scan_clock >= 280896) gba->ppu.scan_clock -= 280896; + int lcd_y = (gba->ppu.scan_clock) / 1232; + int lcd_x = ((gba->ppu.scan_clock) % 1232) / 4; gba->ppu.scan_clock++; - gba->ppu.fast_forward_ticks = gba_ppu_compute_max_fast_forward(gba, render)+1; - gba->ppu.scan_clock+=gba->ppu.fast_forward_ticks; - if(lcd_x==0||lcd_x==GBA_LCD_HBLANK_START||lcd_x==GBA_LCD_HBLANK_END){ - uint16_t disp_stat = gba_io_read16(gba, GBA_DISPSTAT)&~0x7; - uint16_t vcount_cmp = SB_BFE(disp_stat,8,8); - int vcount = (lcd_y+ (lcd_x>=GBA_LCD_HBLANK_END))%228; - bool vblank = lcd_y>=160&&lcd_y<227; - bool hblank = lcd_x>=GBA_LCD_HBLANK_START&&lcd_x< GBA_LCD_HBLANK_END; - disp_stat |= vblank ? 0x1: 0; - disp_stat |= hblank ? 0x2: 0; - disp_stat |= vcount==vcount_cmp ? 0x4: 0; - gba_io_store16(gba,GBA_DISPSTAT,disp_stat); - gba_io_store16(gba,GBA_VCOUNT,vcount); + gba->ppu.fast_forward_ticks = gba_ppu_compute_max_fast_forward(gba, render) + 1; + gba->ppu.scan_clock += gba->ppu.fast_forward_ticks; + if(lcd_x == 0 || lcd_x == GBA_LCD_HBLANK_START || lcd_x == GBA_LCD_HBLANK_END) { + uint16_t disp_stat = gba_io_read16(gba, GBA_DISPSTAT) & ~0x7; + uint16_t vcount_cmp = SB_BFE(disp_stat, 8, 8); + int vcount = (lcd_y + (lcd_x >= GBA_LCD_HBLANK_END)) % 228; + bool vblank = lcd_y >= 160 && lcd_y < 227; + bool hblank = lcd_x >= GBA_LCD_HBLANK_START && lcd_x < GBA_LCD_HBLANK_END; + disp_stat |= vblank ? 0x1 : 0; + disp_stat |= hblank ? 0x2 : 0; + disp_stat |= vcount == vcount_cmp ? 0x4 : 0; + gba_io_store16(gba, GBA_DISPSTAT, disp_stat); + gba_io_store16(gba, GBA_VCOUNT, vcount); uint32_t new_if = 0; - if(hblank!=gba->ppu.last_hblank){ + if(hblank != gba->ppu.last_hblank) { gba->ppu.last_hblank = hblank; - bool hblank_irq_en = SB_BFE(disp_stat,4,1); - if(hblank&&hblank_irq_en) new_if|= (1<< GBA_INT_LCD_HBLANK); - gba->activate_dmas|=gba->dma_wait_ppu; - if(!hblank){ - gba->ppu.dispcnt_pipeline[0]=gba->ppu.dispcnt_pipeline[1]; - gba->ppu.dispcnt_pipeline[1]=gba->ppu.dispcnt_pipeline[2]; - gba->ppu.dispcnt_pipeline[2]=gba_io_read16(gba, GBA_DISPCNT); - } - } - if(lcd_y != gba->ppu.last_lcd_y){ - if(vblank!=gba->ppu.last_vblank){ - if(vblank)gba->ppu.has_hit_vblank=true; + bool hblank_irq_en = SB_BFE(disp_stat, 4, 1); + if(hblank && hblank_irq_en) new_if |= (1 << GBA_INT_LCD_HBLANK); + gba->activate_dmas |= gba->dma_wait_ppu; + if(!hblank) { + gba->ppu.dispcnt_pipeline[0] = gba->ppu.dispcnt_pipeline[1]; + gba->ppu.dispcnt_pipeline[1] = gba->ppu.dispcnt_pipeline[2]; + gba->ppu.dispcnt_pipeline[2] = gba_io_read16(gba, GBA_DISPCNT); + } + } + if(lcd_y != gba->ppu.last_lcd_y) { + if(vblank != gba->ppu.last_vblank) { + if(vblank) gba->ppu.has_hit_vblank = true; gba->ppu.last_vblank = vblank; - bool vblank_irq_en = SB_BFE(disp_stat,3,1); - if(vblank&&vblank_irq_en) new_if|= (1<< GBA_INT_LCD_VBLANK); - gba->activate_dmas|=gba->dma_wait_ppu; + bool vblank_irq_en = SB_BFE(disp_stat, 3, 1); + if(vblank && vblank_irq_en) new_if |= (1 << GBA_INT_LCD_VBLANK); + gba->activate_dmas |= gba->dma_wait_ppu; } - gba->ppu.last_lcd_y = lcd_y; - if(lcd_y==vcount_cmp) { - bool vcnt_irq_en = SB_BFE(disp_stat,5,1); - if(vcnt_irq_en)new_if |= (1<ppu.last_lcd_y = lcd_y; + if(lcd_y == vcount_cmp) { + bool vcnt_irq_en = SB_BFE(disp_stat, 5, 1); + if(vcnt_irq_en) new_if |= (1 << GBA_INT_LCD_VCOUNT); } } - gba_send_interrupt(gba,3,new_if); + gba_send_interrupt(gba, 3, new_if); } - if(!render)return; - - if(lcd_x==GBA_LCD_HBLANK_START){ + if(!render) return; + + if(lcd_x == GBA_LCD_HBLANK_START) { uint16_t dispcnt = gba->ppu.dispcnt_pipeline[0]; - int bg_mode = SB_BFE(dispcnt,0,3); + int bg_mode = SB_BFE(dispcnt, 0, 3); // From Mirei: Affine registers are only incremented when bg_mode is not 0 // and the bg is enabled. - if(bg_mode!=0){ - for(int aff=0;aff<2;++aff){ - bool bg_en = SB_BFE(dispcnt,8+aff+2,1); - if(!bg_en)continue; - int32_t b = (int16_t)gba_io_read16(gba,GBA_BG2PB+(aff)*0x10); - int32_t d = (int16_t)gba_io_read16(gba,GBA_BG2PD+(aff)*0x10); - uint16_t bgcnt = gba_io_read16(gba, GBA_BG2CNT+aff*2); - bool mosaic = SB_BFE(bgcnt,6,1); - if(mosaic){ - uint16_t mos_reg = gba_io_read16(gba,GBA_MOSAIC); - int mos_y = SB_BFE(mos_reg,4,4)+1; - if((lcd_y%mos_y)==0){ - gba->ppu.aff[aff].render_bgx+=b*mos_y; - gba->ppu.aff[aff].render_bgy+=d*mos_y; + if(bg_mode != 0) { + for(int aff = 0; aff < 2; ++aff) { + bool bg_en = SB_BFE(dispcnt, 8 + aff + 2, 1); + if(!bg_en) continue; + int32_t b = (int16_t)gba_io_read16(gba, GBA_BG2PB + (aff)*0x10); + int32_t d = (int16_t)gba_io_read16(gba, GBA_BG2PD + (aff)*0x10); + uint16_t bgcnt = gba_io_read16(gba, GBA_BG2CNT + aff * 2); + bool mosaic = SB_BFE(bgcnt, 6, 1); + if(mosaic) { + uint16_t mos_reg = gba_io_read16(gba, GBA_MOSAIC); + int mos_y = SB_BFE(mos_reg, 4, 4) + 1; + if((lcd_y % mos_y) == 0) { + gba->ppu.aff[aff].render_bgx += b * mos_y; + gba->ppu.aff[aff].render_bgy += d * mos_y; } - }else{ - gba->ppu.aff[aff].render_bgx+=b; - gba->ppu.aff[aff].render_bgy+=d; + } else { + gba->ppu.aff[aff].render_bgx += b; + gba->ppu.aff[aff].render_bgy += d; } } } } - bool reload_ref_points = lcd_x==GBA_LCD_HBLANK_END|| (lcd_y==0&&lcd_x==0); - if(reload_ref_points){ - //Latch BGX and BGY registers - for(int aff=0;aff<2;++aff){ - if(gba->ppu.aff[aff].wrote_bgx||(lcd_y==0&&lcd_x==0)){ - gba->ppu.aff[aff].render_bgx = gba_io_read32(gba,GBA_BG2X+(aff)*0x10); - gba->ppu.aff[aff].render_bgx = SB_BFE(gba->ppu.aff[aff].render_bgx,0,28); - gba->ppu.aff[aff].render_bgx = ((int32_t)(gba->ppu.aff[aff].render_bgx<<4))>>4; - gba->ppu.aff[aff].wrote_bgx = false; + bool reload_ref_points = lcd_x == GBA_LCD_HBLANK_END || (lcd_y == 0 && lcd_x == 0); + if(reload_ref_points) { + // Latch BGX and BGY registers + for(int aff = 0; aff < 2; ++aff) { + if(gba->ppu.aff[aff].wrote_bgx || (lcd_y == 0 && lcd_x == 0)) { + gba->ppu.aff[aff].render_bgx = gba_io_read32(gba, GBA_BG2X + (aff)*0x10); + gba->ppu.aff[aff].render_bgx = SB_BFE(gba->ppu.aff[aff].render_bgx, 0, 28); + gba->ppu.aff[aff].render_bgx = ((int32_t)(gba->ppu.aff[aff].render_bgx << 4)) >> 4; + gba->ppu.aff[aff].wrote_bgx = false; } - if(gba->ppu.aff[aff].wrote_bgy||(lcd_y==0&&lcd_x==0)){ - gba->ppu.aff[aff].render_bgy = gba_io_read32(gba,GBA_BG2Y+(aff)*0x10); - gba->ppu.aff[aff].render_bgy = SB_BFE(gba->ppu.aff[aff].render_bgy,0,28); - gba->ppu.aff[aff].render_bgy = ((int32_t)(gba->ppu.aff[aff].render_bgy<<4))>>4; - gba->ppu.aff[aff].wrote_bgy = false; + if(gba->ppu.aff[aff].wrote_bgy || (lcd_y == 0 && lcd_x == 0)) { + gba->ppu.aff[aff].render_bgy = gba_io_read32(gba, GBA_BG2Y + (aff)*0x10); + gba->ppu.aff[aff].render_bgy = SB_BFE(gba->ppu.aff[aff].render_bgy, 0, 28); + gba->ppu.aff[aff].render_bgy = ((int32_t)(gba->ppu.aff[aff].render_bgy << 4)) >> 4; + gba->ppu.aff[aff].wrote_bgy = false; } } } - uint16_t dispcnt = gba_io_read16(gba,GBA_DISPCNT); - int bg_mode = SB_BFE(dispcnt,0,3); - int obj_vram_map_2d = !SB_BFE(dispcnt,6,1); - int forced_blank = SB_BFE(dispcnt,7,1); - bool visible = lcd_x<240 && lcd_y<160; - //Render sprites over scanline when it completes - if((lcd_y<159 || lcd_y ==227) && lcd_x == GBA_LCD_HBLANK_START){ - int sprite_lcd_y = (lcd_y+1)%228; - uint16_t mos_reg = gba_io_read16(gba,GBA_MOSAIC); - int mos_y = SB_BFE(mos_reg,12,4)+1; + uint16_t dispcnt = gba_io_read16(gba, GBA_DISPCNT); + int bg_mode = SB_BFE(dispcnt, 0, 3); + int obj_vram_map_2d = !SB_BFE(dispcnt, 6, 1); + int forced_blank = SB_BFE(dispcnt, 7, 1); + bool visible = lcd_x < 240 && lcd_y < 160; + // Render sprites over scanline when it completes + if((lcd_y < 159 || lcd_y == 227) && lcd_x == GBA_LCD_HBLANK_START) { + int sprite_lcd_y = (lcd_y + 1) % 228; + uint16_t mos_reg = gba_io_read16(gba, GBA_MOSAIC); + int mos_y = SB_BFE(mos_reg, 12, 4) + 1; // Partial fix to https://github.com/skylersaleh/SkyEmu/issues/316 - if(++gba->ppu.mosaic_y_counter>=mos_y||sprite_lcd_y ==0){ - gba->ppu.mosaic_y_counter=0; + if(++gba->ppu.mosaic_y_counter >= mos_y || sprite_lcd_y == 0) { + gba->ppu.mosaic_y_counter = 0; } - //Render sprites over scanline when it completes - uint8_t default_window_control =0x3f;//bitfield [0-3:bg0-bg3 enable 4:obj enable, 5: special effect enable] - bool winout_enable = SB_BFE(dispcnt,13,3)!=0; + // Render sprites over scanline when it completes + uint8_t default_window_control = 0x3f; // bitfield [0-3:bg0-bg3 enable 4:obj enable, 5: special effect enable] + bool winout_enable = SB_BFE(dispcnt, 13, 3) != 0; uint16_t WINOUT = gba_io_read16(gba, GBA_WINOUT); - if(winout_enable)default_window_control = SB_BFE(WINOUT,0,8); - - for(int x=0;x<240;++x){gba->window[x] = default_window_control;} + if(winout_enable) default_window_control = SB_BFE(WINOUT, 0, 8); + + for(int x = 0; x < 240; ++x) { + gba->window[x] = default_window_control; + } uint8_t obj_window_control = default_window_control; - bool obj_window_enable = SB_BFE(dispcnt,15,1); - if(obj_window_enable)obj_window_control = SB_BFE(WINOUT,8,6); - bool display_obj = SB_BFE(dispcnt,12,1); - if(display_obj){ - for(int o=0;o<128;++o){ - uint16_t attr0 = *(uint16_t*)(gba->mem.oam+o*8+0); - //Attr0 - uint8_t y_coord = SB_BFE(attr0,0,8); - bool rot_scale = SB_BFE(attr0,8,1); - bool double_size = SB_BFE(attr0,9,1)&&rot_scale; - bool obj_disable = SB_BFE(attr0,9,1)&&!rot_scale; - if(obj_disable) continue; - - int obj_mode = SB_BFE(attr0,10,2); //(0=Normal, 1=Semi-Transparent, 2=OBJ Window, 3=Prohibited) - bool mosaic = SB_BFE(attr0,12,1); - bool colors_or_palettes = SB_BFE(attr0,13,1); - int obj_shape = SB_BFE(attr0,14,2);//(0=Square,1=Horizontal,2=Vertical,3=Prohibited) - uint16_t attr1 = *(uint16_t*)(gba->mem.oam+o*8+2); - - int rotscale_param = SB_BFE(attr1,9,5); - bool h_flip = SB_BFE(attr1,12,1)&&!rot_scale; - bool v_flip = SB_BFE(attr1,13,1)&&!rot_scale; - int obj_size = SB_BFE(attr1,14,2); + bool obj_window_enable = SB_BFE(dispcnt, 15, 1); + if(obj_window_enable) obj_window_control = SB_BFE(WINOUT, 8, 6); + bool display_obj = SB_BFE(dispcnt, 12, 1); + if(display_obj) { + for(int o = 0; o < 128; ++o) { + uint16_t attr0 = *(uint16_t *)(gba->mem.oam + o * 8 + 0); + // Attr0 + uint8_t y_coord = SB_BFE(attr0, 0, 8); + bool rot_scale = SB_BFE(attr0, 8, 1); + bool double_size = SB_BFE(attr0, 9, 1) && rot_scale; + bool obj_disable = SB_BFE(attr0, 9, 1) && !rot_scale; + if(obj_disable) continue; + + int obj_mode = SB_BFE(attr0, 10, 2); //(0=Normal, 1=Semi-Transparent, 2=OBJ Window, 3=Prohibited) + bool mosaic = SB_BFE(attr0, 12, 1); + bool colors_or_palettes = SB_BFE(attr0, 13, 1); + int obj_shape = SB_BFE(attr0, 14, 2); //(0=Square,1=Horizontal,2=Vertical,3=Prohibited) + uint16_t attr1 = *(uint16_t *)(gba->mem.oam + o * 8 + 2); + + int rotscale_param = SB_BFE(attr1, 9, 5); + bool h_flip = SB_BFE(attr1, 12, 1) && !rot_scale; + bool v_flip = SB_BFE(attr1, 13, 1) && !rot_scale; + int obj_size = SB_BFE(attr1, 14, 2); // Size Square Horizontal Vertical // 0 8x8 16x8 8x16 // 1 16x16 32x8 8x32 // 2 32x32 32x16 16x32 // 3 64x64 64x32 32x64 - const int xsize_lookup[16]={ - 8,16,8,0, - 16,32,8,0, - 32,32,16,0, - 64,64,32,0 - }; - const int ysize_lookup[16]={ - 8,8,16,0, - 16,8,32,0, - 32,16,32,0, - 64,32,64,0 - }; - - int y_size = ysize_lookup[obj_size*4+obj_shape]; - - if(((sprite_lcd_y-y_coord)&0xff) =0?x_coord:0; - int x_end = x_coord+x_size*(double_size?2:1); - if(x_end>=240)x_end=240; - //Attr2 - //Skip objects disabled by window - uint16_t attr2 = *(uint16_t*)(gba->mem.oam+o*8+4); - int tile_base = SB_BFE(attr2,0,10); + const int xsize_lookup[16] = { + 8, 16, 8, 0, + 16, 32, 8, 0, + 32, 32, 16, 0, + 64, 64, 32, 0}; + const int ysize_lookup[16] = { + 8, 8, 16, 0, + 16, 8, 32, 0, + 32, 16, 32, 0, + 64, 32, 64, 0}; + + int y_size = ysize_lookup[obj_size * 4 + obj_shape]; + + if(((sprite_lcd_y - y_coord) & 0xff) < y_size * (double_size ? 2 : 1)) { + int16_t x_coord = SB_BFE(attr1, 0, 9); + if(SB_BFE(x_coord, 8, 1)) x_coord |= 0xfe00; + + int x_size = xsize_lookup[obj_size * 4 + obj_shape]; + int x_start = x_coord >= 0 ? x_coord : 0; + int x_end = x_coord + x_size * (double_size ? 2 : 1); + if(x_end >= 240) x_end = 240; + // Attr2 + // Skip objects disabled by window + uint16_t attr2 = *(uint16_t *)(gba->mem.oam + o * 8 + 4); + int tile_base = SB_BFE(attr2, 0, 10); // Always place sprites as the highest priority - int priority = SB_BFE(attr2,10,2); - int palette = SB_BFE(attr2,12,4); - for(int x = x_start; x< x_end;++x){ - int sx = (x-x_coord); - int sy = (sprite_lcd_y-y_coord)&0xff; - if(mosaic){ - uint16_t mos_reg = gba_io_read16(gba,GBA_MOSAIC); - int mos_x = SB_BFE(mos_reg,8,4)+1; - int mos_y = SB_BFE(mos_reg,12,4)+1; - sx = ((x/mos_x)*mos_x-x_coord); - if(sx<0)sx=0; - sy = (sprite_lcd_y-y_coord)&0xff; + int priority = SB_BFE(attr2, 10, 2); + int palette = SB_BFE(attr2, 12, 4); + for(int x = x_start; x < x_end; ++x) { + int sx = (x - x_coord); + int sy = (sprite_lcd_y - y_coord) & 0xff; + if(mosaic) { + uint16_t mos_reg = gba_io_read16(gba, GBA_MOSAIC); + int mos_x = SB_BFE(mos_reg, 8, 4) + 1; + int mos_y = SB_BFE(mos_reg, 12, 4) + 1; + sx = ((x / mos_x) * mos_x - x_coord); + if(sx < 0) sx = 0; + sy = (sprite_lcd_y - y_coord) & 0xff; sy -= gba->ppu.mosaic_y_counter; - if(sy<0){sy =0;} + if(sy < 0) { sy = 0; } } - if(rot_scale){ - uint32_t param_base = rotscale_param*0x20; - int32_t a = *(int16_t*)(gba->mem.oam+param_base+0x6); - int32_t b = *(int16_t*)(gba->mem.oam+param_base+0xe); - int32_t c = *(int16_t*)(gba->mem.oam+param_base+0x16); - int32_t d = *(int16_t*)(gba->mem.oam+param_base+0x1e); - - int64_t x1 = sx<<8; - int64_t y1 = sy<<8; - int64_t objref_x = (x_size<<(double_size?8:7)); - int64_t objref_y = (y_size<<(double_size?8:7)); - - int64_t x2 = a*(x1-objref_x) + b*(y1-objref_y)+(x_size<<15); - int64_t y2 = c*(x1-objref_x) + d*(y1-objref_y)+(y_size<<15); - - sx = (x2>>16); - sy = (y2>>16); - if(sx>=x_size||sy>=y_size||sx<0||sy<0)continue; - }else{ - if(h_flip)sx=x_size-sx-1; - if(v_flip)sy=y_size-sy-1; + if(rot_scale) { + uint32_t param_base = rotscale_param * 0x20; + int32_t a = *(int16_t *)(gba->mem.oam + param_base + 0x6); + int32_t b = *(int16_t *)(gba->mem.oam + param_base + 0xe); + int32_t c = *(int16_t *)(gba->mem.oam + param_base + 0x16); + int32_t d = *(int16_t *)(gba->mem.oam + param_base + 0x1e); + + int64_t x1 = sx << 8; + int64_t y1 = sy << 8; + int64_t objref_x = (x_size << (double_size ? 8 : 7)); + int64_t objref_y = (y_size << (double_size ? 8 : 7)); + + int64_t x2 = a * (x1 - objref_x) + b * (y1 - objref_y) + (x_size << 15); + int64_t y2 = c * (x1 - objref_x) + d * (y1 - objref_y) + (y_size << 15); + + sx = (x2 >> 16); + sy = (y2 >> 16); + if(sx >= x_size || sy >= y_size || sx < 0 || sy < 0) continue; + } else { + if(h_flip) sx = x_size - sx - 1; + if(v_flip) sy = y_size - sy - 1; } - int tx = sx%8; - int ty = sy%8; - - int y_tile_stride = obj_vram_map_2d? 32 : x_size/8*(colors_or_palettes? 2:1); - int tile = tile_base + (((sx/8))*(colors_or_palettes? 2:1))+(sy/8)*y_tile_stride; - // Don't allow the column indices to overflow into the row indices in 2D mode. + int tx = sx % 8; + int ty = sy % 8; + + int y_tile_stride = obj_vram_map_2d ? 32 : x_size / 8 * (colors_or_palettes ? 2 : 1); + int tile = tile_base + (((sx / 8)) * (colors_or_palettes ? 2 : 1)) + (sy / 8) * y_tile_stride; + // Don't allow the column indices to overflow into the row indices in 2D mode. // See: https://github.com/skylersaleh/SkyEmu/issues/13 - if(obj_vram_map_2d){ - tile = (tile_base + (((sx/8))*(colors_or_palettes? 2:1)))&31; - tile|= (tile_base + (sy/8)*y_tile_stride)&~31; + if(obj_vram_map_2d) { + tile = (tile_base + (((sx / 8)) * (colors_or_palettes ? 2 : 1))) & 31; + tile |= (tile_base + (sy / 8) * y_tile_stride) & ~31; } - //Tiles >511 are not rendered in bg_mode3-5 since that memory is used to store the bitmap graphics. - if(tile<512&&bg_mode>=3&&bg_mode<=5)continue; + // Tiles >511 are not rendered in bg_mode3-5 since that memory is used to store the bitmap graphics. + if(tile < 512 && bg_mode >= 3 && bg_mode <= 5) continue; uint8_t palette_id; - int obj_tile_base = GBA_OBJ_TILES0_2; - bool transparent = false; - if(colors_or_palettes==false){ - palette_id= gba->mem.vram[obj_tile_base+tile*8*4+tx/2+ty*4]; - palette_id= (palette_id>>((tx&1)*4))&0xf; - transparent=palette_id==0; - palette_id+=palette*16; - }else{ - palette_id=gba->mem.vram[obj_tile_base+tile*8*4+tx+ty*8]; - transparent=palette_id==0; + int obj_tile_base = GBA_OBJ_TILES0_2; + bool transparent = false; + if(colors_or_palettes == false) { + palette_id = gba->mem.vram[obj_tile_base + tile * 8 * 4 + tx / 2 + ty * 4]; + palette_id = (palette_id >> ((tx & 1) * 4)) & 0xf; + transparent = palette_id == 0; + palette_id += palette * 16; + } else { + palette_id = gba->mem.vram[obj_tile_base + tile * 8 * 4 + tx + ty * 8]; + transparent = palette_id == 0; } - uint32_t col = *(uint16_t*)(gba->mem.palette+GBA_OBJ_PALETTE+palette_id*2); - //Handle window objects(not displayed but control the windowing of other things) - if(obj_mode==2&&!transparent){gba->window[x]=obj_window_control; - }else if(obj_mode!=3){ - int type =4; - col=col|(type<<17)|((5-priority)<<28)|((0x7)<<25); - if(obj_mode==1)col|=1<<16; - if((col>>17)>(gba->first_target_buffer[x]>>17)){ - if(transparent){ - //Update priority for transparent pixels (needed for golden sun) - if(SB_BFE(gba->first_target_buffer[x],17,3)!=5) - gba->first_target_buffer[x]=(gba->first_target_buffer[x]&(0x0fffffff))|(col&0xf0000000); - }else gba->first_target_buffer[x]=col; + uint32_t col = *(uint16_t *)(gba->mem.palette + GBA_OBJ_PALETTE + palette_id * 2); + // Handle window objects(not displayed but control the windowing of other things) + if(obj_mode == 2 && !transparent) { + gba->window[x] = obj_window_control; + } else if(obj_mode != 3) { + int type = 4; + col = col | (type << 17) | ((5 - priority) << 28) | ((0x7) << 25); + if(obj_mode == 1) col |= 1 << 16; + if((col >> 17) > (gba->first_target_buffer[x] >> 17)) { + if(transparent) { + // Update priority for transparent pixels (needed for golden sun) + if(SB_BFE(gba->first_target_buffer[x], 17, 3) != 5) + gba->first_target_buffer[x] = (gba->first_target_buffer[x] & (0x0fffffff)) | (col & 0xf0000000); + } else + gba->first_target_buffer[x] = col; } - } + } } } } } - int enabled_windows = SB_BFE(dispcnt,13,3); // [0: win0, 1:win1, 2: objwin] - if(enabled_windows){ - for(int win=1;win>=0;--win){ - bool win_enable = SB_BFE(dispcnt,13+win,1); - if(!win_enable)continue; - uint16_t WINH = gba_io_read16(gba, GBA_WIN0H+2*win); - uint16_t WINV = gba_io_read16(gba, GBA_WIN0V+2*win); - int win_xmin = SB_BFE(WINH,8,8); - int win_xmax = SB_BFE(WINH,0,8); - int win_ymin = SB_BFE(WINV,8,8); - int win_ymax = SB_BFE(WINV,0,8); + int enabled_windows = SB_BFE(dispcnt, 13, 3); // [0: win0, 1:win1, 2: objwin] + if(enabled_windows) { + for(int win = 1; win >= 0; --win) { + bool win_enable = SB_BFE(dispcnt, 13 + win, 1); + if(!win_enable) continue; + uint16_t WINH = gba_io_read16(gba, GBA_WIN0H + 2 * win); + uint16_t WINV = gba_io_read16(gba, GBA_WIN0V + 2 * win); + int win_xmin = SB_BFE(WINH, 8, 8); + int win_xmax = SB_BFE(WINH, 0, 8); + int win_ymin = SB_BFE(WINV, 8, 8); + int win_ymax = SB_BFE(WINV, 0, 8); // Garbage values of X2>240 or X1>X2 are interpreted as X2=240. - // Garbage values of Y2>160 or Y1>Y2 are interpreted as Y2=160. - if(win_xmin>win_xmax)win_xmax=240; - if(win_ymin>win_ymax)win_ymax=161; - if(win_xmax>240)win_xmax=240; - if(sprite_lcd_y=win_ymax)continue; - uint16_t winin = gba_io_read16(gba,GBA_WININ); - uint8_t win_value = SB_BFE(winin,win*8,6); - for(int x=win_xmin;xwindow[x] = win_value; - } - int backdrop_type = 5; - uint32_t backdrop_col = (*(uint16_t*)(gba->mem.palette + GBA_BG_PALETTE+0*2))|(backdrop_type<<17); - for(int x=0;x<240;++x){ + // Garbage values of Y2>160 or Y1>Y2 are interpreted as Y2=160. + if(win_xmin > win_xmax) win_xmax = 240; + if(win_ymin > win_ymax) win_ymax = 161; + if(win_xmax > 240) win_xmax = 240; + if(sprite_lcd_y < win_ymin || sprite_lcd_y >= win_ymax) continue; + uint16_t winin = gba_io_read16(gba, GBA_WININ); + uint8_t win_value = SB_BFE(winin, win * 8, 6); + for(int x = win_xmin; x < win_xmax; ++x) + gba->window[x] = win_value; + } + int backdrop_type = 5; + uint32_t backdrop_col = (*(uint16_t *)(gba->mem.palette + GBA_BG_PALETTE + 0 * 2)) | (backdrop_type << 17); + for(int x = 0; x < 240; ++x) { uint8_t window_control = gba->window[x]; - if(SB_BFE(window_control,4,1)==0)gba->first_target_buffer[x]=backdrop_col; - } - } - } - - if(visible){ - uint8_t window_control =gba->window[lcd_x]; - if(bg_mode==6 ||bg_mode==7){ - //Palette 0 is taken as the background - }else if (bg_mode<=5){ - for(int bg = 3; bg>=0;--bg){ - uint32_t col =0; - if((bg<2&&bg_mode==2)||(bg==3&&bg_mode==1)||(bg!=2&&bg_mode>=3))continue; - bool bg_en = SB_BFE(dispcnt,8+bg,1)&&SB_BFE(gba->ppu.dispcnt_pipeline[0],8+bg,1); - if(!bg_en || SB_BFE(window_control,bg,1)==0)continue; - - bool rot_scale = bg_mode>=1&&bg>=2; - uint16_t bgcnt = gba_io_read16(gba, GBA_BG0CNT+bg*2); - int priority = SB_BFE(bgcnt,0,2); - int character_base = SB_BFE(bgcnt,2,2); - bool mosaic = SB_BFE(bgcnt,6,1); - bool colors = SB_BFE(bgcnt,7,1); - int screen_base = SB_BFE(bgcnt,8,5); - bool display_overflow =SB_BFE(bgcnt,13,1); - int screen_size = SB_BFE(bgcnt,14,2); - - int screen_size_x = (screen_size&1)?512:256; - int screen_size_y = (screen_size>=2)?512:256; - + if(SB_BFE(window_control, 4, 1) == 0) gba->first_target_buffer[x] = backdrop_col; + } + } + } + + if(visible) { + uint8_t window_control = gba->window[lcd_x]; + if(bg_mode == 6 || bg_mode == 7) { + // Palette 0 is taken as the background + } else if(bg_mode <= 5) { + for(int bg = 3; bg >= 0; --bg) { + uint32_t col = 0; + if((bg < 2 && bg_mode == 2) || (bg == 3 && bg_mode == 1) || (bg != 2 && bg_mode >= 3)) continue; + bool bg_en = SB_BFE(dispcnt, 8 + bg, 1) && SB_BFE(gba->ppu.dispcnt_pipeline[0], 8 + bg, 1); + if(!bg_en || SB_BFE(window_control, bg, 1) == 0) continue; + + bool rot_scale = bg_mode >= 1 && bg >= 2; + uint16_t bgcnt = gba_io_read16(gba, GBA_BG0CNT + bg * 2); + int priority = SB_BFE(bgcnt, 0, 2); + int character_base = SB_BFE(bgcnt, 2, 2); + bool mosaic = SB_BFE(bgcnt, 6, 1); + bool colors = SB_BFE(bgcnt, 7, 1); + int screen_base = SB_BFE(bgcnt, 8, 5); + bool display_overflow = SB_BFE(bgcnt, 13, 1); + int screen_size = SB_BFE(bgcnt, 14, 2); + + int screen_size_x = (screen_size & 1) ? 512 : 256; + int screen_size_y = (screen_size >= 2) ? 512 : 256; + int bg_x = 0; int bg_y = 0; - - if(rot_scale){ - screen_size_x = screen_size_y = (16*8)<ppu.aff[bg-2].render_bgx; - int32_t bgy = gba->ppu.aff[bg-2].render_bgy; + int32_t bgx = gba->ppu.aff[bg - 2].render_bgx; + int32_t bgy = gba->ppu.aff[bg - 2].render_bgy; - int32_t a = (int16_t)gba_io_read16(gba,GBA_BG2PA+(bg-2)*0x10); - int32_t c = (int16_t)gba_io_read16(gba,GBA_BG2PC+(bg-2)*0x10); + int32_t a = (int16_t)gba_io_read16(gba, GBA_BG2PA + (bg - 2) * 0x10); + int32_t c = (int16_t)gba_io_read16(gba, GBA_BG2PC + (bg - 2) * 0x10); // Shift lcd_coords into fixed point - int64_t x2 = a*lcd_x + (((int64_t)bgx)); - int64_t y2 = c*lcd_x + (((int64_t)bgy)); - if(mosaic){ - int16_t mos_reg = gba_io_read16(gba,GBA_MOSAIC); - int mos_x = SB_BFE(mos_reg,0,4)+1; - x2 = a*((lcd_x/mos_x)*mos_x) + (((int64_t)bgx)); - y2 = c*((lcd_x/mos_x)*mos_x) + (((int64_t)bgy)); + int64_t x2 = a * lcd_x + (((int64_t)bgx)); + int64_t y2 = c * lcd_x + (((int64_t)bgy)); + if(mosaic) { + int16_t mos_reg = gba_io_read16(gba, GBA_MOSAIC); + int mos_x = SB_BFE(mos_reg, 0, 4) + 1; + x2 = a * ((lcd_x / mos_x) * mos_x) + (((int64_t)bgx)); + y2 = c * ((lcd_x / mos_x) * mos_x) + (((int64_t)bgy)); } + bg_x = (x2 >> 8); + bg_y = (y2 >> 8); - bg_x = (x2>>8); - bg_y = (y2>>8); - - if(display_overflow==0){ - if(bg_x<0||bg_x>=screen_size_x||bg_y<0||bg_y>=screen_size_y)continue; - }else{ - bg_x%=screen_size_x; - bg_y%=screen_size_y; + if(display_overflow == 0) { + if(bg_x < 0 || bg_x >= screen_size_x || bg_y < 0 || bg_y >= screen_size_y) continue; + } else { + bg_x %= screen_size_x; + bg_y %= screen_size_y; } - - }else{ - int16_t hoff = gba_io_read16(gba,GBA_BG0HOFS+bg*4); - int16_t voff = gba_io_read16(gba,GBA_BG0VOFS+bg*4); - hoff=(hoff<<7)>>7; - voff=(voff<<7)>>7; - bg_x = (hoff+lcd_x); - bg_y = (voff+lcd_y); - if(mosaic){ - uint16_t mos_reg = gba_io_read16(gba,GBA_MOSAIC); - int mos_x = SB_BFE(mos_reg,0,4)+1; - int mos_y = SB_BFE(mos_reg,4,4)+1; - bg_x = hoff+(lcd_x/mos_x)*mos_x; - bg_y = voff+(lcd_y/mos_y)*mos_y; + + } else { + int16_t hoff = gba_io_read16(gba, GBA_BG0HOFS + bg * 4); + int16_t voff = gba_io_read16(gba, GBA_BG0VOFS + bg * 4); + hoff = (hoff << 7) >> 7; + voff = (voff << 7) >> 7; + bg_x = (hoff + lcd_x); + bg_y = (voff + lcd_y); + if(mosaic) { + uint16_t mos_reg = gba_io_read16(gba, GBA_MOSAIC); + int mos_x = SB_BFE(mos_reg, 0, 4) + 1; + int mos_y = SB_BFE(mos_reg, 4, 4) + 1; + bg_x = hoff + (lcd_x / mos_x) * mos_x; + bg_y = voff + (lcd_y / mos_y) * mos_y; } } - if(bg_mode==3){ - int p = bg_x+bg_y*240; - int addr = p*2; - col = *(uint16_t*)(gba->mem.vram+addr); - }else if(bg_mode==4){ - int p = bg_x+bg_y*240; - int frame_sel = SB_BFE(dispcnt,4,1); - int addr = p*1+0xA000*frame_sel; + if(bg_mode == 3) { + int p = bg_x + bg_y * 240; + int addr = p * 2; + col = *(uint16_t *)(gba->mem.vram + addr); + } else if(bg_mode == 4) { + int p = bg_x + bg_y * 240; + int frame_sel = SB_BFE(dispcnt, 4, 1); + int addr = p * 1 + 0xA000 * frame_sel; uint8_t pallete_id = gba->mem.vram[addr]; - if(pallete_id==0)continue; - col = *(uint16_t*)(gba->mem.palette+GBA_BG_PALETTE+pallete_id*2); - }else if(bg_mode==5){ - int p = bg_x+bg_y*160; - int frame_sel = SB_BFE(dispcnt,4,1); - int addr = p*2+0xA000*frame_sel; - col = *(uint16_t*)(gba->mem.vram+addr); - }else{ - bg_x = bg_x&(screen_size_x-1); - bg_y = bg_y&(screen_size_y-1); - int bg_tile_x = bg_x/8; - int bg_tile_y = bg_y/8; - - int tile_off = bg_tile_y*(screen_size_x/8)+bg_tile_x; - - int screen_base_addr = screen_base*2048; - int character_base_addr = character_base*16*1024; - - uint16_t tile_data =0; - - int px = bg_x%8; - int py = bg_y%8; - - if(rot_scale)tile_data=gba->mem.vram[screen_base_addr+tile_off]; - else{ - int tile_off = (bg_tile_y%32)*32+(bg_tile_x%32); - if(bg_tile_x>=32)tile_off+=32*32; - if(bg_tile_y>=32)tile_off+=32*32*(screen_size==3?2:1); - tile_data=*(uint16_t*)(gba->mem.vram+screen_base_addr+tile_off*2); - - int h_flip = SB_BFE(tile_data,10,1); - int v_flip = SB_BFE(tile_data,11,1); - if(h_flip)px=7-px; - if(v_flip)py=7-py; + if(pallete_id == 0) continue; + col = *(uint16_t *)(gba->mem.palette + GBA_BG_PALETTE + pallete_id * 2); + } else if(bg_mode == 5) { + int p = bg_x + bg_y * 160; + int frame_sel = SB_BFE(dispcnt, 4, 1); + int addr = p * 2 + 0xA000 * frame_sel; + col = *(uint16_t *)(gba->mem.vram + addr); + } else { + bg_x = bg_x & (screen_size_x - 1); + bg_y = bg_y & (screen_size_y - 1); + int bg_tile_x = bg_x / 8; + int bg_tile_y = bg_y / 8; + + int tile_off = bg_tile_y * (screen_size_x / 8) + bg_tile_x; + + int screen_base_addr = screen_base * 2048; + int character_base_addr = character_base * 16 * 1024; + + uint16_t tile_data = 0; + + int px = bg_x % 8; + int py = bg_y % 8; + + if(rot_scale) + tile_data = gba->mem.vram[screen_base_addr + tile_off]; + else { + int tile_off = (bg_tile_y % 32) * 32 + (bg_tile_x % 32); + if(bg_tile_x >= 32) tile_off += 32 * 32; + if(bg_tile_y >= 32) tile_off += 32 * 32 * (screen_size == 3 ? 2 : 1); + tile_data = *(uint16_t *)(gba->mem.vram + screen_base_addr + tile_off * 2); + + int h_flip = SB_BFE(tile_data, 10, 1); + int v_flip = SB_BFE(tile_data, 11, 1); + if(h_flip) px = 7 - px; + if(v_flip) py = 7 - py; } - int tile_id = SB_BFE(tile_data,0,10); - int palette = SB_BFE(tile_data,12,4); - - uint8_t tile_d=tile_id; - if(colors==false){ - int addr = character_base_addr+tile_id*8*4+px/2+py*4; - tile_d=gba->mem.vram[addr]; - tile_d= (tile_d>>((px&1)*4))&0xf; - //There is an undocumented GBA quirk where tiles over 64KB are not loaded - //https://github.com/skylersaleh/SkyEmu/issues/292 - if(tile_d==0||SB_UNLIKELY(addr>=0x10000))continue; - tile_d+=palette*16; - }else{ - //There is an undocumented GBA quirk where tiles over 64KB are not loaded - //https://github.com/skylersaleh/SkyEmu/issues/292 - int addr=character_base_addr+tile_id*8*8+px+py*8; - tile_d=gba->mem.vram[addr]; - if(tile_d==0||SB_UNLIKELY(addr>=0x10000))continue; + int tile_id = SB_BFE(tile_data, 0, 10); + int palette = SB_BFE(tile_data, 12, 4); + + uint8_t tile_d = tile_id; + if(colors == false) { + int addr = character_base_addr + tile_id * 8 * 4 + px / 2 + py * 4; + tile_d = gba->mem.vram[addr]; + tile_d = (tile_d >> ((px & 1) * 4)) & 0xf; + // There is an undocumented GBA quirk where tiles over 64KB are not loaded + // https://github.com/skylersaleh/SkyEmu/issues/292 + if(tile_d == 0 || SB_UNLIKELY(addr >= 0x10000)) continue; + tile_d += palette * 16; + } else { + // There is an undocumented GBA quirk where tiles over 64KB are not loaded + // https://github.com/skylersaleh/SkyEmu/issues/292 + int addr = character_base_addr + tile_id * 8 * 8 + px + py * 8; + tile_d = gba->mem.vram[addr]; + if(tile_d == 0 || SB_UNLIKELY(addr >= 0x10000)) continue; } uint8_t pallete_id = tile_d; - col = *(uint16_t*)(gba->mem.palette+GBA_BG_PALETTE+pallete_id*2); + col = *(uint16_t *)(gba->mem.palette + GBA_BG_PALETTE + pallete_id * 2); } - col |= (bg<<17) | ((5-priority)<<28)|((4-bg)<<25); - if(col>gba->first_target_buffer[lcd_x]){ + col |= (bg << 17) | ((5 - priority) << 28) | ((4 - bg) << 25); + if(col > gba->first_target_buffer[lcd_x]) { uint32_t t = gba->first_target_buffer[lcd_x]; - gba->first_target_buffer[lcd_x]=col; + gba->first_target_buffer[lcd_x] = col; col = t; } - if(col>gba->second_target_buffer[lcd_x])gba->second_target_buffer[lcd_x]=col; + if(col > gba->second_target_buffer[lcd_x]) gba->second_target_buffer[lcd_x] = col; } } uint32_t col = gba->first_target_buffer[lcd_x]; - int r = SB_BFE(col,0,5); - int g = SB_BFE(col,5,5); - int b = SB_BFE(col,10,5); - uint32_t type = SB_BFE(col,17,3); + int r = SB_BFE(col, 0, 5); + int g = SB_BFE(col, 5, 5); + int b = SB_BFE(col, 10, 5); + uint32_t type = SB_BFE(col, 17, 3); - bool effect_enable = SB_BFE(window_control,5,1); - uint16_t bldcnt = gba_io_read16(gba,GBA_BLDCNT); - int mode = SB_BFE(bldcnt,6,2); + bool effect_enable = SB_BFE(window_control, 5, 1); + uint16_t bldcnt = gba_io_read16(gba, GBA_BLDCNT); + int mode = SB_BFE(bldcnt, 6, 2); - //Semitransparent objects are always selected for blending - if(SB_BFE(col,16,1)){ + // Semitransparent objects are always selected for blending + if(SB_BFE(col, 16, 1)) { uint32_t col2 = gba->second_target_buffer[lcd_x]; - uint32_t type2 = SB_BFE(col2,17,3); - bool blend = SB_BFE(bldcnt,8+type2,1); - if(blend){mode=1;effect_enable=true;} - else effect_enable &= SB_BFE(bldcnt,type,1); - }else effect_enable &= SB_BFE(bldcnt,type,1); - if(effect_enable){ - uint16_t bldy = gba_io_read16(gba,GBA_BLDY); - float evy = SB_BFE(bldy,0,5)/16.; - if(evy>1.0)evy=1; - switch(mode){ - case 0: break; //None - case 1: { - uint32_t col2 = gba->second_target_buffer[lcd_x]; - uint32_t type2 = SB_BFE(col2,17,3); - bool blend = SB_BFE(bldcnt,8+type2,1); - if(blend){ - uint16_t bldalpha= gba_io_read16(gba,GBA_BLDALPHA); - int r2 = SB_BFE(col2,0,5); - int g2 = SB_BFE(col2,5,5); - int b2 = SB_BFE(col2,10,5); - int eva = SB_BFE(bldalpha,0,5); - int evb = SB_BFE(bldalpha,8,5); - if(eva>16)eva=16; - if(evb>16)evb=16; - r = (r*eva+r2*evb)/16; - g = (g*eva+g2*evb)/16; - b = (b*eva+b2*evb)/16; - if(r>31)r = 31; - if(g>31)g = 31; - if(b>31)b = 31; - } - }break; //Alpha Blend - case 2: //Lighten - r = r+(31-r)*evy; - g = g+(31-g)*evy; - b = b+(31-b)*evy; - break; - case 3: //Darken - r = r-(r)*evy; - g = g-(g)*evy; - b = b-(b)*evy; - break; - } - } - if(forced_blank){ - r=g=b=255; - if(gba->stop_mode)r=g=b=0; - } - - int backdrop_type = 5; - uint32_t backdrop_col = (*(uint16_t*)(gba->mem.palette + GBA_BG_PALETTE+0*2))|(backdrop_type<<17); + uint32_t type2 = SB_BFE(col2, 17, 3); + bool blend = SB_BFE(bldcnt, 8 + type2, 1); + if(blend) { + mode = 1; + effect_enable = true; + } else + effect_enable &= SB_BFE(bldcnt, type, 1); + } else + effect_enable &= SB_BFE(bldcnt, type, 1); + if(effect_enable) { + uint16_t bldy = gba_io_read16(gba, GBA_BLDY); + float evy = SB_BFE(bldy, 0, 5) / 16.; + if(evy > 1.0) evy = 1; + switch(mode) { + case 0: break; // None + case 1: { + uint32_t col2 = gba->second_target_buffer[lcd_x]; + uint32_t type2 = SB_BFE(col2, 17, 3); + bool blend = SB_BFE(bldcnt, 8 + type2, 1); + if(blend) { + uint16_t bldalpha = gba_io_read16(gba, GBA_BLDALPHA); + int r2 = SB_BFE(col2, 0, 5); + int g2 = SB_BFE(col2, 5, 5); + int b2 = SB_BFE(col2, 10, 5); + int eva = SB_BFE(bldalpha, 0, 5); + int evb = SB_BFE(bldalpha, 8, 5); + if(eva > 16) eva = 16; + if(evb > 16) evb = 16; + r = (r * eva + r2 * evb) / 16; + g = (g * eva + g2 * evb) / 16; + b = (b * eva + b2 * evb) / 16; + if(r > 31) r = 31; + if(g > 31) g = 31; + if(b > 31) b = 31; + } + } break; // Alpha Blend + case 2: // Lighten + r = r + (31 - r) * evy; + g = g + (31 - g) * evy; + b = b + (31 - b) * evy; + break; + case 3: // Darken + r = r - (r)*evy; + g = g - (g)*evy; + b = b - (b)*evy; + break; + } + } + if(forced_blank) { + r = g = b = 255; + if(gba->stop_mode) r = g = b = 0; + } + + int backdrop_type = 5; + uint32_t backdrop_col = (*(uint16_t *)(gba->mem.palette + GBA_BG_PALETTE + 0 * 2)) | (backdrop_type << 17); gba->first_target_buffer[lcd_x] = backdrop_col; gba->second_target_buffer[lcd_x] = backdrop_col; - int p = (lcd_x+lcd_y*240)*4; - float screen_blend_factor = 0.3*gba->ppu.ghosting_strength; - uint16_t green_swap = gba_io_read16(gba,GBA_GREENSWP); - gba->framebuffer[p+0] = r*8*(1.0-screen_blend_factor)+gba->framebuffer[p+0]*screen_blend_factor; - gba->framebuffer[p+2] = b*8*(1.0-screen_blend_factor)+gba->framebuffer[p+2]*screen_blend_factor; + int p = (lcd_x + lcd_y * 240) * 4; + float screen_blend_factor = 0.3 * gba->ppu.ghosting_strength; + uint16_t green_swap = gba_io_read16(gba, GBA_GREENSWP); + gba->framebuffer[p + 0] = r * 8 * (1.0 - screen_blend_factor) + gba->framebuffer[p + 0] * screen_blend_factor; + gba->framebuffer[p + 2] = b * 8 * (1.0 - screen_blend_factor) + gba->framebuffer[p + 2] * screen_blend_factor; - if(green_swap&1){ - if(p&4) gba->framebuffer[p+1-4] = g*8*(1.0-screen_blend_factor)+gba->framebuffer[p+1-4]*screen_blend_factor; - else gba->framebuffer[p+1+4] = g*8*(1.0-screen_blend_factor)+gba->framebuffer[p+1+4]*screen_blend_factor; - }else{ - gba->framebuffer[p+1] = g*8*(1.0-screen_blend_factor)+gba->framebuffer[p+1]*screen_blend_factor; + if(green_swap & 1) { + if(p & 4) + gba->framebuffer[p + 1 - 4] = g * 8 * (1.0 - screen_blend_factor) + gba->framebuffer[p + 1 - 4] * screen_blend_factor; + else + gba->framebuffer[p + 1 + 4] = g * 8 * (1.0 - screen_blend_factor) + gba->framebuffer[p + 1 + 4] * screen_blend_factor; + } else { + gba->framebuffer[p + 1] = g * 8 * (1.0 - screen_blend_factor) + gba->framebuffer[p + 1] * screen_blend_factor; } } } -static void gba_tick_keypad(sb_joy_t*joy, gba_t* gba){ +static void gba_tick_keypad(sb_joy_t *joy, gba_t *gba) { uint16_t reg_value = 0; - //Null joy updates are used to tick the joypad when mmios are set - if(joy){ - reg_value|= !(joy->inputs[SE_KEY_A]>0.3) <<0; - reg_value|= !(joy->inputs[SE_KEY_B]>0.3) <<1; - reg_value|= !(joy->inputs[SE_KEY_SELECT]>0.3)<<2; - reg_value|= !(joy->inputs[SE_KEY_START]>0.3) <<3; - reg_value|= !(joy->inputs[SE_KEY_RIGHT]>0.3) <<4; - reg_value|= !(joy->inputs[SE_KEY_LEFT]>0.3) <<5; - reg_value|= !(joy->inputs[SE_KEY_UP]>0.3) <<6; - reg_value|= !(joy->inputs[SE_KEY_DOWN]>0.3) <<7; - reg_value|= !(joy->inputs[SE_KEY_R]>0.3) <<8; - reg_value|= !(joy->inputs[SE_KEY_L]>0.3) <<9; + // Null joy updates are used to tick the joypad when mmios are set + if(joy) { + reg_value |= !(joy->inputs[SE_KEY_A] > 0.3) << 0; + reg_value |= !(joy->inputs[SE_KEY_B] > 0.3) << 1; + reg_value |= !(joy->inputs[SE_KEY_SELECT] > 0.3) << 2; + reg_value |= !(joy->inputs[SE_KEY_START] > 0.3) << 3; + reg_value |= !(joy->inputs[SE_KEY_RIGHT] > 0.3) << 4; + reg_value |= !(joy->inputs[SE_KEY_LEFT] > 0.3) << 5; + reg_value |= !(joy->inputs[SE_KEY_UP] > 0.3) << 6; + reg_value |= !(joy->inputs[SE_KEY_DOWN] > 0.3) << 7; + reg_value |= !(joy->inputs[SE_KEY_R] > 0.3) << 8; + reg_value |= !(joy->inputs[SE_KEY_L] > 0.3) << 9; gba_io_store16(gba, GBA_KEYINPUT, reg_value); - }else reg_value = gba_io_read16(gba, GBA_KEYINPUT); + } else + reg_value = gba_io_read16(gba, GBA_KEYINPUT); - uint16_t keycnt = gba_io_read16(gba,GBA_KEYCNT); - bool irq_enable = SB_BFE(keycnt,14,1); - bool irq_condition = SB_BFE(keycnt,15,1);//[0: any key, 1: all keys] - int if_bit = 0; - if(irq_enable||gba->stop_mode){ - uint16_t pressed = SB_BFE(reg_value,0,10)^0x3ff; - uint16_t mask = SB_BFE(keycnt,0,10); + uint16_t keycnt = gba_io_read16(gba, GBA_KEYCNT); + bool irq_enable = SB_BFE(keycnt, 14, 1); + bool irq_condition = SB_BFE(keycnt, 15, 1); //[0: any key, 1: all keys] + int if_bit = 0; + if(irq_enable || gba->stop_mode) { + uint16_t pressed = SB_BFE(reg_value, 0, 10) ^ 0x3ff; + uint16_t mask = SB_BFE(keycnt, 0, 10); - if(irq_condition&&((pressed&mask)==mask))if_bit|= 1<stop_mode=false; + if(if_bit) gba->stop_mode = false; - if(if_bit&&!gba->prev_key_interrupt&&irq_enable){ - gba_send_interrupt(gba,4,if_bit); + if(if_bit && !gba->prev_key_interrupt && irq_enable) { + gba_send_interrupt(gba, 4, if_bit); gba->prev_key_interrupt = true; - }else gba->prev_key_interrupt = false; - + } else + gba->prev_key_interrupt = false; } - } -uint64_t gba_read_eeprom_bitstream(gba_t *gba, uint32_t source_address, int offset, int size, int elem_size, int dir){ - uint64_t data = 0; - for(int i=0;i>(size-i-1)&1); +void gba_store_eeprom_bitstream(gba_t *gba, uint32_t source_address, int offset, int size, int elem_size, int dir, uint64_t data) { + for(int i = 0; i < size; ++i) { + gba_store16(gba, source_address + (i + offset) * elem_size * dir, data >> (size - i - 1) & 1); } } -static FORCE_INLINE int gba_tick_dma(gba_t*gba, int last_tick){ - int ticks =0; - gba->activate_dmas=false; - gba->dma_wait_ppu=false; - for(int i=0;i<4;++i){ - uint16_t cnt_h=gba_io_read16(gba, GBA_DMA0CNT_H+12*i); - bool enable = SB_BFE(cnt_h,15,1); - if(enable){ - bool type = SB_BFE(cnt_h,10,1); // 0: 16b 1:32b - - if(!gba->dma[i].last_enable){ +static FORCE_INLINE int gba_tick_dma(gba_t *gba, int last_tick) { + int ticks = 0; + gba->activate_dmas = false; + gba->dma_wait_ppu = false; + for(int i = 0; i < 4; ++i) { + uint16_t cnt_h = gba_io_read16(gba, GBA_DMA0CNT_H + 12 * i); + bool enable = SB_BFE(cnt_h, 15, 1); + if(enable) { + bool type = SB_BFE(cnt_h, 10, 1); // 0: 16b 1:32b + + if(!gba->dma[i].last_enable) { gba->dma[i].last_enable = enable; - gba->dma[i].source_addr=gba_io_read32(gba,GBA_DMA0SAD+12*i); - gba->dma[i].dest_addr=gba_io_read32(gba,GBA_DMA0DAD+12*i); - //GBA Suite says that these need to be force aligned - if(type){ - gba->dma[i].dest_addr&=~3; - gba->dma[i].source_addr&=~3; - }else{ - gba->dma[i].dest_addr&=~1; - gba->dma[i].source_addr&=~1; - } - gba->dma[i].current_transaction=0; - gba->dma[i].startup_delay=2; - } - int dst_addr_ctl = SB_BFE(cnt_h,5,2); // 0: incr 1: decr 2: fixed 3: incr reload - int src_addr_ctl = SB_BFE(cnt_h,7,2); // 0: incr 1: decr 2: fixed 3: not allowed - bool dma_repeat = SB_BFE(cnt_h,9,1); - int mode = SB_BFE(cnt_h,12,2); - bool irq_enable = SB_BFE(cnt_h,14,1); + gba->dma[i].source_addr = gba_io_read32(gba, GBA_DMA0SAD + 12 * i); + gba->dma[i].dest_addr = gba_io_read32(gba, GBA_DMA0DAD + 12 * i); + // GBA Suite says that these need to be force aligned + if(type) { + gba->dma[i].dest_addr &= ~3; + gba->dma[i].source_addr &= ~3; + } else { + gba->dma[i].dest_addr &= ~1; + gba->dma[i].source_addr &= ~1; + } + gba->dma[i].current_transaction = 0; + gba->dma[i].startup_delay = 2; + } + int dst_addr_ctl = SB_BFE(cnt_h, 5, 2); // 0: incr 1: decr 2: fixed 3: incr reload + int src_addr_ctl = SB_BFE(cnt_h, 7, 2); // 0: incr 1: decr 2: fixed 3: not allowed + bool dma_repeat = SB_BFE(cnt_h, 9, 1); + int mode = SB_BFE(cnt_h, 12, 2); + bool irq_enable = SB_BFE(cnt_h, 14, 1); bool force_first_write_sequential = false; - int transfer_bytes = type? 4:2; + int transfer_bytes = type ? 4 : 2; bool skip_dma = false; - if(gba->dma[i].current_transaction==0){ - if(mode==3 && i ==0)continue; - if(gba->dma[i].startup_delay>=0){ - gba->dma[i].startup_delay-=last_tick; - if(gba->dma[i].startup_delay>=0){ - gba->activate_dmas=true; + if(gba->dma[i].current_transaction == 0) { + if(mode == 3 && i == 0) continue; + if(gba->dma[i].startup_delay >= 0) { + gba->dma[i].startup_delay -= last_tick; + if(gba->dma[i].startup_delay >= 0) { + gba->activate_dmas = true; continue; } - gba->dma[i].startup_delay=-1; + gba->dma[i].startup_delay = -1; } - if(dst_addr_ctl==3){ - gba->dma[i].dest_addr=gba_io_read32(gba,GBA_DMA0DAD+12*i); + if(dst_addr_ctl == 3) { + gba->dma[i].dest_addr = gba_io_read32(gba, GBA_DMA0DAD + 12 * i); } bool last_vblank = gba->dma[i].last_vblank; bool last_hblank = gba->dma[i].last_hblank; gba->dma[i].last_vblank = gba->ppu.last_vblank; gba->dma[i].last_hblank = gba->ppu.last_hblank; - if(mode ==1 && (!gba->ppu.last_vblank||last_vblank)){ - gba->dma_wait_ppu=true; - continue; - } - if(mode==2){ - gba->dma_wait_ppu=true; - uint16_t vcount = gba_io_read16(gba,GBA_VCOUNT); - if(vcount>=160||!gba->ppu.last_hblank||last_hblank)continue; + if(mode == 1 && (!gba->ppu.last_vblank || last_vblank)) { + gba->dma_wait_ppu = true; + continue; } - //Video dma - if(mode==3 && i ==3){ - gba->dma_wait_ppu=true; - uint16_t vcount = gba_io_read16(gba,GBA_VCOUNT); - if(!gba->ppu.last_hblank||last_hblank)continue; - //Video dma starts at scanline 2 - if(vcount==2){gba->dma[i].video_dma_active=true;} - if(!gba->dma[i].video_dma_active)continue; - if(vcount==161){ - dma_repeat=false; - gba->dma[i].video_dma_active=false; + if(mode == 2) { + gba->dma_wait_ppu = true; + uint16_t vcount = gba_io_read16(gba, GBA_VCOUNT); + if(vcount >= 160 || !gba->ppu.last_hblank || last_hblank) continue; + } + // Video dma + if(mode == 3 && i == 3) { + gba->dma_wait_ppu = true; + uint16_t vcount = gba_io_read16(gba, GBA_VCOUNT); + if(!gba->ppu.last_hblank || last_hblank) continue; + // Video dma starts at scanline 2 + if(vcount == 2) { gba->dma[i].video_dma_active = true; } + if(!gba->dma[i].video_dma_active) continue; + if(vcount == 161) { + dma_repeat = false; + gba->dma[i].video_dma_active = false; } } - - if(dst_addr_ctl==3){ - gba->dma[i].dest_addr=gba_io_read32(gba,GBA_DMA0DAD+12*i); - //GBA Suite says that these need to be force aligned - if(type) gba->dma[i].dest_addr&=~3; - else gba->dma[i].dest_addr&=~1; + + if(dst_addr_ctl == 3) { + gba->dma[i].dest_addr = gba_io_read32(gba, GBA_DMA0DAD + 12 * i); + // GBA Suite says that these need to be force aligned + if(type) + gba->dma[i].dest_addr &= ~3; + else + gba->dma[i].dest_addr &= ~1; } - bool audio_dma = (mode==3) && (i==1||i==2); - if(audio_dma){ - if(gba->dma[i].activate_audio_dma==false)continue; - gba->dma[i].activate_audio_dma=false; - int fifo = -1; + bool audio_dma = (mode == 3) && (i == 1 || i == 2); + if(audio_dma) { + if(gba->dma[i].activate_audio_dma == false) continue; + gba->dma[i].activate_audio_dma = false; + int fifo = -1; uint32_t dst = gba->dma[i].dest_addr; - if(dst == GBA_FIFO_A)fifo =0; - if(dst == GBA_FIFO_B)fifo =1; - if(fifo == -1)continue; - } - if(gba->dma[i].source_addr>=0x08000000&&gba->dma[i].dest_addr>=0x08000000){ - force_first_write_sequential=true; - }else{ - if(gba->dma[i].dest_addr>=0x08000000){ + if(dst == GBA_FIFO_A) fifo = 0; + if(dst == GBA_FIFO_B) fifo = 1; + if(fifo == -1) continue; + } + if(gba->dma[i].source_addr >= 0x08000000 && gba->dma[i].dest_addr >= 0x08000000) { + force_first_write_sequential = true; + } else { + if(gba->dma[i].dest_addr >= 0x08000000) { // Allow the in process prefetech to finish before starting DMA - if(!gba->mem.prefetch_size&&gba->mem.prefetch_en)ticks+=gba_compute_access_cycles_dma(gba,gba->dma[i].dest_addr,2)>4; + if(!gba->mem.prefetch_size && gba->mem.prefetch_en) ticks += gba_compute_access_cycles_dma(gba, gba->dma[i].dest_addr, 2) > 4; } } - if(gba->dma[i].source_addr>=0x08000000){ - if(gba->mem.prefetch_en)ticks+=gba_compute_access_cycles_dma(gba,gba->dma[i].source_addr,2)<=4; - } - gba->last_transaction_dma=true; - uint32_t cnt = gba_io_read16(gba,GBA_DMA0CNT_L+12*i); - - if(i!=3)cnt&=0x3fff; - if(cnt==0)cnt = i==3? 0x10000: 0x4000; - - static const uint32_t src_mask[] = { 0x07FFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; - static const uint32_t dst_mask[] = { 0x07FFFFFF, 0x07FFFFFF, 0x07FFFFFF, 0x0FFFFFFF}; - gba->dma[i].source_addr&=src_mask[i]; - gba->dma[i].dest_addr &=dst_mask[i]; - gba_io_store16(gba,GBA_DMA0CNT_L+12*i,cnt); - - if(src_addr_ctl==0&&(dst_addr_ctl==0||dst_addr_ctl==3)&&cnt>2){ - int fast_dma_count = cnt-2; - int bytes = fast_dma_count*transfer_bytes; - int src_addr = gba->dma[i].source_addr; - int dst_addr = gba->dma[i].dest_addr; - - uint8_t *source_start = (uint8_t*)gba_dword_lookup(gba,src_addr,transfer_bytes|GBA_REQ_READ)+(src_addr&2); - uint8_t *dest_start = (uint8_t*)gba_dword_lookup(gba,dst_addr,transfer_bytes|GBA_REQ_WRITE)+(dst_addr&2); - uint8_t *source_end = (uint8_t*)gba_dword_lookup(gba,src_addr+bytes,transfer_bytes|GBA_REQ_READ)+(src_addr&2); - uint8_t *dest_end = (uint8_t*)gba_dword_lookup(gba,dst_addr+bytes,transfer_bytes|GBA_REQ_WRITE)+(dst_addr&2); - if(source_end-source_start==bytes&&dest_end-dest_start==bytes){ - bool overlaps_io = src_addr<=0x04000000&&src_addr+bytes>=0x04000000; - overlaps_io |= dst_addr<=0x05000000&&dst_addr+bytes>=0x04000000; - if((src_addr<0x08000000)&&(src_addr>=0x02000000)&&!overlaps_io){ + if(gba->dma[i].source_addr >= 0x08000000) { + if(gba->mem.prefetch_en) ticks += gba_compute_access_cycles_dma(gba, gba->dma[i].source_addr, 2) <= 4; + } + gba->last_transaction_dma = true; + uint32_t cnt = gba_io_read16(gba, GBA_DMA0CNT_L + 12 * i); + + if(i != 3) cnt &= 0x3fff; + if(cnt == 0) cnt = i == 3 ? 0x10000 : 0x4000; + + static const uint32_t src_mask[] = {0x07FFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; + static const uint32_t dst_mask[] = {0x07FFFFFF, 0x07FFFFFF, 0x07FFFFFF, 0x0FFFFFFF}; + gba->dma[i].source_addr &= src_mask[i]; + gba->dma[i].dest_addr &= dst_mask[i]; + gba_io_store16(gba, GBA_DMA0CNT_L + 12 * i, cnt); + + if(src_addr_ctl == 0 && (dst_addr_ctl == 0 || dst_addr_ctl == 3) && cnt > 2) { + int fast_dma_count = cnt - 2; + int bytes = fast_dma_count * transfer_bytes; + int src_addr = gba->dma[i].source_addr; + int dst_addr = gba->dma[i].dest_addr; + + uint8_t *source_start = (uint8_t *)gba_dword_lookup(gba, src_addr, transfer_bytes | GBA_REQ_READ) + (src_addr & 2); + uint8_t *dest_start = (uint8_t *)gba_dword_lookup(gba, dst_addr, transfer_bytes | GBA_REQ_WRITE) + (dst_addr & 2); + uint8_t *source_end = (uint8_t *)gba_dword_lookup(gba, src_addr + bytes, transfer_bytes | GBA_REQ_READ) + (src_addr & 2); + uint8_t *dest_end = (uint8_t *)gba_dword_lookup(gba, dst_addr + bytes, transfer_bytes | GBA_REQ_WRITE) + (dst_addr & 2); + if(source_end - source_start == bytes && dest_end - dest_start == bytes) { + bool overlaps_io = src_addr <= 0x04000000 && src_addr + bytes >= 0x04000000; + overlaps_io |= dst_addr <= 0x05000000 && dst_addr + bytes >= 0x04000000; + if((src_addr < 0x08000000) && (src_addr >= 0x02000000) && !overlaps_io) { // Restrict the amount of cycles that can be spent on a fast DMA to avoid missing - // events for very large DMAs. - if(fast_dma_count>128)fast_dma_count=128; - bytes = fast_dma_count*transfer_bytes; - memmove(dest_start,source_start, bytes); - gba->dma[i].current_transaction=fast_dma_count; - int trans_type = type?2:0; + // events for very large DMAs. + if(fast_dma_count > 128) fast_dma_count = 128; + bytes = fast_dma_count * transfer_bytes; + memmove(dest_start, source_start, bytes); + gba->dma[i].current_transaction = fast_dma_count; + int trans_type = type ? 2 : 0; // First non-sequential fetch - ticks+=gba_compute_access_cycles_dma(gba, gba->dma[i].dest_addr,trans_type+(force_first_write_sequential?0:1)); - ticks+=gba_compute_access_cycles_dma(gba, src_addr, trans_type+1); + ticks += gba_compute_access_cycles_dma(gba, gba->dma[i].dest_addr, trans_type + (force_first_write_sequential ? 0 : 1)); + ticks += gba_compute_access_cycles_dma(gba, src_addr, trans_type + 1); // Remaining sequential fetches - ticks+=gba_compute_access_cycles_dma(gba, gba->dma[i].dest_addr, trans_type)*(fast_dma_count-1); - ticks+=gba_compute_access_cycles_dma(gba, src_addr, trans_type)*(fast_dma_count-1); + ticks += gba_compute_access_cycles_dma(gba, gba->dma[i].dest_addr, trans_type) * (fast_dma_count - 1); + ticks += gba_compute_access_cycles_dma(gba, src_addr, trans_type) * (fast_dma_count - 1); } } } } - const static int dir_lookup[4]={1,-1,0,1}; - int src_dir = dir_lookup[src_addr_ctl]; - int dst_dir = dir_lookup[dst_addr_ctl]; + const static int dir_lookup[4] = {1, -1, 0, 1}; + int src_dir = dir_lookup[src_addr_ctl]; + int dst_dir = dir_lookup[dst_addr_ctl]; uint32_t src = gba->dma[i].source_addr; uint32_t dst = gba->dma[i].dest_addr; - uint32_t cnt = gba_io_read16(gba,GBA_DMA0CNT_L+12*i); + uint32_t cnt = gba_io_read16(gba, GBA_DMA0CNT_L + 12 * i); // ROM ignores direction and always increments - if(src>=0x08000000&&src<0x0e000000) src_dir=1; - if(dst>=0x08000000&&dst<0x0e000000) dst_dir=1; + if(src >= 0x08000000 && src < 0x0e000000) src_dir = 1; + if(dst >= 0x08000000 && dst < 0x0e000000) dst_dir = 1; // EEPROM DMA transfers - if(i==3 && gba->cart.backup_type==GBA_BACKUP_EEPROM){ - int src_in_eeprom = (src&0x1ffffff)>=gba->cart.rom_size||(src&0x1ffffff)>=0x01ffff00; - int dst_in_eeprom = (dst&0x1ffffff)>=gba->cart.rom_size||(dst&0x1ffffff)>=0x01ffff00; - src_in_eeprom &= src>=0x8000000 && src<=0xDFFFFFF; - dst_in_eeprom &= dst>=0x8000000 && dst<=0xDFFFFFF; + if(i == 3 && gba->cart.backup_type == GBA_BACKUP_EEPROM) { + int src_in_eeprom = (src & 0x1ffffff) >= gba->cart.rom_size || (src & 0x1ffffff) >= 0x01ffff00; + int dst_in_eeprom = (dst & 0x1ffffff) >= gba->cart.rom_size || (dst & 0x1ffffff) >= 0x01ffff00; + src_in_eeprom &= src >= 0x8000000 && src <= 0xDFFFFFF; + dst_in_eeprom &= dst >= 0x8000000 && dst <= 0xDFFFFFF; skip_dma = src_in_eeprom || dst_in_eeprom; - if(dst_in_eeprom){ - if(cnt==73){ + if(dst_in_eeprom) { + if(cnt == 73) { // Write data 6 bit address - uint32_t addr = gba_read_eeprom_bitstream(gba, src, 2, 6, type?4:2, src_dir); - uint64_t data = gba_read_eeprom_bitstream(gba, src, 2+6, 64, type?4:2, src_dir); - ((uint64_t*)gba->mem.cart_backup)[addr]=data; - gba->cart.backup_is_dirty=true; - }else if(cnt==81){ + uint32_t addr = gba_read_eeprom_bitstream(gba, src, 2, 6, type ? 4 : 2, src_dir); + uint64_t data = gba_read_eeprom_bitstream(gba, src, 2 + 6, 64, type ? 4 : 2, src_dir); + ((uint64_t *)gba->mem.cart_backup)[addr] = data; + gba->cart.backup_is_dirty = true; + } else if(cnt == 81) { // Write data 14 bit address - uint32_t addr = gba_read_eeprom_bitstream(gba, src, 2, 14, type?4:2, src_dir)&0x3ff; - uint64_t data = gba_read_eeprom_bitstream(gba, src, 2+14, 64, type?4:2, src_dir); - ((uint64_t*)gba->mem.cart_backup)[addr]=data; - gba->cart.backup_is_dirty=true; - }else if(cnt==9){ + uint32_t addr = gba_read_eeprom_bitstream(gba, src, 2, 14, type ? 4 : 2, src_dir) & 0x3ff; + uint64_t data = gba_read_eeprom_bitstream(gba, src, 2 + 14, 64, type ? 4 : 2, src_dir); + ((uint64_t *)gba->mem.cart_backup)[addr] = data; + gba->cart.backup_is_dirty = true; + } else if(cnt == 9) { // 2 bits "11" (Read Request) // 6 bits eeprom address (MSB first) // 1 bit "0" // Write data 6 bit address - gba->mem.eeprom_addr = gba_read_eeprom_bitstream(gba, src, 2, 6, type?4:2, src_dir); - }else if(cnt==17){ + gba->mem.eeprom_addr = gba_read_eeprom_bitstream(gba, src, 2, 6, type ? 4 : 2, src_dir); + } else if(cnt == 17) { // 2 bits "11" (Read Request) // 14 bits eeprom address (MSB first) // 1 bit "0" // Write data 6 bit address - gba->mem.eeprom_addr = gba_read_eeprom_bitstream(gba, src, 2, 14, type?4:2, src_dir)&0x3ff; - }else{ - printf("Bad cnt: %d for eeprom write\n",cnt); + gba->mem.eeprom_addr = gba_read_eeprom_bitstream(gba, src, 2, 14, type ? 4 : 2, src_dir) & 0x3ff; + } else { + printf("Bad cnt: %d for eeprom write\n", cnt); } - gba->dma[i].current_transaction=cnt; - } - if(src_in_eeprom){ - if(cnt==68){ - uint64_t data = ((uint64_t*)gba->mem.cart_backup)[gba->mem.eeprom_addr]; - gba_store_eeprom_bitstream(gba, dst, 4, 64, type?4:2, dst_dir,data); - }else{ - printf("Bad cnt: %d for eeprom read\n",cnt); + gba->dma[i].current_transaction = cnt; + } + if(src_in_eeprom) { + if(cnt == 68) { + uint64_t data = ((uint64_t *)gba->mem.cart_backup)[gba->mem.eeprom_addr]; + gba_store_eeprom_bitstream(gba, dst, 4, 64, type ? 4 : 2, dst_dir, data); + } else { + printf("Bad cnt: %d for eeprom read\n", cnt); } - gba->dma[i].current_transaction=cnt; + gba->dma[i].current_transaction = cnt; } } - bool audio_dma = (mode==3) && (i==1||i==2); - if(audio_dma){ + bool audio_dma = (mode == 3) && (i == 1 || i == 2); + if(audio_dma) { int fifo = -1; - dst&=~3; - src&=~3; - if(dst == GBA_FIFO_A)fifo =0; - if(dst == GBA_FIFO_B)fifo =1; - for(int x=0;x<4;++x){ - uint32_t src_addr=src+x*4*src_dir; - uint32_t data = gba_read32(gba,src_addr); - gba_audio_fifo_push(gba,fifo,SB_BFE(data,0,8)); - gba_audio_fifo_push(gba,fifo,SB_BFE(data,8,8)); - gba_audio_fifo_push(gba,fifo,SB_BFE(data,16,8)); - gba_audio_fifo_push(gba,fifo,SB_BFE(data,24,8)); - ticks+=gba_compute_access_cycles_dma(gba, src_addr, x!=0? 2:3); - ticks+=gba_compute_access_cycles_dma(gba, dst, x!=0||force_first_write_sequential? 2:3); - } - dst_addr_ctl= 2; - transfer_bytes=4; - cnt=4; - skip_dma=true; - gba->dma[i].current_transaction=cnt; - }else if(!skip_dma){ + dst &= ~3; + src &= ~3; + if(dst == GBA_FIFO_A) fifo = 0; + if(dst == GBA_FIFO_B) fifo = 1; + for(int x = 0; x < 4; ++x) { + uint32_t src_addr = src + x * 4 * src_dir; + uint32_t data = gba_read32(gba, src_addr); + gba_audio_fifo_push(gba, fifo, SB_BFE(data, 0, 8)); + gba_audio_fifo_push(gba, fifo, SB_BFE(data, 8, 8)); + gba_audio_fifo_push(gba, fifo, SB_BFE(data, 16, 8)); + gba_audio_fifo_push(gba, fifo, SB_BFE(data, 24, 8)); + ticks += gba_compute_access_cycles_dma(gba, src_addr, x != 0 ? 2 : 3); + ticks += gba_compute_access_cycles_dma(gba, dst, x != 0 || force_first_write_sequential ? 2 : 3); + } + dst_addr_ctl = 2; + transfer_bytes = 4; + cnt = 4; + skip_dma = true; + gba->dma[i].current_transaction = cnt; + } else if(!skip_dma) { // This code is complicated to handle the per channel DMA latches that are present // Correct implementation is needed to pass latch.gba, Pokemon Pinball (intro explosion), // and the text in Lufia // TODO: There in theory should be separate latches per DMA, but that breaks Hello Kitty // and Tomb Raider - if(gba->dma[i].current_transactiondma[i].current_transaction < cnt) { int x = gba->dma[i].current_transaction++; - int dst_addr = dst+x*transfer_bytes*dst_dir; - int src_addr = src+x*transfer_bytes*src_dir; - if(type){ - if(src_addr>=0x02000000){ - gba->dma[i].latched_transfer = gba_read32(gba,src_addr); - ticks+=gba_compute_access_cycles_dma(gba, src_addr, x!=0? 2:3); + int dst_addr = dst + x * transfer_bytes * dst_dir; + int src_addr = src + x * transfer_bytes * src_dir; + if(type) { + if(src_addr >= 0x02000000) { + gba->dma[i].latched_transfer = gba_read32(gba, src_addr); + ticks += gba_compute_access_cycles_dma(gba, src_addr, x != 0 ? 2 : 3); } - gba_dma_write32(gba,dst_addr,gba->dma[i].latched_transfer); - ticks+=gba_compute_access_cycles_dma(gba, dst_addr, x!=0||force_first_write_sequential? 2:3); - }else{ + gba_dma_write32(gba, dst_addr, gba->dma[i].latched_transfer); + ticks += gba_compute_access_cycles_dma(gba, dst_addr, x != 0 || force_first_write_sequential ? 2 : 3); + } else { int v = 0; - if(src_addr>=0x02000000){ - v= gba->dma[i].latched_transfer = (gba_read16(gba,src_addr))&0xffff; - gba->dma[i].latched_transfer |= gba->dma[i].latched_transfer<<16; - ticks+=gba_compute_access_cycles_dma(gba, src_addr, x!=0? 0:1); - }else v = gba->dma[i].latched_transfer>>(((dst_addr)&0x3)*8); - gba_dma_write16(gba,dst_addr,v&0xffff); - ticks+=gba_compute_access_cycles_dma(gba, dst_addr, x!=0||force_first_write_sequential? 0:1); + if(src_addr >= 0x02000000) { + v = gba->dma[i].latched_transfer = (gba_read16(gba, src_addr)) & 0xffff; + gba->dma[i].latched_transfer |= gba->dma[i].latched_transfer << 16; + ticks += gba_compute_access_cycles_dma(gba, src_addr, x != 0 ? 0 : 1); + } else + v = gba->dma[i].latched_transfer >> (((dst_addr)&0x3) * 8); + gba_dma_write16(gba, dst_addr, v & 0xffff); + ticks += gba_compute_access_cycles_dma(gba, dst_addr, x != 0 || force_first_write_sequential ? 0 : 1); } } } - - if(gba->dma[i].current_transaction>=cnt){ - if(dst_addr_ctl==0||dst_addr_ctl==3) dst+=cnt*transfer_bytes; - else if(dst_addr_ctl==1)dst-=cnt*transfer_bytes; - if(src_addr_ctl==0) src+=cnt*transfer_bytes; - else if(src_addr_ctl==1)src-=cnt*transfer_bytes; - - gba->dma[i].source_addr=src; - gba->dma[i].dest_addr=dst; - - if(irq_enable){ - uint16_t if_bit = 1<<(GBA_INT_DMA0+i); - gba_send_interrupt(gba,4,if_bit); - } - if(!dma_repeat||mode==0){ - cnt_h&=0x7fff; - //gba_io_store16(gba, GBA_DMA0CNT_L+12*i,0); - //Reload on incr reload - enable =false; - gba_io_store16(gba, GBA_DMA0CNT_H+12*i,cnt_h); - }else{ - gba->dma[i].current_transaction=0; + + if(gba->dma[i].current_transaction >= cnt) { + if(dst_addr_ctl == 0 || dst_addr_ctl == 3) + dst += cnt * transfer_bytes; + else if(dst_addr_ctl == 1) + dst -= cnt * transfer_bytes; + if(src_addr_ctl == 0) + src += cnt * transfer_bytes; + else if(src_addr_ctl == 1) + src -= cnt * transfer_bytes; + + gba->dma[i].source_addr = src; + gba->dma[i].dest_addr = dst; + + if(irq_enable) { + uint16_t if_bit = 1 << (GBA_INT_DMA0 + i); + gba_send_interrupt(gba, 4, if_bit); + } + if(!dma_repeat || mode == 0) { + cnt_h &= 0x7fff; + // gba_io_store16(gba, GBA_DMA0CNT_L+12*i,0); + // Reload on incr reload + enable = false; + gba_io_store16(gba, GBA_DMA0CNT_H + 12 * i, cnt_h); + } else { + gba->dma[i].current_transaction = 0; } } } gba->dma[i].last_enable = enable; - if(ticks)break; - } - gba->activate_dmas|=ticks!=0; - - if(gba->last_transaction_dma&&ticks==0){ - ticks+=2; - gba->last_transaction_dma=false; - } - - return ticks; -} -static FORCE_INLINE void gba_tick_sio(gba_t* gba){ - //Just a stub for now; - uint16_t siocnt = gba_io_read16(gba,GBA_SIOCNT); - bool active = SB_BFE(siocnt,7,1); - bool irq_enabled = SB_BFE(siocnt,14,1); - if(active){ - if(gba->sio.last_active==false){ - gba->sio.last_active =true; - gba->sio.ticks_till_transfer_done=8*8; - } - bool internal_clock = SB_BFE(siocnt,0,1); - if(internal_clock)gba->sio.ticks_till_transfer_done--; - if(gba->sio.ticks_till_transfer_done<=0){ - if(irq_enabled){ - uint16_t if_bit = 1<<(GBA_INT_SERIAL); - gba_send_interrupt(gba,4,if_bit); - } - siocnt&= ~(1<<7); - gba_io_store16(gba,GBA_SIOCNT,siocnt); - gba->sio.last_active=false; - gba_io_store8(gba,GBA_SIODATA8,0); - gba_io_store32(gba,GBA_SIODATA32,0); - } - - } -} -static FORCE_INLINE void gba_tick_timers(gba_t* gba){ - gba->deferred_timer_ticks+=1; - if(SB_UNLIKELY(gba->deferred_timer_ticks>=gba->timer_ticks_before_event))gba_compute_timers(gba); -} -static void gba_compute_timers(gba_t* gba){ - int ticks = gba->deferred_timer_ticks; + if(ticks) break; + } + gba->activate_dmas |= ticks != 0; + + if(gba->last_transaction_dma && ticks == 0) { + ticks += 2; + gba->last_transaction_dma = false; + } + + return ticks; +} +static FORCE_INLINE void gba_tick_sio(gba_t *gba) { + // Just a stub for now; + uint16_t siocnt = gba_io_read16(gba, GBA_SIOCNT); + bool active = SB_BFE(siocnt, 7, 1); + bool irq_enabled = SB_BFE(siocnt, 14, 1); + if(active) { + if(gba->sio.last_active == false) { + gba->sio.last_active = true; + gba->sio.ticks_till_transfer_done = 8 * 8; + } + bool internal_clock = SB_BFE(siocnt, 0, 1); + if(internal_clock) gba->sio.ticks_till_transfer_done--; + if(gba->sio.ticks_till_transfer_done <= 0) { + if(irq_enabled) { + uint16_t if_bit = 1 << (GBA_INT_SERIAL); + gba_send_interrupt(gba, 4, if_bit); + } + siocnt &= ~(1 << 7); + gba_io_store16(gba, GBA_SIOCNT, siocnt); + gba->sio.last_active = false; + gba_io_store8(gba, GBA_SIODATA8, 0); + gba_io_store32(gba, GBA_SIODATA32, 0); + } + } +} +static FORCE_INLINE void gba_tick_timers(gba_t *gba) { + gba->deferred_timer_ticks += 1; + if(SB_UNLIKELY(gba->deferred_timer_ticks >= gba->timer_ticks_before_event)) gba_compute_timers(gba); +} +static void gba_compute_timers(gba_t *gba) { + int ticks = gba->deferred_timer_ticks; uint32_t old_global_timer = gba->global_timer; - gba->global_timer+=gba->deferred_timer_ticks; - - gba->deferred_timer_ticks=0; - int last_timer_overflow = 0; - int timer_ticks_before_event = 32768; - const int prescaler_lookup[]={0,6,8,10}; - for(int t=0;t<4;++t){ - uint16_t tm_cnt_h = gba_io_read16(gba,GBA_TM0CNT_H+t*4); - bool enable = SB_BFE(tm_cnt_h,7,1); - if(enable){ - int compensated_ticks = ticks; - uint16_t prescale = SB_BFE(tm_cnt_h,0,2); - bool count_up = SB_BFE(tm_cnt_h,2,1)&&t!=0; - bool irq_en = SB_BFE(tm_cnt_h,6,1); - uint16_t value = gba_io_read16(gba,GBA_TM0CNT_L+t*4); - if(enable!=gba->timers[t].last_enable&&enable){ - gba->timers[t].startup_delay=2; + gba->global_timer += gba->deferred_timer_ticks; + + gba->deferred_timer_ticks = 0; + int last_timer_overflow = 0; + int timer_ticks_before_event = 32768; + const int prescaler_lookup[] = {0, 6, 8, 10}; + for(int t = 0; t < 4; ++t) { + uint16_t tm_cnt_h = gba_io_read16(gba, GBA_TM0CNT_H + t * 4); + bool enable = SB_BFE(tm_cnt_h, 7, 1); + if(enable) { + int compensated_ticks = ticks; + uint16_t prescale = SB_BFE(tm_cnt_h, 0, 2); + bool count_up = SB_BFE(tm_cnt_h, 2, 1) && t != 0; + bool irq_en = SB_BFE(tm_cnt_h, 6, 1); + uint16_t value = gba_io_read16(gba, GBA_TM0CNT_L + t * 4); + if(enable != gba->timers[t].last_enable && enable) { + gba->timers[t].startup_delay = 2; value = gba->timers[t].reload_value; - gba_io_store16(gba,GBA_TM0CNT_L+t*4,value); + gba_io_store16(gba, GBA_TM0CNT_L + t * 4, value); } - if(gba->timers[t].startup_delay>=0){ - gba->timers[t].startup_delay-=ticks; + if(gba->timers[t].startup_delay >= 0) { + gba->timers[t].startup_delay -= ticks; gba->timers[t].last_enable = enable; - if(gba->timers[t].startup_delay>=0){ - if(gba->timers[t].startup_delaytimers[t].startup_delay; + if(gba->timers[t].startup_delay >= 0) { + if(gba->timers[t].startup_delay < timer_ticks_before_event) timer_ticks_before_event = gba->timers[t].startup_delay; continue; } - compensated_ticks=-gba->timers[t].startup_delay; - gba->timers[t].startup_delay=-1; - } - if(count_up){ - if(last_timer_overflow){ - uint32_t v= value; - v+=last_timer_overflow; - last_timer_overflow=0; - while(v>0xffff){ - v=(v+gba->timers[t].reload_value)-0x10000; + compensated_ticks = -gba->timers[t].startup_delay; + gba->timers[t].startup_delay = -1; + } + if(count_up) { + if(last_timer_overflow) { + uint32_t v = value; + v += last_timer_overflow; + last_timer_overflow = 0; + while(v > 0xffff) { + v = (v + gba->timers[t].reload_value) - 0x10000; last_timer_overflow++; } - value=v; + value = v; } - }else{ - last_timer_overflow=0; + } else { + last_timer_overflow = 0; int prescale_duty = prescaler_lookup[prescale]; - int increment = (gba->global_timer>>prescale_duty)-(old_global_timer>>prescale_duty); - int v = value+increment; - while(v>0xffff){ - v=(v+gba->timers[t].reload_value)-0x10000; + int increment = (gba->global_timer >> prescale_duty) - (old_global_timer >> prescale_duty); + int v = value + increment; + while(v > 0xffff) { + v = (v + gba->timers[t].reload_value) - 0x10000; last_timer_overflow++; } - value = v; - int ticks_before_overflow = (int)(0xffff-value)<<(prescale_duty); - if(ticks_before_overflowaudio.fifo[i].write_ptr-gba->audio.fifo[i].read_ptr)&0x1f; - while(samples_to_pop--&& size){ - gba->audio.fifo[i].read_ptr=(gba->audio.fifo[i].read_ptr+1)&0x1f; + value = v; + int ticks_before_overflow = (int)(0xffff - value) << (prescale_duty); + if(ticks_before_overflow < timer_ticks_before_event) timer_ticks_before_event = ticks_before_overflow; + } + if(last_timer_overflow) { + uint16_t soundcnt_h = gba_io_read16(gba, GBA_SOUNDCNT_H); + if(t < 2) { + for(int i = 0; i < 2; ++i) { + int timer = SB_BFE(soundcnt_h, 10 + i * 4, 1); + if(timer != t) continue; + int samples_to_pop = last_timer_overflow; + int size = (gba->audio.fifo[i].write_ptr - gba->audio.fifo[i].read_ptr) & 0x1f; + while(samples_to_pop-- && size) { + gba->audio.fifo[i].read_ptr = (gba->audio.fifo[i].read_ptr + 1) & 0x1f; --size; } - if(sizedma[i+1].activate_audio_dma=gba->activate_dmas=true; + if(size < GBA_AUDIO_DMA_ACTIVATE_THRESHOLD) gba->dma[i + 1].activate_audio_dma = gba->activate_dmas = true; } } - if(irq_en){ - uint16_t if_bit = 1<<(GBA_INT_TIMER0+t); - gba_send_interrupt(gba,4,if_bit); + if(irq_en) { + uint16_t if_bit = 1 << (GBA_INT_TIMER0 + t); + gba_send_interrupt(gba, 4, if_bit); } } - gba->timers[t].reload_value=gba->timers[t].pending_reload_value; - - gba_io_store16(gba,GBA_TM0CNT_L+t*4,value); - }else last_timer_overflow=0; + gba->timers[t].reload_value = gba->timers[t].pending_reload_value; + + gba_io_store16(gba, GBA_TM0CNT_L + t * 4, value); + } else + last_timer_overflow = 0; gba->timers[t].last_enable = enable; } - gba->timer_ticks_before_event=timer_ticks_before_event; -} -static FORCE_INLINE float gba_compute_vol_env_slope(int length_of_step,int dir){ - float step_time = length_of_step/64.0; - float slope = 1./step_time; - if(dir==0)slope*=-1; - if(length_of_step==0)slope=0; - return slope/16.; -} -static FORCE_INLINE float gba_polyblep(float t,float dt){ - if(t<=dt){ - t = t/dt; - return t+t-t*t-1.0;; - }else if (t >= 1-dt){ - t=(t-1.0)/dt; - return t*t+t+t+1.0; - }else return 0; -} -static FORCE_INLINE float gba_bandlimited_square(float t, float duty_cycle,float dt){ + gba->timer_ticks_before_event = timer_ticks_before_event; +} +static FORCE_INLINE float gba_compute_vol_env_slope(int length_of_step, int dir) { + float step_time = length_of_step / 64.0; + float slope = 1. / step_time; + if(dir == 0) slope *= -1; + if(length_of_step == 0) slope = 0; + return slope / 16.; +} +static FORCE_INLINE float gba_polyblep(float t, float dt) { + if(t <= dt) { + t = t / dt; + return t + t - t * t - 1.0; + ; + } else if(t >= 1 - dt) { + t = (t - 1.0) / dt; + return t * t + t + t + 1.0; + } else + return 0; +} +static FORCE_INLINE float gba_bandlimited_square(float t, float duty_cycle, float dt) { float t2 = t - duty_cycle; - if(t2< 0.0)t2 +=1.0; + if(t2 < 0.0) t2 += 1.0; float y = t < duty_cycle ? -1 : 1; - y -= gba_polyblep(t,dt); - y += gba_polyblep(t2,dt); + y -= gba_polyblep(t, dt); + y += gba_polyblep(t2, dt); return y; } -static FORCE_INLINE void gba_send_interrupt(gba_t*gba,int delay,int if_bit){ - if(if_bit){ - gba->active_if_pipe_stages|=1<pipelined_if[delay]|= if_bit; +static FORCE_INLINE void gba_send_interrupt(gba_t *gba, int delay, int if_bit) { + if(if_bit) { + gba->active_if_pipe_stages |= 1 << delay; + gba->pipelined_if[delay] |= if_bit; } } -static FORCE_INLINE void gba_tick_interrupts(gba_t*gba){ - if(SB_UNLIKELY(gba->active_if_pipe_stages)){ +static FORCE_INLINE void gba_tick_interrupts(gba_t *gba) { + if(SB_UNLIKELY(gba->active_if_pipe_stages)) { uint16_t if_bit = gba->pipelined_if[0]; - if(if_bit){ - uint16_t if_val = gba_io_read16(gba,GBA_IF); + if(if_bit) { + uint16_t if_val = gba_io_read16(gba, GBA_IF); if_val |= if_bit; - gba_io_store16(gba,GBA_IF,if_val); + gba_io_store16(gba, GBA_IF, if_val); } - gba->pipelined_if[0]=gba->pipelined_if[1]; - gba->pipelined_if[1]=gba->pipelined_if[2]; - gba->pipelined_if[2]=gba->pipelined_if[3]; - gba->pipelined_if[3]=gba->pipelined_if[4]; - gba->pipelined_if[4]=0; - gba->active_if_pipe_stages>>=1; + gba->pipelined_if[0] = gba->pipelined_if[1]; + gba->pipelined_if[1] = gba->pipelined_if[2]; + gba->pipelined_if[2] = gba->pipelined_if[3]; + gba->pipelined_if[3] = gba->pipelined_if[4]; + gba->pipelined_if[4] = 0; + gba->active_if_pipe_stages >>= 1; } } // Thanks fleroviux! -uint64_t gba_decrypt_arv3(uint64_t code){ +uint64_t gba_decrypt_arv3(uint64_t code) { const uint32_t S0 = 0x7AA9648F; const uint32_t S1 = 0x7FAE6994; const uint32_t S2 = 0xC0EFAAD5; @@ -2857,7 +3019,7 @@ uint64_t gba_decrypt_arv3(uint64_t code){ uint32_t tmp = 0x9E3779B9 << 5; - for (int i = 0; i < 32; i++) { + for(int i = 0; i < 32; i++) { r -= ((l << 4) + S2) ^ (l + tmp) ^ ((l >> 5) + S3); l -= ((r << 4) + S0) ^ (r + tmp) ^ ((r >> 5) + S1); tmp -= 0x9E3779B9; @@ -2865,331 +3027,331 @@ uint64_t gba_decrypt_arv3(uint64_t code){ return ((uint64_t)l << 32) | r; } -bool gba_handle_ar_if_instruction(gba_t* gba, uint32_t left, uint32_t right){ - uint32_t address = ((left<<4)&0x0F000000) | (left&0x000FFFFF); - uint8_t current_code = (left>>24)&0xFF; - uint32_t left_compare = gba_read32(gba,address); +bool gba_handle_ar_if_instruction(gba_t *gba, uint32_t left, uint32_t right) { + uint32_t address = ((left << 4) & 0x0F000000) | (left & 0x000FFFFF); + uint8_t current_code = (left >> 24) & 0xFF; + uint32_t left_compare = gba_read32(gba, address); uint32_t right_compare = right; - int32_t left_compare_signed = 0; - int32_t right_compare_signed = 0; - - switch(current_code&0x6){ - case 0:{ - left_compare &= 0xFF; - right_compare &= 0xFF; - left_compare_signed = (int8_t)(left_compare); - right_compare_signed = (int8_t)(right_compare); - break; - } - case 0x2:{ - left_compare &= 0xFFFF; - right_compare &= 0xFFFF; - left_compare_signed = (int16_t)(left_compare); - right_compare_signed = (int16_t)(right_compare); - break; - } - case 0x4:{ - left_compare_signed = (int32_t)(left_compare); - right_compare_signed = (int32_t)(right_compare); - break; - } - case 0x6:{ - printf("Invalid AR if instruction\n"); - return false; - } + int32_t left_compare_signed = 0; + int32_t right_compare_signed = 0; + + switch(current_code & 0x6) { + case 0: { + left_compare &= 0xFF; + right_compare &= 0xFF; + left_compare_signed = (int8_t)(left_compare); + right_compare_signed = (int8_t)(right_compare); + break; + } + case 0x2: { + left_compare &= 0xFFFF; + right_compare &= 0xFFFF; + left_compare_signed = (int16_t)(left_compare); + right_compare_signed = (int16_t)(right_compare); + break; + } + case 0x4: { + left_compare_signed = (int32_t)(left_compare); + right_compare_signed = (int32_t)(right_compare); + break; + } + case 0x6: { + printf("Invalid AR if instruction\n"); + return false; + } } - switch(current_code&0x38){ - case 0x8:{ - // Equal - return left_compare==right_compare; - } - case 0x10:{ - // Not equal - return left_compare!=right_compare; - } - case 0x18:{ - // Signed < - return left_compare_signed - return left_compare_signed>right_compare_signed; - } - case 0x28:{ - // Unsigned < - return left_compare - return left_compare>right_compare; - } - case 0x38:{ - // Logical AND - return left_compare&&right_compare; - } + switch(current_code & 0x38) { + case 0x8: { + // Equal + return left_compare == right_compare; + } + case 0x10: { + // Not equal + return left_compare != right_compare; + } + case 0x18: { + // Signed < + return left_compare_signed < right_compare_signed; + } + case 0x20: { + // Signed > + return left_compare_signed > right_compare_signed; + } + case 0x28: { + // Unsigned < + return left_compare < right_compare; + } + case 0x30: { + // Unsigned > + return left_compare > right_compare; + } + case 0x38: { + // Logical AND + return left_compare && right_compare; + } } return false; } -bool gba_run_ar_cheat(gba_t* gba, const uint32_t* buffer, uint32_t size){ - if(size%2!=0){ - printf("Invalid Action Replay cheat size:%d\n",size); +bool gba_run_ar_cheat(gba_t *gba, const uint32_t *buffer, uint32_t size) { + if(size % 2 != 0) { + printf("Invalid Action Replay cheat size:%d\n", size); return false; } // stack for if statements // the first element is always true - bool if_stack[32] = {true}; + bool if_stack[32] = {true}; size_t if_stack_index = 0; // Let's treat the AR button as always pressed for now bool ar_button_pressed = true; - for(int i=0;i>32; - uint32_t right=code&0xFFFFFFFF; + for(int i = 0; i < size; i += 2) { + uint64_t code = gba_decrypt_arv3(buffer[i + 1] | ((uint64_t)buffer[i] << 32)); + uint32_t left = code >> 32; + uint32_t right = code & 0xFFFFFFFF; - if (!if_stack[if_stack_index]) + if(!if_stack[if_stack_index]) continue; - if (right == 0x1DC0DE){ + if(right == 0x1DC0DE) { continue; } - if (left!=0){ - uint8_t current_code = (left>>24)&0xFF; - uint32_t address = ((left<<4)&0x0F000000) | (left&0x000FFFFF); + if(left != 0) { + uint8_t current_code = (left >> 24) & 0xFF; + uint32_t address = ((left << 4) & 0x0F000000) | (left & 0x000FFFFF); - switch(current_code){ - case 0x00:{ - uint32_t offset=right>>8; - uint8_t data=right&0xFF; - gba_store8(gba,address+offset,data); - break; - } - case 0x02:{ - uint32_t offset=right>>16; - uint16_t data=right&0xFFFF; - gba_store16(gba,address+offset*2,data); - break; - } - case 0x04:{ - uint32_t data=right; - gba_store32(gba,address,data); - break; - } - case 0x40:{ - uint32_t offset=right>>8; - uint8_t data=right&0xFF; - address=gba_read32(gba,address); - gba_store8(gba,address+offset,data); - break; - } - case 0x42:{ - uint32_t offset=right>>16; - uint16_t data=right&0xFFFF; - address=gba_read32(gba,address); - gba_store16(gba,address+offset*2,data); - break; - } - case 0x44:{ - uint32_t data=right; - address=gba_read32(gba,address); - gba_store32(gba,address,data); - break; - } - case 0x80:{ - uint8_t data=right&0xFF; - uint8_t old_data=gba_read8(gba,address); - gba_store8(gba,address,old_data+data); - break; + switch(current_code) { + case 0x00: { + uint32_t offset = right >> 8; + uint8_t data = right & 0xFF; + gba_store8(gba, address + offset, data); + break; + } + case 0x02: { + uint32_t offset = right >> 16; + uint16_t data = right & 0xFFFF; + gba_store16(gba, address + offset * 2, data); + break; + } + case 0x04: { + uint32_t data = right; + gba_store32(gba, address, data); + break; + } + case 0x40: { + uint32_t offset = right >> 8; + uint8_t data = right & 0xFF; + address = gba_read32(gba, address); + gba_store8(gba, address + offset, data); + break; + } + case 0x42: { + uint32_t offset = right >> 16; + uint16_t data = right & 0xFFFF; + address = gba_read32(gba, address); + gba_store16(gba, address + offset * 2, data); + break; + } + case 0x44: { + uint32_t data = right; + address = gba_read32(gba, address); + gba_store32(gba, address, data); + break; + } + case 0x80: { + uint8_t data = right & 0xFF; + uint8_t old_data = gba_read8(gba, address); + gba_store8(gba, address, old_data + data); + break; + } + case 0x82: { + uint16_t data = right & 0xFFFF; + uint16_t old_data = gba_read16(gba, address); + gba_store16(gba, address, old_data + data); + break; + } + case 0x84: { + uint32_t data = right; + uint32_t old_data = gba_read32(gba, address); + gba_store32(gba, address, old_data + data); + break; + } + case 0xC4: { + continue; + } + case 0xC6: { + uint32_t address = 0x4000000 | (left & 0xFFFFFF); + uint16_t data = right & 0xFFFF; + gba_store16(gba, address, data); + break; + } + case 0xC7: { + uint32_t address = 0x4000000 | (left & 0xFFFFFF); + uint32_t data = right; + gba_store32(gba, address, data); + break; + } + default: { + // if instruction + bool condition = gba_handle_ar_if_instruction(gba, left, right); + + switch(current_code & 0xC0) { + case 0x00: { + if(!condition) { + // skip next instruction + i += 2; + continue; + } } - case 0x82:{ - uint16_t data=right&0xFFFF; - uint16_t old_data=gba_read16(gba,address); - gba_store16(gba,address,old_data+data); + case 0x40: { + if(!condition) { + // skip next two instructions + i += 4; + continue; + } break; } - case 0x84:{ - uint32_t data=right; - uint32_t old_data=gba_read32(gba,address); - gba_store32(gba,address,old_data+data); + case 0x80: { break; } - case 0xC4:{ - continue; - } - case 0xC6:{ - uint32_t address=0x4000000|(left&0xFFFFFF); - uint16_t data=right&0xFFFF; - gba_store16(gba,address,data); + case 0xC0: { + if(!condition) { + // turn off all codes + return true; + } break; } - case 0xC7:{ - uint32_t address=0x4000000|(left&0xFFFFFF); - uint32_t data=right; - gba_store32(gba,address,data); - break; } - default:{ - // if instruction - bool condition = gba_handle_ar_if_instruction(gba,left,right); - - switch(current_code&0xC0){ - case 0x00:{ - if(!condition){ - // skip next instruction - i+=2; - continue; - } - } - case 0x40:{ - if (!condition){ - // skip next two instructions - i+=4; - continue; - } - break; - } - case 0x80:{ - break; - } - case 0xC0:{ - if (!condition){ - // turn off all codes - return true; - } - break; - } - } - if_stack_index++; + if_stack_index++; - if (if_stack_index == 32){ - printf("Action Replay if stack size exceeded\n"); - return false; - } - - if_stack[if_stack_index] = condition; - break; + if(if_stack_index == 32) { + printf("Action Replay if stack size exceeded\n"); + return false; } + + if_stack[if_stack_index] = condition; + break; + } } - }else{ - uint8_t current_code = (right>>24)&0xFF; + } else { + uint8_t current_code = (right >> 24) & 0xFF; - if (right == 0){ + if(right == 0) { // end of code list return true; } - switch(current_code){ - case 0x60:{ - // else - if_stack[if_stack_index]^=true; - break; - } - case 0x40:{ - // end if - if (if_stack_index == 0){ - printf("Unexpected Action Replay end if instruction\n"); - return false; - } - if_stack_index--; - break; - } - case 0x08: { - // AR slowdown - // Probably has no effect on emulators - break; - } - case 0x18: - case 0x1A: - case 0x1C: - case 0x1E:{ - if(i+3>=size)return false; - uint32_t address=0x8000000|((right&0xFFFFFF)<<1); - uint64_t decrypted=gba_decrypt_arv3(buffer[i+3] | ((uint64_t)buffer[i+2] << 32)); - uint16_t data=decrypted>>32; - gba->mem.cart_rom[address&0x1FFFFFF]=data; - gba->mem.cart_rom[(address+1)&0x1FFFFFF]=data>>8; - i+=2; - break; - } - case 0x10:{ - // IF AR_BUTTON THEN [a0aaaaa]=zz - if(i+3>=size)return false; - if (ar_button_pressed) { - uint64_t decrypted=gba_decrypt_arv3(buffer[i+3] | ((uint64_t)buffer[i+2] << 32)); - uint32_t address=((right<<4)&0x0F000000) | (right&0x000FFFFF); - uint8_t data = decrypted>>32; - gba_store8(gba,address,data); - } - i+=2; - break; - } - case 0x12:{ - // IF AR_BUTTON THEN [a0aaaaa]=zzzz - if(i+3>=size)return false; - if (ar_button_pressed) { - uint64_t decrypted=gba_decrypt_arv3(buffer[i+3] | ((uint64_t)buffer[i+2] << 32)); - uint32_t address=((right<<4)&0x0F000000) | (right&0x000FFFFF); - uint16_t data = decrypted>>32; - gba_store16(gba,address,data); - } - i+=2; - break; + switch(current_code) { + case 0x60: { + // else + if_stack[if_stack_index] ^= true; + break; + } + case 0x40: { + // end if + if(if_stack_index == 0) { + printf("Unexpected Action Replay end if instruction\n"); + return false; } - case 0x14:{ - // IF AR_BUTTON THEN [a0aaaaa]=zzzzzzzz - if(i+3>=size)return false; - if (ar_button_pressed) { - uint64_t decrypted=gba_decrypt_arv3(buffer[i+3] | ((uint64_t)buffer[i+2] << 32)); - uint32_t address=((right<<4)&0x0F000000) | (right&0x000FFFFF); - uint32_t data = decrypted>>32; - gba_store32(gba,address,data); + if_stack_index--; + break; + } + case 0x08: { + // AR slowdown + // Probably has no effect on emulators + break; + } + case 0x18: + case 0x1A: + case 0x1C: + case 0x1E: { + if(i + 3 >= size) return false; + uint32_t address = 0x8000000 | ((right & 0xFFFFFF) << 1); + uint64_t decrypted = gba_decrypt_arv3(buffer[i + 3] | ((uint64_t)buffer[i + 2] << 32)); + uint16_t data = decrypted >> 32; + gba->mem.cart_rom[address & 0x1FFFFFF] = data; + gba->mem.cart_rom[(address + 1) & 0x1FFFFFF] = data >> 8; + i += 2; + break; + } + case 0x10: { + // IF AR_BUTTON THEN [a0aaaaa]=zz + if(i + 3 >= size) return false; + if(ar_button_pressed) { + uint64_t decrypted = gba_decrypt_arv3(buffer[i + 3] | ((uint64_t)buffer[i + 2] << 32)); + uint32_t address = ((right << 4) & 0x0F000000) | (right & 0x000FFFFF); + uint8_t data = decrypted >> 32; + gba_store8(gba, address, data); + } + i += 2; + break; + } + case 0x12: { + // IF AR_BUTTON THEN [a0aaaaa]=zzzz + if(i + 3 >= size) return false; + if(ar_button_pressed) { + uint64_t decrypted = gba_decrypt_arv3(buffer[i + 3] | ((uint64_t)buffer[i + 2] << 32)); + uint32_t address = ((right << 4) & 0x0F000000) | (right & 0x000FFFFF); + uint16_t data = decrypted >> 32; + gba_store16(gba, address, data); + } + i += 2; + break; + } + case 0x14: { + // IF AR_BUTTON THEN [a0aaaaa]=zzzzzzzz + if(i + 3 >= size) return false; + if(ar_button_pressed) { + uint64_t decrypted = gba_decrypt_arv3(buffer[i + 3] | ((uint64_t)buffer[i + 2] << 32)); + uint32_t address = ((right << 4) & 0x0F000000) | (right & 0x000FFFFF); + uint32_t data = decrypted >> 32; + gba_store32(gba, address, data); + } + i += 2; + break; + } + case 0x80: + case 0x82: + case 0x84: { + // 00000000 8naaaaaa 000000yy ssccssss repeat cc times [a0aaaaa]=yy + // (with yy=yy+ss, a0aaaaa=a0aaaaa+ssss after each step) + if(i + 3 >= size) return false; + uint64_t decrypted = gba_decrypt_arv3(buffer[i + 3] | ((uint64_t)buffer[i + 2] << 32)); + uint32_t address = ((right << 4) & 0x0F000000) | (right & 0x000FFFFF); + uint8_t repeat = (decrypted >> 16) & 0xFF; + uint8_t data_increment = (decrypted >> 24) & 0xFF; + uint32_t address_increment = decrypted & 0xFFFF; + uint32_t data = decrypted >> 32; + + if((current_code & 0xF) == 0x2) { + address_increment *= 2; + } else if((current_code & 0xF) == 0x4) { + address_increment *= 4; + } + + for(int j = 0; j < repeat; j++) { + if((current_code & 0xF) == 0x2) { + gba_store16(gba, address, data); + } else if((current_code & 0xF) == 0x4) { + gba_store32(gba, address, data); + } else { + gba_store8(gba, address, data); } - i+=2; - break; + address += address_increment; + data += data_increment; } - case 0x80: - case 0x82: - case 0x84:{ - // 00000000 8naaaaaa 000000yy ssccssss repeat cc times [a0aaaaa]=yy - // (with yy=yy+ss, a0aaaaa=a0aaaaa+ssss after each step) - if(i+3>=size)return false; - uint64_t decrypted=gba_decrypt_arv3(buffer[i+3] | ((uint64_t)buffer[i+2] << 32)); - uint32_t address=((right<<4)&0x0F000000) | (right&0x000FFFFF); - uint8_t repeat=(decrypted>>16)&0xFF; - uint8_t data_increment=(decrypted>>24)&0xFF; - uint32_t address_increment=decrypted&0xFFFF; - uint32_t data=decrypted>>32; - - if((current_code&0xF)==0x2){ - address_increment*=2; - } else if((current_code&0xF)==0x4){ - address_increment*=4; - } - - for (int j=0;jaudio.sequencer; addr = gba_inverse_lookup_gb_reg(addr); - int i = (addr-SB_IO_AUD1_LENGTH_DUTY)/5; - if(!addr)return value; - if(addr==SB_IO_SOUND_ON_OFF){ - value&=0xf0; - value|=sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf; + int i = (addr - SB_IO_AUD1_LENGTH_DUTY) / 5; + if(!addr) return value; + if(addr == SB_IO_SOUND_ON_OFF) { + value &= 0xf0; + value |= sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf; } - if(addr>=SB_IO_AUD3_WAVE_BASE&&addraudio.wave_sample_offset)%32)/2; + if(addr >= SB_IO_AUD3_WAVE_BASE && addr < SB_IO_AUD3_WAVE_BASE + 16) { + bool wave_active = SB_BFE(sb_read8_io(gb, SB_IO_SOUND_ON_OFF), 2, 1); + if(wave_active) { + // Addr locked to the read pointer when the wave channel is active + addr = SB_IO_AUD3_WAVE_BASE + ((gb->audio.wave_sample_offset) % 32) / 2; } } - if(addr==SB_IO_AUD1_LENGTH_DUTY||addr==SB_IO_AUD2_LENGTH_DUTY||addr==SB_IO_AUD3_LENGTH||addr==SB_IO_AUD4_LENGTH){ + if(addr == SB_IO_AUD1_LENGTH_DUTY || addr == SB_IO_AUD2_LENGTH_DUTY || addr == SB_IO_AUD3_LENGTH || addr == SB_IO_AUD4_LENGTH) { uint8_t length_duty = value; - if(i==2) seq->length[i] = 256-SB_BFE(length_duty,0,8); - else seq->length[i] = 64-SB_BFE(length_duty,0,6); - }else if(addr==SB_IO_AUD1_VOL_ENV||addr==SB_IO_AUD2_VOL_ENV||addr==SB_IO_AUD4_VOL_ENV){ - bool power = SB_BFE(value,3,5)!=0; - seq->powered[i]= power; - seq->active[i]&=power; - seq->env_direction[i] = (SB_BFE(value,3,1)?1:-1); - seq->env_period[i] = SB_BFE(value,0,3); - if (seq->env_period[i]== 0 &&!seq->env_overflow[i]) { + if(i == 2) + seq->length[i] = 256 - SB_BFE(length_duty, 0, 8); + else + seq->length[i] = 64 - SB_BFE(length_duty, 0, 6); + } else if(addr == SB_IO_AUD1_VOL_ENV || addr == SB_IO_AUD2_VOL_ENV || addr == SB_IO_AUD4_VOL_ENV) { + bool power = SB_BFE(value, 3, 5) != 0; + seq->powered[i] = power; + seq->active[i] &= power; + seq->env_direction[i] = (SB_BFE(value, 3, 1) ? 1 : -1); + seq->env_period[i] = SB_BFE(value, 0, 3); + if(seq->env_period[i] == 0 && !seq->env_overflow[i]) { seq->volume[i] = (seq->volume[i] + 1) & 0xf; } - }else if( addr==SB_IO_AUD1_FREQ||addr==SB_IO_AUD1_FREQ_HI|| - addr==SB_IO_AUD2_FREQ||addr==SB_IO_AUD2_FREQ_HI|| - addr==SB_IO_AUD3_FREQ||addr==SB_IO_AUD3_FREQ_HI - ){ - sb_store8_io(gb,addr,value); - uint8_t freq_lo = sb_read8_io(gb,SB_IO_AUD1_FREQ+i*5); - uint8_t freq_hi = sb_read8_io(gb,SB_IO_AUD1_FREQ_HI+i*5); - seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi,0,3))<<8u); + } else if(addr == SB_IO_AUD1_FREQ || addr == SB_IO_AUD1_FREQ_HI || + addr == SB_IO_AUD2_FREQ || addr == SB_IO_AUD2_FREQ_HI || + addr == SB_IO_AUD3_FREQ || addr == SB_IO_AUD3_FREQ_HI) { + sb_store8_io(gb, addr, value); + uint8_t freq_lo = sb_read8_io(gb, SB_IO_AUD1_FREQ + i * 5); + uint8_t freq_hi = sb_read8_io(gb, SB_IO_AUD1_FREQ_HI + i * 5); + seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi, 0, 3)) << 8u); } return value; } -static uint8_t sb_read_wave_ram(sb_gb_t*gb,int byte){ - return gba_io_read8(gb,GBA_WAVE_RAM+byte); +static uint8_t sb_read_wave_ram(sb_gb_t *gb, int byte) { + return gba_io_read8(gb, GBA_WAVE_RAM + byte); } -static int sb_compute_next_sweep_freq(sb_frame_sequencer_t*seq){ - int shift = seq->sweep_shift?seq->sweep_shift:8; - int32_t increment = (seq->frequency[0] >> shift)*seq->sweep_direction; - int32_t new_frequency = seq->frequency[0]+increment; - seq->sweep_subtracted|=seq->sweep_direction==-1; +static int sb_compute_next_sweep_freq(sb_frame_sequencer_t *seq) { + int shift = seq->sweep_shift ? seq->sweep_shift : 8; + int32_t increment = (seq->frequency[0] >> shift) * seq->sweep_direction; + int32_t new_frequency = seq->frequency[0] + increment; + seq->sweep_subtracted |= seq->sweep_direction == -1; return new_frequency; } -static void sb_tick_frame_sweep(sb_frame_sequencer_t*seq){ +static void sb_tick_frame_sweep(sb_frame_sequencer_t *seq) { int32_t new_frequency = sb_compute_next_sweep_freq(seq); - if(new_frequency>2047){ - seq->active[0]=false; - new_frequency = 2047; - }else if(new_frequency<0)new_frequency=0; - if(seq->sweep_shift){ - seq->frequency[0]= new_frequency; + if(new_frequency > 2047) { + seq->active[0] = false; + new_frequency = 2047; + } else if(new_frequency < 0) + new_frequency = 0; + if(seq->sweep_shift) { + seq->frequency[0] = new_frequency; new_frequency = sb_compute_next_sweep_freq(seq); - if(new_frequency>2047){ - seq->active[0]=false; - new_frequency = 2047; + if(new_frequency > 2047) { + seq->active[0] = false; + new_frequency = 2047; } } } -static void sb_tick_frame_seq(sb_gb_t*gb,sb_frame_sequencer_t* seq){ - int step = (seq->step_counter++)%8; - //Tick sweep - if(step==2||step==6){ - if(seq->active[0]&&seq->sweep_enable){ - if(seq->sweep_timer>0)seq->sweep_timer--; - if(seq->sweep_timer == 0){ - if(seq->sweep_period > 0){ +static void sb_tick_frame_seq(sb_gb_t *gb, sb_frame_sequencer_t *seq) { + int step = (seq->step_counter++) % 8; + // Tick sweep + if(step == 2 || step == 6) { + if(seq->active[0] && seq->sweep_enable) { + if(seq->sweep_timer > 0) seq->sweep_timer--; + if(seq->sweep_timer == 0) { + if(seq->sweep_period > 0) { seq->sweep_timer = seq->sweep_period; sb_tick_frame_sweep(seq); - }else seq->sweep_timer = 8; + } else + seq->sweep_timer = 8; } } } - //Tick envelope - if(step==7){ - for(int i=0;i<4;++i){ - if(i==2)continue; - if(seq->env_period[i]){ - if(seq->env_period_timer[i]>0)seq->env_period_timer[i]--; - if(seq->env_period_timer[i]==0){ - seq->env_period_timer[i]=seq->env_period[i]; + // Tick envelope + if(step == 7) { + for(int i = 0; i < 4; ++i) { + if(i == 2) continue; + if(seq->env_period[i]) { + if(seq->env_period_timer[i] > 0) seq->env_period_timer[i]--; + if(seq->env_period_timer[i] == 0) { + seq->env_period_timer[i] = seq->env_period[i]; int volume = seq->volume[i]; - volume+=seq->env_direction[i]; - if(volume<=0){volume=0;seq->env_overflow[i]=true;} - if(volume>0xF){volume=0xF;seq->env_overflow[i]=true;}; - seq->volume[i]=volume; + volume += seq->env_direction[i]; + if(volume <= 0) { + volume = 0; + seq->env_overflow[i] = true; + } + if(volume > 0xF) { + volume = 0xF; + seq->env_overflow[i] = true; + }; + seq->volume[i] = volume; } } } } - if((step%2)==0){ - //Tick length - for(int i=0;i<4;++i){ - if(!seq->use_length[i])continue; - if(seq->length[i]>0)seq->length[i]--; - if(seq->length[i]==0){ - seq->active[i]=false; - seq->length[i] = i==2?256:64; + if((step % 2) == 0) { + // Tick length + for(int i = 0; i < 4; ++i) { + if(!seq->use_length[i]) continue; + if(seq->length[i] > 0) seq->length[i]--; + if(seq->length[i] == 0) { + seq->active[i] = false; + seq->length[i] = i == 2 ? 256 : 64; seq->use_length[i] = false; } } } - int nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - for(int i=0;i<4;++i){ - seq->active[i]&=seq->powered[i]; + int nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + for(int i = 0; i < 4; ++i) { + seq->active[i] &= seq->powered[i]; bool active = seq->active[i]; - nrf_52|=active<audio; - sb_frame_sequencer_t* seq = &audio->sequencer; - int nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - bool master_enable = SB_BFE(nrf_52,7,1); - if(!master_enable){ - for(int i=SB_IO_AUD1_TONE_SWEEP;iactive[i]=false; - seq->powered[i]=false; - seq->length[i]=0; +static void sb_process_audio_writes(sb_gb_t *gb) { + sb_audio_t *audio = &gb->audio; + sb_frame_sequencer_t *seq = &audio->sequencer; + int nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + bool master_enable = SB_BFE(nrf_52, 7, 1); + if(!master_enable) { + for(int i = SB_IO_AUD1_TONE_SWEEP; i < SB_IO_SOUND_ON_OFF; ++i) { + sb_store8_io(gb, i, 0); + } + for(int i = 0; i < 4; ++i) { + if(sb_gbc_enable(gb) || i != 3) { + seq->active[i] = false; + seq->powered[i] = false; + seq->length[i] = 0; } - seq->use_length[i]=false; + seq->use_length[i] = false; } - - }else{ + + } else { uint8_t freq_sweep1 = sb_read8_io(gb, SB_IO_AUD1_TONE_SWEEP); - seq->sweep_period=SB_BFE(freq_sweep1, 4, 3); - seq->sweep_shift=SB_BFE(freq_sweep1, 0, 3); - seq->sweep_direction= SB_BFE(freq_sweep1, 3,1)? -1. : 1; - for(int i=0;i<4;++i){ - bool prev_length_en = seq->use_length[i]; - uint8_t freq_hi = sb_read8_io(gb,SB_IO_AUD1_FREQ_HI+i*5); - seq->use_length[i]= SB_BFE(freq_hi,6,1); - uint8_t vol_env = sb_read8_io(gb,SB_IO_AUD1_VOL_ENV+i*5); - if(i==2){ - bool power = SB_BFE(sb_read8_io(gb,SB_IO_AUD3_POWER),7,1); - seq->powered[i]=power; - } - if(i!=0){ - uint8_t freq_lo = sb_read8_io(gb,SB_IO_AUD1_FREQ+i*5); - seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi,0,3))<<8u); - } - if(i==2){ + seq->sweep_period = SB_BFE(freq_sweep1, 4, 3); + seq->sweep_shift = SB_BFE(freq_sweep1, 0, 3); + seq->sweep_direction = SB_BFE(freq_sweep1, 3, 1) ? -1. : 1; + for(int i = 0; i < 4; ++i) { + bool prev_length_en = seq->use_length[i]; + uint8_t freq_hi = sb_read8_io(gb, SB_IO_AUD1_FREQ_HI + i * 5); + seq->use_length[i] = SB_BFE(freq_hi, 6, 1); + uint8_t vol_env = sb_read8_io(gb, SB_IO_AUD1_VOL_ENV + i * 5); + if(i == 2) { + bool power = SB_BFE(sb_read8_io(gb, SB_IO_AUD3_POWER), 7, 1); + seq->powered[i] = power; + } + if(i != 0) { + uint8_t freq_lo = sb_read8_io(gb, SB_IO_AUD1_FREQ + i * 5); + seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi, 0, 3)) << 8u); + } + if(i == 2) { seq->env_direction[i] = 0; seq->env_period[i] = 0; - }else{ - seq->env_direction[i] = (SB_BFE(vol_env,3,1)?1:-1); - seq->env_period[i] = SB_BFE(vol_env,0,3); - } - bool triggered = SB_BFE(freq_hi,7,1); - if(triggered){ - uint8_t length_duty = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY+i*5); - uint8_t freq_lo = sb_read8_io(gb,SB_IO_AUD1_FREQ+i*5); - seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi,0,3))<<8u); - seq->volume[i] = SB_BFE(vol_env,4,4); - - if(seq->length[i]==0)seq->length[i]=i==2?256:64; - if(i==3)seq->lfsr4 = 0x7FFF; - if(i==2){ - audio->wave_sample_offset=31; - audio->wave_freq_timer=4; - } - seq->env_period_timer[i]=0; - seq->env_overflow[i]=false; - seq->chan_t[i]=0; - seq->active[i]=true; - if(i==0){ - seq->sweep_subtracted=false; - seq->sweep_enable = seq->sweep_period||seq->sweep_shift; - seq->sweep_timer=seq->sweep_period; - if(seq->sweep_timer==0)seq->sweep_timer=8; - if (seq->sweep_shift && sb_compute_next_sweep_freq(seq) > 2047) { + } else { + seq->env_direction[i] = (SB_BFE(vol_env, 3, 1) ? 1 : -1); + seq->env_period[i] = SB_BFE(vol_env, 0, 3); + } + bool triggered = SB_BFE(freq_hi, 7, 1); + if(triggered) { + uint8_t length_duty = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY + i * 5); + uint8_t freq_lo = sb_read8_io(gb, SB_IO_AUD1_FREQ + i * 5); + seq->frequency[i] = freq_lo | ((int)(SB_BFE(freq_hi, 0, 3)) << 8u); + seq->volume[i] = SB_BFE(vol_env, 4, 4); + + if(seq->length[i] == 0) seq->length[i] = i == 2 ? 256 : 64; + if(i == 3) seq->lfsr4 = 0x7FFF; + if(i == 2) { + audio->wave_sample_offset = 31; + audio->wave_freq_timer = 4; + } + seq->env_period_timer[i] = 0; + seq->env_overflow[i] = false; + seq->chan_t[i] = 0; + seq->active[i] = true; + if(i == 0) { + seq->sweep_subtracted = false; + seq->sweep_enable = seq->sweep_period || seq->sweep_shift; + seq->sweep_timer = seq->sweep_period; + if(seq->sweep_timer == 0) seq->sweep_timer = 8; + if(seq->sweep_shift && sb_compute_next_sweep_freq(seq) > 2047) { seq->active[0] = false; - } - seq->sweep_enable = seq->sweep_period>0||seq->sweep_shift>0; + } + seq->sweep_enable = seq->sweep_period > 0 || seq->sweep_shift > 0; } } - if(i==0&&seq->sweep_subtracted&&seq->sweep_direction!=-1){ - seq->active[0]= false; + if(i == 0 && seq->sweep_subtracted && seq->sweep_direction != -1) { + seq->active[0] = false; seq->sweep_enable = false; } - if(seq->use_length[i]&&!prev_length_en){ - bool second_half_of_length_period = (seq->step_counter&1); - if(second_half_of_length_period){ - if(seq->length[i])seq->length[i]--; - if(seq->length[i]==0){ - if(triggered) seq->length[i]=i==2?255:63; - else{ - seq->active[i]=false; - seq->use_length[i]=triggered&&seq->use_length[i]; + if(seq->use_length[i] && !prev_length_en) { + bool second_half_of_length_period = (seq->step_counter & 1); + if(second_half_of_length_period) { + if(seq->length[i]) seq->length[i]--; + if(seq->length[i] == 0) { + if(triggered) + seq->length[i] = i == 2 ? 255 : 63; + else { + seq->active[i] = false; + seq->use_length[i] = triggered && seq->use_length[i]; } } } } - sb_store8_io(gb, SB_IO_AUD1_FREQ_HI+i*5,freq_hi&0x7f); + sb_store8_io(gb, SB_IO_AUD1_FREQ_HI + i * 5, freq_hi & 0x7f); } } - nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; - for(int i=0;i<4;++i){ - seq->active[i]&=seq->powered[i]; + nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; + for(int i = 0; i < 4; ++i) { + seq->active[i] &= seq->powered[i]; bool active = seq->active[i]; - nrf_52|=active<audio; - sb_frame_sequencer_t* seq = &audio->sequencer; - - if(delta_time>1.0/60.)delta_time = 1.0/60.; - audio->current_sim_time +=delta_time; - #ifdef GBA_AUDIO - uint32_t prev_audio_clock = audio->audio_clock; - audio->audio_clock+=cycles; - cycles = (audio->audio_clock-(prev_audio_clock&~3))/4; - uint32_t frame_cycles = (audio->audio_clock-(prev_audio_clock&~32767))/32768; - while(frame_cycles--)gba_tick_frame_seq(gb,seq); - #endif +static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t *emu, double delta_time, int cycles) { + + sb_audio_t *audio = &gb->audio; + sb_frame_sequencer_t *seq = &audio->sequencer; + + if(delta_time > 1.0 / 60.) delta_time = 1.0 / 60.; + audio->current_sim_time += delta_time; +#ifdef GBA_AUDIO + uint32_t prev_audio_clock = audio->audio_clock; + audio->audio_clock += cycles; + cycles = (audio->audio_clock - (prev_audio_clock & ~3)) / 4; + uint32_t frame_cycles = (audio->audio_clock - (prev_audio_clock & ~32767)) / 32768; + while(frame_cycles--) + gba_tick_frame_seq(gb, seq); +#endif int freq_tim = audio->wave_freq_timer; - freq_tim-=cycles; - if(freq_tim<0){ - int wave_inc_count = (-freq_tim-1)/((2048-seq->frequency[2])*2)+1; - audio->wave_sample_offset+= wave_inc_count; - freq_tim +=(2048-seq->frequency[2])*2*wave_inc_count; - unsigned wav_samp = (audio->wave_sample_offset)%32; - int dat =sb_read_wave_ram(gb,wav_samp/2); + freq_tim -= cycles; + if(freq_tim < 0) { + int wave_inc_count = (-freq_tim - 1) / ((2048 - seq->frequency[2]) * 2) + 1; + audio->wave_sample_offset += wave_inc_count; + freq_tim += (2048 - seq->frequency[2]) * 2 * wave_inc_count; + unsigned wav_samp = (audio->wave_sample_offset) % 32; + int dat = sb_read_wave_ram(gb, wav_samp / 2); audio->curr_wave_data = dat; - int offset = (wav_samp&1)? 0:4; - audio->curr_wave_sample = ((dat>>offset)&0xf); + int offset = (wav_samp & 1) ? 0 : 4; + audio->curr_wave_sample = ((dat >> offset) & 0xf); } - audio->wave_freq_timer=freq_tim; + audio->wave_freq_timer = freq_tim; audio->current_sample_generated_time -= (int)(audio->current_sim_time); audio->current_sim_time -= (int)(audio->current_sim_time); - if(audio->current_sample_generated_time >audio->current_sim_time)return; + if(audio->current_sample_generated_time > audio->current_sim_time) return; - int nrf_52 = sb_read8_io(gb,SB_IO_SOUND_ON_OFF)&0xf0; + int nrf_52 = sb_read8_io(gb, SB_IO_SOUND_ON_OFF) & 0xf0; - bool master_enable = SB_BFE(nrf_52,7,1); - if(!master_enable)return; - float sample_delta_t = 1.0/SE_AUDIO_SAMPLE_RATE; + bool master_enable = SB_BFE(nrf_52, 7, 1); + if(!master_enable) return; + float sample_delta_t = 1.0 / SE_AUDIO_SAMPLE_RATE; - const static float duty_lookup[]={0.125,0.25,0.5,0.75}; - uint8_t length_duty1 = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY); - float duty1 = duty_lookup[SB_BFE(length_duty1,6,2)]; - uint8_t length_duty2 = sb_read8_io(gb, SB_IO_AUD2_LENGTH_DUTY); - float duty2 = duty_lookup[SB_BFE(length_duty2,6,2)]; + const static float duty_lookup[] = {0.125, 0.25, 0.5, 0.75}; + uint8_t length_duty1 = sb_read8_io(gb, SB_IO_AUD1_LENGTH_DUTY); + float duty1 = duty_lookup[SB_BFE(length_duty1, 6, 2)]; + uint8_t length_duty2 = sb_read8_io(gb, SB_IO_AUD2_LENGTH_DUTY); + float duty2 = duty_lookup[SB_BFE(length_duty2, 6, 2)]; - uint8_t power3 = sb_read8_io(gb,SB_IO_AUD3_POWER); - uint8_t vol_env3 = sb_read8_io(gb,SB_IO_AUD3_VOL); - int channel3_shift = SB_BFE(vol_env3,5,2)-1; - if(SB_BFE(power3,7,1)==0||channel3_shift==-1)channel3_shift=4; + uint8_t power3 = sb_read8_io(gb, SB_IO_AUD3_POWER); + uint8_t vol_env3 = sb_read8_io(gb, SB_IO_AUD3_VOL); + int channel3_shift = SB_BFE(vol_env3, 5, 2) - 1; + if(SB_BFE(power3, 7, 1) == 0 || channel3_shift == -1) channel3_shift = 4; - uint8_t poly4 = sb_read8_io(gb,SB_IO_AUD4_POLY); - float r4 = SB_BFE(poly4,0,3); - uint8_t s4 = SB_BFE(poly4,4,4); - bool sevenBit4 = SB_BFE(poly4,3,1); - if(r4==0)r4=0.5; + uint8_t poly4 = sb_read8_io(gb, SB_IO_AUD4_POLY); + float r4 = SB_BFE(poly4, 0, 3); + uint8_t s4 = SB_BFE(poly4, 4, 4); + bool sevenBit4 = SB_BFE(poly4, 3, 1); + if(r4 == 0) r4 = 0.5; - uint8_t master_vol = sb_read8_io(gb,SB_IO_MASTER_VOLUME); - float master_left = SB_BFE(master_vol,4,3)/7.; - float master_right = SB_BFE(master_vol,0,3)/7.; + uint8_t master_vol = sb_read8_io(gb, SB_IO_MASTER_VOLUME); + float master_left = SB_BFE(master_vol, 4, 3) / 7.; + float master_right = SB_BFE(master_vol, 0, 3) / 7.; - uint8_t chan_sel = sb_read8_io(gb,SB_IO_SOUND_OUTPUT_SEL); - //These are type int to allow them to be multiplied to enable/disable - float chan_l[6]={0};float chan_r[6]={0}; - for(int i=0;i<4;++i){ - chan_l[i] = SB_BFE(chan_sel,i,1); - chan_r[i] = SB_BFE(chan_sel,i+4,1); + uint8_t chan_sel = sb_read8_io(gb, SB_IO_SOUND_OUTPUT_SEL); + // These are type int to allow them to be multiplied to enable/disable + float chan_l[6] = {0}; + float chan_r[6] = {0}; + for(int i = 0; i < 4; ++i) { + chan_l[i] = SB_BFE(chan_sel, i, 1); + chan_r[i] = SB_BFE(chan_sel, i + 4, 1); } - #ifdef GBA_AUDIO +#ifdef GBA_AUDIO { - uint16_t soundcnt_h = gba_io_read16(gb,GBA_SOUNDCNT_H); - //These are type int to allow them to be multiplied to enable/disable - uint16_t chan_sel = gba_io_read16(gb,GBA_SOUNDCNT_L); - /* soundcnth + uint16_t soundcnt_h = gba_io_read16(gb, GBA_SOUNDCNT_H); + // These are type int to allow them to be multiplied to enable/disable + uint16_t chan_sel = gba_io_read16(gb, GBA_SOUNDCNT_L); + /* soundcnth 0-1 R/W Sound # 1-4 Volume (0=25%, 1=50%, 2=100%, 3=Prohibited) 2 R/W DMA Sound A Volume (0=50%, 1=100%) 3 R/W DMA Sound B Volume (0=50%, 1=100%) @@ -3603,114 +3777,120 @@ static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t*emu, doubl 12 R/W DMA Sound B Enable RIGHT (0=Disable, 1=Enable) 13 R/W DMA Sound B Enable LEFT (0=Disable, 1=Enable) 14 R/W DMA Sound B Timer Select (0=Timer 0, 1=Timer 1) - 15 W? DMA Sound B Reset FIFO (1=Reset)*/ - float psg_volume_lookup[4]={0.25,0.5,1.0,0.}; - float psg_volume = psg_volume_lookup[SB_BFE(soundcnt_h,0,2)]*0.25; + 15 W? DMA Sound B Reset FIFO (1=Reset)*/ + float psg_volume_lookup[4] = {0.25, 0.5, 1.0, 0.}; + float psg_volume = psg_volume_lookup[SB_BFE(soundcnt_h, 0, 2)] * 0.25; - float r_vol = SB_BFE(chan_sel,0,3)/7.*psg_volume; - float l_vol = SB_BFE(chan_sel,4,3)/7.*psg_volume; - for(int i=0;i<4;++i){ + float r_vol = SB_BFE(chan_sel, 0, 3) / 7. * psg_volume; + float l_vol = SB_BFE(chan_sel, 4, 3) / 7. * psg_volume; + for(int i = 0; i < 4; ++i) { chan_r[i] *= r_vol; chan_l[i] *= l_vol; } // Channel volume for each FIFO - for(int i=0;i<2;++i){ + for(int i = 0; i < 2; ++i) { // Volume - chan_r[i+4]=chan_l[i+4]= SB_BFE(soundcnt_h,2+i,1)? 1.0: 0.5; - chan_r[i+4]*= SB_BFE(soundcnt_h,8+i*4,1); - chan_l[i+4]*= SB_BFE(soundcnt_h,9+i*4,1); + chan_r[i + 4] = chan_l[i + 4] = SB_BFE(soundcnt_h, 2 + i, 1) ? 1.0 : 0.5; + chan_r[i + 4] *= SB_BFE(soundcnt_h, 8 + i * 4, 1); + chan_l[i + 4] *= SB_BFE(soundcnt_h, 9 + i * 4, 1); } - gba_io_store16(gb,GBA_SOUNDCNT_H,soundcnt_h&~((1<<11)|(1<<15))); - master_left=master_right=1; + gba_io_store16(gb, GBA_SOUNDCNT_H, soundcnt_h & ~((1 << 11) | (1 << 15))); + master_left = master_right = 1; } - #endif +#endif float freq_hz[4]; - for(int i=0;i<2;++i){freq_hz[i]= 131072./(2048-seq->frequency[i]);} - freq_hz[2]= (65536.)/(2048-seq->frequency[2]); - freq_hz[3] = 524288.0/r4/pow(2.0,s4+1); - while(audio->current_sample_generated_time < audio->current_sim_time){ - - audio->current_sample_generated_time+=sample_delta_t; - - if((sb_ring_buffer_size(&emu->audio_ring_buff)+3>SB_AUDIO_RING_BUFFER_SIZE)) continue; - - //Advance each channel - for(int i=0;i<4;++i)seq->chan_t[i] +=sample_delta_t*freq_hz[i]; - //Generate new noise value if needed - if(seq->chan_t[3]>=1.0) { + for(int i = 0; i < 2; ++i) { + freq_hz[i] = 131072. / (2048 - seq->frequency[i]); + } + freq_hz[2] = (65536.) / (2048 - seq->frequency[2]); + freq_hz[3] = 524288.0 / r4 / pow(2.0, s4 + 1); + while(audio->current_sample_generated_time < audio->current_sim_time) { + + audio->current_sample_generated_time += sample_delta_t; + + if((sb_ring_buffer_size(&emu->audio_ring_buff) + 3 > SB_AUDIO_RING_BUFFER_SIZE)) continue; + + // Advance each channel + for(int i = 0; i < 4; ++i) + seq->chan_t[i] += sample_delta_t * freq_hz[i]; + // Generate new noise value if needed + if(seq->chan_t[3] >= 1.0) { int bit = (seq->lfsr4 ^ (seq->lfsr4 >> 1)) & 1; seq->lfsr4 >>= 1; seq->lfsr4 |= bit << 14; - if (sevenBit4) { + if(sevenBit4) { seq->lfsr4 &= ~(1 << 7); seq->lfsr4 |= bit << 6; } } - - //Loopback - for(int i=0;i<4;++i) seq->chan_t[i]-=(int)seq->chan_t[i]; - - //Compute and clamp Volume Envelopes + + // Loopback + for(int i = 0; i < 4; ++i) + seq->chan_t[i] -= (int)seq->chan_t[i]; + + // Compute and clamp Volume Envelopes float v[4]; - for(int i=0;i<4;++i)v[i] = seq->active[i]?seq->volume[i]/15.:0; + for(int i = 0; i < 4; ++i) + v[i] = seq->active[i] ? seq->volume[i] / 15. : 0; v[2] = 1.0; - int dat = audio->curr_wave_sample >>channel3_shift; - int wav_offset = 8>>channel3_shift; - + int dat = audio->curr_wave_sample >> channel3_shift; + int wav_offset = 8 >> channel3_shift; + float channels[6]; - channels[0] = sb_bandlimited_square(seq->chan_t[0],duty1,sample_delta_t*freq_hz[0])*v[0]; - channels[1] = sb_bandlimited_square(seq->chan_t[1],duty2,sample_delta_t*freq_hz[1])*v[1]; - channels[2] = (dat-wav_offset)/8.; - channels[3] = ((seq->lfsr4 & 1) * 2.-1.)*v[3]; - - #ifdef GBA_AUDIO - for(int i=0;i<2;++i)channels[4+i] = audio->fifo[i].data[audio->fifo[i].read_ptr&0x1f]/128.; - #else - for(int i=0;i<2;++i)channels[4+i] =0; - #endif - - //Mix channels + channels[0] = sb_bandlimited_square(seq->chan_t[0], duty1, sample_delta_t * freq_hz[0]) * v[0]; + channels[1] = sb_bandlimited_square(seq->chan_t[1], duty2, sample_delta_t * freq_hz[1]) * v[1]; + channels[2] = (dat - wav_offset) / 8.; + channels[3] = ((seq->lfsr4 & 1) * 2. - 1.) * v[3]; + +#ifdef GBA_AUDIO + for(int i = 0; i < 2; ++i) + channels[4 + i] = audio->fifo[i].data[audio->fifo[i].read_ptr & 0x1f] / 128.; +#else + for(int i = 0; i < 2; ++i) + channels[4 + i] = 0; +#endif + + // Mix channels float sample_volume_l = 0; float sample_volume_r = 0; - for(int i=0;i<6;++i){ - float l = channels[i]*chan_l[i]; - float r = channels[i]*chan_r[i]; - if(l>=-2.&&l<=2)sample_volume_l+=l; - if(r>=-2.&&r<=2)sample_volume_r+=r; - } - - sample_volume_l*=0.25; - sample_volume_r*=0.25; - sample_volume_l*=master_left; - sample_volume_r*=master_right; + for(int i = 0; i < 6; ++i) { + float l = channels[i] * chan_l[i]; + float r = channels[i] * chan_r[i]; + if(l >= -2. && l <= 2) sample_volume_l += l; + if(r >= -2. && r <= 2) sample_volume_r += r; + } + + sample_volume_l *= 0.25; + sample_volume_r *= 0.25; + sample_volume_l *= master_left; + sample_volume_r *= master_right; const float lowpass_coef = 0.999; - emu->mix_l_volume = emu->mix_l_volume*lowpass_coef + fabs(sample_volume_l)*(1.0-lowpass_coef); - emu->mix_r_volume = emu->mix_r_volume*lowpass_coef + fabs(sample_volume_r)*(1.0-lowpass_coef); - - for(int i=0;i<6;++i){ - emu->audio_channel_output[i] = emu->audio_channel_output[i]*lowpass_coef - + fabs(channels[i])*(1.0-lowpass_coef); + emu->mix_l_volume = emu->mix_l_volume * lowpass_coef + fabs(sample_volume_l) * (1.0 - lowpass_coef); + emu->mix_r_volume = emu->mix_r_volume * lowpass_coef + fabs(sample_volume_r) * (1.0 - lowpass_coef); + + for(int i = 0; i < 6; ++i) { + emu->audio_channel_output[i] = emu->audio_channel_output[i] * lowpass_coef + fabs(channels[i]) * (1.0 - lowpass_coef); } // Clipping - if(sample_volume_l>1.0)sample_volume_l=1; - if(sample_volume_r>1.0)sample_volume_r=1; - if(sample_volume_l<-1.0)sample_volume_l=-1; - if(sample_volume_r<-1.0)sample_volume_r=-1; - if(!(audio->capacitor_l<2&&audio->capacitor_l>-2))audio->capacitor_l=0; - if(!(audio->capacitor_r<2&&audio->capacitor_r>-2))audio->capacitor_r=0; - float out_l = sample_volume_l-audio->capacitor_l; - float out_r = sample_volume_r-audio->capacitor_r; - audio->capacitor_l = (sample_volume_l-out_l)*0.996; - audio->capacitor_r = (sample_volume_r-out_r)*0.996; + if(sample_volume_l > 1.0) sample_volume_l = 1; + if(sample_volume_r > 1.0) sample_volume_r = 1; + if(sample_volume_l < -1.0) sample_volume_l = -1; + if(sample_volume_r < -1.0) sample_volume_r = -1; + if(!(audio->capacitor_l < 2 && audio->capacitor_l > -2)) audio->capacitor_l = 0; + if(!(audio->capacitor_r < 2 && audio->capacitor_r > -2)) audio->capacitor_r = 0; + float out_l = sample_volume_l - audio->capacitor_l; + float out_r = sample_volume_r - audio->capacitor_r; + audio->capacitor_l = (sample_volume_l - out_l) * 0.996; + audio->capacitor_r = (sample_volume_r - out_r) * 0.996; // Quantization - unsigned write_entry0 = (emu->audio_ring_buff.write_ptr++)%SB_AUDIO_RING_BUFFER_SIZE; - unsigned write_entry1 = (emu->audio_ring_buff.write_ptr++)%SB_AUDIO_RING_BUFFER_SIZE; + unsigned write_entry0 = (emu->audio_ring_buff.write_ptr++) % SB_AUDIO_RING_BUFFER_SIZE; + unsigned write_entry1 = (emu->audio_ring_buff.write_ptr++) % SB_AUDIO_RING_BUFFER_SIZE; - emu->audio_ring_buff.data[write_entry0] = out_l*32760; - emu->audio_ring_buff.data[write_entry1] = out_r*32760; + emu->audio_ring_buff.data[write_entry0] = out_l * 32760; + emu->audio_ring_buff.data[write_entry1] = out_r * 32760; } } @@ -3722,46 +3902,43 @@ static FORCE_INLINE void sb_process_audio(sb_gb_t *gb, sb_emu_state_t*emu, doubl #undef sb_frame_sequencer_t #undef sb_audio_t #undef sb_gb_t -#undef sb_read8_io +#undef sb_read8_io #undef sb_store8_io #undef sb_bandlimited_square #undef sb_gbc_enable #undef sb_read_wave_ram - - -#undef SB_IO_AUD1_TONE_SWEEP -#undef SB_IO_AUD1_LENGTH_DUTY -#undef SB_IO_AUD1_VOL_ENV -#undef SB_IO_AUD1_FREQ -#undef SB_IO_AUD1_FREQ_HI -#undef SB_IO_AUD2_LENGTH_DUTY -#undef SB_IO_AUD2_VOL_ENV -#undef SB_IO_AUD2_FREQ -#undef SB_IO_AUD2_FREQ_HI -#undef SB_IO_AUD3_POWER -#undef SB_IO_AUD3_LENGTH -#undef SB_IO_AUD3_VOL -#undef SB_IO_AUD3_FREQ -#undef SB_IO_AUD3_FREQ_HI -#undef SB_IO_AUD3_WAVE_BASE -#undef SB_IO_AUD4_LENGTH -#undef SB_IO_AUD4_VOL_ENV -#undef SB_IO_AUD4_POLY -#undef SB_IO_AUD4_COUNTER -#undef SB_IO_MASTER_VOLUME -#undef SB_IO_SOUND_OUTPUT_SEL -#undef SB_IO_SOUND_ON_OFF - -#undef GBA_AUDIO +#undef SB_IO_AUD1_TONE_SWEEP +#undef SB_IO_AUD1_LENGTH_DUTY +#undef SB_IO_AUD1_VOL_ENV +#undef SB_IO_AUD1_FREQ +#undef SB_IO_AUD1_FREQ_HI +#undef SB_IO_AUD2_LENGTH_DUTY +#undef SB_IO_AUD2_VOL_ENV +#undef SB_IO_AUD2_FREQ +#undef SB_IO_AUD2_FREQ_HI +#undef SB_IO_AUD3_POWER +#undef SB_IO_AUD3_LENGTH +#undef SB_IO_AUD3_VOL +#undef SB_IO_AUD3_FREQ +#undef SB_IO_AUD3_FREQ_HI +#undef SB_IO_AUD3_WAVE_BASE +#undef SB_IO_AUD4_LENGTH +#undef SB_IO_AUD4_VOL_ENV +#undef SB_IO_AUD4_POLY +#undef SB_IO_AUD4_COUNTER +#undef SB_IO_MASTER_VOLUME +#undef SB_IO_SOUND_OUTPUT_SEL +#undef SB_IO_SOUND_ON_OFF + +#undef GBA_AUDIO // END GB REUSE CODE SHIM// - -void gba_tick(sb_emu_state_t* emu, gba_t* gba,gba_scratch_t *scratch){ +void gba_tick(sb_emu_state_t *emu, gba_t *gba, gba_scratch_t *scratch) { gba->framebuffer = scratch->framebuffer; - gba->mem.bios = scratch->bios; - gba->mem.cart_rom= emu->rom_data; + gba->mem.bios = scratch->bios; + gba->mem.cart_rom = emu->rom_data; gba->cpu.log_cmp_file = scratch->log_cmp_file; gba->cpu.read8 = arm7_read8; gba->cpu.read16 = arm7_read16; @@ -3771,70 +3948,83 @@ void gba_tick(sb_emu_state_t* emu, gba_t* gba,gba_scratch_t *scratch){ gba->cpu.write8 = arm7_write8; gba->cpu.write16 = arm7_write16; gba->cpu.write32 = arm7_write32; - gba->cpu.user_data=gba; + gba->cpu.user_data = gba; - uint64_t* d = (uint64_t*)gba->mem.mmio_debug_access_buffer; - for(int i=0;imem.mmio_debug_access_buffer)/8;++i){ - d[i]&=0x9191919191919191ULL; + uint64_t *d = (uint64_t *)gba->mem.mmio_debug_access_buffer; + for(int i = 0; i < sizeof(gba->mem.mmio_debug_access_buffer) / 8; ++i) { + d[i] &= 0x9191919191919191ULL; } - gba_tick_keypad(&emu->joy,gba); - gba->ppu.has_hit_vblank=false; + gba_tick_keypad(&emu->joy, gba); + gba->ppu.has_hit_vblank = false; float solar_value = emu->joy.solar_sensor; - if(!(solar_value <1.00))solar_value=1.00; - if(!(solar_value >0.00))solar_value=0.00; - gba->solar_sensor.value = 0xE7-solar_value*(0xE7-0x32); + if(!(solar_value < 1.00)) solar_value = 1.00; + if(!(solar_value > 0.00)) solar_value = 0.00; + gba->solar_sensor.value = 0xE7 - solar_value * (0xE7 - 0x32); gba->ppu.ghosting_strength = emu->screen_ghosting_strength; - while(true){ - int ticks = gba->activate_dmas? gba_tick_dma(gba,gba->last_cpu_tick) :0; - if(!ticks&&gba->residual_dma_ticks){ticks=gba->residual_dma_ticks;gba->residual_dma_ticks=0;} - if(!ticks){ - gba->cpu.i_cycles=0; - gba->mem.requests=0; - if(!gba->cpu.phased_op_id){ - uint16_t int_if = gba_io_read16(gba,GBA_IF); - if(SB_UNLIKELY(int_if)){ - int_if &= gba_io_read16(gba,GBA_IE); - uint32_t ime = gba_io_read32(gba,GBA_IME); - int_if *= SB_BFE(ime,0,1); + while(true) { + int ticks = gba->activate_dmas ? gba_tick_dma(gba, gba->last_cpu_tick) : 0; + if(!ticks && gba->residual_dma_ticks) { + ticks = gba->residual_dma_ticks; + gba->residual_dma_ticks = 0; + } + if(!ticks) { + gba->cpu.i_cycles = 0; + gba->mem.requests = 0; + if(!gba->cpu.phased_op_id) { + uint16_t int_if = gba_io_read16(gba, GBA_IF); + if(SB_UNLIKELY(int_if)) { + int_if &= gba_io_read16(gba, GBA_IE); + uint32_t ime = gba_io_read32(gba, GBA_IME); + int_if *= SB_BFE(ime, 0, 1); arm7_process_interrupts(&gba->cpu, int_if); } - if(SB_UNLIKELY(gba->cpu.trigger_breakpoint)){emu->run_mode = SB_MODE_PAUSE; gba->cpu.trigger_breakpoint=false; break;} + if(SB_UNLIKELY(gba->cpu.trigger_breakpoint)) { + emu->run_mode = SB_MODE_PAUSE; + gba->cpu.trigger_breakpoint = false; + break; + } } arm7_exec_instruction(&gba->cpu); - gba->last_cpu_tick=ticks = gba->mem.requests+gba->cpu.i_cycles; + gba->last_cpu_tick = ticks = gba->mem.requests + gba->cpu.i_cycles; } gba_tick_sio(gba); int ppu_fast_forward = gba->ppu.fast_forward_ticks; - int timer_fast_forward = gba->timer_ticks_before_event-gba->deferred_timer_ticks; - int fast_forward_ticks=ppu_fast_forwardticks){ - if(gba->cpu.wait_for_interrupt)ticks=fast_forward_ticks; - else fast_forward_ticks=ticks; - } - if(SB_UNLIKELY(gba->active_if_pipe_stages)){ - for(int i=0;irtc.total_clocks_ticked+=fast_forward_ticks; - gba->deferred_timer_ticks+=fast_forward_ticks; - gba->ppu.fast_forward_ticks-=fast_forward_ticks; - ticks -=fast_forward_ticks>ticks?ticks:fast_forward_ticks; - double delta_t = ((double)ticks+fast_forward_ticks)/(16*1024*1024); - gba_tick_audio(gba, emu,delta_t,ticks+fast_forward_ticks); - - bool last_activate_dmas =gba->activate_dmas; - gba->rtc.total_clocks_ticked+=ticks; - for(int t = 0;tactivate_dmas&&!last_activate_dmas){gba->residual_dma_ticks=ticks-t-1;gba->last_cpu_tick=t+1;} + int timer_fast_forward = gba->timer_ticks_before_event - gba->deferred_timer_ticks; + int fast_forward_ticks = ppu_fast_forward < timer_fast_forward ? ppu_fast_forward : timer_fast_forward; + if(fast_forward_ticks > ticks) { + if(gba->cpu.wait_for_interrupt) + ticks = fast_forward_ticks; + else + fast_forward_ticks = ticks; + } + if(SB_UNLIKELY(gba->active_if_pipe_stages)) { + for(int i = 0; i < fast_forward_ticks; ++i) + gba_tick_interrupts(gba); + } + gba->rtc.total_clocks_ticked += fast_forward_ticks; + gba->deferred_timer_ticks += fast_forward_ticks; + gba->ppu.fast_forward_ticks -= fast_forward_ticks; + ticks -= fast_forward_ticks > ticks ? ticks : fast_forward_ticks; + double delta_t = ((double)ticks + fast_forward_ticks) / (16 * 1024 * 1024); + gba_tick_audio(gba, emu, delta_t, ticks + fast_forward_ticks); + + bool last_activate_dmas = gba->activate_dmas; + gba->rtc.total_clocks_ticked += ticks; + for(int t = 0; t < ticks; ++t) { + if(gba->activate_dmas && !last_activate_dmas) { + gba->residual_dma_ticks = ticks - t - 1; + gba->last_cpu_tick = t + 1; + } gba_tick_interrupts(gba); gba_tick_timers(gba); - gba_tick_ppu(gba,emu->render_frame); + gba_tick_ppu(gba, emu->render_frame); } - if(SB_UNLIKELY(gba->ppu.has_hit_vblank||gba->stop_mode))break; - } - emu->joy.rumble = SB_BFE(gba->cart.gpio_data,3,1); - //LCD turns off in stop mode - if(gba->stop_mode)memset(scratch->framebuffer,0,sizeof(scratch->framebuffer)); + if(SB_UNLIKELY(gba->ppu.has_hit_vblank || gba->stop_mode)) break; + } + emu->joy.rumble = SB_BFE(gba->cart.gpio_data, 3, 1); + // LCD turns off in stop mode + if(gba->stop_mode) memset(scratch->framebuffer, 0, sizeof(scratch->framebuffer)); } #endif diff --git a/src/ios_support.h b/src/ios_support.h index a7a1d5b46..00b7e94ae 100644 --- a/src/ios_support.h +++ b/src/ios_support.h @@ -1,7 +1,7 @@ #ifndef IOS_SUPPORT_H #define IOS_SUPPORT_H 1 -void se_ios_open_file_picker( int num_extensions, const char ** extensions); -void se_ios_get_safe_ui_padding(float *top, float* bottom,float* left, float *right); +void se_ios_open_file_picker(int num_extensions, const char **extensions); +void se_ios_get_safe_ui_padding(float *top, float *bottom, float *left, float *right); void se_ios_set_documents_working_directory(); #endif diff --git a/src/localization.c b/src/localization.c index 63d03bbe1..4134fd769 100644 --- a/src/localization.c +++ b/src/localization.c @@ -10,12 +10,12 @@ #include #endif -// Strings added in v3 requiring translation: +// Strings added in v3 requiring translation: // - "Avoid NDS Touchscreen" // - ICON_FK_PLUS " New" // - "Create new files in path" (which replaced "Create new save files in Save Path") // - ICON_FK_KEY " Action Replay Codes" (optional) -// - "Cheat Code Path" +// - "Cheat Code Path" // Strings added in v4 requiring translation: // - "Disabled in Hardcore Mode" @@ -23,10 +23,10 @@ // - "Slow" // - "Fast Forward" -//#define SHOW_TRANSLATE_ME 1 +// #define SHOW_TRANSLATE_ME 1 -//Special thanks to https://github.com/shooterspps and Nilay for the Chinese Translation -static char* zh_localization_array[]={ +// Special thanks to https://github.com/shooterspps and Nilay for the Chinese Translation +static char *zh_localization_array[] = { ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " 载入游戏", "Up", "上", "Down", "下", @@ -36,10 +36,10 @@ static char* zh_localization_array[]={ "Select", "选择", "Fold Screen (NDS)", "折叠屏幕 (NDS)", "Tap Screen (NDS)", "点击屏幕 (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "模拟器 " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "模拟器 " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "模拟器 " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "模拟器 " ICON_FK_FAST_FORWARD, + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "模拟器 " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "模拟器 " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "模拟器 " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "模拟器 " ICON_FK_FAST_FORWARD, "Capture State 0", "即时存档 0", "Restore State 0", "即时读档 0", "Capture State 1", "即时存档 1", @@ -109,7 +109,7 @@ static char* zh_localization_array[]={ "You can also drag & drop a ROM/save file to load it", "你也可以通过拖放载入一个 ROM/存档文件", "Open ROM", "打开 ROM", ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " 载入最近玩过的游戏", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " 导出存档", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " 导出存档", "No recently played games", "最近没有玩过游戏", ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " 控制器", "Controller", "控制器", @@ -137,7 +137,7 @@ static char* zh_localization_array[]={ "Reset Palette to Defaults", "重置调色板默认值", ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " 键盘快捷键", "Reset Default Keybinds", "重置键盘快捷键默认值", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " 高级", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " 高级", "Light Mode", "浅色模式", "Show Debug Tools", "显示调试工具", "Adjust volume", "调节音量", @@ -209,31 +209,29 @@ static char* zh_localization_array[]={ "MENU", "菜单", "Enable Turbo and Hold Button Modifiers", "启用按住按键连发", "Scale", "缩放", - "Scale: %.2f","缩放 %.2f", - "GBA Color Correction Type","GBA 颜色校正类型", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " 界面", - "Full Screen","全屏", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " 额外搜索路径", - "Save File/State Path","即时存档/文件路径", - "BIOS/Firmware Path","BIOS/固件路径", - "Create new save files in Save Path","在存档路径中创建新的存档文件", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " BIOS/固件文件位置", - "Force GB games to run in DMG mode","强制在 DMG 模式下运行 GB 游戏", - "Enable HTTP Control Server","启用 HTTP 服务器控制", - "Server Port","服务器端口", - "Toggle Full Screen","切换全屏", - //Strings added in V3 + "Scale: %.2f", "缩放 %.2f", + "GBA Color Correction Type", "GBA 颜色校正类型", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " 界面", + "Full Screen", "全屏", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " 额外搜索路径", + "Save File/State Path", "即时存档/文件路径", + "BIOS/Firmware Path", "BIOS/固件路径", + "Create new save files in Save Path", "在存档路径中创建新的存档文件", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " BIOS/固件文件位置", + "Force GB games to run in DMG mode", "强制在 DMG 模式下运行 GB 游戏", + "Enable HTTP Control Server", "启用 HTTP 服务器控制", + "Server Port", "服务器端口", + "Toggle Full Screen", "切换全屏", + // Strings added in V3 "Avoid NDS Touchscreen", "避开NDS触屏", ICON_FK_PLUS " New", ICON_FK_PLUS " 新建", ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Action Replay 代码", "Create new files in paths", "在路径中创建新文件", "Cheat Code Path", "作弊码路径", - NULL,NULL -}; - + NULL, NULL}; // Armenian translation by https://github.com/udxs -static char* hy_localization_array[]={ +static char *hy_localization_array[] = { ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Տեղադրեք Խաղ", "Up", "Վերև", "Down", "Ներքև", @@ -243,10 +241,10 @@ static char* hy_localization_array[]={ "Select", "Ընտրեք", "Fold Screen (NDS)", "Ծալեք Էկր. (NDS)", "Tap Screen (NDS)", "Հպեք Էկր. (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Վերարտադ. " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Վերարտադ. " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Վերարտադ. " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Վերարտադ. " ICON_FK_FAST_FORWARD, + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Վերարտադ. " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Վերարտադ. " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Վերարտադ. " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Վերարտադ. " ICON_FK_FAST_FORWARD, "Capture State 0", "Նկարեք Վիճակը 0", "Restore State 0", "Վերա. Վիճակը 0", "Capture State 1", "Նկարեք Վիճակը 1", @@ -316,7 +314,7 @@ static char* hy_localization_array[]={ "You can also drag & drop a ROM/save file to load it", "Կարող եք նաև քաշել և թողնել որևէ ROM թե պահվածկ՝ այն տեղադրելու համար", "Open ROM", "Բացեք «ROM»", ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Տեղադրեք Վերջերս Խաղացված", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD "Արտահանեք Պահվածկ", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD "Արտահանեք Պահվածկ", "No recently played games", "Վերջերս խաղարկված չկա:", ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Կարգավորիչներ", "Controller", "Կարգավորիչն", @@ -344,7 +342,7 @@ static char* hy_localization_array[]={ "Reset Palette to Defaults", "Վերականգնեք Լռելյայն Գունապնակը", ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Կոճակների Կապերը", "Reset Default Keybinds", "Վերականգնեք Կոճակների Լռելյայն Կապերը", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Բարդ", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Բարդ", "Light Mode", "Լույսի թեմա", "Show Debug Tools", "Ցույց Տվեք Ինժեներական Գործիքները", "Adjust volume", "Կարգավորեք ձայնի ծավալը", @@ -416,33 +414,32 @@ static char* hy_localization_array[]={ "MENU", "ՄԵՆՅՈՒ", "Enable Turbo and Hold Button Modifiers", "Միացնեք Տուրբո և Մոդիֆիկատորների Կոճակները", "Scale", "Չափս", - "Scale: %.2f","Չափս %.2f", - "GBA Color Correction Type","Գույնի Ուղղման Տեսակը", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " Միջերես", - "Full Screen","Ամբողջ էկրանով", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Լրացուցիչ Փնտրելու Վայրեր", - "Save File/State Path","Պահպանեք Վայրերը", - "BIOS/Firmware Path","BIOS/Որոնվածը Վայրը", - "Create new save files in Save Path","Ստեղծեք նոր պահպանման ֆայլեր Պահպանել Վայրը", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " BIOS/Որոնվածը Ֆայլեր", - "Force GB games to run in DMG mode","Ստիպել «ԳԲ» խաղերին աշխատել «DMG» ռեժիմով", - "Enable HTTP Control Server","Միացնեք «HTTP» Կառավարման Սերվերը", - "Server Port","Սերվերի Պորտ", - "Toggle Full Screen","Ամբողջ էկրանը", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Չենք կարող գտնել բոլոր անհրաժեշտ\nBIOS/Գործարկման ROM/Որոնվածային ֆայլերը:", - "Accuracy will suffer and some features won't work.","Ճշգրտությունը կտուժի\nև որոշ գործառույթներ չեն աշխատի:", - //New in v3 + "Scale: %.2f", "Չափս %.2f", + "GBA Color Correction Type", "Գույնի Ուղղման Տեսակը", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " Միջերես", + "Full Screen", "Ամբողջ էկրանով", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Լրացուցիչ Փնտրելու Վայրեր", + "Save File/State Path", "Պահպանեք Վայրերը", + "BIOS/Firmware Path", "BIOS/Որոնվածը Վայրը", + "Create new save files in Save Path", "Ստեղծեք նոր պահպանման ֆայլեր Պահպանել Վայրը", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " BIOS/Որոնվածը Ֆայլեր", + "Force GB games to run in DMG mode", "Ստիպել «ԳԲ» խաղերին աշխատել «DMG» ռեժիմով", + "Enable HTTP Control Server", "Միացնեք «HTTP» Կառավարման Սերվերը", + "Server Port", "Սերվերի Պորտ", + "Toggle Full Screen", "Ամբողջ էկրանը", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Չենք կարող գտնել բոլոր անհրաժեշտ\nBIOS/Գործարկման ROM/Որոնվածային ֆայլերը:", + "Accuracy will suffer and some features won't work.", "Ճշգրտությունը կտուժի\nև որոշ գործառույթներ չեն աշխատի:", + // New in v3 "Avoid NDS Touchscreen", "Մի ծածկեք NDS-ի էկրանը կառավարիչներով", ICON_FK_PLUS " New", ICON_FK_PLUS "Ավելացնեք", ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " «Action Replay» Կոդեր", "Create new files in paths", "Ստեղծեք նոր ֆայլեր ուղիներով", "Cheat Code Path", "Խաբել Կոդը Ուղին", - NULL,NULL -}; + NULL, NULL}; // Greek translation by https://github.com/OFFTKP -static char* gr_localization_array[]={ +static char *gr_localization_array[] = { ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Φόρτωση Παιχνιδιού", "Up", "Πάνω", "Down", "Κάτω", @@ -452,10 +449,10 @@ static char* gr_localization_array[]={ "Select", "Επιλογή", "Fold Screen (NDS)", "Δίπλωμα Οθ. (NDS)", "Tap Screen (NDS)", "Άγγιγμα Οθ. (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Εξομοιωτής " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Εξομοιωτής " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Εξομοιωτής " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Εξομοιωτής " ICON_FK_FAST_FORWARD, + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Εξομοιωτής " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Εξομοιωτής " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Εξομοιωτής " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Εξομοιωτής " ICON_FK_FAST_FORWARD, "Capture State 0", "Αποθήκ. Κατάστ. 0", "Restore State 0", "Φόρτωση Κατάστ. 0", "Capture State 1", "Αποθήκ. Κατάστ. 1", @@ -525,7 +522,7 @@ static char* gr_localization_array[]={ "You can also drag & drop a ROM/save file to load it", "Μπορείς επίσης να σύρεις ένα ROM/αρχείο αποθήκευσης για να το φορτώσεις", "Open ROM", "Άνοιγμα ROM", ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Φόρτωση Πρόσφατα Παιγμένου Παιχνιδιού", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Εξαγωγή Αποθήκευσης", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Εξαγωγή Αποθήκευσης", "No recently played games", "Δεν υπάρχουν πρόσφατα παιγμένα παιχνίδια", ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Χειριστήρια", "Controller", "Χειριστήριο", @@ -553,7 +550,7 @@ static char* gr_localization_array[]={ "Reset Palette to Defaults", "Επαναφορά Παλέτας στις Προεπιλογές", ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Πλήκτρα", "Reset Default Keybinds", "Επαναφορά Προεπιλεγμένων Πλήκτρων", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Για Προχωρημένους", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Για Προχωρημένους", "Light Mode", "Φωτεινή Λειτουργία", "Show Debug Tools", "Εμφάνιση Εργαλείων Αποσφαλμάτωσης", "Adjust volume", "Ρύθμιση Έντασης", @@ -625,32 +622,31 @@ static char* gr_localization_array[]={ "MENU", "Μενού", "Enable Turbo and Hold Button Modifiers", "Ενεργ. Τροποπ. Τούρμπο και Πατημένου Κουμπιού", "Scale", "Κλίμακα", - "Scale: %.2f","Κλίμακα: %.2f", - "GBA Color Correction Type","Τύπος Διόρθ. Χρώματος GBA", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " Γραφικό Περιβάλλον Διεπαφής Χρήστη", - "Full Screen","Πλήρης Οθόνη", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Επιπλέον Μονοπάτια Αναζήτησης", - "Save File/State Path","Μονοπ. Αποθηκ. Καταστ.", - "BIOS/Firmware Path","Μονοπ. BIOS/Υλικολογ.", - "Create new save files in Save Path","Δημιουργία νέων αρχείων στο Μονοπάτι Αποθήκευσης", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " Βρέθεντα BIOS/Υλικολογισμικά αρχεία", - "Force GB games to run in DMG mode","Αναγκαστική εκκίν. GB παιχνιδιών σε DMG λειτουργία", - "Enable HTTP Control Server","Ενεργοποίηση HTTP Σέρβερ Ελέγχου", - "Server Port","Θύρα Σέρβερ", - "Toggle Full Screen","Εναλλ. Πλήρους Οθ.", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Δεν βρέθηκαν όλα τα απαραίτητα BIOS/Boot ROM/Υλικολογισμικά αρχεία.", - "Accuracy will suffer and some features won't work.","Η ακρίβεια θα επηρεαστεί και ορισμένες λειτουργίες δεν θα λειτουργήσουν.", + "Scale: %.2f", "Κλίμακα: %.2f", + "GBA Color Correction Type", "Τύπος Διόρθ. Χρώματος GBA", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " Γραφικό Περιβάλλον Διεπαφής Χρήστη", + "Full Screen", "Πλήρης Οθόνη", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Επιπλέον Μονοπάτια Αναζήτησης", + "Save File/State Path", "Μονοπ. Αποθηκ. Καταστ.", + "BIOS/Firmware Path", "Μονοπ. BIOS/Υλικολογ.", + "Create new save files in Save Path", "Δημιουργία νέων αρχείων στο Μονοπάτι Αποθήκευσης", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " Βρέθεντα BIOS/Υλικολογισμικά αρχεία", + "Force GB games to run in DMG mode", "Αναγκαστική εκκίν. GB παιχνιδιών σε DMG λειτουργία", + "Enable HTTP Control Server", "Ενεργοποίηση HTTP Σέρβερ Ελέγχου", + "Server Port", "Θύρα Σέρβερ", + "Toggle Full Screen", "Εναλλ. Πλήρους Οθ.", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Δεν βρέθηκαν όλα τα απαραίτητα BIOS/Boot ROM/Υλικολογισμικά αρχεία.", + "Accuracy will suffer and some features won't work.", "Η ακρίβεια θα επηρεαστεί και ορισμένες λειτουργίες δεν θα λειτουργήσουν.", // New in v3 "Avoid NDS Touchscreen", "Αποφυγή οθ. αφής NDS", ICON_FK_PLUS " New", ICON_FK_PLUS " Νέο", ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Action Replay", "Create new files in paths", "Δημιουργία νέων αρχείων στα μονοπάτια", "Cheat Code Path", "Μονοπάτι Cheat Code", - NULL,NULL -}; + NULL, NULL}; // Dutch translation by https://github.com/DenSinH -static char* nl_localization_array[]={ +static char *nl_localization_array[] = { ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Spel laden", "Up", "Omhoog", "Down", "Omlaag", @@ -660,10 +656,10 @@ static char* nl_localization_array[]={ "Select", "Select", "Fold Screen (NDS)", "Scherm dichtvouwen (NDS)", "Tap Screen (NDS)", "Scherm aanraken (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Emulator " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Emulator " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Emulator " ICON_FK_FAST_FORWARD, + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Emulator " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Emulator " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Emulator " ICON_FK_FAST_FORWARD, "Capture State 0", "Staat 0 vastleggen", "Restore State 0", "Staat 0 herstellen", "Capture State 1", "Staat 1 vastleggen", @@ -733,7 +729,7 @@ static char* nl_localization_array[]={ "You can also drag & drop a ROM/save file to load it", "Je kan ook een ROM- of savebestand slepen en neerzetten om het te laden", "Open ROM", "ROM Openen", ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Laad Recent Gespeeld Spel", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Save Exporteren", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Save Exporteren", "No recently played games", "Geen recent gespeelde spellen", ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Controllers", "Controller", "Controller", @@ -761,7 +757,7 @@ static char* nl_localization_array[]={ "Reset Palette to Defaults", "Paletten Naar Standaard Herstellen", ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Sneltoetsen", "Reset Default Keybinds", "Standaard Sneltoetsen Herstellen", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Geavanceerd", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Geavanceerd", "Light Mode", "Lichte Modus", "Show Debug Tools", "Debug Hulpprogrammas Weergeven", "Adjust volume", "Volume Aanpassen", @@ -833,31 +829,30 @@ static char* nl_localization_array[]={ "MENU", "MENU", "Enable Turbo and Hold Button Modifiers", "Turbo- en Indrukkingsaanpassingen Inschakelen", "Scale", "Schaal", - "Scale: %.2f","Schaal %.2f", - "GBA Color Correction Type","GBA Kleurcorrectie Type", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " GUI", - "Full Screen","Volledig Scherm", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Extra Zoekpaden", - "Save File/State Path","Save Bestand/Staat Pad", - "BIOS/Firmware Path","BIOS/Firmware Pad", - "Create new save files in Save Path","Nieuwe savebestanden in Save Pad maken", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " BIOS/Firmwarebestanden Gevonden", - "Force GB games to run in DMG mode","Forceer GB spellen in DMG modus te runnen", - "Enable HTTP Control Server","HTTP Controleserver Inschakelen", - "Server Port","Server Port", - "Toggle Full Screen","Volledig Scherm In- of Uitschakelen", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Kan niet alle benodigde BIOS/Boot ROM/Firmwarebestanden vinden", - "Accuracy will suffer and some features won't work.","Precisie zal minder worden en sommige functies zullen niet werken", - //New in v3 + "Scale: %.2f", "Schaal %.2f", + "GBA Color Correction Type", "GBA Kleurcorrectie Type", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " GUI", + "Full Screen", "Volledig Scherm", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Extra Zoekpaden", + "Save File/State Path", "Save Bestand/Staat Pad", + "BIOS/Firmware Path", "BIOS/Firmware Pad", + "Create new save files in Save Path", "Nieuwe savebestanden in Save Pad maken", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " BIOS/Firmwarebestanden Gevonden", + "Force GB games to run in DMG mode", "Forceer GB spellen in DMG modus te runnen", + "Enable HTTP Control Server", "HTTP Controleserver Inschakelen", + "Server Port", "Server Port", + "Toggle Full Screen", "Volledig Scherm In- of Uitschakelen", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Kan niet alle benodigde BIOS/Boot ROM/Firmwarebestanden vinden", + "Accuracy will suffer and some features won't work.", "Precisie zal minder worden en sommige functies zullen niet werken", + // New in v3 "Avoid NDS Touchscreen", "Vermijd NDS Aanraakscherm", ICON_FK_PLUS " New", ICON_FK_PLUS " Nieuw", ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Action Replay Codes", "Create new files in paths", "Maak nieuwe bestanden in paden", "Cheat Code Path", "Cheat Code Pad", - NULL,NULL -}; + NULL, NULL}; // Danish Translation by https://github.com/nadiaholmquist -static char* da_localization_array[]={ +static char *da_localization_array[] = { ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Åbn spil", "Up", "Op", "Down", "Ned", @@ -867,10 +862,10 @@ static char* da_localization_array[]={ "Select", "Select", "Fold Screen (NDS)", "Fold skærm (NDS)", "Tap Screen (NDS)", "Rør skærm (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Emulator " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Emulator " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Emulator " ICON_FK_FAST_FORWARD, + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Emulator " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Emulator " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Emulator " ICON_FK_FAST_FORWARD, "Capture State 0", "Gem snapshot 0", "Restore State 0", "Gendan snapshot 0", "Capture State 1", "Gem snapshot 1", @@ -940,7 +935,7 @@ static char* da_localization_array[]={ "You can also drag & drop a ROM/save file to load it", "Du kan også trække og slippe et ROM eller gemt spil for at åbne det", "Open ROM", "Åbn ROM", ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Åbn nyligt spillet spil", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Eksporter gemt spil", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Eksporter gemt spil", "No recently played games", "Ingen nyligt spillede spil", ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Controllere", "Controller", "Controller", @@ -968,7 +963,7 @@ static char* da_localization_array[]={ "Reset Palette to Defaults", "Nulstil palet til standard", ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Tastaturbindinger", "Reset Default Keybinds", "Nulstil til standard-tastaturbindinger", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Avanceret", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Avanceret", "Light Mode", "Lys tilstand", "Show Debug Tools", "Vis værktøjer til fejlfinding", "Adjust volume", "Juster lydstyrke", @@ -1039,31 +1034,30 @@ static char* da_localization_array[]={ "MENU", "Menu", "Enable Turbo and Hold Button Modifiers", "Aktiver turbo og hold af knapper", "Scale", "Skalering", - "Scale: %.2f","Skalering: %.2f", - "GBA Color Correction Type","Farvekorrektur-type for GBA", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " Grænseflade", - "Full Screen","Fuld skærm", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Ekstra søgestier", - "Save File/State Path","Sti til gem/snapshots", - "BIOS/Firmware Path","Sti til BIOS/firmware", - "Create new save files in Save Path","Opret nye gemt spil-filer under gemte-stien", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " Fundne BIOS/firmware-filer", - "Force GB games to run in DMG mode","Gennemtving GB-spil at køre i DMG-tilstand", - "Enable HTTP Control Server","Aktiver HTTP-kontrolserver", - "Server Port","Serverport", - "Toggle Full Screen","Fuld skærm til/fra", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Kan ikke finde alle nødvendige BIOS-, boot ROM-\neller firmware-filer.", - "Accuracy will suffer and some features won't work.","Emulering vil være mindre akkurat og nogle funk-\ntioner vil ikke virke.", - //New in V3 + "Scale: %.2f", "Skalering: %.2f", + "GBA Color Correction Type", "Farvekorrektur-type for GBA", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " Grænseflade", + "Full Screen", "Fuld skærm", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Ekstra søgestier", + "Save File/State Path", "Sti til gem/snapshots", + "BIOS/Firmware Path", "Sti til BIOS/firmware", + "Create new save files in Save Path", "Opret nye gemt spil-filer under gemte-stien", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " Fundne BIOS/firmware-filer", + "Force GB games to run in DMG mode", "Gennemtving GB-spil at køre i DMG-tilstand", + "Enable HTTP Control Server", "Aktiver HTTP-kontrolserver", + "Server Port", "Serverport", + "Toggle Full Screen", "Fuld skærm til/fra", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Kan ikke finde alle nødvendige BIOS-, boot ROM-\neller firmware-filer.", + "Accuracy will suffer and some features won't work.", "Emulering vil være mindre akkurat og nogle funk-\ntioner vil ikke virke.", + // New in V3 "Avoid NDS Touchscreen", "Undgå NDS-touchskærm", ICON_FK_PLUS " New", ICON_FK_PLUS " Ny", ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Action Replay-koder", "Create new files in paths", "Opret nye filer under stierne", "Cheat Code Path", "Snydekode-sti", - NULL,NULL -}; + NULL, NULL}; // German translation https://github.com/ladystarbreeze -static char* de_localization_array[]={ +static char *de_localization_array[] = { ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Lade Spiel", "Up", "Hoch", "Down", "Runter", @@ -1073,10 +1067,10 @@ static char* de_localization_array[]={ "Select", "Select", "Fold Screen (NDS)", "Bildschirm zuklappen (NDS)", "Tap Screen (NDS)", "Bildschirm berühren (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Emulator " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Emulator " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Emulator " ICON_FK_FAST_FORWARD, + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Emulator " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Emulator " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Emulator " ICON_FK_FAST_FORWARD, "Capture State 0", "Erstelle Save 0", "Restore State 0", "Lade Save 0", "Capture State 1", "Erstelle Save 1", @@ -1146,7 +1140,7 @@ static char* de_localization_array[]={ "You can also drag & drop a ROM/save file to load it", "Du kannst ein ROM/Save auch durch Ziehen und Ablegen laden", "Open ROM", "Öffne ROM", ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Lade zuletzt gespieltes Spiel", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Exportiere Save", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Exportiere Save", "No recently played games", "Keine zuletzt gespielten Spiele", ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Controller", "Controller", "Controller", @@ -1174,7 +1168,7 @@ static char* de_localization_array[]={ "Reset Palette to Defaults", "Stelle Standardpalette wieder her", ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Tastenbelegung", "Reset Default Keybinds", "Stelle Standardbelegung wieder her", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Erweitert", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Erweitert", "Light Mode", "Helles Design", "Show Debug Tools", "Zeige Debug-Tools", "Adjust volume", "Passe Lautstärke an", @@ -1246,596 +1240,595 @@ static char* de_localization_array[]={ "MENU", "MENÜ", "Enable Turbo and Hold Button Modifiers", "Schalte Turbo- und Hold-Modifizierer ein", "Scale", "Skalierung", - "Scale: %.2f","Skalierung: %.2f", - "GBA Color Correction Type","GBA-Farbkorrekturtyp", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " Benutzeroberfläche", - "Full Screen","Vollbildschirm", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Weitere Suchpfade", - "Save File/State Path","Save-Pfad", - "BIOS/Firmware Path","BIOS-/Firmwarepfad", - "Create new save files in Save Path","Erstelle neues Save in Save-Pfad", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " BIOS-/Firmwaredateien gefunden", - "Force GB games to run in DMG mode","Zwinge GB-Spiele, im DMG-Modus zu laufen", - "Enable HTTP Control Server","Aktiviere HTTP-Kontrollserver", - "Server Port","Serverport", - "Toggle Full Screen","Vollbild ein/aus", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Nicht alle benötigten BIOS-/Boot-ROM-/Firmwaredateien konnten gefunden werden.", - "Accuracy will suffer and some features won't work.","Genauigkeit ist verringert und einige Funktionen werden nicht funkionieren.", + "Scale: %.2f", "Skalierung: %.2f", + "GBA Color Correction Type", "GBA-Farbkorrekturtyp", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " Benutzeroberfläche", + "Full Screen", "Vollbildschirm", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Weitere Suchpfade", + "Save File/State Path", "Save-Pfad", + "BIOS/Firmware Path", "BIOS-/Firmwarepfad", + "Create new save files in Save Path", "Erstelle neues Save in Save-Pfad", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " BIOS-/Firmwaredateien gefunden", + "Force GB games to run in DMG mode", "Zwinge GB-Spiele, im DMG-Modus zu laufen", + "Enable HTTP Control Server", "Aktiviere HTTP-Kontrollserver", + "Server Port", "Serverport", + "Toggle Full Screen", "Vollbild ein/aus", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Nicht alle benötigten BIOS-/Boot-ROM-/Firmwaredateien konnten gefunden werden.", + "Accuracy will suffer and some features won't work.", "Genauigkeit ist verringert und einige Funktionen werden nicht funkionieren.", // New in v3 "Avoid NDS Touchscreen", "Meide NDS-Touchscreen", - ICON_FK_PLUS " New", ICON_FK_PLUS " Neu" - ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Action Replay-Codes", + ICON_FK_PLUS " New", ICON_FK_PLUS " Neu" ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Action Replay-Codes", "Create new files in paths", "Erstelle neue Dateien in Pfaden", "Cheat Code Path", "Cheatcode-Pfad", - NULL,NULL -}; + NULL, NULL}; // Italian translation by https://github.com/SimoneN64 -static char* it_localization_array[]={ - ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Carica Gioco", - "Up", "Sù", - "Down", "Giù", - "Left", "Sinistra", - "Right", "Destra", - "Start", "Start", - "Select", "Select", - "Fold Screen (NDS)", "Piega (NDS)", - "Tap Screen (NDS)", "Tocca (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulatore " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Emulatore " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Emulatore " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Emulatore " ICON_FK_FAST_FORWARD, - "Capture State 0", "Cattura Stato 0", - "Restore State 0", "Ripristina Stato 0", - "Capture State 1", "Cattura Stato 1", - "Restore State 1", "Ripristina Stato 1", - "Capture State 2", "Cattura Stato 2", - "Restore State 2", "Ripristina Stato 2", - "Capture State 3", "Cattura Stato 3", - "Restore State 3", "Ripristina Stato 3", - "Analog Up/Down", "Analogico Sù/Giù", - "Analog Left/Right", "Analogico Sinistra/Destra", - "Analog L", "Analogico L", - "Analog R", "Analogico R", - "Display FPS: %2.1f\n", "FPS dello schermo: %2.1f\n", - "Emulation FPS: %2.1f\n", "FPS d'emulazione: %2.1f\n", - ICON_FK_VOLUME_UP " Audio", ICON_FK_VOLUME_UP " Audio", - "Left Audio Channel", "Canale Sinistro dell'Audio", - "Right Audio Channel", "Canale Destro dell'Audio", - "Channel 0", "Canale 0", - "Channel 1", "Canale 1", - "Channel 2", "Canale 2", - "Channel 3", "Canale 3", - "Channel 4", "Canale 4", - "Channel 5", "Canale 5", - "Channel 6", "Canale 6", - "Channel 7", "Canale 7", - "Channel 8", "Canale 8", - "Channel 9", "Canale 9", - "Channel A", "Canale A", - "Channel B", "Canale B", - "Channel C", "Canale C", - "Channel D", "Canale D", - "Channel E", "Canale E", - "Channel F", "Canale F", - "Channel 1 (Square)", "Canale 1 (Quadra)", - "Channel 2 (Square)", "Canale 2 (Quadra)", - "Channel 3 (Wave)", "Canale 3 (Tabella)", - "Channel 4 (Noise)", "Canale 4 (Rumore)", - "Channel A (FIFO)", "Canale A (FIFO)", - "Channel B (FIFO)", "Canale B (FIFO)", - "Audio Ring (Samples Available: %d)", "Anello Audio (Campioni disponibili: %d)", - "Audio Watchdog Triggered %d Times", "Watch-dog Audio innescato %d volte", - ICON_FK_INFO_CIRCLE " Build Info", ICON_FK_INFO_CIRCLE " Info Build", - "Commit Hash:", "Hash del Commit:", - ICON_FK_SERVER " Registers", ICON_FK_SERVER " Registri", - ICON_FK_LIST_OL " Disassembly", ICON_FK_LIST_OL " Disassembly", - ICON_FK_EXCHANGE " Read/Write Memory Address", ICON_FK_EXCHANGE " Indirizzo memoria Read/Write", - "address", "indirizzo", - "data (32 bit)", "dato (32 bit)", - "data (16 bit)", "dato (16 bit)", - "data (8 bit)", "dato (8 bit)", - "data (signed 32b)", "dato (-/+32 bit)", - "data (signed 16b)", "dato (-/+16 bit)", - "data (signed 8b)", "dato (-/+8 bit)", - ICON_FK_PENCIL_SQUARE_O " Memory", ICON_FK_PENCIL_SQUARE_O " Memoria", - ICON_FK_AREA_CHART " Emulator Stats", ICON_FK_AREA_CHART " Statistiche Emulatore", - "Show/Hide %s Panel\n", "Nascondi/mostra pannello %s\n", - "Press new button " ICON_FK_SIGN_IN, "Premi il nuovo tasto " ICON_FK_SIGN_IN, - "Move Axis ", "Asse Movimento ", - "Not bound", "Non assegnato", - "Hat %d %s", "Hat %d %s", - "Analog %d %s", "Analogico %d %s", - "Key %d", "Tasto %d", - "Analog %d (%0.2f)", "Analogico %d (%0.2f)", - "Load ROM from file (.gb, .gbc, .gba, .zip)", "Carica ROM da file (.gb, .gbc, .gba, .zip)", - "You can also drag & drop a ROM to load it", "Puoi anche trascinare una ROM per caricarla", - "Load ROM(.gb, .gbc, .gba, .zip), save(.sav), or GBA bios (gba_bios.bin) from file", "Carica una ROM(.gb, .gbc, .gba, .zip), salvataggio(.sav), o bios GBA (gba_bios.bin) da file", - "You can also drag & drop a ROM/save file to load it", "Puoi anche trascinare una ROM/file di salvataggio per caricarla/o", - "Open ROM", "Apri ROM", - ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Carica Gioco giocato di recente", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Esporta Salvataggio", - "No recently played games", "Nessun gioco giocato di recente", - ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Controller", - "Controller", "Controller", - "No Controller", "Nessun Controller", - "Reset Default Controller Bindings", "Reimposta assegnazioni default per il controller", - "Rumble Supported", "Rumble Supportato", - "Rumble Not Supported", "Rumble Non Supportato", - ICON_FK_FLOPPY_O " Save States", ICON_FK_FLOPPY_O " Salvataggi di Stato", - "Save Slot %d", "Slot %d", - "Capture", "Cattura", - "Restore", "Ripristina", - "This save state came from an incompatible build. SkyEmu has attempted to recover it, but there may be issues", "Questo salvataggio di stato deriva da una build incompatibile. SkyEmu ha provato a recuperarlo, ma potrebbero esserci problemi", - ICON_FK_DESKTOP " Display Settings", ICON_FK_DESKTOP " Impostazioni Display", - "Screen Shader", "Shader Schermo", - "Pixelate\0Bilinear\0LCD\0LCD & Subpixels\0Smooth Upscale (xBRZ)\0", "Pixellato\0Bilineare\0LCD\0LCD & Subpixels\0Upscaling Liscio (xBRZ)\0", - "Screen Rotation", "Rotazione Schermo", - "0 degrees\00090 degrees\000180 degrees\000270 degrees\0", "0°\00090°\000180°\000270°\0", - "Color Correction", "Correzione Colore", - "Strength: %.2f", "Forza: %.2f", - "Screen Ghosting", "Schermo Fantasma", - "Force Integer Scaling", "Forza il ridimensionamento a numeri interi", - "Stretch Screen to Fit", "Allarga lo schermo per riempire", - "Game Boy Color Palette", "Palette Game Boy Color", - "GB Palette %d", "Palette GB %d", - "Reset Palette to Defaults", "Reimposta palette default", - ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Assegnazione tasti", - "Reset Default Keybinds", "Reimposta assegnazioni default per i tasti", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Avanzate", - "Light Mode", "Modalità chiara", - "Show Debug Tools", "Mostra strumenti di Debug", - "Adjust volume", "Aggiusta il volume", - "Show/Hide Menu Panel", "Mostra/Nascondi il pannello Menu", - "Rewind at 8x speed", "Riavvolgi a velocità 8x", - "Rewind at 4x speed", "Riavvolgi a velocità 4x", - "Toggle pause/play.\n When paused, the rom selection screen will be shown.", "Alterna play/pausa.\n Quando in pausa, il dialogo di selezione della rom verrà mostrato.", - "Run at 2x Speed", "Esegui a velocità 2x", - "Run at the fastest speed possible", "Esegui quanto più veloce possibile", - "Screen", "Schermo", - "LCD Shader Init", "Inizializzazione shader LCD", - "Menu", "Menu", - "Copy as..", "Copia come..", - "Current", "Attuale", - "Original", "Originale", - "Opacity", "Opacità", - ICON_FK_HAND_O_RIGHT " Touch Control Settings", ICON_FK_HAND_O_RIGHT " Impostazioni controllo Touch", - "Hide when inactive", "Nascondi quando inattivo", - ICON_FK_FILE_O " Dump Memory to File", ICON_FK_FILE_O " Scarica contenuto della memoria su File", - "Start Address", "Indirizzo di inizio", - "Size", "Dimensione", - "Save Memory Dump", "Salva contenuto della memoria", - ICON_FK_RANDOM " Last Branch Locations", ICON_FK_RANDOM " Posizione dell'ultima diramazione", - "Opacity: %.2f", "Opacità: %.2f", - "Step Instruction", "Esegui istruzione", - "Step Frame", "Esegui Frame", - "Disconnect Log", "Disconnetti Log", - ICON_FK_FOLDER_OPEN " Open File From Disk", ICON_FK_FOLDER_OPEN " Apri File Dal Disco", - "Exit File Browser", "Esci dall'Esplora File", - "Go back to recently loaded games", "Torna ai giochi caricati di recente", - "Go to parent directory", "Torna alla cartella madre", - "UP", "SÙ", - "DOWN", "GIÙ", - "LEFT", "SINISTRA", - "RIGHT", "DESTRA", - "Reset Game", "Riavvia Gioco", - "Turbo A", "Turbo A", - "Turbo B", "Turbo B", - "Turbo X", "Turbo X", - "Turbo Y", "Turbo Y", - "Turbo L", "Turbo L", - "Turbo R", "Turbo R", - "Solar Sensor+", "Sensore Solare+", - "Solar Sensor-", "Sensore Solare-", - "Theme", "Tema", - "Solar Sensor", "Sensore Solare", - "Brightness: %.2f", "Luminosità: %.2f", - "Dark\0Light\0Black\0", "Scuro\0Chiaro\0Nero\0", - "Always Show Menu/Nav Bar", "Mostra barra Menu/Nav sempre", - "Language", "Lingua", - "SPACE", "SPAZIO", - "ESCAPE", "ESC", - "ENTER", "INVIO", - "BACKSPACE", "BACKSPACE", - "INSERT", "INSERT", - "DELETE", "DELETE", - "RIGHT", "DESTRA", - "LEFT", "SINISTRA", - "DOWN", "GIÙ", - "UP", "SÙ", - "LEFT_SHIFT", "Shift Sinistro", - "LEFT_CONTROL", "Control Sinistro", - "LEFT_ALT", "Alt Sinistro", - "LEFT_SUPER", "Super Sinistro", - "RIGHT_SHIFT", "Shift Destro", - "RIGHT_CONTROL", "Control Destro", - "RIGHT_ALT", "Alt Destro", - "RIGHT_SUPER", "Super Destro", - "MENU", "MENU", - "Enable Turbo and Hold Button Modifiers", "Abilità modificatori tasti Turbo e Hold", - "Scale", "Dimensione", - "Scale: %.2f","Dimensione %.2f", - "GBA Color Correction Type","Tipo correzione colore GBA", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " GUI", - "Full Screen","Schermo Intero", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Path Aggiuntivi per la Ricerca", - "Save File/State Path","Path salvataggi", - "BIOS/Firmware Path","Path BIOS", - "Create new save files in Save Path","Crea nuovi salvataggi di file nella Path dei salvataggi", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " File del BIOS/Firmware situati", - "Force GB games to run in DMG mode","Forza esecuzione dei giochi GB in modalità DMG", - "Enable HTTP Control Server","Abilità server di controllo tramite HTTP", - "Server Port","Porta Server", - "Toggle Full Screen","Full Screen", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Non ho trovato i file di Boot-ROM/BIOS/Firmware.", - "Accuracy will suffer and some features won't work.","L'accuratezza e alcune feature ne risentiranno.", - //New in V3 - "Avoid NDS Touchscreen", "Evita il touchscreen del NDS", - ICON_FK_PLUS " New", ICON_FK_PLUS " Nuovo", - ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Codici Action Replay", - "Create new files in paths", "Crea nuovi file nei path", - "Cheat Code Path", "Path dei trucchi", - NULL,NULL -}; +static char *it_localization_array[] = { + ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Carica Gioco", + "Up", "Sù", + "Down", "Giù", + "Left", "Sinistra", + "Right", "Destra", + "Start", "Start", + "Select", "Select", + "Fold Screen (NDS)", "Piega (NDS)", + "Tap Screen (NDS)", "Tocca (NDS)", + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Emulatore " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Emulatore " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Emulatore " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Emulatore " ICON_FK_FAST_FORWARD, + "Capture State 0", "Cattura Stato 0", + "Restore State 0", "Ripristina Stato 0", + "Capture State 1", "Cattura Stato 1", + "Restore State 1", "Ripristina Stato 1", + "Capture State 2", "Cattura Stato 2", + "Restore State 2", "Ripristina Stato 2", + "Capture State 3", "Cattura Stato 3", + "Restore State 3", "Ripristina Stato 3", + "Analog Up/Down", "Analogico Sù/Giù", + "Analog Left/Right", "Analogico Sinistra/Destra", + "Analog L", "Analogico L", + "Analog R", "Analogico R", + "Display FPS: %2.1f\n", "FPS dello schermo: %2.1f\n", + "Emulation FPS: %2.1f\n", "FPS d'emulazione: %2.1f\n", + ICON_FK_VOLUME_UP " Audio", ICON_FK_VOLUME_UP " Audio", + "Left Audio Channel", "Canale Sinistro dell'Audio", + "Right Audio Channel", "Canale Destro dell'Audio", + "Channel 0", "Canale 0", + "Channel 1", "Canale 1", + "Channel 2", "Canale 2", + "Channel 3", "Canale 3", + "Channel 4", "Canale 4", + "Channel 5", "Canale 5", + "Channel 6", "Canale 6", + "Channel 7", "Canale 7", + "Channel 8", "Canale 8", + "Channel 9", "Canale 9", + "Channel A", "Canale A", + "Channel B", "Canale B", + "Channel C", "Canale C", + "Channel D", "Canale D", + "Channel E", "Canale E", + "Channel F", "Canale F", + "Channel 1 (Square)", "Canale 1 (Quadra)", + "Channel 2 (Square)", "Canale 2 (Quadra)", + "Channel 3 (Wave)", "Canale 3 (Tabella)", + "Channel 4 (Noise)", "Canale 4 (Rumore)", + "Channel A (FIFO)", "Canale A (FIFO)", + "Channel B (FIFO)", "Canale B (FIFO)", + "Audio Ring (Samples Available: %d)", "Anello Audio (Campioni disponibili: %d)", + "Audio Watchdog Triggered %d Times", "Watch-dog Audio innescato %d volte", + ICON_FK_INFO_CIRCLE " Build Info", ICON_FK_INFO_CIRCLE " Info Build", + "Commit Hash:", "Hash del Commit:", + ICON_FK_SERVER " Registers", ICON_FK_SERVER " Registri", + ICON_FK_LIST_OL " Disassembly", ICON_FK_LIST_OL " Disassembly", + ICON_FK_EXCHANGE " Read/Write Memory Address", ICON_FK_EXCHANGE " Indirizzo memoria Read/Write", + "address", "indirizzo", + "data (32 bit)", "dato (32 bit)", + "data (16 bit)", "dato (16 bit)", + "data (8 bit)", "dato (8 bit)", + "data (signed 32b)", "dato (-/+32 bit)", + "data (signed 16b)", "dato (-/+16 bit)", + "data (signed 8b)", "dato (-/+8 bit)", + ICON_FK_PENCIL_SQUARE_O " Memory", ICON_FK_PENCIL_SQUARE_O " Memoria", + ICON_FK_AREA_CHART " Emulator Stats", ICON_FK_AREA_CHART " Statistiche Emulatore", + "Show/Hide %s Panel\n", "Nascondi/mostra pannello %s\n", + "Press new button " ICON_FK_SIGN_IN, "Premi il nuovo tasto " ICON_FK_SIGN_IN, + "Move Axis ", "Asse Movimento ", + "Not bound", "Non assegnato", + "Hat %d %s", "Hat %d %s", + "Analog %d %s", "Analogico %d %s", + "Key %d", "Tasto %d", + "Analog %d (%0.2f)", "Analogico %d (%0.2f)", + "Load ROM from file (.gb, .gbc, .gba, .zip)", "Carica ROM da file (.gb, .gbc, .gba, .zip)", + "You can also drag & drop a ROM to load it", "Puoi anche trascinare una ROM per caricarla", + "Load ROM(.gb, .gbc, .gba, .zip), save(.sav), or GBA bios (gba_bios.bin) from file", "Carica una ROM(.gb, .gbc, .gba, .zip), salvataggio(.sav), o bios GBA (gba_bios.bin) da file", + "You can also drag & drop a ROM/save file to load it", "Puoi anche trascinare una ROM/file di salvataggio per caricarla/o", + "Open ROM", "Apri ROM", + ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Carica Gioco giocato di recente", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Esporta Salvataggio", + "No recently played games", "Nessun gioco giocato di recente", + ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Controller", + "Controller", "Controller", + "No Controller", "Nessun Controller", + "Reset Default Controller Bindings", "Reimposta assegnazioni default per il controller", + "Rumble Supported", "Rumble Supportato", + "Rumble Not Supported", "Rumble Non Supportato", + ICON_FK_FLOPPY_O " Save States", ICON_FK_FLOPPY_O " Salvataggi di Stato", + "Save Slot %d", "Slot %d", + "Capture", "Cattura", + "Restore", "Ripristina", + "This save state came from an incompatible build. SkyEmu has attempted to recover it, but there may be issues", "Questo salvataggio di stato deriva da una build incompatibile. SkyEmu ha provato a recuperarlo, ma potrebbero esserci problemi", + ICON_FK_DESKTOP " Display Settings", ICON_FK_DESKTOP " Impostazioni Display", + "Screen Shader", "Shader Schermo", + "Pixelate\0Bilinear\0LCD\0LCD & Subpixels\0Smooth Upscale (xBRZ)\0", "Pixellato\0Bilineare\0LCD\0LCD & Subpixels\0Upscaling Liscio (xBRZ)\0", + "Screen Rotation", "Rotazione Schermo", + "0 degrees\00090 degrees\000180 degrees\000270 degrees\0", "0°\00090°\000180°\000270°\0", + "Color Correction", "Correzione Colore", + "Strength: %.2f", "Forza: %.2f", + "Screen Ghosting", "Schermo Fantasma", + "Force Integer Scaling", "Forza il ridimensionamento a numeri interi", + "Stretch Screen to Fit", "Allarga lo schermo per riempire", + "Game Boy Color Palette", "Palette Game Boy Color", + "GB Palette %d", "Palette GB %d", + "Reset Palette to Defaults", "Reimposta palette default", + ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Assegnazione tasti", + "Reset Default Keybinds", "Reimposta assegnazioni default per i tasti", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Avanzate", + "Light Mode", "Modalità chiara", + "Show Debug Tools", "Mostra strumenti di Debug", + "Adjust volume", "Aggiusta il volume", + "Show/Hide Menu Panel", "Mostra/Nascondi il pannello Menu", + "Rewind at 8x speed", "Riavvolgi a velocità 8x", + "Rewind at 4x speed", "Riavvolgi a velocità 4x", + "Toggle pause/play.\n When paused, the rom selection screen will be shown.", "Alterna play/pausa.\n Quando in pausa, il dialogo di selezione della rom verrà mostrato.", + "Run at 2x Speed", "Esegui a velocità 2x", + "Run at the fastest speed possible", "Esegui quanto più veloce possibile", + "Screen", "Schermo", + "LCD Shader Init", "Inizializzazione shader LCD", + "Menu", "Menu", + "Copy as..", "Copia come..", + "Current", "Attuale", + "Original", "Originale", + "Opacity", "Opacità", + ICON_FK_HAND_O_RIGHT " Touch Control Settings", ICON_FK_HAND_O_RIGHT " Impostazioni controllo Touch", + "Hide when inactive", "Nascondi quando inattivo", + ICON_FK_FILE_O " Dump Memory to File", ICON_FK_FILE_O " Scarica contenuto della memoria su File", + "Start Address", "Indirizzo di inizio", + "Size", "Dimensione", + "Save Memory Dump", "Salva contenuto della memoria", + ICON_FK_RANDOM " Last Branch Locations", ICON_FK_RANDOM " Posizione dell'ultima diramazione", + "Opacity: %.2f", "Opacità: %.2f", + "Step Instruction", "Esegui istruzione", + "Step Frame", "Esegui Frame", + "Disconnect Log", "Disconnetti Log", + ICON_FK_FOLDER_OPEN " Open File From Disk", ICON_FK_FOLDER_OPEN " Apri File Dal Disco", + "Exit File Browser", "Esci dall'Esplora File", + "Go back to recently loaded games", "Torna ai giochi caricati di recente", + "Go to parent directory", "Torna alla cartella madre", + "UP", "SÙ", + "DOWN", "GIÙ", + "LEFT", "SINISTRA", + "RIGHT", "DESTRA", + "Reset Game", "Riavvia Gioco", + "Turbo A", "Turbo A", + "Turbo B", "Turbo B", + "Turbo X", "Turbo X", + "Turbo Y", "Turbo Y", + "Turbo L", "Turbo L", + "Turbo R", "Turbo R", + "Solar Sensor+", "Sensore Solare+", + "Solar Sensor-", "Sensore Solare-", + "Theme", "Tema", + "Solar Sensor", "Sensore Solare", + "Brightness: %.2f", "Luminosità: %.2f", + "Dark\0Light\0Black\0", "Scuro\0Chiaro\0Nero\0", + "Always Show Menu/Nav Bar", "Mostra barra Menu/Nav sempre", + "Language", "Lingua", + "SPACE", "SPAZIO", + "ESCAPE", "ESC", + "ENTER", "INVIO", + "BACKSPACE", "BACKSPACE", + "INSERT", "INSERT", + "DELETE", "DELETE", + "RIGHT", "DESTRA", + "LEFT", "SINISTRA", + "DOWN", "GIÙ", + "UP", "SÙ", + "LEFT_SHIFT", "Shift Sinistro", + "LEFT_CONTROL", "Control Sinistro", + "LEFT_ALT", "Alt Sinistro", + "LEFT_SUPER", "Super Sinistro", + "RIGHT_SHIFT", "Shift Destro", + "RIGHT_CONTROL", "Control Destro", + "RIGHT_ALT", "Alt Destro", + "RIGHT_SUPER", "Super Destro", + "MENU", "MENU", + "Enable Turbo and Hold Button Modifiers", "Abilità modificatori tasti Turbo e Hold", + "Scale", "Dimensione", + "Scale: %.2f", "Dimensione %.2f", + "GBA Color Correction Type", "Tipo correzione colore GBA", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " GUI", + "Full Screen", "Schermo Intero", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Path Aggiuntivi per la Ricerca", + "Save File/State Path", "Path salvataggi", + "BIOS/Firmware Path", "Path BIOS", + "Create new save files in Save Path", "Crea nuovi salvataggi di file nella Path dei salvataggi", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " File del BIOS/Firmware situati", + "Force GB games to run in DMG mode", "Forza esecuzione dei giochi GB in modalità DMG", + "Enable HTTP Control Server", "Abilità server di controllo tramite HTTP", + "Server Port", "Porta Server", + "Toggle Full Screen", "Full Screen", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Non ho trovato i file di Boot-ROM/BIOS/Firmware.", + "Accuracy will suffer and some features won't work.", "L'accuratezza e alcune feature ne risentiranno.", + // New in V3 + "Avoid NDS Touchscreen", "Evita il touchscreen del NDS", + ICON_FK_PLUS " New", ICON_FK_PLUS " Nuovo", + ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Codici Action Replay", + "Create new files in paths", "Crea nuovi file nei path", + "Cheat Code Path", "Path dei trucchi", + NULL, NULL}; // Russian translation by https://github.com/GreatA1exander -static char* ru_localization_array[]={ - ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Загрузить игру", - "Up", "Вверх", - "Down", "Вниз", - "Left", "Лево", - "Right", "Право", - "Start", "Начинать", - "Select", "Выбирать", - "Fold Screen (NDS)", "Закрыть Эк. (NDS)", - "Tap Screen (NDS)", "Нажать Эк. (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Эмулятор " ICON_FK_PAUSE "/" ICON_FK_PLAY, - "Emulator " ICON_FK_BACKWARD, "Эмулятор " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, "Эмулятор " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, "Эмулятор " ICON_FK_FAST_FORWARD, - "Capture State 0", "Поймать Coc. 0", - "Restore State 0", "Загрузить Coc. 0", - "Capture State 1", "Поймать Coc. 1", - "Restore State 1", "Загрузить Coc. 1", - "Capture State 2", "Поймать Coc. 2", - "Restore State 2", "Загрузить Coc. 2", - "Capture State 3", "Поймать Coc. 3", - "Restore State 3", "Загрузить Coc. 3", - "Analog Up/Down", "Аналогичискый Вверх/Вниз", - "Analog Left/Right", "Аналогичискый Лево/Право", - "Analog L", "Аналогичискый L", - "Analog R", "Аналогичискый R", - "Display FPS: %2.1f\n", "Видимый FPS: %2.1f\n", - "Emulation FPS: %2.1f\n", "Эмуляторскии FPS: %2.1f\n", - ICON_FK_VOLUME_UP " Звук", ICON_FK_VOLUME_UP " Звук", - "Left Audio Channel", "Левый звуковой канал", - "Right Audio Channel", "Правый звуковой канал", - "Channel 0", "Канал 0", - "Channel 1", "Канал 1", - "Channel 2", "Канал 2", - "Channel 3", "Канал 3", - "Channel 4", "Канал 4", - "Channel 5", "Канал 5", - "Channel 6", "Канал 6", - "Channel 7", "Канал 7", - "Channel 8", "Канал 8", - "Channel 9", "Канал 9", - "Channel A", "Канал A", - "Channel B", "Канал B", - "Channel C", "Канал C", - "Channel D", "Канал D", - "Channel E", "Канал E", - "Channel F", "Канал F", - "Channel 1 (Square)", "Канал 1 (Квадрат)", - "Channel 2 (Square)", "Канал 2 (Квадрат)", - "Channel 3 (Wave)", "Канал 3 (Волна)", - "Channel 4 (Noise)", "Канал 4 (Шум)", - "Channel A (FIFO)", "Канал A (FIFO)", - "Channel B (FIFO)", "Канал B (FIFO)", - "Audio Ring (Samples Available: %d)", "Звуковое кольцо (Доступны образцы: %d)", - "Audio Watchdog Triggered %d Times", "Сработал сторожевой таймер аудио %d раз", - ICON_FK_INFO_CIRCLE " Build Info", ICON_FK_INFO_CIRCLE " Информация о сборке", - "Commit Hash:", "Хэш:", - ICON_FK_SERVER " Registers", ICON_FK_SERVER " Регистры", - ICON_FK_LIST_OL " Disassembly", ICON_FK_LIST_OL " Разборка", - ICON_FK_EXCHANGE " Read/Write Memory Address", ICON_FK_EXCHANGE " Адрес памяти Read/Write", - "address", "Адрес", - "data (32 bit)", "Данные (32 bit)", - "data (16 bit)", "Данные (16 bit)", - "data (8 bit)", "Данные (8 bit)", - "data (signed 32b)", "Данные (±32 bit)", - "data (signed 16b)", "Данные (±16 bit)", - "data (signed 8b)", "Данные (±8 bit)", - ICON_FK_PENCIL_SQUARE_O " Memory", ICON_FK_PENCIL_SQUARE_O " Память", - ICON_FK_AREA_CHART " Emulator Stats", ICON_FK_AREA_CHART " Статистики эмулятора", - "Show/Hide %s Panel\n", "Показывать/Прятать Панель %s\n", - "Press new button " ICON_FK_SIGN_IN, "Нажимать новую кнопку " ICON_FK_SIGN_IN, - "Move Axis ", "Подвижная ось ", - "Not bound", "Не привязана", - "Hat %d %s", "Шапка %d %s", - "Analog %d %s", "Аналог %d %s", - "Key %d", "Клавиша %d", - "Analog %d (%0.2f)", "Аналог %d (%0.2f)", - "Load ROM from file (.gb, .gbc, .gba, .zip)", "Загрузить ROM из файла (.gb, .gbc, .gba, .zip)", - "You can also drag & drop a ROM to load it", "Вы также можете перетащить ROM и загрузить его", - "Load ROM(.gb, .gbc, .gba, .zip), save(.sav), or GBA bios (gba_bios.bin) from file", "Загрузить ROM(.gb, .gbc, .gba, .zip), сохраненный файл(.sav), или биос GBA (gba_bios.bin) из файла", - "You can also drag & drop a ROM/save file to load it", "Вы также можете перетащить ROM/файл и загрузить его", - "Open ROM", "Открыть ROM", - ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Загрузить недавно сыгранную игру", - ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Экспорт файл сохранения", - "No recently played games", "Нет недавно сыгранных игр", - ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Контроллеры", - "Controller", "Контроллер", - "No Controller", "Отсутствует Контроллер", - "Reset Default Controller Bindings", "Сбросить привязки контроллера", - "Rumble Supported", "Громыхание существует", - "Rumble Not Supported", "Громыхание не существует", - ICON_FK_FLOPPY_O " Save States", ICON_FK_FLOPPY_O " Сохранение состояния", - "Save Slot %d", "Слот %d", - "Capture", "Поймать", - "Restore", "Загрузить", - "This save state came from an incompatible build. SkyEmu has attempted to recover it, but there may be issues", "Это состояние сохранения получено из несовместимой сборки. SkyEmu попытался восстановить его, но могут возникнуть проблемы", - ICON_FK_DESKTOP " Display Settings", ICON_FK_DESKTOP " Настройки отображения", - "Screen Shader", "Шейдер экрана", - "Pixelate\0Bilinear\0LCD\0LCD & Subpixels\0Smooth Upscale (xBRZ)\0", "Пикселизация\0Билинейный\0LCD\0LCD & субпиксель\0Плавно увеличиват разрешение (xBRZ)\0", - "Screen Rotation", "Вращение экрана", - "0 degrees\00090 degrees\000180 degrees\000270 degrees\0", "0°\00090°\000180°\000270°\0", - "Color Correction", "Коррекция цвета", - "Сила: %.2f", "Forza: %.2f", - "Screen Ghosting", "Призрак экрана", - "Force Integer Scaling", "Целочисленное разрешение мандата", - "Stretch Screen to Fit", "Растянуть экран по размеру", - "Game Boy Color Palette", "Палитра Game Boy Color", - "GB Palette %d", "Палитра GB %d", - "Reset Palette to Defaults", "Сбросить палитру", - ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Связки клавиш", - "Reset Default Keybinds", "Сбросить сочетания клавиш", - ICON_FK_WRENCH " Advanced",ICON_FK_WRENCH " Сложный", - "Light Mode", "Яркий режим", - "Show Debug Tools", "Показать инструменты отладки", - "Adjust volume", "Отрегулировать громкость", - "Show/Hide Menu Panel", "Показать/скрыть панель меню", - "Rewind at 8x speed", "Перемотка назад с 8-кратной скоростью", - "Rewind at 4x speed", "Перемотка назад с 4-кратной скоростью", - "Toggle pause/play.\n When paused, the rom selection screen will be shown.", "Переключить паузу/пуск.\n При паузе будет показан экран выбора ROM.", - "Run at 2x Speed", "Играть с удвоенной скоростью", - "Run at the fastest speed possible", "Играть на максимальной скорости", - "Screen", "Экран", - "LCD Shader Init", "Инициализация шейдера LCD", - "Menu", "Меню", - "Copy as..", "Скопировать как..", - "Current", "Действительный", - "Original", "Оригинал", - "Opacity", "Непрозрачность", - ICON_FK_HAND_O_RIGHT " Touch Control Settings", ICON_FK_HAND_O_RIGHT " Настройки касания", - "Hide when inactive", "Прятать когда неактивен", - ICON_FK_FILE_O " Dump Memory to File", ICON_FK_FILE_O " Дамп памяти в файл", - "Start Address", "Начальный адрес", - "Size", "Размер", - "Save Memory Dump", "Сохранить дамп памяти", - ICON_FK_RANDOM " Last Branch Locations", ICON_FK_RANDOM " Местоположения последней ветки", - "Opacity: %.2f", "Непрозрачность: %.2f", - "Step Instruction", "Шаг инструкция", - "Step Frame", "Шаг Рамки", - "Disconnect Log", "Выключить журнал", - ICON_FK_FOLDER_OPEN " Open File From Disk", ICON_FK_FOLDER_OPEN " Открыть файл с диска", - "Exit File Browser", "Выйти файлового браузера", - "Go back to recently loaded games", "Вернуться к недавно загруженным играм", - "Go to parent directory", "Перейти в родительский папку", - "UP", "ВВЕРХ", - "DOWN", "ВНИЗ", - "LEFT", "ЛЕВО", - "RIGHT", "ПРАВО", - "Reset Game", "Перезапуск игри", - "Turbo A", "Турбо A", - "Turbo B", "Турбо B", - "Turbo X", "Турбо X", - "Turbo Y", "Турбо Y", - "Turbo L", "Турбо L", - "Turbo R", "Турбо R", - "Solar Sensor+", "Солнечный+", - "Solar Sensor-", "Солнечный-", - "Theme", "Тема", - "Solar Sensor", "Солнечный датчик", - "Brightness: %.2f", "Яркость: %.2f", - "Dark\0Light\0Black\0", "Тьма\0Свет\0Черный\0", - "Always Show Menu/Nav Bar", "Всегда показывать панель меню/навигации", - "Language", "Язык", - "SPACE", "ПРОБЕЛ", - "ESCAPE", "ESC", - "ENTER", "ENTER", - "BACKSPACE", "BACK", - "INSERT", "INSERT", - "DELETE", "DELETE", - "RIGHT", "ПРАВО", - "LEFT", "ЛЕВО", - "DOWN", "ВНИЗ", - "UP", "ВВЕРХ", - "LEFT_SHIFT", "Левый шифт", - "LEFT_CONTROL", "Левый контроль", - "LEFT_ALT", "Левый альт", - "LEFT_SUPER", "Левый супер", - "RIGHT_SHIFT", "Правый шифт", - "RIGHT_CONTROL", "Правый контроль", - "RIGHT_ALT", "Правый альт", - "RIGHT_SUPER", "Правый супер", - "MENU", "MENU", - "Enable Turbo and Hold Button Modifiers", "Включить Turbo и Hold", - "Scale", "Масштаб", - "Scale: %.2f","Масштаб %.2f", - "GBA Color Correction Type","Тип коррекции цвета GBA", - ICON_FK_TEXT_HEIGHT " GUI",ICON_FK_TEXT_HEIGHT " GUI", - "Full Screen","Полноэкранный", - ICON_FK_CODE_FORK " Additional Search Paths",ICON_FK_CODE_FORK " Дополнительные пути поиска", - "Save File/State Path","Путь сохранений", - "BIOS/Firmware Path","Путь BIOS", - "Create new save files in Save Path","Создайте новые файлы сохранения в пути сохранения", - ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files",ICON_FK_CROSSHAIRS " Найдены файлы BIOS/Firmware", - "Force GB games to run in DMG mode","Заставить игры GB работать в режиме DMG", - "Enable HTTP Control Server","Включить сервер управления HTTP", - "Server Port","Порт сервер", - "Toggle Full Screen","Полноэкранный", - "Can't find all needed BIOS/Boot ROM/Firmware Files.","Не удается найти все файлы BIOS/Boot ROM/Firmware.", - "Accuracy will suffer and some features won't work.","Точность будет страдать, и некоторые функции не будут работать.", - //New in V3 - "Avoid NDS Touchscreen", "Не используйте второй экран NDS", - ICON_FK_PLUS " New", ICON_FK_PLUS " Новый", - ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Коды Action Replay", - "Create new files in paths", "Создавать новые файлы в путях", - "Cheat Code Path", "Путь к чит-кодам", - NULL,NULL -}; +static char *ru_localization_array[] = { + ICON_FK_FILE_O " Load Game", ICON_FK_FILE_O " Загрузить игру", + "Up", "Вверх", + "Down", "Вниз", + "Left", "Лево", + "Right", "Право", + "Start", "Начинать", + "Select", "Выбирать", + "Fold Screen (NDS)", "Закрыть Эк. (NDS)", + "Tap Screen (NDS)", "Нажать Эк. (NDS)", + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, "Эмулятор " ICON_FK_PAUSE "/" ICON_FK_PLAY, + "Emulator " ICON_FK_BACKWARD, "Эмулятор " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, "Эмулятор " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, "Эмулятор " ICON_FK_FAST_FORWARD, + "Capture State 0", "Поймать Coc. 0", + "Restore State 0", "Загрузить Coc. 0", + "Capture State 1", "Поймать Coc. 1", + "Restore State 1", "Загрузить Coc. 1", + "Capture State 2", "Поймать Coc. 2", + "Restore State 2", "Загрузить Coc. 2", + "Capture State 3", "Поймать Coc. 3", + "Restore State 3", "Загрузить Coc. 3", + "Analog Up/Down", "Аналогичискый Вверх/Вниз", + "Analog Left/Right", "Аналогичискый Лево/Право", + "Analog L", "Аналогичискый L", + "Analog R", "Аналогичискый R", + "Display FPS: %2.1f\n", "Видимый FPS: %2.1f\n", + "Emulation FPS: %2.1f\n", "Эмуляторскии FPS: %2.1f\n", + ICON_FK_VOLUME_UP " Звук", ICON_FK_VOLUME_UP " Звук", + "Left Audio Channel", "Левый звуковой канал", + "Right Audio Channel", "Правый звуковой канал", + "Channel 0", "Канал 0", + "Channel 1", "Канал 1", + "Channel 2", "Канал 2", + "Channel 3", "Канал 3", + "Channel 4", "Канал 4", + "Channel 5", "Канал 5", + "Channel 6", "Канал 6", + "Channel 7", "Канал 7", + "Channel 8", "Канал 8", + "Channel 9", "Канал 9", + "Channel A", "Канал A", + "Channel B", "Канал B", + "Channel C", "Канал C", + "Channel D", "Канал D", + "Channel E", "Канал E", + "Channel F", "Канал F", + "Channel 1 (Square)", "Канал 1 (Квадрат)", + "Channel 2 (Square)", "Канал 2 (Квадрат)", + "Channel 3 (Wave)", "Канал 3 (Волна)", + "Channel 4 (Noise)", "Канал 4 (Шум)", + "Channel A (FIFO)", "Канал A (FIFO)", + "Channel B (FIFO)", "Канал B (FIFO)", + "Audio Ring (Samples Available: %d)", "Звуковое кольцо (Доступны образцы: %d)", + "Audio Watchdog Triggered %d Times", "Сработал сторожевой таймер аудио %d раз", + ICON_FK_INFO_CIRCLE " Build Info", ICON_FK_INFO_CIRCLE " Информация о сборке", + "Commit Hash:", "Хэш:", + ICON_FK_SERVER " Registers", ICON_FK_SERVER " Регистры", + ICON_FK_LIST_OL " Disassembly", ICON_FK_LIST_OL " Разборка", + ICON_FK_EXCHANGE " Read/Write Memory Address", ICON_FK_EXCHANGE " Адрес памяти Read/Write", + "address", "Адрес", + "data (32 bit)", "Данные (32 bit)", + "data (16 bit)", "Данные (16 bit)", + "data (8 bit)", "Данные (8 bit)", + "data (signed 32b)", "Данные (±32 bit)", + "data (signed 16b)", "Данные (±16 bit)", + "data (signed 8b)", "Данные (±8 bit)", + ICON_FK_PENCIL_SQUARE_O " Memory", ICON_FK_PENCIL_SQUARE_O " Память", + ICON_FK_AREA_CHART " Emulator Stats", ICON_FK_AREA_CHART " Статистики эмулятора", + "Show/Hide %s Panel\n", "Показывать/Прятать Панель %s\n", + "Press new button " ICON_FK_SIGN_IN, "Нажимать новую кнопку " ICON_FK_SIGN_IN, + "Move Axis ", "Подвижная ось ", + "Not bound", "Не привязана", + "Hat %d %s", "Шапка %d %s", + "Analog %d %s", "Аналог %d %s", + "Key %d", "Клавиша %d", + "Analog %d (%0.2f)", "Аналог %d (%0.2f)", + "Load ROM from file (.gb, .gbc, .gba, .zip)", "Загрузить ROM из файла (.gb, .gbc, .gba, .zip)", + "You can also drag & drop a ROM to load it", "Вы также можете перетащить ROM и загрузить его", + "Load ROM(.gb, .gbc, .gba, .zip), save(.sav), or GBA bios (gba_bios.bin) from file", "Загрузить ROM(.gb, .gbc, .gba, .zip), сохраненный файл(.sav), или биос GBA (gba_bios.bin) из файла", + "You can also drag & drop a ROM/save file to load it", "Вы также можете перетащить ROM/файл и загрузить его", + "Open ROM", "Открыть ROM", + ICON_FK_CLOCK_O " Load Recently Played Game", ICON_FK_CLOCK_O " Загрузить недавно сыгранную игру", + ICON_FK_DOWNLOAD " Export Save", ICON_FK_DOWNLOAD " Экспорт файл сохранения", + "No recently played games", "Нет недавно сыгранных игр", + ICON_FK_GAMEPAD " Controllers", ICON_FK_GAMEPAD " Контроллеры", + "Controller", "Контроллер", + "No Controller", "Отсутствует Контроллер", + "Reset Default Controller Bindings", "Сбросить привязки контроллера", + "Rumble Supported", "Громыхание существует", + "Rumble Not Supported", "Громыхание не существует", + ICON_FK_FLOPPY_O " Save States", ICON_FK_FLOPPY_O " Сохранение состояния", + "Save Slot %d", "Слот %d", + "Capture", "Поймать", + "Restore", "Загрузить", + "This save state came from an incompatible build. SkyEmu has attempted to recover it, but there may be issues", "Это состояние сохранения получено из несовместимой сборки. SkyEmu попытался восстановить его, но могут возникнуть проблемы", + ICON_FK_DESKTOP " Display Settings", ICON_FK_DESKTOP " Настройки отображения", + "Screen Shader", "Шейдер экрана", + "Pixelate\0Bilinear\0LCD\0LCD & Subpixels\0Smooth Upscale (xBRZ)\0", "Пикселизация\0Билинейный\0LCD\0LCD & субпиксель\0Плавно увеличиват разрешение (xBRZ)\0", + "Screen Rotation", "Вращение экрана", + "0 degrees\00090 degrees\000180 degrees\000270 degrees\0", "0°\00090°\000180°\000270°\0", + "Color Correction", "Коррекция цвета", + "Сила: %.2f", "Forza: %.2f", + "Screen Ghosting", "Призрак экрана", + "Force Integer Scaling", "Целочисленное разрешение мандата", + "Stretch Screen to Fit", "Растянуть экран по размеру", + "Game Boy Color Palette", "Палитра Game Boy Color", + "GB Palette %d", "Палитра GB %d", + "Reset Palette to Defaults", "Сбросить палитру", + ICON_FK_KEYBOARD_O " Keybinds", ICON_FK_KEYBOARD_O " Связки клавиш", + "Reset Default Keybinds", "Сбросить сочетания клавиш", + ICON_FK_WRENCH " Advanced", ICON_FK_WRENCH " Сложный", + "Light Mode", "Яркий режим", + "Show Debug Tools", "Показать инструменты отладки", + "Adjust volume", "Отрегулировать громкость", + "Show/Hide Menu Panel", "Показать/скрыть панель меню", + "Rewind at 8x speed", "Перемотка назад с 8-кратной скоростью", + "Rewind at 4x speed", "Перемотка назад с 4-кратной скоростью", + "Toggle pause/play.\n When paused, the rom selection screen will be shown.", "Переключить паузу/пуск.\n При паузе будет показан экран выбора ROM.", + "Run at 2x Speed", "Играть с удвоенной скоростью", + "Run at the fastest speed possible", "Играть на максимальной скорости", + "Screen", "Экран", + "LCD Shader Init", "Инициализация шейдера LCD", + "Menu", "Меню", + "Copy as..", "Скопировать как..", + "Current", "Действительный", + "Original", "Оригинал", + "Opacity", "Непрозрачность", + ICON_FK_HAND_O_RIGHT " Touch Control Settings", ICON_FK_HAND_O_RIGHT " Настройки касания", + "Hide when inactive", "Прятать когда неактивен", + ICON_FK_FILE_O " Dump Memory to File", ICON_FK_FILE_O " Дамп памяти в файл", + "Start Address", "Начальный адрес", + "Size", "Размер", + "Save Memory Dump", "Сохранить дамп памяти", + ICON_FK_RANDOM " Last Branch Locations", ICON_FK_RANDOM " Местоположения последней ветки", + "Opacity: %.2f", "Непрозрачность: %.2f", + "Step Instruction", "Шаг инструкция", + "Step Frame", "Шаг Рамки", + "Disconnect Log", "Выключить журнал", + ICON_FK_FOLDER_OPEN " Open File From Disk", ICON_FK_FOLDER_OPEN " Открыть файл с диска", + "Exit File Browser", "Выйти файлового браузера", + "Go back to recently loaded games", "Вернуться к недавно загруженным играм", + "Go to parent directory", "Перейти в родительский папку", + "UP", "ВВЕРХ", + "DOWN", "ВНИЗ", + "LEFT", "ЛЕВО", + "RIGHT", "ПРАВО", + "Reset Game", "Перезапуск игри", + "Turbo A", "Турбо A", + "Turbo B", "Турбо B", + "Turbo X", "Турбо X", + "Turbo Y", "Турбо Y", + "Turbo L", "Турбо L", + "Turbo R", "Турбо R", + "Solar Sensor+", "Солнечный+", + "Solar Sensor-", "Солнечный-", + "Theme", "Тема", + "Solar Sensor", "Солнечный датчик", + "Brightness: %.2f", "Яркость: %.2f", + "Dark\0Light\0Black\0", "Тьма\0Свет\0Черный\0", + "Always Show Menu/Nav Bar", "Всегда показывать панель меню/навигации", + "Language", "Язык", + "SPACE", "ПРОБЕЛ", + "ESCAPE", "ESC", + "ENTER", "ENTER", + "BACKSPACE", "BACK", + "INSERT", "INSERT", + "DELETE", "DELETE", + "RIGHT", "ПРАВО", + "LEFT", "ЛЕВО", + "DOWN", "ВНИЗ", + "UP", "ВВЕРХ", + "LEFT_SHIFT", "Левый шифт", + "LEFT_CONTROL", "Левый контроль", + "LEFT_ALT", "Левый альт", + "LEFT_SUPER", "Левый супер", + "RIGHT_SHIFT", "Правый шифт", + "RIGHT_CONTROL", "Правый контроль", + "RIGHT_ALT", "Правый альт", + "RIGHT_SUPER", "Правый супер", + "MENU", "MENU", + "Enable Turbo and Hold Button Modifiers", "Включить Turbo и Hold", + "Scale", "Масштаб", + "Scale: %.2f", "Масштаб %.2f", + "GBA Color Correction Type", "Тип коррекции цвета GBA", + ICON_FK_TEXT_HEIGHT " GUI", ICON_FK_TEXT_HEIGHT " GUI", + "Full Screen", "Полноэкранный", + ICON_FK_CODE_FORK " Additional Search Paths", ICON_FK_CODE_FORK " Дополнительные пути поиска", + "Save File/State Path", "Путь сохранений", + "BIOS/Firmware Path", "Путь BIOS", + "Create new save files in Save Path", "Создайте новые файлы сохранения в пути сохранения", + ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files", ICON_FK_CROSSHAIRS " Найдены файлы BIOS/Firmware", + "Force GB games to run in DMG mode", "Заставить игры GB работать в режиме DMG", + "Enable HTTP Control Server", "Включить сервер управления HTTP", + "Server Port", "Порт сервер", + "Toggle Full Screen", "Полноэкранный", + "Can't find all needed BIOS/Boot ROM/Firmware Files.", "Не удается найти все файлы BIOS/Boot ROM/Firmware.", + "Accuracy will suffer and some features won't work.", "Точность будет страдать, и некоторые функции не будут работать.", + // New in V3 + "Avoid NDS Touchscreen", "Не используйте второй экран NDS", + ICON_FK_PLUS " New", ICON_FK_PLUS " Новый", + ICON_FK_KEY " Action Replay Codes", ICON_FK_KEY " Коды Action Replay", + "Create new files in paths", "Создавать новые файлы в путях", + "Cheat Code Path", "Путь к чит-кодам", + NULL, NULL}; -char ** localization_map=NULL; -size_t localization_size=0; -int se_get_default_language(); +char **localization_map = NULL; +size_t localization_size = 0; +int se_get_default_language(); -int se_localize_cmp(const void *a, const void*b){return strcmp(((const char**)a)[0],((const char**)b)[0]);} -void se_set_language(int language_enum){ - char ** new_map = NULL; - if(language_enum==SE_LANG_DEFAULT)language_enum = se_get_default_language(); - if(language_enum==SE_LANG_CHINESE)new_map = zh_localization_array; - if(language_enum==SE_LANG_ARMENIAN)new_map = hy_localization_array; - if(language_enum==SE_LANG_GREEK)new_map = gr_localization_array; - if(language_enum==SE_LANG_DUTCH)new_map = nl_localization_array; - if(language_enum==SE_LANG_DANISH)new_map = da_localization_array; - if(language_enum==SE_LANG_GERMAN)new_map = de_localization_array; - if(language_enum==SE_LANG_ITALIAN)new_map = it_localization_array; - if(language_enum==SE_LANG_RUSSIAN)new_map = ru_localization_array; - if(new_map!=localization_map){ - localization_map=new_map; - localization_size=0; - if(localization_map){ - while(localization_map[localization_size*2])++localization_size; - qsort(localization_map,localization_size,sizeof(const char*)*2,se_localize_cmp); - } +int se_localize_cmp(const void *a, const void *b) { return strcmp(((const char **)a)[0], ((const char **)b)[0]); } +void se_set_language(int language_enum) { + char **new_map = NULL; + if(language_enum == SE_LANG_DEFAULT) language_enum = se_get_default_language(); + if(language_enum == SE_LANG_CHINESE) new_map = zh_localization_array; + if(language_enum == SE_LANG_ARMENIAN) new_map = hy_localization_array; + if(language_enum == SE_LANG_GREEK) new_map = gr_localization_array; + if(language_enum == SE_LANG_DUTCH) new_map = nl_localization_array; + if(language_enum == SE_LANG_DANISH) new_map = da_localization_array; + if(language_enum == SE_LANG_GERMAN) new_map = de_localization_array; + if(language_enum == SE_LANG_ITALIAN) new_map = it_localization_array; + if(language_enum == SE_LANG_RUSSIAN) new_map = ru_localization_array; + if(new_map != localization_map) { + localization_map = new_map; + localization_size = 0; + if(localization_map) { + while(localization_map[localization_size * 2]) + ++localization_size; + qsort(localization_map, localization_size, sizeof(const char *) * 2, se_localize_cmp); } + } } -int se_convert_locale_to_enum(const char* clocale) { - // Convert the detected language to lowercase for easier comparison - char lowercase_locale[128]; // Assuming the language code won't exceed 16 characters - int i = 0; +int se_convert_locale_to_enum(const char *clocale) { + // Convert the detected language to lowercase for easier comparison + char lowercase_locale[128]; // Assuming the language code won't exceed 16 characters + int i = 0; - //Normalize case, remove country code, and code page - while (clocale[i] != '\0' && clocale[i] != '.' && clocale[i] != '_' && clocale[i] != '-' && i < 127) { - lowercase_locale[i] = tolower(clocale[i]); - i++; - } - lowercase_locale[i] = '\0'; + // Normalize case, remove country code, and code page + while(clocale[i] != '\0' && clocale[i] != '.' && clocale[i] != '_' && clocale[i] != '-' && i < 127) { + lowercase_locale[i] = tolower(clocale[i]); + i++; + } + lowercase_locale[i] = '\0'; - // Match the language to the enumeration based on ISO 639-1 and ISO 639-2 codes - // See (https://www.loc.gov/standards/iso639-2/php/code_list.php) - if (strcmp(lowercase_locale, "en") == 0 || strcmp(lowercase_locale, "eng") == 0 || strcmp(lowercase_locale, "english") == 0) { - return SE_LANG_ENGLISH; - } else if (strcmp(lowercase_locale, "ar") == 0 || strcmp(lowercase_locale, "ara") == 0 || strcmp(lowercase_locale, "arabic") == 0) { - return SE_LANG_ARABIC; - } else if (strcmp(lowercase_locale, "hy") == 0 || strcmp(lowercase_locale, "arm") == 0 || strcmp(lowercase_locale, "armenian") == 0) { - return SE_LANG_ARMENIAN; - } else if (strcmp(lowercase_locale, "bn") == 0 || strcmp(lowercase_locale, "ben") == 0 || strcmp(lowercase_locale, "bengali") == 0) { - return SE_LANG_BENGALI; - } else if (strcmp(lowercase_locale, "zh") == 0 || strcmp(lowercase_locale, "chi") == 0 || strcmp(lowercase_locale, "zho") == 0 || strcmp(lowercase_locale, "chinese") == 0) { - return SE_LANG_CHINESE; - } else if (strcmp(lowercase_locale, "da") == 0 || strcmp(lowercase_locale, "dan") == 0 || strcmp(lowercase_locale, "danish") == 0) { - return SE_LANG_DANISH; - } else if (strcmp(lowercase_locale, "nl") == 0 || strcmp(lowercase_locale, "dut") == 0 || strcmp(lowercase_locale, "dutch") == 0) { - return SE_LANG_DUTCH; - } else if (strcmp(lowercase_locale, "fr") == 0 || strcmp(lowercase_locale, "fre") == 0 || strcmp(lowercase_locale, "fra") == 0 || strcmp(lowercase_locale, "french") == 0) { - return SE_LANG_FRENCH; - } else if (strcmp(lowercase_locale, "de") == 0 || strcmp(lowercase_locale, "ger") == 0 || strcmp(lowercase_locale, "deu") == 0 || strcmp(lowercase_locale, "german") == 0) { - return SE_LANG_GERMAN; - } else if (strcmp(lowercase_locale, "el") == 0 || strcmp(lowercase_locale, "gre") == 0 || strcmp(lowercase_locale, "ell") == 0 || strcmp(lowercase_locale, "greek") == 0) { - return SE_LANG_GREEK; - } else if (strcmp(lowercase_locale, "hi") == 0 || strcmp(lowercase_locale, "hin") == 0 || strcmp(lowercase_locale, "hindi") == 0) { - return SE_LANG_HINDI; - } else if (strcmp(lowercase_locale, "it") == 0 || strcmp(lowercase_locale, "ita") == 0 || strcmp(lowercase_locale, "italian") == 0) { - return SE_LANG_ITALIAN; - } else if (strcmp(lowercase_locale, "ja") == 0 || strcmp(lowercase_locale, "jpn") == 0 || strcmp(lowercase_locale, "japanese") == 0) { - return SE_LANG_JAPANESE; - } else if (strcmp(lowercase_locale, "ko") == 0 || strcmp(lowercase_locale, "kor") == 0 || strcmp(lowercase_locale, "korean") == 0) { - return SE_LANG_KOREAN; - } else if (strcmp(lowercase_locale, "pt") == 0 || strcmp(lowercase_locale, "por") == 0 || strcmp(lowercase_locale, "portuguese") == 0) { - return SE_LANG_PORTUGESE; - } else if (strcmp(lowercase_locale, "ru") == 0 || strcmp(lowercase_locale, "rus") == 0 || strcmp(lowercase_locale, "russian") == 0) { - return SE_LANG_RUSSIAN; - } else if (strcmp(lowercase_locale, "es") == 0 || strcmp(lowercase_locale, "spa") == 0 || strcmp(lowercase_locale, "spanish") == 0) { - return SE_LANG_SPANISH; - } - return SE_LANG_DEFAULT; + // Match the language to the enumeration based on ISO 639-1 and ISO 639-2 codes + // See (https://www.loc.gov/standards/iso639-2/php/code_list.php) + if(strcmp(lowercase_locale, "en") == 0 || strcmp(lowercase_locale, "eng") == 0 || strcmp(lowercase_locale, "english") == 0) { + return SE_LANG_ENGLISH; + } else if(strcmp(lowercase_locale, "ar") == 0 || strcmp(lowercase_locale, "ara") == 0 || strcmp(lowercase_locale, "arabic") == 0) { + return SE_LANG_ARABIC; + } else if(strcmp(lowercase_locale, "hy") == 0 || strcmp(lowercase_locale, "arm") == 0 || strcmp(lowercase_locale, "armenian") == 0) { + return SE_LANG_ARMENIAN; + } else if(strcmp(lowercase_locale, "bn") == 0 || strcmp(lowercase_locale, "ben") == 0 || strcmp(lowercase_locale, "bengali") == 0) { + return SE_LANG_BENGALI; + } else if(strcmp(lowercase_locale, "zh") == 0 || strcmp(lowercase_locale, "chi") == 0 || strcmp(lowercase_locale, "zho") == 0 || strcmp(lowercase_locale, "chinese") == 0) { + return SE_LANG_CHINESE; + } else if(strcmp(lowercase_locale, "da") == 0 || strcmp(lowercase_locale, "dan") == 0 || strcmp(lowercase_locale, "danish") == 0) { + return SE_LANG_DANISH; + } else if(strcmp(lowercase_locale, "nl") == 0 || strcmp(lowercase_locale, "dut") == 0 || strcmp(lowercase_locale, "dutch") == 0) { + return SE_LANG_DUTCH; + } else if(strcmp(lowercase_locale, "fr") == 0 || strcmp(lowercase_locale, "fre") == 0 || strcmp(lowercase_locale, "fra") == 0 || strcmp(lowercase_locale, "french") == 0) { + return SE_LANG_FRENCH; + } else if(strcmp(lowercase_locale, "de") == 0 || strcmp(lowercase_locale, "ger") == 0 || strcmp(lowercase_locale, "deu") == 0 || strcmp(lowercase_locale, "german") == 0) { + return SE_LANG_GERMAN; + } else if(strcmp(lowercase_locale, "el") == 0 || strcmp(lowercase_locale, "gre") == 0 || strcmp(lowercase_locale, "ell") == 0 || strcmp(lowercase_locale, "greek") == 0) { + return SE_LANG_GREEK; + } else if(strcmp(lowercase_locale, "hi") == 0 || strcmp(lowercase_locale, "hin") == 0 || strcmp(lowercase_locale, "hindi") == 0) { + return SE_LANG_HINDI; + } else if(strcmp(lowercase_locale, "it") == 0 || strcmp(lowercase_locale, "ita") == 0 || strcmp(lowercase_locale, "italian") == 0) { + return SE_LANG_ITALIAN; + } else if(strcmp(lowercase_locale, "ja") == 0 || strcmp(lowercase_locale, "jpn") == 0 || strcmp(lowercase_locale, "japanese") == 0) { + return SE_LANG_JAPANESE; + } else if(strcmp(lowercase_locale, "ko") == 0 || strcmp(lowercase_locale, "kor") == 0 || strcmp(lowercase_locale, "korean") == 0) { + return SE_LANG_KOREAN; + } else if(strcmp(lowercase_locale, "pt") == 0 || strcmp(lowercase_locale, "por") == 0 || strcmp(lowercase_locale, "portuguese") == 0) { + return SE_LANG_PORTUGESE; + } else if(strcmp(lowercase_locale, "ru") == 0 || strcmp(lowercase_locale, "rus") == 0 || strcmp(lowercase_locale, "russian") == 0) { + return SE_LANG_RUSSIAN; + } else if(strcmp(lowercase_locale, "es") == 0 || strcmp(lowercase_locale, "spa") == 0 || strcmp(lowercase_locale, "spanish") == 0) { + return SE_LANG_SPANISH; + } + return SE_LANG_DEFAULT; } -const char* se_language_string(int language_enum){ - switch (language_enum){ - case SE_LANG_DEFAULT: return se_localize("Default"); - case SE_LANG_ENGLISH: return "English"; - case SE_LANG_DUTCH: return "Nederlands"; - case SE_LANG_DANISH: return "Dansk"; - case SE_LANG_GERMAN: return "Deutsch"; - case SE_LANG_ITALIAN: return "Italiano"; - // These languages require unicode support to represent correctly +const char *se_language_string(int language_enum) { + switch(language_enum) { + case SE_LANG_DEFAULT: return se_localize("Default"); + case SE_LANG_ENGLISH: return "English"; + case SE_LANG_DUTCH: return "Nederlands"; + case SE_LANG_DANISH: return "Dansk"; + case SE_LANG_GERMAN: return "Deutsch"; + case SE_LANG_ITALIAN: + return "Italiano"; + // These languages require unicode support to represent correctly #ifdef UNICODE_GUI - case SE_LANG_CHINESE: return "中文"; - case SE_LANG_ARMENIAN: return "Հայերեն"; - case SE_LANG_GREEK: return "Ελληνικά"; - case SE_LANG_RUSSIAN: return "Русский"; -#endif - } - return ""; + case SE_LANG_CHINESE: return "中文"; + case SE_LANG_ARMENIAN: return "Հայերեն"; + case SE_LANG_GREEK: return "Ελληνικά"; + case SE_LANG_RUSSIAN: return "Русский"; +#endif + } + return ""; } #ifdef PLATFORM_ANDROID -extern void se_android_get_language(char* language_buffer, size_t buffer_size); +extern void se_android_get_language(char *language_buffer, size_t buffer_size); +#endif +int se_get_default_language() { + static int default_lang = SE_LANG_DEFAULT; + if(default_lang == SE_LANG_DEFAULT) { +#if defined(PLATFORM_IOS) || defined(PLATFORM_MACOS) + // Try to get from CF Locale + if(default_lang == SE_LANG_DEFAULT) { + char lang_buffer[128]; + CFArrayRef langs = CFLocaleCopyPreferredLanguages(); + CFStringRef lang_code = CFArrayGetValueAtIndex(langs, 0); + CFStringGetCString(lang_code, lang_buffer, 128, kCFStringEncodingUTF8); + default_lang = se_convert_locale_to_enum(lang_buffer); + if(default_lang != SE_LANG_DEFAULT) printf("Detected CF locale language: %s (enum: %s)\n", lang_buffer, se_language_string(default_lang)); + } #endif -int se_get_default_language(){ - static int default_lang = SE_LANG_DEFAULT; - if(default_lang==SE_LANG_DEFAULT){ - #if defined(PLATFORM_IOS) || defined(PLATFORM_MACOS) - // Try to get from CF Locale - if(default_lang == SE_LANG_DEFAULT){ - char lang_buffer[128]; - CFArrayRef langs = CFLocaleCopyPreferredLanguages(); - CFStringRef lang_code = CFArrayGetValueAtIndex(langs, 0); - CFStringGetCString(lang_code, lang_buffer, 128, kCFStringEncodingUTF8); - default_lang = se_convert_locale_to_enum(lang_buffer); - if(default_lang != SE_LANG_DEFAULT) printf("Detected CF locale language: %s (enum: %s)\n", lang_buffer ,se_language_string(default_lang)); - } - #endif #ifdef PLATFORM_ANDROID - // Try to get from JNI - if(default_lang == SE_LANG_DEFAULT){ - char lang_buffer[128]; - se_android_get_language(lang_buffer,sizeof(lang_buffer)); - default_lang = se_convert_locale_to_enum(lang_buffer); - if(default_lang != SE_LANG_DEFAULT) printf("Detected language from JNI: %s (enum: %s)\n", lang_buffer ,se_language_string(default_lang)); - } + // Try to get from JNI + if(default_lang == SE_LANG_DEFAULT) { + char lang_buffer[128]; + se_android_get_language(lang_buffer, sizeof(lang_buffer)); + default_lang = se_convert_locale_to_enum(lang_buffer); + if(default_lang != SE_LANG_DEFAULT) printf("Detected language from JNI: %s (enum: %s)\n", lang_buffer, se_language_string(default_lang)); + } #endif - // Try to get from environment - if(default_lang == SE_LANG_DEFAULT){ - char* clocale = getenv("LANG"); - if(clocale) default_lang = se_convert_locale_to_enum(clocale); - if(default_lang != SE_LANG_DEFAULT) printf("Detected environment locale language: %s (enum: %s)\n", clocale ,se_language_string(default_lang)); - } + // Try to get from environment + if(default_lang == SE_LANG_DEFAULT) { + char *clocale = getenv("LANG"); + if(clocale) default_lang = se_convert_locale_to_enum(clocale); + if(default_lang != SE_LANG_DEFAULT) printf("Detected environment locale language: %s (enum: %s)\n", clocale, se_language_string(default_lang)); + } - // Try to get from setlocale - if(default_lang == SE_LANG_DEFAULT){ - setlocale(LC_ALL, ""); - char* clocale = setlocale(LC_ALL, NULL); - if(clocale) default_lang = se_convert_locale_to_enum(clocale); - if(default_lang != SE_LANG_DEFAULT) printf("Detected C locale language: %s (enum: %s)\n", clocale ,se_language_string(default_lang)); - } - - if(default_lang == SE_LANG_DEFAULT){ - printf("Couldn't detect language, defaulting to English\n"); - default_lang = SE_LANG_ENGLISH; - } - #ifdef PLATFORM_WINDOWS - //Needed to let windows open files from UTF-8 paths - setlocale(LC_ALL, ".65001"); - #endif + // Try to get from setlocale + if(default_lang == SE_LANG_DEFAULT) { + setlocale(LC_ALL, ""); + char *clocale = setlocale(LC_ALL, NULL); + if(clocale) default_lang = se_convert_locale_to_enum(clocale); + if(default_lang != SE_LANG_DEFAULT) printf("Detected C locale language: %s (enum: %s)\n", clocale, se_language_string(default_lang)); } - return default_lang; + if(default_lang == SE_LANG_DEFAULT) { + printf("Couldn't detect language, defaulting to English\n"); + default_lang = SE_LANG_ENGLISH; + } +#ifdef PLATFORM_WINDOWS + // Needed to let windows open files from UTF-8 paths + setlocale(LC_ALL, ".65001"); +#endif + } + return default_lang; } -const char* se_localize(const char* string){ - if(localization_map==NULL)return string; - const char** result = (const char**)bsearch(&string,localization_map,localization_size,sizeof(const char*)*2,se_localize_cmp); - if(!result)return string; - else return result[1]; +const char *se_localize(const char *string) { + if(localization_map == NULL) return string; + const char **result = (const char **)bsearch(&string, localization_map, localization_size, sizeof(const char *) * 2, se_localize_cmp); + if(!result) + return string; + else + return result[1]; } diff --git a/src/localization.h b/src/localization.h index 8992d3ff8..8043a78b9 100644 --- a/src/localization.h +++ b/src/localization.h @@ -1,29 +1,29 @@ #ifndef LOCALIZATION_H #define LOCALIZATION_H -#define SE_LANG_DEFAULT 0 -#define SE_LANG_ENGLISH 5 -#define SE_LANG_ARABIC 10 -#define SE_LANG_ARMENIAN 15 -#define SE_LANG_BENGALI 20 -#define SE_LANG_CHINESE 25 -#define SE_LANG_DANISH 27 -#define SE_LANG_DUTCH 30 -#define SE_LANG_FRENCH 35 -#define SE_LANG_GERMAN 40 -#define SE_LANG_GREEK 45 -#define SE_LANG_HINDI 50 -#define SE_LANG_ITALIAN 65 -#define SE_LANG_JAPANESE 55 -#define SE_LANG_KOREAN 60 +#define SE_LANG_DEFAULT 0 +#define SE_LANG_ENGLISH 5 +#define SE_LANG_ARABIC 10 +#define SE_LANG_ARMENIAN 15 +#define SE_LANG_BENGALI 20 +#define SE_LANG_CHINESE 25 +#define SE_LANG_DANISH 27 +#define SE_LANG_DUTCH 30 +#define SE_LANG_FRENCH 35 +#define SE_LANG_GERMAN 40 +#define SE_LANG_GREEK 45 +#define SE_LANG_HINDI 50 +#define SE_LANG_ITALIAN 65 +#define SE_LANG_JAPANESE 55 +#define SE_LANG_KOREAN 60 #define SE_LANG_PORTUGESE 70 -#define SE_LANG_RUSSIAN 75 -#define SE_LANG_SPANISH 80 +#define SE_LANG_RUSSIAN 75 +#define SE_LANG_SPANISH 80 #define SE_MAX_LANG_VALUE 86 -void se_set_language(int language_enum);//i.e. SE_LANG_ENGLISH -const char* se_language_string(int language_enum);//returns "" if language is not supported -const char* se_localize(const char* string); -int se_convert_locale_to_enum(const char* clocale); +void se_set_language(int language_enum); // i.e. SE_LANG_ENGLISH +const char *se_language_string(int language_enum); // returns "" if language is not supported +const char *se_localize(const char *string); +int se_convert_locale_to_enum(const char *clocale); #endif \ No newline at end of file diff --git a/src/main.c b/src/main.c index bfc729027..aae2bcd5c 100644 --- a/src/main.c +++ b/src/main.c @@ -4,10 +4,10 @@ * * Copyright (c) 2021 Skyler "Sky" Saleh * -**/ + **/ #include -#define SE_AUDIO_SAMPLE_RATE 48000 +#define SE_AUDIO_SAMPLE_RATE 48000 #define SE_AUDIO_BUFF_CHANNELS 2 #define SE_REBIND_TIMER_LENGTH 5.0 @@ -15,7 +15,7 @@ #ifdef ENABLE_HTTP_CONTROL_SERVER #include "http_control_server.h" -#endif +#endif #include "gba.h" #include "nds.h" @@ -51,14 +51,14 @@ #include "tinydir.h" #ifdef PLATFORM_ANDROID - #include +#include #endif #ifdef PLATFORM_IOS #include "ios_support.h" #endif #ifdef USE_SDL #include "SDL.h" -#endif +#endif #ifdef PLATFORM_ANDROID #include #endif @@ -70,1244 +70,1260 @@ #define SE_ANDROID_CONTROLLER_NAME "Default Controller" -#define SE_HAT_MASK (1<<16) -#define SE_JOY_POS_MASK (1<<17) -#define SE_JOY_NEG_MASK (1<<18) +#define SE_HAT_MASK (1 << 16) +#define SE_JOY_POS_MASK (1 << 17) +#define SE_JOY_NEG_MASK (1 << 18) -#define GBA_SKYEMU_CORRECTION 0 +#define GBA_SKYEMU_CORRECTION 0 #define GBA_HIGAN_CORRECTION 1 #define SE_FIELD_INDENT 125 -const static char* se_keybind_names[SE_NUM_KEYBINDS]={ - "A", - "B", - "X", - "Y", - "Up", - "Down", - "Left", - "Right", - "L", - "R", - "Start", - "Select", - "Fold Screen (NDS)", - "Tap Screen (NDS)", - "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, // NOLINT - "Emulator " ICON_FK_BACKWARD, - "Emulator " ICON_FK_FORWARD, - "Emulator " ICON_FK_FAST_FORWARD, - "Capture State 0", - "Restore State 0", - "Capture State 1", - "Restore State 1", - "Capture State 2", - "Restore State 2", - "Capture State 3", - "Restore State 3", - "Reset Game", - "Turbo A", - "Turbo B", - "Turbo X", - "Turbo Y", - "Turbo L", - "Turbo R", - "Solar Sensor+", - "Solar Sensor-", - "Toggle Full Screen" -}; +const static char *se_keybind_names[SE_NUM_KEYBINDS] = { + "A", + "B", + "X", + "Y", + "Up", + "Down", + "Left", + "Right", + "L", + "R", + "Start", + "Select", + "Fold Screen (NDS)", + "Tap Screen (NDS)", + "Emulator " ICON_FK_PAUSE "/" ICON_FK_PLAY, // NOLINT + "Emulator " ICON_FK_BACKWARD, + "Emulator " ICON_FK_FORWARD, + "Emulator " ICON_FK_FAST_FORWARD, + "Capture State 0", + "Restore State 0", + "Capture State 1", + "Restore State 1", + "Capture State 2", + "Restore State 2", + "Capture State 3", + "Restore State 3", + "Reset Game", + "Turbo A", + "Turbo B", + "Turbo X", + "Turbo Y", + "Turbo L", + "Turbo R", + "Solar Sensor+", + "Solar Sensor-", + "Toggle Full Screen"}; #define SE_ANALOG_UP_DOWN 0 #define SE_ANALOG_LEFT_RIGHT 1 -#define SE_ANALOG_L 2 -#define SE_ANALOG_R 3 -#define SE_NUM_ANALOGBINDS 4 - -const static char* se_analog_bind_names[]={ - "Analog Up/Down", - "Analog Left/Right", - "Analog L", - "Analog R", +#define SE_ANALOG_L 2 +#define SE_ANALOG_R 3 +#define SE_NUM_ANALOGBINDS 4 + +const static char *se_analog_bind_names[] = { + "Analog Up/Down", + "Analog Left/Right", + "Analog L", + "Analog R", }; -//Reserve space for extra keybinds/analog binds so that adding them in new versions don't break -//a users settings. +// Reserve space for extra keybinds/analog binds so that adding them in new versions don't break +// a users settings. #define SE_NUM_BINDS_ALLOC 64 -#define GUI_MAX_IMAGES_PER_FRAME 16 -#define SE_NUM_RECENT_PATHS 32 -#define SE_FONT_CACHE_PAGE_SIZE 16 +#define GUI_MAX_IMAGES_PER_FRAME 16 +#define SE_NUM_RECENT_PATHS 32 +#define SE_FONT_CACHE_PAGE_SIZE 16 #define SE_MAX_UNICODE_CODE_POINT 0xffff -typedef struct{ - int bind_being_set; - double rebind_start_time;//The time that the rebind button was pressed (used for the timer to cancel keybinding) - int last_bind_activitiy;// ID of binding with latest activity only within the current frame. -1 if no keys pressed/movement during frame. +typedef struct { + int bind_being_set; + double rebind_start_time; // The time that the rebind button was pressed (used for the timer to cancel keybinding) + int last_bind_activitiy; // ID of binding with latest activity only within the current frame. -1 if no keys pressed/movement during frame. int32_t bound_id[SE_NUM_BINDS_ALLOC]; - float value[SE_NUM_BINDS_ALLOC]; -}se_keybind_state_t; -typedef struct{ + float value[SE_NUM_BINDS_ALLOC]; +} se_keybind_state_t; +typedef struct { char name[128]; char guid[64]; - #ifdef USE_SDL - SDL_Joystick * sdl_joystick; - SDL_GameController * sdl_gc; - #endif - bool active; - bool connected; +#ifdef USE_SDL + SDL_Joystick *sdl_joystick; + SDL_GameController *sdl_gc; +#endif + bool active; + bool connected; se_keybind_state_t key; se_keybind_state_t analog; - double axis_last_zero_time[256]; -}se_controller_state_t; -typedef struct{ + double axis_last_zero_time[256]; +} se_controller_state_t; +typedef struct { char path[SB_FILE_PATH_SIZE]; -}se_game_info_t; -typedef struct{ - // This structure is directly saved out for the user settings. - // Be very careful to keep alignment and ordering the same otherwise you will break the settings. +} se_game_info_t; +typedef struct { + // This structure is directly saved out for the user settings. + // Be very careful to keep alignment and ordering the same otherwise you will break the settings. uint32_t draw_debug_menu; - float volume; - uint32_t theme; - uint32_t settings_file_version; + float volume; + uint32_t theme; + uint32_t settings_file_version; uint32_t gb_palette[4]; - float ghosting; - float color_correction; - uint32_t integer_scaling; - uint32_t screen_shader; //0: pixels, 1: lcd, 2: lcd+subpixels, 3: upscale - uint32_t screen_rotation; //0: No rotation, 1: Rotate Left, 2: Rotate Right, 3: Upside Down + float ghosting; + float color_correction; + uint32_t integer_scaling; + uint32_t screen_shader; // 0: pixels, 1: lcd, 2: lcd+subpixels, 3: upscale + uint32_t screen_rotation; // 0: No rotation, 1: Rotate Left, 2: Rotate Right, 3: Upside Down uint32_t stretch_to_fit; uint32_t auto_hide_touch_controls; - float touch_controls_opacity; + float touch_controls_opacity; uint32_t always_show_menubar; uint32_t language; - float touch_controls_scale; - uint32_t touch_controls_show_turbo; + float touch_controls_scale; + uint32_t touch_controls_show_turbo; uint32_t save_to_path; - uint32_t force_dmg_mode; + uint32_t force_dmg_mode; uint32_t gba_color_correction_mode; // 0 = SkyEmu, 1 = Higan - uint32_t http_control_server_port; + uint32_t http_control_server_port; uint32_t http_control_server_enable; uint32_t avoid_overlaping_touchscreen; - float custom_font_scale; - uint32_t hardcore_mode; + float custom_font_scale; + uint32_t hardcore_mode; uint32_t padding[228]; -}persistent_settings_t; -_Static_assert(sizeof(persistent_settings_t)==1024, "persistent_settings_t must be exactly 1024 bytes"); +} persistent_settings_t; +_Static_assert(sizeof(persistent_settings_t) == 1024, "persistent_settings_t must be exactly 1024 bytes"); #define SE_STATS_GRAPH_DATA 256 -typedef struct{ +typedef struct { double last_render_time; double last_emu_time; - float volume_l; - float volume_r; - float waveform_l[SE_STATS_GRAPH_DATA]; - float waveform_r[SE_STATS_GRAPH_DATA]; - float waveform_fps_emulation[SE_STATS_GRAPH_DATA]; - float waveform_fps_render[SE_STATS_GRAPH_DATA]; -}se_emulator_stats_t; -#define SE_FILE_BROWSER_CLOSED 0 -#define SE_FILE_BROWSER_OPEN 1 + float volume_l; + float volume_r; + float waveform_l[SE_STATS_GRAPH_DATA]; + float waveform_r[SE_STATS_GRAPH_DATA]; + float waveform_fps_emulation[SE_STATS_GRAPH_DATA]; + float waveform_fps_render[SE_STATS_GRAPH_DATA]; +} se_emulator_stats_t; +#define SE_FILE_BROWSER_CLOSED 0 +#define SE_FILE_BROWSER_OPEN 1 #define SE_FILE_BROWSER_SELECTED 2 -typedef struct{ - char current_path[SB_FILE_PATH_SIZE]; - char file_path[SB_FILE_PATH_SIZE]; - int state; // 0 = Closed no file selected, 1= Open, 2 = closed file selected - tinydir_file* cached_files; - char cached_path[SB_FILE_PATH_SIZE]; - char cached_ext_filter[SB_FILE_PATH_SIZE]; - size_t num_cached_files; - double cached_time; - tinydir_dir cached_dir; - bool has_cache; - bool allow_directory; - unsigned num_file_types; - const char** file_types; - void (*file_open_fn)(const char* dir); - char * output_path; -}se_file_browser_state_t; -typedef struct{ +typedef struct { + char current_path[SB_FILE_PATH_SIZE]; + char file_path[SB_FILE_PATH_SIZE]; + int state; // 0 = Closed no file selected, 1= Open, 2 = closed file selected + tinydir_file *cached_files; + char cached_path[SB_FILE_PATH_SIZE]; + char cached_ext_filter[SB_FILE_PATH_SIZE]; + size_t num_cached_files; + double cached_time; + tinydir_dir cached_dir; + bool has_cache; + bool allow_directory; + unsigned num_file_types; + const char **file_types; + void (*file_open_fn)(const char *dir); + char *output_path; +} se_file_browser_state_t; +typedef struct { uint32_t turbo_toggle; - uint32_t hold_toggle; + uint32_t hold_toggle; uint32_t last_turbo_toggle_presses; uint32_t last_hold_toggle_presses; -}se_touch_controls_t; +} se_touch_controls_t; -typedef struct{ +typedef struct { char save[SB_FILE_PATH_SIZE]; char bios[SB_FILE_PATH_SIZE]; char cheat_codes[SB_FILE_PATH_SIZE]; char theme[SB_FILE_PATH_SIZE]; char custom_font[SB_FILE_PATH_SIZE]; char padding[3][SB_FILE_PATH_SIZE]; -}se_search_paths_t; +} se_search_paths_t; -_Static_assert(sizeof(se_search_paths_t)==SB_FILE_PATH_SIZE*8, "se_search_paths_t must contain 8 paths"); +_Static_assert(sizeof(se_search_paths_t) == SB_FILE_PATH_SIZE * 8, "se_search_paths_t must contain 8 paths"); #define SE_MAX_BIOS_FILES 8 #define SE_BIOS_NAME_SIZE 32 #define SE_UI_DESKTOP 0 -#define SE_UI_ANDROID 1 +#define SE_UI_ANDROID 1 #define SE_UI_IOS 2 #define SE_UI_WEB 3 -typedef struct{ +typedef struct { char path[SE_MAX_BIOS_FILES][SB_FILE_PATH_SIZE]; char name[SE_MAX_BIOS_FILES][SE_BIOS_NAME_SIZE]; bool success[SE_MAX_BIOS_FILES]; -}se_bios_info_t; - -#define SE_MAX_CONTROL_POINTS 32 -#define SE_REGION_NAME 0 -#define SE_REGION_AUTHOR 1 -#define SE_REGION_BEZEL_PORTRAIT 2 -#define SE_REGION_BEZEL_LANDSCAPE 3 -#define SE_REGION_KEY_L 4 -#define SE_REGION_KEY_L_PRESSED 5 -#define SE_REGION_KEY_R 6 -#define SE_REGION_KEY_R_PRESSED 7 -#define SE_REGION_KEY_START 8 -#define SE_REGION_KEY_START_PRESSED 9 -#define SE_REGION_KEY_SELECT 10 -#define SE_REGION_KEY_SELECT_PRESSED 11 -#define SE_REGION_KEY_A 12 -#define SE_REGION_KEY_A_PRESSED 13 -#define SE_REGION_KEY_B 14 -#define SE_REGION_KEY_B_PRESSED 15 -#define SE_REGION_KEY_X 16 -#define SE_REGION_KEY_X_PRESSED 17 -#define SE_REGION_KEY_Y 18 -#define SE_REGION_KEY_Y_PRESSED 19 -#define SE_REGION_KEY_TURBO 20 -#define SE_REGION_KEY_TURBO_PRESSED 21 -#define SE_REGION_KEY_HOLD 22 -#define SE_REGION_KEY_HOLD_PRESSED 23 -#define SE_REGION_KEY_BLANK 24 -#define SE_REGION_KEY_BLANK_PRESSED 25 -#define SE_REGION_DPAD_UL 26 -#define SE_REGION_DPAD_UP 27 -#define SE_REGION_DPAD_UR 28 -#define SE_REGION_DPAD_LEFT 29 -#define SE_REGION_DPAD_CENTER 30 -#define SE_REGION_DPAD_RIGHT 31 -#define SE_REGION_DPAD_DL 32 -#define SE_REGION_DPAD_DOWN 33 -#define SE_REGION_DPAD_DR 34 -#define SE_REGION_MENU 35 -#define SE_REGION_MENU_HOVER 36 -#define SE_REGION_MENU_ACTIVE 37 -#define SE_REGION_MAX_REWIND 38 -#define SE_REGION_MAX_REWIND_HOVER 39 -#define SE_REGION_MAX_REWIND_ACTIVE 40 -#define SE_REGION_REWIND 41 -#define SE_REGION_REWIND_HOVER 42 -#define SE_REGION_REWIND_ACTIVE 43 -#define SE_REGION_PLAY 44 -#define SE_REGION_PLAY_HOVER 45 -#define SE_REGION_PLAY_ACTIVE 46 -#define SE_REGION_PAUSE 47 -#define SE_REGION_PAUSE_HOVER 48 -#define SE_REGION_PAUSE_ACTIVE 49 -#define SE_REGION_FF 50 -#define SE_REGION_FF_HOVER 51 -#define SE_REGION_FF_ACTIVE 52 -#define SE_REGION_MAX_FF 53 -#define SE_REGION_MAX_FF_HOVER 54 -#define SE_REGION_MAX_FF_ACTIVE 55 -#define SE_REGION_BLANK 56 -#define SE_REGION_BLANK_HOVER 57 -#define SE_REGION_BLANK_ACTIVE 58 -#define SE_REGION_VOL_EMPTY 59 -#define SE_REGION_VOL_EMPTY_ACTIVE 60 -#define SE_REGION_VOL_FULL 61 -#define SE_REGION_VOL_FULL_ACTIVE 62 -#define SE_REGION_VOL_KNOB 63 -#define SE_REGION_VOL_KNOB_ACTIVE 64 -#define SE_REGION_MENUBAR 65 -#define SE_TOTAL_REGIONS 66 - -#define SE_RESIZE_STRETCH 0 -#define SE_RESIZE_FIXED 0x80 - -#define SE_SCREEN_NONE 0 -#define SE_SCREEN_BOTH 0xC0 - -#define SE_NO_SORT 0 -#define SE_SORT_ALPHA_ASC 1 +} se_bios_info_t; + +#define SE_MAX_CONTROL_POINTS 32 +#define SE_REGION_NAME 0 +#define SE_REGION_AUTHOR 1 +#define SE_REGION_BEZEL_PORTRAIT 2 +#define SE_REGION_BEZEL_LANDSCAPE 3 +#define SE_REGION_KEY_L 4 +#define SE_REGION_KEY_L_PRESSED 5 +#define SE_REGION_KEY_R 6 +#define SE_REGION_KEY_R_PRESSED 7 +#define SE_REGION_KEY_START 8 +#define SE_REGION_KEY_START_PRESSED 9 +#define SE_REGION_KEY_SELECT 10 +#define SE_REGION_KEY_SELECT_PRESSED 11 +#define SE_REGION_KEY_A 12 +#define SE_REGION_KEY_A_PRESSED 13 +#define SE_REGION_KEY_B 14 +#define SE_REGION_KEY_B_PRESSED 15 +#define SE_REGION_KEY_X 16 +#define SE_REGION_KEY_X_PRESSED 17 +#define SE_REGION_KEY_Y 18 +#define SE_REGION_KEY_Y_PRESSED 19 +#define SE_REGION_KEY_TURBO 20 +#define SE_REGION_KEY_TURBO_PRESSED 21 +#define SE_REGION_KEY_HOLD 22 +#define SE_REGION_KEY_HOLD_PRESSED 23 +#define SE_REGION_KEY_BLANK 24 +#define SE_REGION_KEY_BLANK_PRESSED 25 +#define SE_REGION_DPAD_UL 26 +#define SE_REGION_DPAD_UP 27 +#define SE_REGION_DPAD_UR 28 +#define SE_REGION_DPAD_LEFT 29 +#define SE_REGION_DPAD_CENTER 30 +#define SE_REGION_DPAD_RIGHT 31 +#define SE_REGION_DPAD_DL 32 +#define SE_REGION_DPAD_DOWN 33 +#define SE_REGION_DPAD_DR 34 +#define SE_REGION_MENU 35 +#define SE_REGION_MENU_HOVER 36 +#define SE_REGION_MENU_ACTIVE 37 +#define SE_REGION_MAX_REWIND 38 +#define SE_REGION_MAX_REWIND_HOVER 39 +#define SE_REGION_MAX_REWIND_ACTIVE 40 +#define SE_REGION_REWIND 41 +#define SE_REGION_REWIND_HOVER 42 +#define SE_REGION_REWIND_ACTIVE 43 +#define SE_REGION_PLAY 44 +#define SE_REGION_PLAY_HOVER 45 +#define SE_REGION_PLAY_ACTIVE 46 +#define SE_REGION_PAUSE 47 +#define SE_REGION_PAUSE_HOVER 48 +#define SE_REGION_PAUSE_ACTIVE 49 +#define SE_REGION_FF 50 +#define SE_REGION_FF_HOVER 51 +#define SE_REGION_FF_ACTIVE 52 +#define SE_REGION_MAX_FF 53 +#define SE_REGION_MAX_FF_HOVER 54 +#define SE_REGION_MAX_FF_ACTIVE 55 +#define SE_REGION_BLANK 56 +#define SE_REGION_BLANK_HOVER 57 +#define SE_REGION_BLANK_ACTIVE 58 +#define SE_REGION_VOL_EMPTY 59 +#define SE_REGION_VOL_EMPTY_ACTIVE 60 +#define SE_REGION_VOL_FULL 61 +#define SE_REGION_VOL_FULL_ACTIVE 62 +#define SE_REGION_VOL_KNOB 63 +#define SE_REGION_VOL_KNOB_ACTIVE 64 +#define SE_REGION_MENUBAR 65 +#define SE_TOTAL_REGIONS 66 + +#define SE_RESIZE_STRETCH 0 +#define SE_RESIZE_FIXED 0x80 + +#define SE_SCREEN_NONE 0 +#define SE_SCREEN_BOTH 0xC0 + +#define SE_NO_SORT 0 +#define SE_SORT_ALPHA_ASC 1 #define SE_SORT_ALPHA_DESC 2 -typedef struct{ +typedef struct { uint16_t start_pixel; uint16_t end_pixel; - uint8_t resize_control; - uint8_t screen_control; - uint8_t gamepad_control; -}se_control_point_t; - -typedef struct{ - int x,y; - int w,h; - bool active; + uint8_t resize_control; + uint8_t screen_control; + uint8_t gamepad_control; +} se_control_point_t; + +typedef struct { + int x, y; + int w, h; + bool active; se_control_point_t control_points_x[SE_MAX_CONTROL_POINTS]; se_control_point_t control_points_y[SE_MAX_CONTROL_POINTS]; -}se_theme_region_t; - -typedef struct{ - sg_image image; - uint32_t im_w; - uint32_t im_h; - uint32_t version_code; - uint8_t palettes[5*4]; +} se_theme_region_t; + +typedef struct { + sg_image image; + uint32_t im_w; + uint32_t im_h; + uint32_t version_code; + uint8_t palettes[5 * 4]; se_theme_region_t regions[SE_TOTAL_REGIONS]; -}se_custom_theme_t; +} se_custom_theme_t; typedef struct { - uint64_t laptime; - sg_pass_action pass_action; - sg_image image_stack[GUI_MAX_IMAGES_PER_FRAME]; - int current_image; - int screen_width; - int screen_height; - float dpi_override; - int button_state[SAPP_MAX_KEYCODES]; - struct{ - bool active; - float pos[2]; - }touch_points[SAPP_MAX_TOUCHPOINTS]; - float last_touch_time; - int mem_view_address; - int mem_dump_size; - int mem_dump_start_address; - bool sidebar_open; - se_keybind_state_t key; - se_controller_state_t controller; - se_game_info_t recently_loaded_games[SE_NUM_RECENT_PATHS]; - int sorted_recently_loaded_games[SE_NUM_RECENT_PATHS]; - int recent_games_sort_type; - persistent_settings_t settings; - persistent_settings_t last_saved_settings; - bool overlay_open; - se_emulator_stats_t emu_stats; - // Utilize a watchdog channel to detect if the audio context has encountered an error - // and restart it if a problem occurred. - int audio_watchdog_timer; - int audio_watchdog_triggered; - bool block_touchscreen; - bool test_runner_mode; - sg_shader lcd_prog; - sg_buffer quad_vb; - sg_pipeline lcd_pipeline; - se_file_browser_state_t file_browser; - float mouse_pos[2]; - bool mouse_button[3]; - float menubar_hide_timer; - se_touch_controls_t touch_controls; - se_search_paths_t paths; - se_search_paths_t last_saved_paths; - se_bios_info_t bios_info; - sg_image font_atlas_image; - uint8_t font_cache_page_valid[(SE_MAX_UNICODE_CODE_POINT+1)/SE_FONT_CACHE_PAGE_SIZE]; - bool update_font_atlas; - sb_joy_t hcs_joypad; - int editing_cheat_index; //-1 when not editing a cheat - char cheat_path[SB_FILE_PATH_SIZE]; - ImFont* mono_font; - - uint32_t current_click_region_id; - uint32_t max_click_region_id; - uint32_t ui_type; - bool fake_paths; - char loaded_theme_path[SB_FILE_PATH_SIZE]; - char loaded_custom_font_path[SB_FILE_PATH_SIZE]; - se_custom_theme_t theme; - bool ran_from_launcher; - char search_buffer[32]; + uint64_t laptime; + sg_pass_action pass_action; + sg_image image_stack[GUI_MAX_IMAGES_PER_FRAME]; + int current_image; + int screen_width; + int screen_height; + float dpi_override; + int button_state[SAPP_MAX_KEYCODES]; + struct { + bool active; + float pos[2]; + } touch_points[SAPP_MAX_TOUCHPOINTS]; + float last_touch_time; + int mem_view_address; + int mem_dump_size; + int mem_dump_start_address; + bool sidebar_open; + se_keybind_state_t key; + se_controller_state_t controller; + se_game_info_t recently_loaded_games[SE_NUM_RECENT_PATHS]; + int sorted_recently_loaded_games[SE_NUM_RECENT_PATHS]; + int recent_games_sort_type; + persistent_settings_t settings; + persistent_settings_t last_saved_settings; + bool overlay_open; + se_emulator_stats_t emu_stats; + // Utilize a watchdog channel to detect if the audio context has encountered an error + // and restart it if a problem occurred. + int audio_watchdog_timer; + int audio_watchdog_triggered; + bool block_touchscreen; + bool test_runner_mode; + sg_shader lcd_prog; + sg_buffer quad_vb; + sg_pipeline lcd_pipeline; + se_file_browser_state_t file_browser; + float mouse_pos[2]; + bool mouse_button[3]; + float menubar_hide_timer; + se_touch_controls_t touch_controls; + se_search_paths_t paths; + se_search_paths_t last_saved_paths; + se_bios_info_t bios_info; + sg_image font_atlas_image; + uint8_t font_cache_page_valid[(SE_MAX_UNICODE_CODE_POINT + 1) / SE_FONT_CACHE_PAGE_SIZE]; + bool update_font_atlas; + sb_joy_t hcs_joypad; + int editing_cheat_index; //-1 when not editing a cheat + char cheat_path[SB_FILE_PATH_SIZE]; + ImFont *mono_font; + + uint32_t current_click_region_id; + uint32_t max_click_region_id; + uint32_t ui_type; + bool fake_paths; + char loaded_theme_path[SB_FILE_PATH_SIZE]; + char loaded_custom_font_path[SB_FILE_PATH_SIZE]; + se_custom_theme_t theme; + bool ran_from_launcher; + char search_buffer[32]; } gui_state_t; -#define SE_REWIND_BUFFER_SIZE (1024*1024) +#define SE_REWIND_BUFFER_SIZE (1024 * 1024) #define SE_REWIND_SEGMENT_SIZE 64 -#define SE_LAST_DELTA_IN_TX (1u<<31) +#define SE_LAST_DELTA_IN_TX (1u << 31) -#define SE_NUM_SAVE_STATES 4 -#define SE_MAX_SCREENSHOT_SIZE (NDS_LCD_H*NDS_LCD_W*2*4) +#define SE_NUM_SAVE_STATES 4 +#define SE_MAX_SCREENSHOT_SIZE (NDS_LCD_H * NDS_LCD_W * 2 * 4) -#define SE_NUM_CHEATS 32 +#define SE_NUM_CHEATS 32 #define SE_MAX_CHEAT_NAME_SIZE 32 #define SE_MAX_CHEAT_CODE_SIZE 256 -#define SE_THEME_DARK 0 -#define SE_THEME_LIGHT 1 -#define SE_THEME_BLACK 2 +#define SE_THEME_DARK 0 +#define SE_THEME_LIGHT 1 +#define SE_THEME_BLACK 2 #define SE_THEME_CUSTOM 3 -#define SE_MENU_BAR_HEIGHT 24 +#define SE_MENU_BAR_HEIGHT 24 #define SE_MENU_BAR_BUTTON_WIDTH 30 -#define SE_TOGGLE_WIDTH 35 -#define SE_VOLUME_SLIDER_WIDTH 100 +#define SE_TOGGLE_WIDTH 35 +#define SE_VOLUME_SLIDER_WIDTH 100 -//TODO: Clean this up to use unions... -sb_emu_state_t emu_state = {.pc_breakpoint = -1, .joy.solar_sensor=0.5}; -#define SE_MAX_CONST(A,B) ((A)>(B)? (A) : (B) ) -typedef union{ +// TODO: Clean this up to use unions... +sb_emu_state_t emu_state = {.pc_breakpoint = -1, .joy.solar_sensor = 0.5}; +#define SE_MAX_CONST(A, B) ((A) > (B) ? (A) : (B)) +typedef union { sb_gb_t gb; - gba_t gba; - nds_t nds; + gba_t gba; + nds_t nds; // Raw data padded out to 64B to make rewind efficient - uint64_t raw_data[SE_MAX_CONST(SE_MAX_CONST(sizeof(gba_t), sizeof(nds_t)), sizeof(sb_gb_t))/SE_REWIND_SEGMENT_SIZE+1]; -}se_core_state_t; -typedef union{ + uint64_t raw_data[SE_MAX_CONST(SE_MAX_CONST(sizeof(gba_t), sizeof(nds_t)), sizeof(sb_gb_t)) / SE_REWIND_SEGMENT_SIZE + 1]; +} se_core_state_t; +typedef union { gba_scratch_t gba; - gb_scratch_t gb; + gb_scratch_t gb; nds_scratch_t nds; -}se_core_scratch_t; +} se_core_scratch_t; -typedef struct{ - uint32_t offset; - uint64_t data[SE_REWIND_SEGMENT_SIZE/8]; -}se_core_delta_t; -typedef struct{ +typedef struct { + uint32_t offset; + uint64_t data[SE_REWIND_SEGMENT_SIZE / 8]; +} se_core_delta_t; +typedef struct { se_core_delta_t deltas[SE_REWIND_BUFFER_SIZE]; - uint32_t size; - uint32_t index; - bool first_push; - se_core_state_t last_core; -}se_core_rewind_buffer_t; -typedef struct{ - uint8_t screenshot[SE_MAX_SCREENSHOT_SIZE]; - int32_t screenshot_width; - int32_t screenshot_height; - int32_t system; - int32_t valid; //0: invalid, 1: Valid (Perfect Save State) 2: Valid (BESS restore) + uint32_t size; + uint32_t index; + bool first_push; + se_core_state_t last_core; +} se_core_rewind_buffer_t; +typedef struct { + uint8_t screenshot[SE_MAX_SCREENSHOT_SIZE]; + int32_t screenshot_width; + int32_t screenshot_height; + int32_t system; + int32_t valid; // 0: invalid, 1: Valid (Perfect Save State) 2: Valid (BESS restore) se_core_state_t state; -}se_save_state_t; -typedef struct{ - char name[SE_MAX_CHEAT_NAME_SIZE]; +} se_save_state_t; +typedef struct { + char name[SE_MAX_CHEAT_NAME_SIZE]; uint32_t buffer[SE_MAX_CHEAT_CODE_SIZE]; - uint32_t size; //In 32bit words - int32_t state; //-1: invalid, 0: inactive, 1: active -}se_cheat_t; -typedef struct{ - char name[39]; //Emulator Name - char build[41];//Emulator build/commit hash - uint32_t bess_offset; //Number of bytes after the se_emu_id where the save state descriptor is located. - uint32_t system; //SYSTEM_UNKNOWN=0 ,SYSTEM_GB=1, SYSTEM_GBA=2, SYSTEM_NDS 3 - uint8_t padding[20];//Zero padding -}se_emu_id; -gui_state_t gui_state={ .update_font_atlas=true }; - -void se_draw_image(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, bool has_alpha); -void se_draw_lcd(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, float rotation,bool is_touch); -void se_load_rom_overlay(bool visible); -void sb_draw_onscreen_controller(sb_emu_state_t*state, int controller_h, int controller_y_pad,bool preview); -void se_reset_save_states(); -void se_reset_cheats(); -void se_set_new_controller(se_controller_state_t* cont, int index); -bool se_run_ar_cheat(const uint32_t* buffer, uint32_t size); -static void se_emscripten_flush_fs(); -static uint32_t se_save_best_effort_state(se_core_state_t* state); -static bool se_load_best_effort_state(se_core_state_t* state,uint8_t *save_state_data, uint32_t size, uint32_t bess_offset); -static size_t se_get_core_size(); -uint8_t* se_hcs_callback(const char* cmd, const char** params, uint64_t* result_size, const char** mime_type); -void se_open_file_browser(bool clicked, float x, float y, float w, float h, void (*file_open_fn)(const char* dir), const char ** file_types,char * output_path); -void se_file_browser_accept(const char * path); -void se_run_all_ar_cheats(); -void se_load_cheats(const char * filename); -void se_save_cheats(const char* filename); -void se_convert_cheat_code(char * text_code, int cheat_index); -static void se_reset_core(); -static bool se_load_theme_from_file(const char * filename); -static bool se_draw_theme_region(int region, float x, float y, float w, float h); -static bool se_draw_theme_region_tint(int region, float x, float y, float w, float h,uint32_t tint); -static bool se_draw_theme_region_tint_partial(int region, float x, float y, float w, float h, float w_ratio, float h_ratio, uint32_t tint); -static const char* se_get_pref_path(){ + uint32_t size; // In 32bit words + int32_t state; //-1: invalid, 0: inactive, 1: active +} se_cheat_t; +typedef struct { + char name[39]; // Emulator Name + char build[41]; // Emulator build/commit hash + uint32_t bess_offset; // Number of bytes after the se_emu_id where the save state descriptor is located. + uint32_t system; // SYSTEM_UNKNOWN=0 ,SYSTEM_GB=1, SYSTEM_GBA=2, SYSTEM_NDS 3 + uint8_t padding[20]; // Zero padding +} se_emu_id; +gui_state_t gui_state = {.update_font_atlas = true}; + +void se_draw_image(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, bool has_alpha); +void se_draw_lcd(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, float rotation, bool is_touch); +void se_load_rom_overlay(bool visible); +void sb_draw_onscreen_controller(sb_emu_state_t *state, int controller_h, int controller_y_pad, bool preview); +void se_reset_save_states(); +void se_reset_cheats(); +void se_set_new_controller(se_controller_state_t *cont, int index); +bool se_run_ar_cheat(const uint32_t *buffer, uint32_t size); +static void se_emscripten_flush_fs(); +static uint32_t se_save_best_effort_state(se_core_state_t *state); +static bool se_load_best_effort_state(se_core_state_t *state, uint8_t *save_state_data, uint32_t size, uint32_t bess_offset); +static size_t se_get_core_size(); +uint8_t *se_hcs_callback(const char *cmd, const char **params, uint64_t *result_size, const char **mime_type); +void se_open_file_browser(bool clicked, float x, float y, float w, float h, void (*file_open_fn)(const char *dir), const char **file_types, char *output_path); +void se_file_browser_accept(const char *path); +void se_run_all_ar_cheats(); +void se_load_cheats(const char *filename); +void se_save_cheats(const char *filename); +void se_convert_cheat_code(char *text_code, int cheat_index); +static void se_reset_core(); +static bool se_load_theme_from_file(const char *filename); +static bool se_draw_theme_region(int region, float x, float y, float w, float h); +static bool se_draw_theme_region_tint(int region, float x, float y, float w, float h, uint32_t tint); +static bool se_draw_theme_region_tint_partial(int region, float x, float y, float w, float h, float w_ratio, float h_ratio, uint32_t tint); +static const char *se_get_pref_path() { #if defined(EMSCRIPTEN) return "/offline/"; #elif defined(USE_SDL) - static const char* cached_pref_path=NULL; - if(cached_pref_path==NULL)cached_pref_path=SDL_GetPrefPath("Sky","SkyEmu"); + static const char *cached_pref_path = NULL; + if(cached_pref_path == NULL) cached_pref_path = SDL_GetPrefPath("Sky", "SkyEmu"); return cached_pref_path; #elif defined(PLATFORM_ANDROID) - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); - if(activity->internalDataPath)return activity->internalDataPath; + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); + if(activity->internalDataPath) return activity->internalDataPath; #endif return ""; } #ifdef PLATFORM_ANDROID float se_android_get_display_dpi_scale(); #endif -static float se_dpi_scale(){ - if(gui_state.dpi_override)return gui_state.dpi_override/120.; +static float se_dpi_scale() { + if(gui_state.dpi_override) return gui_state.dpi_override / 120.; static float dpi_scale = -1.0; - if(dpi_scale>0.)return dpi_scale; + if(dpi_scale > 0.) return dpi_scale; dpi_scale = sapp_dpi_scale(); - if(dpi_scale<=0)dpi_scale=1.; - dpi_scale*=1.10; + if(dpi_scale <= 0) dpi_scale = 1.; + dpi_scale *= 1.10; #ifdef PLATFORM_ANDROID dpi_scale = se_android_get_display_dpi_scale(); #endif return dpi_scale; } -static void se_cache_glyphs(const char* input_string){ - #ifdef UNICODE_GUI - utf8proc_int32_t codepoint_ref=0; +static void se_cache_glyphs(const char *input_string) { +#ifdef UNICODE_GUI + utf8proc_int32_t codepoint_ref = 0; const utf8proc_uint8_t *str = (const utf8proc_uint8_t *)input_string; - while(str[0]){ + while(str[0]) { int size = utf8proc_iterate(str, -1, &codepoint_ref); - if(size<=0)break; - str+=size; - if(codepoint_ref>SE_MAX_UNICODE_CODE_POINT)continue;; - uint32_t font_cache_page = codepoint_ref/SE_FONT_CACHE_PAGE_SIZE; - if(gui_state.font_cache_page_valid[font_cache_page]==0x0){ - gui_state.font_cache_page_valid[font_cache_page]=0x1; - gui_state.update_font_atlas=true; - } - } - #endif -} -char* se_replace_fake_path(char * new_path){ - static char fake_path[SB_FILE_PATH_SIZE]; - if(gui_state.fake_paths){ - const char* base, *filename, *ext; - sb_breakup_path(new_path,&base, &filename,&ext); - char* new_base = "/fakepath/"; - if(gui_state.ui_type==SE_UI_ANDROID)new_base = "/storage/emulated/0/Android/data/com.sky.SkyEmu/"; - snprintf(fake_path,sizeof(fake_path),"%s%s.%s",new_base,filename,ext); - new_path = fake_path; + if(size <= 0) break; + str += size; + if(codepoint_ref > SE_MAX_UNICODE_CODE_POINT) continue; + ; + uint32_t font_cache_page = codepoint_ref / SE_FONT_CACHE_PAGE_SIZE; + if(gui_state.font_cache_page_valid[font_cache_page] == 0x0) { + gui_state.font_cache_page_valid[font_cache_page] = 0x1; + gui_state.update_font_atlas = true; + } + } +#endif +} +char *se_replace_fake_path(char *new_path) { + static char fake_path[SB_FILE_PATH_SIZE]; + if(gui_state.fake_paths) { + const char *base, *filename, *ext; + sb_breakup_path(new_path, &base, &filename, &ext); + char *new_base = "/fakepath/"; + if(gui_state.ui_type == SE_UI_ANDROID) new_base = "/storage/emulated/0/Android/data/com.sky.SkyEmu/"; + snprintf(fake_path, sizeof(fake_path), "%s%s.%s", new_base, filename, ext); + new_path = fake_path; } return new_path; } -static inline const char* se_localize_and_cache(const char* input_str){ - const char * localized_string = se_localize(input_str); +static inline const char *se_localize_and_cache(const char *input_str) { + const char *localized_string = se_localize(input_str); se_cache_glyphs(localized_string); return localized_string; } -static inline bool se_checkbox(const char* label, bool * v){ - return igCheckbox(se_localize_and_cache(label),v); +static inline bool se_checkbox(const char *label, bool *v) { + return igCheckbox(se_localize_and_cache(label), v); } -static void se_text(const char* label,...){ +static void se_text(const char *label, ...) { va_list args; va_start(args, label); - igTextV(se_localize_and_cache(label),args); + igTextV(se_localize_and_cache(label), args); va_end(args); } -static void se_text_disabled(const char* label,...){ +static void se_text_disabled(const char *label, ...) { va_list args; va_start(args, label); - igTextDisabledV(se_localize_and_cache(label),args); + igTextDisabledV(se_localize_and_cache(label), args); va_end(args); } -static bool se_combo_str(const char* label,int* current_item,const char* items_separated_by_zeros,int popup_max_height_in_items){ - const char* localize_string= items_separated_by_zeros; - while(localize_string[0]){ +static bool se_combo_str(const char *label, int *current_item, const char *items_separated_by_zeros, int popup_max_height_in_items) { + const char *localize_string = items_separated_by_zeros; + while(localize_string[0]) { se_cache_glyphs(localize_string); - localize_string+=strlen(localize_string)+1; + localize_string += strlen(localize_string) + 1; } - return igComboStr(se_localize_and_cache(label),current_item,se_localize_and_cache(items_separated_by_zeros),popup_max_height_in_items); + return igComboStr(se_localize_and_cache(label), current_item, se_localize_and_cache(items_separated_by_zeros), popup_max_height_in_items); } -static int se_slider_float(const char* label,float* v,float v_min,float v_max,const char* format){ - return igSliderFloat(se_localize_and_cache(label),v,v_min,v_max,se_localize_and_cache(format),ImGuiSliderFlags_AlwaysClamp); +static int se_slider_float(const char *label, float *v, float v_min, float v_max, const char *format) { + return igSliderFloat(se_localize_and_cache(label), v, v_min, v_max, se_localize_and_cache(format), ImGuiSliderFlags_AlwaysClamp); } -static bool se_input_int(const char* label,int* v,int step,int step_fast,ImGuiInputTextFlags flags){ - return igInputInt(se_localize_and_cache(label),v,step,step_fast,flags); +static bool se_input_int(const char *label, int *v, int step, int step_fast, ImGuiInputTextFlags flags) { + return igInputInt(se_localize_and_cache(label), v, step, step_fast, flags); } -static bool se_input_uint32(const char* label,uint32_t* v,int step,int step_fast,ImGuiInputTextFlags flags){ - int val = *v; - bool ret = se_input_int(label,&val,step,step_fast,flags); +static bool se_input_uint32(const char *label, uint32_t *v, int step, int step_fast, ImGuiInputTextFlags flags) { + int val = *v; + bool ret = se_input_int(label, &val, step, step_fast, flags); *v = val; return ret; } -static bool se_input_int32(const char* label,int32_t* v,int step,int step_fast,ImGuiInputTextFlags flags){ - int val = *v; - bool ret = se_input_int(label,&val,step,step_fast,flags); +static bool se_input_int32(const char *label, int32_t *v, int step, int step_fast, ImGuiInputTextFlags flags) { + int val = *v; + bool ret = se_input_int(label, &val, step, step_fast, flags); *v = val; return ret; } -static bool se_button_themed(int region, const char* label, ImVec2 size, bool always_draw_label){ - label=se_localize_and_cache(label); +static bool se_button_themed(int region, const char *label, ImVec2 size, bool always_draw_label) { + label = se_localize_and_cache(label); ImVec2 label_size; - igCalcTextSize(&label_size,label, NULL, true,-1.0); - ImGuiStyle * style = igGetStyle(); + igCalcTextSize(&label_size, label, NULL, true, -1.0); + ImGuiStyle *style = igGetStyle(); igCalcItemSize(&size, size, label_size.x + style->FramePadding.x * 2.0f, label_size.y + style->FramePadding.y * 2.0f); - ImVec2 pos,v; + ImVec2 pos, v; igGetCursorPos(&pos); igGetWindowPos(&v); - pos.x+=v.x-igGetScrollX(); - pos.y+=v.y-igGetScrollY(); + pos.x += v.x - igGetScrollX(); + pos.y += v.y - igGetScrollY(); ImGuiStyle restore_style = *style; - if(gui_state.settings.theme==SE_THEME_CUSTOM && gui_state.theme.regions[region].active){ - for(int i=0;iColors[i].w = 0.; - if(always_draw_label){ + if(gui_state.settings.theme == SE_THEME_CUSTOM && gui_state.theme.regions[region].active) { + for(int i = 0; i < ImGuiCol_COUNT; ++i) + style->Colors[i].w = 0.; + if(always_draw_label) { style->Colors[ImGuiCol_Text] = restore_style.Colors[ImGuiCol_Text]; style->Colors[ImGuiCol_TextDisabled] = restore_style.Colors[ImGuiCol_TextDisabled]; } } - bool hover = igIsMouseHoveringRect((ImVec2){pos.x,pos.y},(ImVec2){pos.x+size.x,pos.y+size.y},true); + bool hover = igIsMouseHoveringRect((ImVec2){pos.x, pos.y}, (ImVec2){pos.x + size.x, pos.y + size.y}, true); float alpha = 1.0; - if(hover) alpha=0.75; - uint32_t tint = 0x00ffffff|((uint32_t)(alpha*255)<<24u); - if(!se_draw_theme_region_tint(region, pos.x,pos.y,size.x,size.y,tint)) - *style = restore_style; - bool button_result = igButton(label,size); + if(hover) alpha = 0.75; + uint32_t tint = 0x00ffffff | ((uint32_t)(alpha * 255) << 24u); + if(!se_draw_theme_region_tint(region, pos.x, pos.y, size.x, size.y, tint)) + *style = restore_style; + bool button_result = igButton(label, size); - *style = restore_style; + *style = restore_style; return button_result; } -bool se_slider_float_themed(const char* label, float* p_data, float p_min, float p_max, const char* format){ - if(igGetCurrentWindow()->SkipItems)return false; +bool se_slider_float_themed(const char *label, float *p_data, float p_min, float p_max, const char *format) { + if(igGetCurrentWindow()->SkipItems) return false; label = se_localize_and_cache(label); format = se_localize_and_cache(format); const float w = igCalcItemWidth(); ImVec2 label_size; - igCalcTextSize(&label_size,label, NULL, true,-1); - ImVec2 pos,v; + igCalcTextSize(&label_size, label, NULL, true, -1); + ImVec2 pos, v; igGetCursorPos(&pos); igGetWindowPos(&v); - pos.x+=v.x-igGetScrollX(); - pos.y+=v.y-igGetScrollY(); - ImGuiStyle * style = igGetStyle(); - ImGuiStyle restore_style = *style; + pos.x += v.x - igGetScrollX(); + pos.y += v.y - igGetScrollY(); + ImGuiStyle *style = igGetStyle(); + ImGuiStyle restore_style = *style; - ImVec2 frame_size ={w, label_size.y + style->FramePadding.y * 2.0f}; - float bar_growth =0.0; + ImVec2 frame_size = {w, label_size.y + style->FramePadding.y * 2.0f}; + float bar_growth = 0.0; ImVec2 orig_pos = pos; - ImVec2 orig_size= frame_size; - pos.x-=frame_size.x*bar_growth; - pos.y-=frame_size.y*bar_growth; - frame_size.x+=frame_size.x*bar_growth; - frame_size.y+=frame_size.y*bar_growth; - - if(gui_state.settings.theme==SE_THEME_CUSTOM && gui_state.theme.regions[SE_REGION_VOL_EMPTY].active){ - for(int i=0;iColors[i].w = 0.; + ImVec2 orig_size = frame_size; + pos.x -= frame_size.x * bar_growth; + pos.y -= frame_size.y * bar_growth; + frame_size.x += frame_size.x * bar_growth; + frame_size.y += frame_size.y * bar_growth; + + if(gui_state.settings.theme == SE_THEME_CUSTOM && gui_state.theme.regions[SE_REGION_VOL_EMPTY].active) { + for(int i = 0; i < ImGuiCol_COUNT; ++i) + style->Colors[i].w = 0.; style->Colors[ImGuiCol_Text] = restore_style.Colors[ImGuiCol_Text]; style->Colors[ImGuiCol_TextDisabled] = restore_style.Colors[ImGuiCol_TextDisabled]; } - bool hover = igIsMouseHoveringRect((ImVec2){pos.x,pos.y},(ImVec2){pos.x+frame_size.x,pos.y+frame_size.y},true); + bool hover = igIsMouseHoveringRect((ImVec2){pos.x, pos.y}, (ImVec2){pos.x + frame_size.x, pos.y + frame_size.y}, true); float alpha = 1.0; - if(hover) alpha=0.75; - uint32_t tint = 0x00ffffff|((uint32_t)(alpha*255)<<24u); - se_draw_theme_region_tint(SE_REGION_VOL_EMPTY, pos.x,pos.y,frame_size.x,frame_size.y,tint); - float bar_value = (*p_data-p_min)/(p_max-p_min); - if(bar_value<0.0)bar_value=0; - if(bar_value>1.0)bar_value=1.0; + if(hover) alpha = 0.75; + uint32_t tint = 0x00ffffff | ((uint32_t)(alpha * 255) << 24u); + se_draw_theme_region_tint(SE_REGION_VOL_EMPTY, pos.x, pos.y, frame_size.x, frame_size.y, tint); + float bar_value = (*p_data - p_min) / (p_max - p_min); + if(bar_value < 0.0) bar_value = 0; + if(bar_value > 1.0) bar_value = 1.0; float grab_padding = 2.0; - float knob_size =style->GrabMinSize+grab_padding*2.0; - float knob_x = orig_pos.x+ bar_value*(orig_size.x-knob_size)+knob_size*0.5; - bar_value=(knob_x-pos.x)/frame_size.x; - se_draw_theme_region_tint_partial(SE_REGION_VOL_FULL, pos.x,pos.y,frame_size.x,frame_size.y,bar_value,1.0,tint); - float render_knob_size = 20.0; - se_draw_theme_region_tint(SE_REGION_VOL_KNOB, knob_x-render_knob_size*0.5,pos.y,render_knob_size,frame_size.y,tint); + float knob_size = style->GrabMinSize + grab_padding * 2.0; + float knob_x = orig_pos.x + bar_value * (orig_size.x - knob_size) + knob_size * 0.5; + bar_value = (knob_x - pos.x) / frame_size.x; + se_draw_theme_region_tint_partial(SE_REGION_VOL_FULL, pos.x, pos.y, frame_size.x, frame_size.y, bar_value, 1.0, tint); + float render_knob_size = 20.0; + se_draw_theme_region_tint(SE_REGION_VOL_KNOB, knob_x - render_knob_size * 0.5, pos.y, render_knob_size, frame_size.y, tint); igPushAllowKeyboardFocus(false); // disables focus by tab - bool button_result = igSliderFloat(label,p_data,p_min,p_max,format,ImGuiSliderFlags_AlwaysClamp); + bool button_result = igSliderFloat(label, p_data, p_min, p_max, format, ImGuiSliderFlags_AlwaysClamp); igPopAllowKeyboardFocus(); - *style = restore_style; + *style = restore_style; return button_result; - } -bool se_slider_int_themed(const char* label, int* v, float v_min, float v_max, const char* format){ +bool se_slider_int_themed(const char *label, int *v, float v_min, float v_max, const char *format) { float vf = *v; - bool ret = se_slider_float_themed(label, &vf, v_min, v_max, format); + bool ret = se_slider_float_themed(label, &vf, v_min, v_max, format); *v = vf; return ret; } -static bool se_button(const char* label, ImVec2 size){ - return se_button_themed(SE_REGION_BLANK,se_localize_and_cache(label),size,true); +static bool se_button(const char *label, ImVec2 size) { + return se_button_themed(SE_REGION_BLANK, se_localize_and_cache(label), size, true); } -static bool se_input_path(const char* label, char* new_path, ImGuiInputTextFlags flags){ +static bool se_input_path(const char *label, char *new_path, ImGuiInputTextFlags flags) { int win_w = igGetWindowWidth(); - se_text(label);igSameLine(SE_FIELD_INDENT,0); + se_text(label); + igSameLine(SE_FIELD_INDENT, 0); igPushIDStr(label); - bool read_only = (flags&ImGuiInputTextFlags_ReadOnly)!=0; - float button_w = 25; - bool has_path = strlen(new_path); - if(!read_only)igPushItemWidth(has_path?-button_w*2 : -button_w); - else igPushItemWidth(-1); + bool read_only = (flags & ImGuiInputTextFlags_ReadOnly) != 0; + float button_w = 25; + bool has_path = strlen(new_path); + if(!read_only) + igPushItemWidth(has_path ? -button_w * 2 : -button_w); + else + igPushItemWidth(-1); new_path = se_replace_fake_path(new_path); - bool b = igInputText("##",new_path,SB_FILE_PATH_SIZE,flags|ImGuiInputTextFlags_ReadOnly,NULL,NULL); + bool b = igInputText("##", new_path, SB_FILE_PATH_SIZE, flags | ImGuiInputTextFlags_ReadOnly, NULL, NULL); igPopItemWidth(); - if(!read_only){ - if(has_path){ - igSameLine(0,1); - if(se_button("" ICON_FK_TIMES,(ImVec2){button_w-2,0})){ - strncpy(new_path,"",SB_FILE_PATH_SIZE); + if(!read_only) { + if(has_path) { + igSameLine(0, 1); + if(se_button("" ICON_FK_TIMES, (ImVec2){button_w - 2, 0})) { + strncpy(new_path, "", SB_FILE_PATH_SIZE); } } - igSameLine(0,1); - bool clicked = false; - if(se_button("" ICON_FK_FOLDER_OPEN,(ImVec2){button_w-2,0}))clicked = true; - - if(igIsItemVisible()){ + igSameLine(0, 1); + bool clicked = false; + if(se_button("" ICON_FK_FOLDER_OPEN, (ImVec2){button_w - 2, 0})) clicked = true; + + if(igIsItemVisible()) { ImVec2 min, max; igGetItemRectMin(&min); igGetItemRectMax(&max); ImGuiStyle *style = igGetStyle(); - max.x+=style->FramePadding.y; - max.y+=style->FramePadding.y; - static const char *types[]={"$DIR$",NULL}; - se_open_file_browser(clicked, min.x, min.y, max.x-min.x, max.y-min.y, NULL,types,new_path); + max.x += style->FramePadding.y; + max.y += style->FramePadding.y; + static const char *types[] = {"$DIR$", NULL}; + se_open_file_browser(clicked, min.x, min.y, max.x - min.x, max.y - min.y, NULL, types, new_path); } } igPopID(); - return b; + return b; } -static bool se_input_file_callback(const char* label, char* new_path, const char**types,void (*file_open_fn)(const char*), ImGuiInputTextFlags flags){ +static bool se_input_file_callback(const char *label, char *new_path, const char **types, void (*file_open_fn)(const char *), ImGuiInputTextFlags flags) { int win_w = igGetWindowWidth(); - se_text(label);igSameLine(SE_FIELD_INDENT,0); + se_text(label); + igSameLine(SE_FIELD_INDENT, 0); igPushIDStr(label); - bool read_only = (flags&ImGuiInputTextFlags_ReadOnly)!=0; - float button_w = 25; - bool has_path = strlen(new_path); - if(!read_only)igPushItemWidth(has_path?-button_w*2 : -button_w); - else igPushItemWidth(-1); + bool read_only = (flags & ImGuiInputTextFlags_ReadOnly) != 0; + float button_w = 25; + bool has_path = strlen(new_path); + if(!read_only) + igPushItemWidth(has_path ? -button_w * 2 : -button_w); + else + igPushItemWidth(-1); new_path = se_replace_fake_path(new_path); - bool b = igInputText("##",new_path,SB_FILE_PATH_SIZE,flags|ImGuiInputTextFlags_ReadOnly,NULL,NULL); + bool b = igInputText("##", new_path, SB_FILE_PATH_SIZE, flags | ImGuiInputTextFlags_ReadOnly, NULL, NULL); igPopItemWidth(); - if(!read_only){ - if(has_path){ - igSameLine(0,1); - if(se_button("" ICON_FK_TIMES,(ImVec2){button_w-2,0})){ - gui_state.file_browser.output_path=new_path; - gui_state.file_browser.file_open_fn=file_open_fn; + if(!read_only) { + if(has_path) { + igSameLine(0, 1); + if(se_button("" ICON_FK_TIMES, (ImVec2){button_w - 2, 0})) { + gui_state.file_browser.output_path = new_path; + gui_state.file_browser.file_open_fn = file_open_fn; se_file_browser_accept(""); } } - igSameLine(0,1); - bool clicked = false; - if(se_button("" ICON_FK_FOLDER_OPEN,(ImVec2){button_w-2,0}))clicked = true; - - if(igIsItemVisible()){ + igSameLine(0, 1); + bool clicked = false; + if(se_button("" ICON_FK_FOLDER_OPEN, (ImVec2){button_w - 2, 0})) clicked = true; + + if(igIsItemVisible()) { ImVec2 min, max; igGetItemRectMin(&min); igGetItemRectMax(&max); ImGuiStyle *style = igGetStyle(); - max.x+=style->FramePadding.y; - max.y+=style->FramePadding.y; - se_open_file_browser(clicked, min.x, min.y, max.x-min.x, max.y-min.y, file_open_fn,types,new_path); + max.x += style->FramePadding.y; + max.y += style->FramePadding.y; + se_open_file_browser(clicked, min.x, min.y, max.x - min.x, max.y - min.y, file_open_fn, types, new_path); } } igPopID(); - return b; + return b; } -static bool se_input_file(const char* label, char* new_path, const char**types, ImGuiInputTextFlags flags){ - return se_input_file_callback(label,new_path,types,NULL,flags); +static bool se_input_file(const char *label, char *new_path, const char **types, ImGuiInputTextFlags flags) { + return se_input_file_callback(label, new_path, types, NULL, flags); } void se_mkdir(char *path) { - char *sep = strrchr(path, '/'); - if(sep != NULL) { - *sep = 0; - se_mkdir(path); - *sep = '/'; - } - if(mkdir(path, 0777) && errno != EEXIST) - printf("error while trying to create '%s'\n%m\n", path); + char *sep = strrchr(path, '/'); + if(sep != NULL) { + *sep = 0; + se_mkdir(path); + *sep = '/'; + } + if(mkdir(path, 0777) && errno != EEXIST) + printf("error while trying to create '%s'\n%m\n", path); } FILE *se_fopen_mkdir(const char *fpath, char *mode) { - char *path = strdup(fpath); - char *sep = strrchr(path, '/'); - char *sep2 = strrchr(path, '\\'); - if(sep2&&(!sep||sep2 0) { - fwrite(buffer, 1, read, dest); + while((read = fread(buffer, 1, sizeof(buffer), source)) > 0) { + fwrite(buffer, 1, read, dest); } fclose(source); fclose(dest); } -void se_bios_file_open_fn(const char* dir){ - //Make use of the fact that the accept function is called before the output path is updated. - char * se_bios_file_open_tmp_path = gui_state.file_browser.output_path; - if(strncmp(dir,se_bios_file_open_tmp_path,SB_FILE_PATH_SIZE)!=0){ - if(sb_file_exists(se_bios_file_open_tmp_path)||strncmp(dir,"",SB_FILE_PATH_SIZE)==0)remove(se_bios_file_open_tmp_path); - if(strncmp(dir,"",SB_FILE_PATH_SIZE)!=0)se_copy_file(dir,se_bios_file_open_tmp_path); - } - emu_state.run_mode=SB_MODE_RESET; -} - -const char* se_keycode_to_string(int keycode){ - switch(keycode){ - default: return "Unknown"; - case SAPP_KEYCODE_SPACE: return "SPACE"; - case SAPP_KEYCODE_APOSTROPHE: return "'"; - case SAPP_KEYCODE_COMMA: return ","; - case SAPP_KEYCODE_MINUS: return "-"; - case SAPP_KEYCODE_PERIOD: return "."; - case SAPP_KEYCODE_SLASH: return "/"; - case SAPP_KEYCODE_0: return "0"; - case SAPP_KEYCODE_1: return "1"; - case SAPP_KEYCODE_2: return "2"; - case SAPP_KEYCODE_3: return "3"; - case SAPP_KEYCODE_4: return "4"; - case SAPP_KEYCODE_5: return "5"; - case SAPP_KEYCODE_6: return "6"; - case SAPP_KEYCODE_7: return "7"; - case SAPP_KEYCODE_8: return "8"; - case SAPP_KEYCODE_9: return "9"; - case SAPP_KEYCODE_SEMICOLON: return ";"; - case SAPP_KEYCODE_EQUAL: return "="; - case SAPP_KEYCODE_A: return "A"; - case SAPP_KEYCODE_B: return "B"; - case SAPP_KEYCODE_C: return "C"; - case SAPP_KEYCODE_D: return "D"; - case SAPP_KEYCODE_E: return "E"; - case SAPP_KEYCODE_F: return "F"; - case SAPP_KEYCODE_G: return "G"; - case SAPP_KEYCODE_H: return "H"; - case SAPP_KEYCODE_I: return "I"; - case SAPP_KEYCODE_J: return "J"; - case SAPP_KEYCODE_K: return "K"; - case SAPP_KEYCODE_L: return "L"; - case SAPP_KEYCODE_M: return "M"; - case SAPP_KEYCODE_N: return "N"; - case SAPP_KEYCODE_O: return "O"; - case SAPP_KEYCODE_P: return "P"; - case SAPP_KEYCODE_Q: return "Q"; - case SAPP_KEYCODE_R: return "R"; - case SAPP_KEYCODE_S: return "S"; - case SAPP_KEYCODE_T: return "T"; - case SAPP_KEYCODE_U: return "U"; - case SAPP_KEYCODE_V: return "V"; - case SAPP_KEYCODE_W: return "W"; - case SAPP_KEYCODE_X: return "X"; - case SAPP_KEYCODE_Y: return "Y"; - case SAPP_KEYCODE_Z: return "Z"; - case SAPP_KEYCODE_LEFT_BRACKET: return "["; - case SAPP_KEYCODE_BACKSLASH: return "\\"; - case SAPP_KEYCODE_RIGHT_BRACKET: return "]"; - case SAPP_KEYCODE_GRAVE_ACCENT: return "`"; - case SAPP_KEYCODE_WORLD_1: return "WORLD 1"; - case SAPP_KEYCODE_WORLD_2: return "WORLD 2"; - case SAPP_KEYCODE_ESCAPE: return "ESCAPE"; - case SAPP_KEYCODE_ENTER: return "ENTER"; - case SAPP_KEYCODE_TAB: return "TAB"; - case SAPP_KEYCODE_BACKSPACE: return "BACKSPACE"; - case SAPP_KEYCODE_INSERT: return "INSERT"; - case SAPP_KEYCODE_DELETE: return "DELETE"; - case SAPP_KEYCODE_RIGHT: return "RIGHT"; - case SAPP_KEYCODE_LEFT: return "LEFT"; - case SAPP_KEYCODE_DOWN: return "DOWN"; - case SAPP_KEYCODE_UP: return "UP"; - case SAPP_KEYCODE_PAGE_UP: return "PAGE UP"; - case SAPP_KEYCODE_PAGE_DOWN: return "PAGE DOWN"; - case SAPP_KEYCODE_HOME: return "HOME"; - case SAPP_KEYCODE_END: return "END"; - case SAPP_KEYCODE_CAPS_LOCK: return "CAPS LOCK"; - case SAPP_KEYCODE_SCROLL_LOCK: return "SCROLL LOCK"; - case SAPP_KEYCODE_NUM_LOCK: return "NUM LOCK"; - case SAPP_KEYCODE_PRINT_SCREEN: return "PRINT SCREEN"; - case SAPP_KEYCODE_PAUSE: return "PAUSE"; - case SAPP_KEYCODE_F1: return "F1"; - case SAPP_KEYCODE_F2: return "F2"; - case SAPP_KEYCODE_F3: return "F3"; - case SAPP_KEYCODE_F4: return "F4"; - case SAPP_KEYCODE_F5: return "F5"; - case SAPP_KEYCODE_F6: return "F6"; - case SAPP_KEYCODE_F7: return "F7"; - case SAPP_KEYCODE_F8: return "F8"; - case SAPP_KEYCODE_F9: return "F9"; - case SAPP_KEYCODE_F10: return "F10"; - case SAPP_KEYCODE_F11: return "F11"; - case SAPP_KEYCODE_F12: return "F12"; - case SAPP_KEYCODE_F13: return "F13"; - case SAPP_KEYCODE_F14: return "F14"; - case SAPP_KEYCODE_F15: return "F15"; - case SAPP_KEYCODE_F16: return "F16"; - case SAPP_KEYCODE_F17: return "F17"; - case SAPP_KEYCODE_F18: return "F18"; - case SAPP_KEYCODE_F19: return "F19"; - case SAPP_KEYCODE_F20: return "F20"; - case SAPP_KEYCODE_F21: return "F21"; - case SAPP_KEYCODE_F22: return "F22"; - case SAPP_KEYCODE_F23: return "F23"; - case SAPP_KEYCODE_F24: return "F24"; - case SAPP_KEYCODE_F25: return "F25"; - case SAPP_KEYCODE_KP_0: return "KP 0"; - case SAPP_KEYCODE_KP_1: return "KP 1"; - case SAPP_KEYCODE_KP_2: return "KP 2"; - case SAPP_KEYCODE_KP_3: return "KP 3"; - case SAPP_KEYCODE_KP_4: return "KP 4"; - case SAPP_KEYCODE_KP_5: return "KP 5"; - case SAPP_KEYCODE_KP_6: return "KP 6"; - case SAPP_KEYCODE_KP_7: return "KP 7"; - case SAPP_KEYCODE_KP_8: return "KP 8"; - case SAPP_KEYCODE_KP_9: return "KP 9"; - case SAPP_KEYCODE_KP_DECIMAL: return "KP ."; - case SAPP_KEYCODE_KP_DIVIDE: return "KP /"; - case SAPP_KEYCODE_KP_MULTIPLY: return "KP *"; - case SAPP_KEYCODE_KP_SUBTRACT: return "KP -"; - case SAPP_KEYCODE_KP_ADD: return "KP +"; - case SAPP_KEYCODE_KP_ENTER: return "KP ENTER"; - case SAPP_KEYCODE_KP_EQUAL: return "KP ="; - case SAPP_KEYCODE_LEFT_SHIFT: return "LEFT SHIFT"; - case SAPP_KEYCODE_LEFT_CONTROL: return "LEFT CONTROL"; - case SAPP_KEYCODE_LEFT_ALT: return "LEFT ALT"; - case SAPP_KEYCODE_LEFT_SUPER: return "LEFT SUPER"; - case SAPP_KEYCODE_RIGHT_SHIFT: return "RIGHT SHIFT"; - case SAPP_KEYCODE_RIGHT_CONTROL: return "RIGHT CONTROL"; - case SAPP_KEYCODE_RIGHT_ALT: return "RIGHT ALT"; - case SAPP_KEYCODE_RIGHT_SUPER: return "RIGHT SUPER"; - case SAPP_KEYCODE_MENU: return "MENU"; - } -} - - -se_core_state_t core; -se_core_scratch_t scratch; +void se_bios_file_open_fn(const char *dir) { + // Make use of the fact that the accept function is called before the output path is updated. + char *se_bios_file_open_tmp_path = gui_state.file_browser.output_path; + if(strncmp(dir, se_bios_file_open_tmp_path, SB_FILE_PATH_SIZE) != 0) { + if(sb_file_exists(se_bios_file_open_tmp_path) || strncmp(dir, "", SB_FILE_PATH_SIZE) == 0) remove(se_bios_file_open_tmp_path); + if(strncmp(dir, "", SB_FILE_PATH_SIZE) != 0) se_copy_file(dir, se_bios_file_open_tmp_path); + } + emu_state.run_mode = SB_MODE_RESET; +} + +const char *se_keycode_to_string(int keycode) { + switch(keycode) { + default: return "Unknown"; + case SAPP_KEYCODE_SPACE: return "SPACE"; + case SAPP_KEYCODE_APOSTROPHE: return "'"; + case SAPP_KEYCODE_COMMA: return ","; + case SAPP_KEYCODE_MINUS: return "-"; + case SAPP_KEYCODE_PERIOD: return "."; + case SAPP_KEYCODE_SLASH: return "/"; + case SAPP_KEYCODE_0: return "0"; + case SAPP_KEYCODE_1: return "1"; + case SAPP_KEYCODE_2: return "2"; + case SAPP_KEYCODE_3: return "3"; + case SAPP_KEYCODE_4: return "4"; + case SAPP_KEYCODE_5: return "5"; + case SAPP_KEYCODE_6: return "6"; + case SAPP_KEYCODE_7: return "7"; + case SAPP_KEYCODE_8: return "8"; + case SAPP_KEYCODE_9: return "9"; + case SAPP_KEYCODE_SEMICOLON: return ";"; + case SAPP_KEYCODE_EQUAL: return "="; + case SAPP_KEYCODE_A: return "A"; + case SAPP_KEYCODE_B: return "B"; + case SAPP_KEYCODE_C: return "C"; + case SAPP_KEYCODE_D: return "D"; + case SAPP_KEYCODE_E: return "E"; + case SAPP_KEYCODE_F: return "F"; + case SAPP_KEYCODE_G: return "G"; + case SAPP_KEYCODE_H: return "H"; + case SAPP_KEYCODE_I: return "I"; + case SAPP_KEYCODE_J: return "J"; + case SAPP_KEYCODE_K: return "K"; + case SAPP_KEYCODE_L: return "L"; + case SAPP_KEYCODE_M: return "M"; + case SAPP_KEYCODE_N: return "N"; + case SAPP_KEYCODE_O: return "O"; + case SAPP_KEYCODE_P: return "P"; + case SAPP_KEYCODE_Q: return "Q"; + case SAPP_KEYCODE_R: return "R"; + case SAPP_KEYCODE_S: return "S"; + case SAPP_KEYCODE_T: return "T"; + case SAPP_KEYCODE_U: return "U"; + case SAPP_KEYCODE_V: return "V"; + case SAPP_KEYCODE_W: return "W"; + case SAPP_KEYCODE_X: return "X"; + case SAPP_KEYCODE_Y: return "Y"; + case SAPP_KEYCODE_Z: return "Z"; + case SAPP_KEYCODE_LEFT_BRACKET: return "["; + case SAPP_KEYCODE_BACKSLASH: return "\\"; + case SAPP_KEYCODE_RIGHT_BRACKET: return "]"; + case SAPP_KEYCODE_GRAVE_ACCENT: return "`"; + case SAPP_KEYCODE_WORLD_1: return "WORLD 1"; + case SAPP_KEYCODE_WORLD_2: return "WORLD 2"; + case SAPP_KEYCODE_ESCAPE: return "ESCAPE"; + case SAPP_KEYCODE_ENTER: return "ENTER"; + case SAPP_KEYCODE_TAB: return "TAB"; + case SAPP_KEYCODE_BACKSPACE: return "BACKSPACE"; + case SAPP_KEYCODE_INSERT: return "INSERT"; + case SAPP_KEYCODE_DELETE: return "DELETE"; + case SAPP_KEYCODE_RIGHT: return "RIGHT"; + case SAPP_KEYCODE_LEFT: return "LEFT"; + case SAPP_KEYCODE_DOWN: return "DOWN"; + case SAPP_KEYCODE_UP: return "UP"; + case SAPP_KEYCODE_PAGE_UP: return "PAGE UP"; + case SAPP_KEYCODE_PAGE_DOWN: return "PAGE DOWN"; + case SAPP_KEYCODE_HOME: return "HOME"; + case SAPP_KEYCODE_END: return "END"; + case SAPP_KEYCODE_CAPS_LOCK: return "CAPS LOCK"; + case SAPP_KEYCODE_SCROLL_LOCK: return "SCROLL LOCK"; + case SAPP_KEYCODE_NUM_LOCK: return "NUM LOCK"; + case SAPP_KEYCODE_PRINT_SCREEN: return "PRINT SCREEN"; + case SAPP_KEYCODE_PAUSE: return "PAUSE"; + case SAPP_KEYCODE_F1: return "F1"; + case SAPP_KEYCODE_F2: return "F2"; + case SAPP_KEYCODE_F3: return "F3"; + case SAPP_KEYCODE_F4: return "F4"; + case SAPP_KEYCODE_F5: return "F5"; + case SAPP_KEYCODE_F6: return "F6"; + case SAPP_KEYCODE_F7: return "F7"; + case SAPP_KEYCODE_F8: return "F8"; + case SAPP_KEYCODE_F9: return "F9"; + case SAPP_KEYCODE_F10: return "F10"; + case SAPP_KEYCODE_F11: return "F11"; + case SAPP_KEYCODE_F12: return "F12"; + case SAPP_KEYCODE_F13: return "F13"; + case SAPP_KEYCODE_F14: return "F14"; + case SAPP_KEYCODE_F15: return "F15"; + case SAPP_KEYCODE_F16: return "F16"; + case SAPP_KEYCODE_F17: return "F17"; + case SAPP_KEYCODE_F18: return "F18"; + case SAPP_KEYCODE_F19: return "F19"; + case SAPP_KEYCODE_F20: return "F20"; + case SAPP_KEYCODE_F21: return "F21"; + case SAPP_KEYCODE_F22: return "F22"; + case SAPP_KEYCODE_F23: return "F23"; + case SAPP_KEYCODE_F24: return "F24"; + case SAPP_KEYCODE_F25: return "F25"; + case SAPP_KEYCODE_KP_0: return "KP 0"; + case SAPP_KEYCODE_KP_1: return "KP 1"; + case SAPP_KEYCODE_KP_2: return "KP 2"; + case SAPP_KEYCODE_KP_3: return "KP 3"; + case SAPP_KEYCODE_KP_4: return "KP 4"; + case SAPP_KEYCODE_KP_5: return "KP 5"; + case SAPP_KEYCODE_KP_6: return "KP 6"; + case SAPP_KEYCODE_KP_7: return "KP 7"; + case SAPP_KEYCODE_KP_8: return "KP 8"; + case SAPP_KEYCODE_KP_9: return "KP 9"; + case SAPP_KEYCODE_KP_DECIMAL: return "KP ."; + case SAPP_KEYCODE_KP_DIVIDE: return "KP /"; + case SAPP_KEYCODE_KP_MULTIPLY: return "KP *"; + case SAPP_KEYCODE_KP_SUBTRACT: return "KP -"; + case SAPP_KEYCODE_KP_ADD: return "KP +"; + case SAPP_KEYCODE_KP_ENTER: return "KP ENTER"; + case SAPP_KEYCODE_KP_EQUAL: return "KP ="; + case SAPP_KEYCODE_LEFT_SHIFT: return "LEFT SHIFT"; + case SAPP_KEYCODE_LEFT_CONTROL: return "LEFT CONTROL"; + case SAPP_KEYCODE_LEFT_ALT: return "LEFT ALT"; + case SAPP_KEYCODE_LEFT_SUPER: return "LEFT SUPER"; + case SAPP_KEYCODE_RIGHT_SHIFT: return "RIGHT SHIFT"; + case SAPP_KEYCODE_RIGHT_CONTROL: return "RIGHT CONTROL"; + case SAPP_KEYCODE_RIGHT_ALT: return "RIGHT ALT"; + case SAPP_KEYCODE_RIGHT_SUPER: return "RIGHT SUPER"; + case SAPP_KEYCODE_MENU: return "MENU"; + } +} + +se_core_state_t core; +se_core_scratch_t scratch; se_core_rewind_buffer_t rewind_buffer; -se_save_state_t save_states[SE_NUM_SAVE_STATES]; -se_cheat_t cheats[SE_NUM_CHEATS]; - -bool se_more_rewind_deltas(se_core_rewind_buffer_t* rewind, uint32_t index){ - return (rewind->deltas[index%SE_REWIND_BUFFER_SIZE].offset&SE_LAST_DELTA_IN_TX)==0; -} -void se_push_rewind_state(se_core_state_t* core, se_core_rewind_buffer_t* rewind){ - if(!rewind->first_push){ - rewind->first_push=true; - rewind->last_core= *core; - return; - } - int total_segments = sizeof(se_core_state_t)/SE_REWIND_SEGMENT_SIZE; - uint64_t * new_data = (uint64_t*)core; - uint64_t * old_data = (uint64_t*)&rewind->last_core; - int total_deltas =0; - for(int s=0; sindex%SE_REWIND_BUFFER_SIZE; - int offset = s; - if(total_deltas==0)offset|= SE_LAST_DELTA_IN_TX; - for(int s_off = 0; s_off< SE_REWIND_SEGMENT_SIZE/8;++s_off){ - rewind->deltas[rewind_index].data[s_off] =old_data[base_off+s_off]; - old_data[base_off+s_off]= new_data[base_off+s_off]; - } +se_save_state_t save_states[SE_NUM_SAVE_STATES]; +se_cheat_t cheats[SE_NUM_CHEATS]; + +bool se_more_rewind_deltas(se_core_rewind_buffer_t *rewind, uint32_t index) { + return (rewind->deltas[index % SE_REWIND_BUFFER_SIZE].offset & SE_LAST_DELTA_IN_TX) == 0; +} +void se_push_rewind_state(se_core_state_t *core, se_core_rewind_buffer_t *rewind) { + if(!rewind->first_push) { + rewind->first_push = true; + rewind->last_core = *core; + return; + } + int total_segments = sizeof(se_core_state_t) / SE_REWIND_SEGMENT_SIZE; + uint64_t *new_data = (uint64_t *)core; + uint64_t *old_data = (uint64_t *)&rewind->last_core; + int total_deltas = 0; + for(int s = 0; s < total_segments; ++s) { + bool delta = false; + int base_off = s * SE_REWIND_SEGMENT_SIZE / 8; + for(int s_off = 0; s_off < SE_REWIND_SEGMENT_SIZE / 8; ++s_off) { + if(new_data[base_off + s_off] != old_data[base_off + s_off]) { + delta = true; + break; + } + } + if(delta) { + int rewind_index = rewind->index % SE_REWIND_BUFFER_SIZE; + int offset = s; + if(total_deltas == 0) offset |= SE_LAST_DELTA_IN_TX; + for(int s_off = 0; s_off < SE_REWIND_SEGMENT_SIZE / 8; ++s_off) { + rewind->deltas[rewind_index].data[s_off] = old_data[base_off + s_off]; + old_data[base_off + s_off] = new_data[base_off + s_off]; + } rewind->deltas[rewind_index].offset = offset; rewind->index++; rewind->size++; ++total_deltas; } } - if(rewind->size>=SE_REWIND_BUFFER_SIZE)rewind->size=SE_REWIND_BUFFER_SIZE-1; - rewind->index= rewind->index%SE_REWIND_BUFFER_SIZE; - //Discard partial transactions remaing - while(rewind->size>0 && se_more_rewind_deltas(rewind,rewind->index-rewind->size))rewind->size--; + if(rewind->size >= SE_REWIND_BUFFER_SIZE) rewind->size = SE_REWIND_BUFFER_SIZE - 1; + rewind->index = rewind->index % SE_REWIND_BUFFER_SIZE; + // Discard partial transactions remaing + while(rewind->size > 0 && se_more_rewind_deltas(rewind, rewind->index - rewind->size)) + rewind->size--; } -void se_rewind_state_single_tick(se_core_state_t* core, se_core_rewind_buffer_t* rewind){ - uint64_t * old_data = (uint64_t*)&rewind->last_core; - int rewound_deltas=0; - bool more_transactions = true; - while(rewind->size&&more_transactions){ +void se_rewind_state_single_tick(se_core_state_t *core, se_core_rewind_buffer_t *rewind) { + uint64_t *old_data = (uint64_t *)&rewind->last_core; + int rewound_deltas = 0; + bool more_transactions = true; + while(rewind->size && more_transactions) { ++rewound_deltas; --rewind->size; - uint32_t rewind_index = (--rewind->index)%SE_REWIND_BUFFER_SIZE; - int s = rewind->deltas[rewind_index].offset; - if(s&SE_LAST_DELTA_IN_TX){ - more_transactions=false; - s&=~SE_LAST_DELTA_IN_TX; + uint32_t rewind_index = (--rewind->index) % SE_REWIND_BUFFER_SIZE; + int s = rewind->deltas[rewind_index].offset; + if(s & SE_LAST_DELTA_IN_TX) { + more_transactions = false; + s &= ~SE_LAST_DELTA_IN_TX; } - int base_off = s*SE_REWIND_SEGMENT_SIZE/8; - for(int s_off = 0; s_off< SE_REWIND_SEGMENT_SIZE/8;++s_off){ - old_data[base_off+s_off]=rewind->deltas[rewind_index].data[s_off]; + int base_off = s * SE_REWIND_SEGMENT_SIZE / 8; + for(int s_off = 0; s_off < SE_REWIND_SEGMENT_SIZE / 8; ++s_off) { + old_data[base_off + s_off] = rewind->deltas[rewind_index].data[s_off]; } } - rewind->index= rewind->index%SE_REWIND_BUFFER_SIZE; + rewind->index = rewind->index % SE_REWIND_BUFFER_SIZE; *core = rewind->last_core; } -void se_reset_rewind_buffer(se_core_rewind_buffer_t* rewind){ - rewind->index = rewind->size = 0; +void se_reset_rewind_buffer(se_core_rewind_buffer_t *rewind) { + rewind->index = rewind->size = 0; rewind->first_push = false; } -se_emu_id se_get_emu_id(){ - se_emu_id emu_id={0}; - strncpy(emu_id.name,"SkyEmu",sizeof(emu_id.name)); - strncpy(emu_id.build,GIT_COMMIT_HASH,sizeof(emu_id.build)); +se_emu_id se_get_emu_id() { + se_emu_id emu_id = {0}; + strncpy(emu_id.name, "SkyEmu", sizeof(emu_id.name)); + strncpy(emu_id.build, GIT_COMMIT_HASH, sizeof(emu_id.build)); return emu_id; } -uint8_t* se_save_state_to_image(se_save_state_t * save_state, uint32_t *width, uint32_t *height){ - se_emu_id emu_id=se_get_emu_id(); +uint8_t *se_save_state_to_image(se_save_state_t *save_state, uint32_t *width, uint32_t *height) { + se_emu_id emu_id = se_get_emu_id(); emu_id.bess_offset = se_save_best_effort_state(&save_state->state); emu_id.system = save_state->system; - printf("Bess offset: %d\n",emu_id.bess_offset); + printf("Bess offset: %d\n", emu_id.bess_offset); size_t save_state_size = se_get_core_size(); - size_t net_save_state_size = sizeof(emu_id)+save_state_size; - int screenshot_size = save_state->screenshot_width*save_state->screenshot_height; - - int scale = 1; - while(screenshot_size*scale*scalestate); - for(int y=0;yscreenshot_height*scale;++y){ - for(int x=0;xscreenshot_width*scale;++x){ - int px = x/scale; - int py = y/scale; - int p = (px+py*save_state->screenshot_width); - uint8_t r = save_state->screenshot[p*4+0]; - uint8_t g = save_state->screenshot[p*4+1]; - uint8_t b = save_state->screenshot[p*4+2]; - uint8_t a = 0xff; - int p_out = x+y*save_state->screenshot_width*scale; - uint8_t data =0; - if(p_outscreenshot_width*scale; - *height = save_state->screenshot_height*scale; + size_t net_save_state_size = sizeof(emu_id) + save_state_size; + int screenshot_size = save_state->screenshot_width * save_state->screenshot_height; + + int scale = 1; + while(screenshot_size * scale * scale < net_save_state_size) + scale++; + + uint8_t *imdata = malloc(scale * scale * screenshot_size * 4); + uint8_t *emu_id_dat = (uint8_t *)&emu_id; + uint8_t *save_state_dat = (uint8_t *)&(save_state->state); + for(int y = 0; y < save_state->screenshot_height * scale; ++y) { + for(int x = 0; x < save_state->screenshot_width * scale; ++x) { + int px = x / scale; + int py = y / scale; + int p = (px + py * save_state->screenshot_width); + uint8_t r = save_state->screenshot[p * 4 + 0]; + uint8_t g = save_state->screenshot[p * 4 + 1]; + uint8_t b = save_state->screenshot[p * 4 + 2]; + uint8_t a = 0xff; + int p_out = x + y * save_state->screenshot_width * scale; + uint8_t data = 0; + if(p_out < sizeof(emu_id)) + data = emu_id_dat[p_out]; + else if(p_out - sizeof(emu_id) < save_state_size) + data = save_state_dat[p_out - sizeof(emu_id)]; + + r &= 0xfC; + g &= 0xfC; + b &= 0xfC; + a &= 0xfC; + + r |= SB_BFE(data, 0, 2); + g |= SB_BFE(data, 2, 2); + b |= SB_BFE(data, 4, 2); + a |= SB_BFE(data, 6, 2); + imdata[p_out * 4 + 0] = r; + imdata[p_out * 4 + 1] = g; + imdata[p_out * 4 + 2] = b; + imdata[p_out * 4 + 3] = a; + } + } + *width = save_state->screenshot_width * scale; + *height = save_state->screenshot_height * scale; return imdata; } -bool se_save_state_to_disk(se_save_state_t* save_state, const char* filename){ - if(emu_state.rom_loaded==false)return false; - uint32_t width=0, height=0; - uint8_t* imdata = se_save_state_to_image(save_state, &width,&height); - bool success= stbi_write_png(filename, width,height, 4, imdata, 0); +bool se_save_state_to_disk(se_save_state_t *save_state, const char *filename) { + if(emu_state.rom_loaded == false) return false; + uint32_t width = 0, height = 0; + uint8_t *imdata = se_save_state_to_image(save_state, &width, &height); + bool success = stbi_write_png(filename, width, height, 4, imdata, 0); free(imdata); se_emscripten_flush_fs(); return success; } -bool se_bess_state_restore(uint8_t*state_data, size_t data_size, const se_emu_id emu_id, se_save_state_t* state){ +bool se_bess_state_restore(uint8_t *state_data, size_t data_size, const se_emu_id emu_id, se_save_state_t *state) { state->state = core; printf("Attempting BESS Restore\n"); - if(sizeof(emu_id)>data_size)return false; - size_t save_state_size = data_size-sizeof(emu_id); - uint8_t *data = state_data +sizeof(emu_id); - bool valid = se_load_best_effort_state(&(state->state),data, save_state_size, emu_id.bess_offset); - printf("Valid:%d\n",valid); - if(!valid){ - state->screenshot_width=1; - state->screenshot_height=1; - state->screenshot[0] = 0; - state->screenshot[1] = 0; - state->screenshot[2] = 0; - state->screenshot[3] = 255; - } - return valid; -} -bool se_load_state_from_disk(se_save_state_t* save_state, const char* filename){ + if(sizeof(emu_id) > data_size) return false; + size_t save_state_size = data_size - sizeof(emu_id); + uint8_t *data = state_data + sizeof(emu_id); + bool valid = se_load_best_effort_state(&(state->state), data, save_state_size, emu_id.bess_offset); + printf("Valid:%d\n", valid); + if(!valid) { + state->screenshot_width = 1; + state->screenshot_height = 1; + state->screenshot[0] = 0; + state->screenshot[1] = 0; + state->screenshot[2] = 0; + state->screenshot[3] = 255; + } + return valid; +} +bool se_load_state_from_disk(se_save_state_t *save_state, const char *filename) { save_state->valid = false; - int im_w, im_h, im_c; + int im_w, im_h, im_c; uint8_t *imdata = stbi_load(filename, &im_w, &im_h, &im_c, 4); - if(!imdata)return false; + if(!imdata) return false; - uint8_t *data = malloc(im_w*im_h); - size_t data_size = im_w*im_h; - for(int i=0;i=sizeof(save_state->screenshot))downscale++; - save_state->screenshot_width=im_w/downscale; - save_state->screenshot_height=im_h/downscale; - for(int y=0;yscreenshot_width; - for(int i=0;i<3;++i)save_state->screenshot[p2*4+i]= imdata[p1*4+i]; - save_state->screenshot[p2*4+3]=0xff; - } - } - + d |= SB_BFE(imdata[i * 4 + 0], 0, 2) << 0; + d |= SB_BFE(imdata[i * 4 + 1], 0, 2) << 2; + d |= SB_BFE(imdata[i * 4 + 2], 0, 2) << 4; + d |= SB_BFE(imdata[i * 4 + 3], 0, 2) << 6; + data[i] = d; + } + int downscale = 1; + while((im_w / downscale) * (im_h / downscale) * 4 >= sizeof(save_state->screenshot)) + downscale++; + save_state->screenshot_width = im_w / downscale; + save_state->screenshot_height = im_h / downscale; + for(int y = 0; y < im_h; y += downscale) { + for(int x = 0; x < im_w; x += downscale) { + int p1 = x + y * im_w; + int p2 = x / downscale + (y / downscale) * save_state->screenshot_width; + for(int i = 0; i < 3; ++i) + save_state->screenshot[p2 * 4 + i] = imdata[p1 * 4 + i]; + save_state->screenshot[p2 * 4 + 3] = 0xff; + } + } + stbi_image_free(imdata); - bool valid = data_sizesystem = comp_id.system; - if(!bess&&se_get_core_size()+sizeof(se_emu_id)<=data_size){ - memcpy(&(save_state->state), data+sizeof(se_emu_id), se_get_core_size()); - save_state->valid = 1; - }else if(se_bess_state_restore(data, data_size,comp_id, save_state)){ + if(!bess && se_get_core_size() + sizeof(se_emu_id) <= data_size) { + memcpy(&(save_state->state), data + sizeof(se_emu_id), se_get_core_size()); + save_state->valid = 1; + } else if(se_bess_state_restore(data, data_size, comp_id, save_state)) { save_state->valid = 2; } - - if(save_state->valid)printf("Loaded save state:%s\n",filename); - else printf("Failed to load state from file:%s\n",filename); + + if(save_state->valid) + printf("Loaded save state:%s\n", filename); + else + printf("Failed to load state from file:%s\n", filename); } free(data); return save_state->valid; } -double se_time(){ - static uint64_t base_time=0; - if(base_time==0) base_time= stm_now(); - return stm_sec(stm_diff(stm_now(),base_time)); +double se_time() { + static uint64_t base_time = 0; + if(base_time == 0) base_time = stm_now(); + return stm_sec(stm_diff(stm_now(), base_time)); } -static void se_tooltip(const char * tooltip){ - if(igGetCurrentContext()->HoveredIdTimer<1.5||gui_state.last_touch_time>0)return; - if (igIsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)&&!igIsItemActive()){ +static void se_tooltip(const char *tooltip) { + if(igGetCurrentContext()->HoveredIdTimer < 1.5 || gui_state.last_touch_time > 0) return; + if(igIsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !igIsItemActive()) { igSetTooltip(se_localize_and_cache(tooltip)); } } -double se_fps_counter(int tick){ - static int call = -1; +double se_fps_counter(int tick) { + static int call = -1; static double last_t = 0; - static double fps = 1.0/60.0; - if(!tick)return 1.0/fps; - if(call==-1){ + static double fps = 1.0 / 60.0; + if(!tick) return 1.0 / fps; + if(call == -1) { call = 0; last_t = se_time(); - fps = 1.0/60; - }else{ - call+=tick; + fps = 1.0 / 60; + } else { + call += tick; double t = se_time(); - double delta = t-last_t; - if(delta>0.5){ - fps=delta/call; + double delta = t - last_t; + if(delta > 0.5) { + fps = delta / call; last_t = t; - call=0; + call = 0; } - } - return 1.0/fps; + return 1.0 / fps; } -static void se_emscripten_flush_fs(){ +static void se_emscripten_flush_fs() { #if defined(EMSCRIPTEN) - EM_ASM( FS.syncfs(function (err) {});); + EM_ASM( FS.syncfs(function (err) {});); #endif } -void se_load_search_paths(){ +void se_load_search_paths() { char settings_path[SB_FILE_PATH_SIZE]; - snprintf(settings_path,SB_FILE_PATH_SIZE,"%ssearch_paths.bin",se_get_pref_path()); - if(!sb_load_file_data_into_buffer(settings_path,(void*)&gui_state.paths,sizeof(gui_state.paths)))memset(&gui_state.paths,0,sizeof(gui_state.paths)); - char * paths[]={ - gui_state.paths.save, - gui_state.paths.bios, - gui_state.paths.cheat_codes - }; - for(int i=0;iname)/sizeof(info->name[0]);++i){ - if(info->name[i][0]==0){ - strncpy(info->name[i],name,sizeof(info->name[i])); - strncpy(info->path[i],bios_create_path,sizeof(info->path[i])); - info->success[i]=loaded_bios; + se_bios_info_t *info = &gui_state.bios_info; + for(int i = 0; i < sizeof(info->name) / sizeof(info->name[0]); ++i) { + if(info->name[i][0] == 0) { + strncpy(info->name[i], name, sizeof(info->name[i])); + strncpy(info->path[i], bios_create_path, sizeof(info->path[i])); + info->success[i] = loaded_bios; break; } - if(strcmp(info->name[i],name)==0){ - if(loaded_bios){ - strncpy(info->path[i],bios_path,sizeof(info->path[i])); - info->success[i]=true; + if(strcmp(info->name[i], name) == 0) { + if(loaded_bios) { + strncpy(info->path[i], bios_path, sizeof(info->path[i])); + info->success[i] = true; } break; } @@ -1315,60 +1331,63 @@ bool se_load_bios_file(const char* name, const char* base_path, const char* file free(bios_data); return loaded_bios; } -static int se_game_info_alpha_comparator(const void* a, const void* b){ - const int ga = *(int*)a; - const int gb = *(int*)b; - return strcmp(gui_state.recently_loaded_games[ga].path,gui_state.recently_loaded_games[gb].path); -} -static int se_game_info_rev_alpha_comparator(const void* a, const void* b){ - const int ga = *(int*)a; - const int gb = *(int*)b; - return strcmp(gui_state.recently_loaded_games[gb].path,gui_state.recently_loaded_games[ga].path); -} -static void se_sort_recent_games_list(){ - int size = 0; - for(int i=0;irecently_loaded_games[i].path)==0)break; - fprintf(f,"%s\n",gui->recently_loaded_games[i].path); + for(int i = 0; i < SE_NUM_RECENT_PATHS; ++i) { + if(strcmp("", gui->recently_loaded_games[i].path) == 0) break; + fprintf(f, "%s\n", gui->recently_loaded_games[i].path); } fclose(f); se_emscripten_flush_fs(); se_sort_recent_games_list(); } -static void se_load_recent_games_list(){ - gui_state_t* gui = &gui_state; - char pref_path[SB_FILE_PATH_SIZE]; - snprintf(pref_path,SB_FILE_PATH_SIZE,"%s/%s",se_get_pref_path(), "recent_games.txt"); - FILE* f = fopen(pref_path,"rb"); - if(!f)return; - for(int i=0;irecently_loaded_games[i].path,0,SB_FILE_PATH_SIZE); - } - for(int i=0;irecently_loaded_games[i].path, SB_FILE_PATH_SIZE,f); - if(res==NULL)break; - //Get rid of newline and carriage return characters at end - while(*res){ - if(*res=='\n'||*res=='\r')*res='\0'; +static void se_load_recent_games_list() { + gui_state_t *gui = &gui_state; + char pref_path[SB_FILE_PATH_SIZE]; + snprintf(pref_path, SB_FILE_PATH_SIZE, "%s/%s", se_get_pref_path(), "recent_games.txt"); + FILE *f = fopen(pref_path, "rb"); + if(!f) return; + for(int i = 0; i < SE_NUM_RECENT_PATHS; ++i) { + memset(gui->recently_loaded_games[i].path, 0, SB_FILE_PATH_SIZE); + } + for(int i = 0; i < SE_NUM_RECENT_PATHS; ++i) { + char *res = fgets(gui->recently_loaded_games[i].path, SB_FILE_PATH_SIZE, f); + if(res == NULL) break; + // Get rid of newline and carriage return characters at end + while(*res) { + if(*res == '\n' || *res == '\r') *res = '\0'; ++res; } } @@ -1376,158 +1395,157 @@ static void se_load_recent_games_list(){ se_sort_recent_games_list(); } -bool se_key_is_pressed(int keycode){ - if(keycode>SAPP_MAX_KEYCODES||keycode==-1)return false; - // Don't let keyboard input reach emulator when ImGUI is capturing it. - // Allow inputs if the touch screen is being pressed as the screen is an ImGUI object that - // registers drag events. - if(igGetIO()->WantCaptureKeyboard && ! emu_state.joy.inputs[SE_KEY_PEN_DOWN] )return false; +bool se_key_is_pressed(int keycode) { + if(keycode > SAPP_MAX_KEYCODES || keycode == -1) return false; + // Don't let keyboard input reach emulator when ImGUI is capturing it. + // Allow inputs if the touch screen is being pressed as the screen is an ImGUI object that + // registers drag events. + if(igGetIO()->WantCaptureKeyboard && !emu_state.joy.inputs[SE_KEY_PEN_DOWN]) return false; return gui_state.button_state[keycode]; } -static sg_image* se_get_image(){ - if(gui_state.current_imagelast_emu_time; + double delta = time - stats->last_emu_time; stats->last_emu_time = time; - double fps = 1.0/delta*frames_emulated; + double fps = 1.0 / delta * frames_emulated; int abs_frames = abs(frames_emulated); - for(int i=0;iwaveform_fps_emulation[i]=stats->waveform_fps_emulation[i+abs_frames]; + for(int i = 0; i < SE_STATS_GRAPH_DATA - abs_frames; ++i) { + stats->waveform_fps_emulation[i] = stats->waveform_fps_emulation[i + abs_frames]; } - for(int i=0;iwaveform_fps_emulation[SE_STATS_GRAPH_DATA-abs_frames+i]= fps; + for(int i = 0; i < abs_frames; ++i) + stats->waveform_fps_emulation[SE_STATS_GRAPH_DATA - abs_frames + i] = fps; } -void se_draw_emu_stats(){ +void se_draw_emu_stats() { se_emulator_stats_t *stats = &gui_state.emu_stats; - double curr_time = se_time(); - double fps_render = 1.0/(curr_time-stats->last_render_time); - stats->last_render_time=curr_time; - float render_min=1e9, render_max=0, render_avg=0; - float emulate_min=1e9, emulate_max=0, emulate_avg=0; - int render_data_points = 0; - int emulate_data_points =0; - - se_record_emulation_frame_stats(&gui_state.emu_stats,emu_state.frame); - - for(int i=0;iwaveform_fps_render[i]=stats->waveform_fps_render[i+1]; - if(stats->waveform_fps_render[i]>render_max)render_max=stats->waveform_fps_render[i]; - if(stats->waveform_fps_render[i]waveform_fps_render[i]; - render_avg+=1.0/stats->waveform_fps_render[i]; + double curr_time = se_time(); + double fps_render = 1.0 / (curr_time - stats->last_render_time); + stats->last_render_time = curr_time; + float render_min = 1e9, render_max = 0, render_avg = 0; + float emulate_min = 1e9, emulate_max = 0, emulate_avg = 0; + int render_data_points = 0; + int emulate_data_points = 0; + + se_record_emulation_frame_stats(&gui_state.emu_stats, emu_state.frame); + + for(int i = 0; i < SE_STATS_GRAPH_DATA - 1; ++i) { + stats->waveform_fps_render[i] = stats->waveform_fps_render[i + 1]; + if(stats->waveform_fps_render[i] > render_max) render_max = stats->waveform_fps_render[i]; + if(stats->waveform_fps_render[i] < render_min) render_min = stats->waveform_fps_render[i]; + render_avg += 1.0 / stats->waveform_fps_render[i]; render_data_points++; - - if(stats->waveform_fps_emulation[i]>emulate_max)emulate_max=stats->waveform_fps_emulation[i]; - if(stats->waveform_fps_emulation[i]waveform_fps_emulation[i]; - if(fabs(stats->waveform_fps_emulation[i])>1.0){ - emulate_avg+=1.0/fabs(stats->waveform_fps_emulation[i]); + if(stats->waveform_fps_emulation[i] > emulate_max) emulate_max = stats->waveform_fps_emulation[i]; + if(stats->waveform_fps_emulation[i] < emulate_min) emulate_min = stats->waveform_fps_emulation[i]; + if(fabs(stats->waveform_fps_emulation[i]) > 1.0) { + emulate_avg += 1.0 / fabs(stats->waveform_fps_emulation[i]); ++emulate_data_points; } } - if(render_data_points<1)render_data_points=1; - if(emulate_data_points<1)emulate_data_points=1; - render_avg/=render_data_points; - render_avg=1.0/render_avg; - emulate_avg/=emulate_data_points; - emulate_avg=1.0/emulate_avg; - if(stats->waveform_fps_emulation[SE_STATS_GRAPH_DATA-1]<0)emulate_avg*=-1; + if(render_data_points < 1) render_data_points = 1; + if(emulate_data_points < 1) emulate_data_points = 1; + render_avg /= render_data_points; + render_avg = 1.0 / render_avg; + emulate_avg /= emulate_data_points; + emulate_avg = 1.0 / emulate_avg; + if(stats->waveform_fps_emulation[SE_STATS_GRAPH_DATA - 1] < 0) emulate_avg *= -1; - stats->waveform_fps_render[SE_STATS_GRAPH_DATA-1] = fps_render; + stats->waveform_fps_render[SE_STATS_GRAPH_DATA - 1] = fps_render; - for(int i=0;iwaveform_l[i]=l; - stats->waveform_r[i]=r; + for(int i = 0; i < SE_STATS_GRAPH_DATA; ++i) { + float l = emu_state.audio_ring_buff.data[(emu_state.audio_ring_buff.write_ptr - i * 2 - 2) % SB_AUDIO_RING_BUFFER_SIZE] / 32768.; + float r = emu_state.audio_ring_buff.data[(emu_state.audio_ring_buff.write_ptr - i * 2 - 1) % SB_AUDIO_RING_BUFFER_SIZE] / 32768.; + stats->waveform_l[i] = l; + stats->waveform_r[i] = r; } float content_width = igGetWindowContentRegionWidth(); se_text(ICON_FK_CLOCK_O " FPS"); igSeparator(); char label_tmp[128]; - snprintf(label_tmp,128,se_localize_and_cache("Display FPS: %2.1f\n"),render_avg); - igPlotLinesFloatPtr("",stats->waveform_fps_render,SE_STATS_GRAPH_DATA,0,label_tmp,0,render_max*1.3,(ImVec2){content_width,80},4); + snprintf(label_tmp, 128, se_localize_and_cache("Display FPS: %2.1f\n"), render_avg); + igPlotLinesFloatPtr("", stats->waveform_fps_render, SE_STATS_GRAPH_DATA, 0, label_tmp, 0, render_max * 1.3, (ImVec2){content_width, 80}, 4); + + snprintf(label_tmp, 128, se_localize_and_cache("Emulation FPS: %2.1f\n"), emulate_avg); + igPlotLinesFloatPtr("", stats->waveform_fps_emulation, SE_STATS_GRAPH_DATA, 0, label_tmp, emulate_min, emulate_max * 1.3, (ImVec2){content_width, 80}, 4); - snprintf(label_tmp,128,se_localize_and_cache("Emulation FPS: %2.1f\n"),emulate_avg); - igPlotLinesFloatPtr("",stats->waveform_fps_emulation,SE_STATS_GRAPH_DATA,0,label_tmp,emulate_min,emulate_max*1.3,(ImVec2){content_width,80},4); - se_text(ICON_FK_VOLUME_UP " Audio"); igSeparator(); - igPlotLinesFloatPtr("",stats->waveform_l,SE_STATS_GRAPH_DATA,0,se_localize_and_cache("Left Audio Channel"),-1,1,(ImVec2){content_width,80},4); - igPlotLinesFloatPtr("",stats->waveform_r,SE_STATS_GRAPH_DATA,0,se_localize_and_cache("Right Audio Channel"),-1,1,(ImVec2){content_width,80},4); - - const char* null_names[] = {NULL}; - const char ** channel_names = null_names; - if(emu_state.system == SYSTEM_GB){ - static const char* names[] ={"Channel 1 (Square)","Channel 2 (Square)","Channel 3 (Wave)","Channel 4 (Noise)",NULL}; - channel_names= names; - }else if(emu_state.system == SYSTEM_GBA){ - static const char* names[] ={"Channel 1 (Square)","Channel 2 (Square)","Channel 3 (Wave)","Channel 4 (Noise)", "Channel A (FIFO)", "Channel B (FIFO)",NULL}; - channel_names= names; - }else if(emu_state.system == SYSTEM_NDS){ - static const char* names[] ={ - "Channel 0","Channel 1","Channel 2","Channel 3", - "Channel 4","Channel 5","Channel 6","Channel 7", - "Channel 8","Channel 9","Channel A","Channel B", - "Channel C","Channel D","Channel E","Channel F", - NULL}; - channel_names= names; - } - for(int i=0;i<16;++i){ - if(!channel_names[i])break; + igPlotLinesFloatPtr("", stats->waveform_l, SE_STATS_GRAPH_DATA, 0, se_localize_and_cache("Left Audio Channel"), -1, 1, (ImVec2){content_width, 80}, 4); + igPlotLinesFloatPtr("", stats->waveform_r, SE_STATS_GRAPH_DATA, 0, se_localize_and_cache("Right Audio Channel"), -1, 1, (ImVec2){content_width, 80}, 4); + + const char *null_names[] = {NULL}; + const char **channel_names = null_names; + if(emu_state.system == SYSTEM_GB) { + static const char *names[] = {"Channel 1 (Square)", "Channel 2 (Square)", "Channel 3 (Wave)", "Channel 4 (Noise)", NULL}; + channel_names = names; + } else if(emu_state.system == SYSTEM_GBA) { + static const char *names[] = {"Channel 1 (Square)", "Channel 2 (Square)", "Channel 3 (Wave)", "Channel 4 (Noise)", "Channel A (FIFO)", "Channel B (FIFO)", NULL}; + channel_names = names; + } else if(emu_state.system == SYSTEM_NDS) { + static const char *names[] = { + "Channel 0", "Channel 1", "Channel 2", "Channel 3", + "Channel 4", "Channel 5", "Channel 6", "Channel 7", + "Channel 8", "Channel 9", "Channel A", "Channel B", + "Channel C", "Channel D", "Channel E", "Channel F", + NULL}; + channel_names = names; + } + for(int i = 0; i < 16; ++i) { + if(!channel_names[i]) break; se_text(channel_names[i]); - igSameLine(content_width*0.42,0); - igProgressBar(emu_state.audio_channel_output[i],(ImVec2){content_width*0.6,0},""); + igSameLine(content_width * 0.42, 0); + igProgressBar(emu_state.audio_channel_output[i], (ImVec2){content_width * 0.6, 0}, ""); } - float audio_buff_size = sb_ring_buffer_size(&emu_state.audio_ring_buff)/(float)SB_AUDIO_RING_BUFFER_SIZE; - snprintf(label_tmp,128,se_localize_and_cache("Audio Ring (Samples Available: %d)"),sb_ring_buffer_size(&emu_state.audio_ring_buff)); + float audio_buff_size = sb_ring_buffer_size(&emu_state.audio_ring_buff) / (float)SB_AUDIO_RING_BUFFER_SIZE; + snprintf(label_tmp, 128, se_localize_and_cache("Audio Ring (Samples Available: %d)"), sb_ring_buffer_size(&emu_state.audio_ring_buff)); se_text(label_tmp); - igProgressBar(audio_buff_size,(ImVec2){content_width,0},""); - snprintf(label_tmp,128,se_localize_and_cache("Audio Watchdog Triggered %d Times"),gui_state.audio_watchdog_triggered); + igProgressBar(audio_buff_size, (ImVec2){content_width, 0}, ""); + snprintf(label_tmp, 128, se_localize_and_cache("Audio Watchdog Triggered %d Times"), gui_state.audio_watchdog_triggered); se_text(label_tmp); se_text(ICON_FK_INFO_CIRCLE " Build Info"); @@ -1535,184 +1553,190 @@ void se_draw_emu_stats(){ se_text("Branch \"%s\" built on %s %s", GIT_BRANCH, __DATE__, __TIME__); se_text("Commit Hash:"); igPushItemWidth(-1); - igInputText("##COMMIT_HASH",GIT_COMMIT_HASH,sizeof(GIT_COMMIT_HASH),ImGuiInputTextFlags_ReadOnly,NULL,NULL); + igInputText("##COMMIT_HASH", GIT_COMMIT_HASH, sizeof(GIT_COMMIT_HASH), ImGuiInputTextFlags_ReadOnly, NULL, NULL); igPopItemWidth(); - } -void se_psg_debugger(){ +void se_psg_debugger() { // NOTE: GB and GBA framesequencer should each contain the same struct data - sb_frame_sequencer_t* seq = emu_state.system == SYSTEM_GB ? &core.gb.audio.sequencer : (sb_frame_sequencer_t*)&core.gba.audio.sequencer; + sb_frame_sequencer_t *seq = emu_state.system == SYSTEM_GB ? &core.gb.audio.sequencer : (sb_frame_sequencer_t *)&core.gba.audio.sequencer; - for(int i=0;i<4;++i){ - se_text("Channel %d",i+1); + for(int i = 0; i < 4; ++i) { + se_text("Channel %d", i + 1); igSeparator(); se_checkbox("Active", &seq->active[i]); se_checkbox("Powered", &seq->powered[i]); - se_text("Channel t: %f",seq->chan_t[i]); + se_text("Channel t: %f", seq->chan_t[i]); se_checkbox("Use Length", &seq->use_length[i]); - se_input_int32("Length", &seq->length[i],1,10,ImGuiInputTextFlags_None); - se_input_uint32("Volume", &seq->volume[i],1,10,ImGuiInputTextFlags_None); - se_input_uint32("Frequency", &seq->frequency[i],1,10,ImGuiInputTextFlags_None); - - if(i==0){ + se_input_int32("Length", &seq->length[i], 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Volume", &seq->volume[i], 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Frequency", &seq->frequency[i], 1, 10, ImGuiInputTextFlags_None); + + if(i == 0) { se_checkbox("Sweep Enable", &seq->sweep_enable); - se_input_int32("Sweep Dir.", &seq->sweep_direction,1,10,ImGuiInputTextFlags_None); - se_input_uint32("Sweep Timer", &seq->sweep_timer,1,10,ImGuiInputTextFlags_None); - se_input_uint32("Sweep Period", &seq->sweep_period,1,10,ImGuiInputTextFlags_None); - se_input_uint32("Sweep Shift", &seq->sweep_shift,1,10,ImGuiInputTextFlags_None); - } - se_input_int32("Env Dir.", &seq->env_direction[i],1,10,ImGuiInputTextFlags_None); - se_input_uint32("Env Period", &seq->env_period[i],1,10,ImGuiInputTextFlags_None); - se_input_uint32("Env Timer", &seq->env_period_timer[i],1,10,ImGuiInputTextFlags_None); + se_input_int32("Sweep Dir.", &seq->sweep_direction, 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Sweep Timer", &seq->sweep_timer, 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Sweep Period", &seq->sweep_period, 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Sweep Shift", &seq->sweep_shift, 1, 10, ImGuiInputTextFlags_None); + } + se_input_int32("Env Dir.", &seq->env_direction[i], 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Env Period", &seq->env_period[i], 1, 10, ImGuiInputTextFlags_None); + se_input_uint32("Env Timer", &seq->env_period_timer[i], 1, 10, ImGuiInputTextFlags_None); se_checkbox("Env Overflowed", &seq->env_overflow[i]); - if(i==3){ - se_text("LFSR Value: %04x",seq->lfsr4); + if(i == 3) { + se_text("LFSR Value: %04x", seq->lfsr4); } } } -void se_draw_arm_state(const char* label, arm7_t *arm, emu_byte_read_t read){ - const char* reg_names[]={"R0","R1","R2","R3","R4","R5","R6","R7","R8","R9 (SB)","R10 (SL)","R11 (FP)","R12 (IP)","R13 (SP)","R14 (LR)","R15 (" ICON_FK_BUG ")","CPSR","SPSR",NULL}; // NOLINT - if(se_button("Step Instruction",(ImVec2){0,0})){ - arm->step_instructions=1; - emu_state.run_mode= SB_MODE_RUN; +void se_draw_arm_state(const char *label, arm7_t *arm, emu_byte_read_t read) { + const char *reg_names[] = {"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9 (SB)", "R10 (SL)", "R11 (FP)", "R12 (IP)", "R13 (SP)", "R14 (LR)", "R15 (" ICON_FK_BUG ")", "CPSR", "SPSR", NULL}; // NOLINT + if(se_button("Step Instruction", (ImVec2){0, 0})) { + arm->step_instructions = 1; + emu_state.run_mode = SB_MODE_RUN; } - igSameLine(0,4); - if(se_button("Step Frame",(ImVec2){0,0})){ - emu_state.step_frames=1; - emu_state.run_mode=SB_MODE_STEP; + igSameLine(0, 4); + if(se_button("Step Frame", (ImVec2){0, 0})) { + emu_state.step_frames = 1; + emu_state.run_mode = SB_MODE_STEP; } - if(arm->log_cmp_file){ - igSameLine(0,0); - if(se_button("Disconnect Log",(ImVec2){0,0})){ + if(arm->log_cmp_file) { + igSameLine(0, 0); + if(se_button("Disconnect Log", (ImVec2){0, 0})) { fclose(arm->log_cmp_file); - arm->log_cmp_file=NULL; + arm->log_cmp_file = NULL; } } - int r = 0; + int r = 0; se_text(ICON_FK_SERVER " Registers"); igSeparator(); - int w= igGetWindowWidth(); - while(reg_names[r]){ - int value = arm7_reg_read(arm,r); - if(r%2){ + int w = igGetWindowWidth(); + while(reg_names[r]) { + int value = arm7_reg_read(arm, r); + if(r % 2) { igSetNextItemWidth(-50); - igSameLine(w*0.5,0); - }else igSetNextItemWidth((w-100)*0.5); + igSameLine(w * 0.5, 0); + } else + igSetNextItemWidth((w - 100) * 0.5); - if(se_input_int(reg_names[r],&value, 0,0,ImGuiInputTextFlags_CharsHexadecimal)){ - arm7_reg_write(arm,r,value); + if(se_input_int(reg_names[r], &value, 0, 0, ImGuiInputTextFlags_CharsHexadecimal)) { + arm7_reg_write(arm, r, value); } ++r; } - uint32_t cpsr = arm7_reg_read(arm,CPSR); - int flag_bits[]={ - 31,30,29,28, - 27,5,6,7, + uint32_t cpsr = arm7_reg_read(arm, CPSR); + int flag_bits[] = { + 31, + 30, + 29, + 28, + 27, + 5, + 6, + 7, }; - const char * flag_names[]={ - "N","Z","C","V","Q","T","F","I",NULL - }; - for(int i=0;idebug_branch_ring_offset;++i){ - uint32_t ind = (arm->debug_branch_ring_offset-i-1); - ind%=ARM_DEBUG_BRANCH_RING_SIZE; - se_text("%d",i+1); - igSameLine(60,0); - se_text("0x%08x",arm->debug_branch_ring[ind]); + igBeginChildStr(("##BranchLoc"), (ImVec2){0, 150}, true, ImGuiWindowFlags_None); + for(int i = 0; i < ARM_DEBUG_BRANCH_RING_SIZE && i < arm->debug_branch_ring_offset; ++i) { + uint32_t ind = (arm->debug_branch_ring_offset - i - 1); + ind %= ARM_DEBUG_BRANCH_RING_SIZE; + se_text("%d", i + 1); + igSameLine(60, 0); + se_text("0x%08x", arm->debug_branch_ring[ind]); } igEndChild(); - if(clear_step_data)arm->debug_branch_ring_offset=0; + if(clear_step_data) arm->debug_branch_ring_offset = 0; se_text("SWI"); igSeparator(); - igBeginChildStr(("##SWI"),(ImVec2){0,150},true,ImGuiWindowFlags_None); - for(int i=0;idebug_swi_ring_offset;++i){ - uint32_t ind = (arm->debug_swi_ring_offset-i-1); - ind%=ARM_DEBUG_SWI_RING_SIZE; - se_text("%d",i+1); - igSameLine(60,0); - if(arm->debug_swi_ring_times[ind]>=2)se_text("SWI 0x%02x (%dx)",arm->debug_swi_ring[ind],arm->debug_swi_ring_times[ind]); - else se_text("SWI 0x%02x",arm->debug_swi_ring[ind]); + igBeginChildStr(("##SWI"), (ImVec2){0, 150}, true, ImGuiWindowFlags_None); + for(int i = 0; i < ARM_DEBUG_SWI_RING_SIZE && i < arm->debug_swi_ring_offset; ++i) { + uint32_t ind = (arm->debug_swi_ring_offset - i - 1); + ind %= ARM_DEBUG_SWI_RING_SIZE; + se_text("%d", i + 1); + igSameLine(60, 0); + if(arm->debug_swi_ring_times[ind] >= 2) + se_text("SWI 0x%02x (%dx)", arm->debug_swi_ring[ind], arm->debug_swi_ring_times[ind]); + else + se_text("SWI 0x%02x", arm->debug_swi_ring[ind]); } igEndChild(); - if(clear_step_data)arm->debug_swi_ring_offset=0; - + if(clear_step_data) arm->debug_swi_ring_offset = 0; } -void gb_cpu_debugger(){ - sb_gb_t* gb = &core.gb; +void gb_cpu_debugger() { + sb_gb_t *gb = &core.gb; sb_gb_cpu_t *cpu_state = &gb->cpu; - if(se_button("Step Instruction",(ImVec2){0,0})){ - emu_state.step_instructions=1; - emu_state.run_mode= SB_MODE_STEP; + if(se_button("Step Instruction", (ImVec2){0, 0})) { + emu_state.step_instructions = 1; + emu_state.run_mode = SB_MODE_STEP; } - igSameLine(0,4); - if(se_button("Step Frame",(ImVec2){0,0})){ - emu_state.step_frames=1; - emu_state.run_mode=SB_MODE_STEP; + igSameLine(0, 4); + if(se_button("Step Frame", (ImVec2){0, 0})) { + emu_state.step_frames = 1; + emu_state.run_mode = SB_MODE_STEP; } - const char *register_names_16b[] = {"AF", "BC", "DE", "HL", "SP", "PC", NULL}; @@ -1723,13 +1747,17 @@ void gb_cpu_debugger(){ "E", "H", "L", NULL}; int register_values_8b[] = { - SB_U16_HI(cpu_state->af), SB_U16_LO(cpu_state->af), - SB_U16_HI(cpu_state->bc), SB_U16_LO(cpu_state->bc), - SB_U16_HI(cpu_state->de), SB_U16_LO(cpu_state->de), - SB_U16_HI(cpu_state->hl), SB_U16_LO(cpu_state->hl), + SB_U16_HI(cpu_state->af), + SB_U16_LO(cpu_state->af), + SB_U16_HI(cpu_state->bc), + SB_U16_LO(cpu_state->bc), + SB_U16_HI(cpu_state->de), + SB_U16_LO(cpu_state->de), + SB_U16_HI(cpu_state->hl), + SB_U16_LO(cpu_state->hl), }; - const char *flag_names[] = {"Z", "N", "H", "C","Inter. En.", "Prefix", "Wait Inter", NULL}; + const char *flag_names[] = {"Z", "N", "H", "C", "Inter. En.", "Prefix", "Wait Inter", NULL}; bool flag_values[] = { SB_BFE(cpu_state->af, SB_Z_BIT, 1), // Z @@ -1738,321 +1766,330 @@ void gb_cpu_debugger(){ SB_BFE(cpu_state->af, SB_C_BIT, 1), // C cpu_state->interrupt_enable, cpu_state->prefix_op, - cpu_state->wait_for_interrupt - }; - int w= igGetWindowWidth(); - int r = 0; + cpu_state->wait_for_interrupt}; + int w = igGetWindowWidth(); + int r = 0; se_text(ICON_FK_SERVER " 16b Registers"); igSeparator(); - while(register_names_16b[r]){ + while(register_names_16b[r]) { int value = register_values_16b[r]; - if(r%2){ + if(r % 2) { igSetNextItemWidth(-50); - igSameLine(w*0.5,0); - }else igSetNextItemWidth((w-100)*0.5); - se_input_int(register_names_16b[r],&value, 0,0,ImGuiInputTextFlags_CharsHexadecimal); + igSameLine(w * 0.5, 0); + } else + igSetNextItemWidth((w - 100) * 0.5); + se_input_int(register_names_16b[r], &value, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); ++r; } - r = 0; + r = 0; se_text(ICON_FK_SERVER " 8b Registers"); igSeparator(); - while(register_names_8b[r]){ + while(register_names_8b[r]) { int value = register_values_8b[r]; - if(r%2){ + if(r % 2) { igSetNextItemWidth(-50); - igSameLine(w*0.5,0); - }else igSetNextItemWidth((w-100)*0.5); - se_input_int(register_names_8b[r],&value, 0,0,ImGuiInputTextFlags_CharsHexadecimal); + igSameLine(w * 0.5, 0); + } else + igSetNextItemWidth((w - 100) * 0.5); + se_input_int(register_names_8b[r], &value, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); ++r; } - r = 0; + r = 0; se_text(ICON_FK_SERVER " Flag Registers"); igSeparator(); - while(flag_names[r]){ + while(flag_names[r]) { bool value = flag_values[r]; - if(r%2){ + if(r % 2) { igSetNextItemWidth(-50); - igSameLine(w*0.5,0); - }else igSetNextItemWidth((w-100)*0.5); - se_checkbox(flag_names[r],&value); + igSameLine(w * 0.5, 0); + } else + igSetNextItemWidth((w - 100) * 0.5); + se_checkbox(flag_names[r], &value); ++r; } se_text(ICON_FK_SERVER " Instructions"); igSeparator(); - - for (int i = -6; i < 5; ++i) { - char instr_str[80]; - int pc_render = i + cpu_state->pc; - int opcode = sb_read8(gb, pc_render); - if(pc_render==cpu_state->pc){ - igPushStyleColorVec4(ImGuiCol_Text, (ImVec4){1.f, 0.f, 0.f, 1.f}); - se_text("PC " ICON_FK_ARROW_RIGHT); - igSameLine(40,0); - snprintf(instr_str,80,"0x%04x:", pc_render); - instr_str[79]=0; - se_text(instr_str); - igSameLine(130,0); - se_text(sb_decode_table[opcode].opcode_name); - igPopStyleColor(1); - }else{ - snprintf(instr_str,80,"0x%04x:", (int)pc_render); - instr_str[79]=0; - se_text(""); - igSameLine(40,0); - se_text(instr_str); - igSameLine(130,0); - se_text(sb_decode_table[opcode].opcode_name); - } - } + + for(int i = -6; i < 5; ++i) { + char instr_str[80]; + int pc_render = i + cpu_state->pc; + int opcode = sb_read8(gb, pc_render); + if(pc_render == cpu_state->pc) { + igPushStyleColorVec4(ImGuiCol_Text, (ImVec4){1.f, 0.f, 0.f, 1.f}); + se_text("PC " ICON_FK_ARROW_RIGHT); + igSameLine(40, 0); + snprintf(instr_str, 80, "0x%04x:", pc_render); + instr_str[79] = 0; + se_text(instr_str); + igSameLine(130, 0); + se_text(sb_decode_table[opcode].opcode_name); + igPopStyleColor(1); + } else { + snprintf(instr_str, 80, "0x%04x:", (int)pc_render); + instr_str[79] = 0; + se_text(""); + igSameLine(40, 0); + se_text(instr_str); + igSameLine(130, 0); + se_text(sb_decode_table[opcode].opcode_name); + } + } } -void se_draw_mem_debug_state(const char* label, gui_state_t* gui, emu_byte_read_t read,emu_byte_write_t write){ +void se_draw_mem_debug_state(const char *label, gui_state_t *gui, emu_byte_read_t read, emu_byte_write_t write) { se_text(ICON_FK_EXCHANGE " Read/Write Memory Address"); igSeparator(); - se_input_int("address",&gui->mem_view_address, 1,5,ImGuiInputTextFlags_CharsHexadecimal); + se_input_int("address", &gui->mem_view_address, 1, 5, ImGuiInputTextFlags_CharsHexadecimal); igSeparator(); - int v = se_read32(read,gui->mem_view_address); - if(se_input_int("data (32 bit)",&v, 1,5,ImGuiInputTextFlags_CharsHexadecimal)){ - se_write32(write,gui->mem_view_address,v); + int v = se_read32(read, gui->mem_view_address); + if(se_input_int("data (32 bit)", &v, 1, 5, ImGuiInputTextFlags_CharsHexadecimal)) { + se_write32(write, gui->mem_view_address, v); } - v = se_read16(read,gui->mem_view_address); - if(se_input_int("data (16 bit)",&v, 1,5,ImGuiInputTextFlags_CharsHexadecimal)){ - se_write16(write,gui->mem_view_address,v); + v = se_read16(read, gui->mem_view_address); + if(se_input_int("data (16 bit)", &v, 1, 5, ImGuiInputTextFlags_CharsHexadecimal)) { + se_write16(write, gui->mem_view_address, v); } v = (*read)(gui->mem_view_address); - if(se_input_int("data (8 bit)",&v, 1,5,ImGuiInputTextFlags_CharsHexadecimal)){ - (*write)(gui->mem_view_address,v); + if(se_input_int("data (8 bit)", &v, 1, 5, ImGuiInputTextFlags_CharsHexadecimal)) { + (*write)(gui->mem_view_address, v); } - v = se_read32(read,gui->mem_view_address); - if(se_input_int("data (signed 32b)",&v, 1,5,ImGuiInputTextFlags_None)){ - se_write32(write,gui->mem_view_address,v); + v = se_read32(read, gui->mem_view_address); + if(se_input_int("data (signed 32b)", &v, 1, 5, ImGuiInputTextFlags_None)) { + se_write32(write, gui->mem_view_address, v); } - v = se_read16(read,gui->mem_view_address); - if(se_input_int("data (signed 16b)",&v, 1,5,ImGuiInputTextFlags_None)){ - se_write16(write,gui->mem_view_address,v); + v = se_read16(read, gui->mem_view_address); + if(se_input_int("data (signed 16b)", &v, 1, 5, ImGuiInputTextFlags_None)) { + se_write16(write, gui->mem_view_address, v); } v = (*read)(gui->mem_view_address); - if(se_input_int("data (signed 8b)",&v, 1,5,ImGuiInputTextFlags_None)){ - (*write)(gui->mem_view_address,v); + if(se_input_int("data (signed 8b)", &v, 1, 5, ImGuiInputTextFlags_None)) { + (*write)(gui->mem_view_address, v); } se_text(ICON_FK_FILE_O " Dump Memory to File"); igSeparator(); - se_input_int("Start Address",&gui->mem_dump_start_address, 1,5,ImGuiInputTextFlags_CharsHexadecimal); - se_input_int("Size",&gui->mem_dump_size, 1,5,ImGuiInputTextFlags_None); - if(se_button("Save Memory Dump",(ImVec2){0,0})){ - uint8_t *data = (uint8_t*)malloc(gui->mem_dump_size); - for(int i=0;imem_dump_size;++i)data[i]=(*read)(gui->mem_dump_start_address+i); - const char *base, *file_name,*ext; - sb_breakup_path(emu_state.save_file_path,&base,&file_name,&ext); + se_input_int("Start Address", &gui->mem_dump_start_address, 1, 5, ImGuiInputTextFlags_CharsHexadecimal); + se_input_int("Size", &gui->mem_dump_size, 1, 5, ImGuiInputTextFlags_None); + if(se_button("Save Memory Dump", (ImVec2){0, 0})) { + uint8_t *data = (uint8_t *)malloc(gui->mem_dump_size); + for(int i = 0; i < gui->mem_dump_size; ++i) + data[i] = (*read)(gui->mem_dump_start_address + i); + const char *base, *file_name, *ext; + sb_breakup_path(emu_state.save_file_path, &base, &file_name, &ext); char new_path[SB_FILE_PATH_SIZE]; - snprintf(new_path,SB_FILE_PATH_SIZE,"%s/%s-memdump.bin",base,file_name); - sb_save_file_data(new_path,data,gui->mem_dump_size); + snprintf(new_path, SB_FILE_PATH_SIZE, "%s/%s-memdump.bin", base, file_name); + sb_save_file_data(new_path, data, gui->mem_dump_size); free(data); } - } -void gb_tile_map_debugger(){ - sb_gb_t *gb = &core.gb; - static uint8_t tmp_image[512*512*3]; +void gb_tile_map_debugger() { + sb_gb_t *gb = &core.gb; + static uint8_t tmp_image[512 * 512 * 3]; uint8_t ctrl = sb_read8_direct(gb, SB_IO_LCD_CTRL); - int bg_tile_map_base = SB_BFE(ctrl,3,1)==1 ? 0x9c00 : 0x9800; - int bg_win_tile_data_mode = SB_BFE(ctrl,4,1)==1; - int win_tile_map_base = SB_BFE(ctrl,6,1)==1 ? 0x9c00 : 0x9800; + int bg_tile_map_base = SB_BFE(ctrl, 3, 1) == 1 ? 0x9c00 : 0x9800; + int bg_win_tile_data_mode = SB_BFE(ctrl, 4, 1) == 1; + int win_tile_map_base = SB_BFE(ctrl, 6, 1) == 1 ? 0x9c00 : 0x9800; ImVec2 win; igGetWindowPos(&win); // Draw Tilemaps - for(int tile_map = 0;tile_map<2;++tile_map){ - int image_height = 32*(8+2); - int image_width = 32*(8+2); - float scale = igGetWindowContentRegionWidth()/image_width; + for(int tile_map = 0; tile_map < 2; ++tile_map) { + int image_height = 32 * (8 + 2); + int image_width = 32 * (8 + 2); + float scale = igGetWindowContentRegionWidth() / image_width; - int wx = sb_read8_direct(gb, SB_IO_LCD_WX)-7; + int wx = sb_read8_direct(gb, SB_IO_LCD_WX) - 7; int wy = sb_read8_direct(gb, SB_IO_LCD_WY); int sx = sb_read8_direct(gb, SB_IO_LCD_SX); int sy = sb_read8_direct(gb, SB_IO_LCD_SY); - int box_x1 = tile_map ==0 ? sx : wx; - int box_x2 = box_x1+(SB_LCD_W-1); - int box_y1 = tile_map ==0 ? sy : wy; - int box_y2 = box_y1+(SB_LCD_H-1); - int tile_map_base = tile_map==0? bg_tile_map_base:win_tile_map_base; - se_text("%s Tile Map",tile_map == 0 ? "Background" : "Window"); + int box_x1 = tile_map == 0 ? sx : wx; + int box_x2 = box_x1 + (SB_LCD_W - 1); + int box_y1 = tile_map == 0 ? sy : wy; + int box_y2 = box_y1 + (SB_LCD_H - 1); + int tile_map_base = tile_map == 0 ? bg_tile_map_base : win_tile_map_base; + se_text("%s Tile Map", tile_map == 0 ? "Background" : "Window"); igSeparator(); - int x = igGetCursorPosX()+win.x-igGetScrollX(); - int y = igGetCursorPosY()+win.y-igGetScrollY(); - int w = image_width*scale; - int h = image_height*scale; - int scanline = tile_map==0 ? gb->lcd.curr_scanline +sy : gb->lcd.curr_window_scanline; - for(int yt = 0; yt<32;++yt) - for(int xt = 0; xt<32;++xt) - for(int py = 0;py<8;++py) - for(int px = 0;px<8;++px){ - int x = xt*8+px; - int y = yt*8+py; - int color_id = sb_lookup_tile(gb,x,y,tile_map_base,bg_win_tile_data_mode); - int p = (xt*10+(px)+1)+(yt*10+py+1)*image_width; - int r=0,g=0,b=0; - sb_lookup_palette_color(gb,color_id,&r,&g,&b); - if(((x==(box_x1%256)||x==(box_x2%256)) && (((y-box_y1)&0xff)>=0 && ((box_y2-y)&0xff) <=box_y2-box_y1))|| - ((y==(box_y1%256)||y==(box_y2%256)) && (((x-box_x1)&0xff)>=0 && ((box_x2-x)&0xff) <=box_x2-box_x1))){ - r=255; g=b=0; + int x = igGetCursorPosX() + win.x - igGetScrollX(); + int y = igGetCursorPosY() + win.y - igGetScrollY(); + int w = image_width * scale; + int h = image_height * scale; + int scanline = tile_map == 0 ? gb->lcd.curr_scanline + sy : gb->lcd.curr_window_scanline; + for(int yt = 0; yt < 32; ++yt) + for(int xt = 0; xt < 32; ++xt) + for(int py = 0; py < 8; ++py) + for(int px = 0; px < 8; ++px) { + int x = xt * 8 + px; + int y = yt * 8 + py; + int color_id = sb_lookup_tile(gb, x, y, tile_map_base, bg_win_tile_data_mode); + int p = (xt * 10 + (px) + 1) + (yt * 10 + py + 1) * image_width; + int r = 0, g = 0, b = 0; + sb_lookup_palette_color(gb, color_id, &r, &g, &b); + if(((x == (box_x1 % 256) || x == (box_x2 % 256)) && (((y - box_y1) & 0xff) >= 0 && ((box_y2 - y) & 0xff) <= box_y2 - box_y1)) || + ((y == (box_y1 % 256) || y == (box_y2 % 256)) && (((x - box_x1) & 0xff) >= 0 && ((box_x2 - x) & 0xff) <= box_x2 - box_x1))) { + r = 255; + g = b = 0; } - if(y == (scanline&0xff) &&(((x-box_x1)&0xff)>=0 && (((x-box_x1)&0xff)>=0 && ((box_x2-x)&0xff) <=box_x2-box_x1))){ - b = 255; r=g=0; + if(y == (scanline & 0xff) && (((x - box_x1) & 0xff) >= 0 && (((x - box_x1) & 0xff) >= 0 && ((box_x2 - x) & 0xff) <= box_x2 - box_x1))) { + b = 255; + r = g = 0; } - tmp_image[p*3+0]=r; - tmp_image[p*3+1]=g; - tmp_image[p*3+2]=b; + tmp_image[p * 3 + 0] = r; + tmp_image[p * 3 + 1] = g; + tmp_image[p * 3 + 2] = b; } - se_draw_image(tmp_image,image_width,image_height, x*se_dpi_scale(), y*se_dpi_scale(), w*se_dpi_scale(),h*se_dpi_scale(), false); - igDummy((ImVec2){w,h}); - - const char * name = tile_map == 0 ? "Background" : "Window"; - ImVec2 mouse_pos = {gui_state.mouse_pos[0]/se_dpi_scale(),gui_state.mouse_pos[1]/se_dpi_scale()}; - mouse_pos.x-=x; - mouse_pos.y-=y; - if(mouse_pos.x=0 && mouse_pos.y>=0){ - int tx = (mouse_pos.x -1)/w*32; - int ty = (mouse_pos.y -1)/h*32; - int t = tx+ty*32; - int tile_data0 = sb_read_vram(gb, tile_map_base+t,0); - int tile_data1 = sb_read_vram(gb, tile_map_base+t,1); - se_text("Tile (%d, %d) Index=0x%02x Attr=0x%02x)",tx,ty,tile_data0,tile_data1); - }else se_text("No tile hovered"); - } -} -void gb_tile_data_debugger(){ - sb_gb_t *gb= &core.gb; - static uint8_t tmp_image[512*512*3]; - ImVec2 win; + se_draw_image(tmp_image, image_width, image_height, x * se_dpi_scale(), y * se_dpi_scale(), w * se_dpi_scale(), h * se_dpi_scale(), false); + igDummy((ImVec2){w, h}); + + const char *name = tile_map == 0 ? "Background" : "Window"; + ImVec2 mouse_pos = {gui_state.mouse_pos[0] / se_dpi_scale(), gui_state.mouse_pos[1] / se_dpi_scale()}; + mouse_pos.x -= x; + mouse_pos.y -= y; + if(mouse_pos.x < w && mouse_pos.y < h && + mouse_pos.x >= 0 && mouse_pos.y >= 0) { + int tx = (mouse_pos.x - 1) / w * 32; + int ty = (mouse_pos.y - 1) / h * 32; + int t = tx + ty * 32; + int tile_data0 = sb_read_vram(gb, tile_map_base + t, 0); + int tile_data1 = sb_read_vram(gb, tile_map_base + t, 1); + se_text("Tile (%d, %d) Index=0x%02x Attr=0x%02x)", tx, ty, tile_data0, tile_data1); + } else + se_text("No tile hovered"); + } +} +void gb_tile_data_debugger() { + sb_gb_t *gb = &core.gb; + static uint8_t tmp_image[512 * 512 * 3]; + ImVec2 win; igGetWindowPos(&win); uint8_t ctrl = sb_read8_direct(gb, SB_IO_LCD_CTRL); - int bg_tile_map_base = SB_BFE(ctrl,3,1)==1 ? 0x9c00 : 0x9800; - int bg_win_tile_data_mode = SB_BFE(ctrl,4,1)==1; - int win_tile_map_base = SB_BFE(ctrl,6,1)==1 ? 0x9c00 : 0x9800; + int bg_tile_map_base = SB_BFE(ctrl, 3, 1) == 1 ? 0x9c00 : 0x9800; + int bg_win_tile_data_mode = SB_BFE(ctrl, 4, 1) == 1; + int win_tile_map_base = SB_BFE(ctrl, 6, 1) == 1 ? 0x9c00 : 0x9800; // Draw tile data arrays - for(int tile_data_bank = 0;tile_data_bank=0 && mouse_pos.y>=0){ - int px = (mouse_pos.x -1)/w*image_width; - int py = (mouse_pos.y -1)/h*image_height; + if(mouse_pos.x < w && mouse_pos.y < h && + mouse_pos.x >= 0 && mouse_pos.y >= 0) { + int px = (mouse_pos.x - 1) / w * image_width; + int py = (mouse_pos.y - 1) / h * image_height; - int tx = px/8; - int ty = py/8; - px%=8; - py%=8; - int t = tx+ty*32; - int d = tile_data_base+py*2+ t*16; - uint8_t data1 = sb_read_vram(gb,d,tile_data_bank); - uint8_t data2 = sb_read_vram(gb,d+1,tile_data_bank); - uint8_t value = SB_BFE(data1,px,1)+SB_BFE(data2,px,1)*2; - se_text("Tile 0x%02x tx:%d ty:%d color:%d",t&0xff,px,py,value); - }else se_text("No tile hovered"); + int tx = px / 8; + int ty = py / 8; + px %= 8; + py %= 8; + int t = tx + ty * 32; + int d = tile_data_base + py * 2 + t * 16; + uint8_t data1 = sb_read_vram(gb, d, tile_data_bank); + uint8_t data2 = sb_read_vram(gb, d + 1, tile_data_bank); + uint8_t value = SB_BFE(data1, px, 1) + SB_BFE(data2, px, 1) * 2; + se_text("Tile 0x%02x tx:%d ty:%d color:%d", t & 0xff, px, py, value); + } else + se_text("No tile hovered"); } } -void se_draw_io_state(const char * label, mmio_reg_t* mmios, int mmios_size, emu_byte_read_t read, emu_byte_write_t write, emu_mmio_access_type access_type){ - for(int i = 0; i1)se_text("%s (Bits [%d:%d])",mmios[i].bits[f].name,start, start+size-1); - else se_text("%s (Bit %d)",mmios[i].bits[f].name,start); + igSameLine(0, 2); + if(size > 1) + se_text("%s (Bits [%d:%d])", mmios[i].bits[f].name, start, start + size - 1); + else + se_text("%s (Bit %d)", mmios[i].bits[f].name, start); } igPopID(); } - if(!has_fields){ - int v = data; + if(!has_fields) { + int v = data; igPushIDInt(0); igPushItemWidth(150); - if(se_input_int("",&v, 1,5,ImGuiInputTextFlags_CharsHexadecimal)){ - se_write32(write,addr,v); + if(se_input_int("", &v, 1, 5, ImGuiInputTextFlags_CharsHexadecimal)) { + se_write32(write, addr, v); } - igSameLine(0,2); + igSameLine(0, 2); se_text("Data"); igPopID(); } igSeparator(); - if(se_checkbox("CPU breakpoint on access",&access.trigger_breakpoint)){ - access_type(addr,access.trigger_breakpoint); + if(se_checkbox("CPU breakpoint on access", &access.trigger_breakpoint)) { + access_type(addr, access.trigger_breakpoint); } igTreePop(); } @@ -2064,870 +2101,892 @@ void se_draw_io_state(const char * label, mmio_reg_t* mmios, int mmios_size, emu ///////////////////////////////// // Used for file loading dialogs -static const char* valid_rom_file_types[] = { "*.gb", "*.gba","*.gbc" ,"*.nds","*.zip",NULL}; -void se_load_rom_from_emu_state(sb_emu_state_t*emu){ - if(!emu->rom_data)return; - printf("Loading: %s\n",emu_state.rom_path); - emu_state.rom_loaded = false; - if(gba_load_rom(emu, &core.gba, &scratch.gba)){ +static const char *valid_rom_file_types[] = {"*.gb", "*.gba", "*.gbc", "*.nds", "*.zip", NULL}; +void se_load_rom_from_emu_state(sb_emu_state_t *emu) { + if(!emu->rom_data) return; + printf("Loading: %s\n", emu_state.rom_path); + emu_state.rom_loaded = false; + if(gba_load_rom(emu, &core.gba, &scratch.gba)) { emu->system = SYSTEM_GBA; emu->rom_loaded = true; - }else if(sb_load_rom(emu,&core.gb,&scratch.gb)){ + } else if(sb_load_rom(emu, &core.gb, &scratch.gb)) { emu->system = SYSTEM_GB; - emu->rom_loaded = true; - }else if(nds_load_rom(emu,&core.nds,&scratch.nds)){ + emu->rom_loaded = true; + } else if(nds_load_rom(emu, &core.nds, &scratch.nds)) { emu->system = SYSTEM_NDS; - emu->rom_loaded = true; + emu->rom_loaded = true; } } -void se_load_rom(const char *filename){ +void se_load_rom(const char *filename) { se_reset_rewind_buffer(&rewind_buffer); se_reset_save_states(); se_reset_cheats(); se_reset_bios_info(); - emu_state.force_dmg_mode=gui_state.settings.force_dmg_mode; - //Compute Save File Path + emu_state.force_dmg_mode = gui_state.settings.force_dmg_mode; + // Compute Save File Path { - char *save_file=emu_state.save_file_path; + char *save_file = emu_state.save_file_path; save_file[0] = '\0'; - const char* base, *c, *ext; - sb_breakup_path(filename,&base, &c, &ext); - #if defined(EMSCRIPTEN) - if(sb_path_has_file_ext(filename,".sav")||sb_path_has_file_ext(filename,".code")){ - if(strncmp(filename,gui_state.recently_loaded_games[0].path,SB_FILE_PATH_SIZE)!=0){ - return se_load_rom(gui_state.recently_loaded_games[0].path); - } - return; + const char *base, *c, *ext; + sb_breakup_path(filename, &base, &c, &ext); +#if defined(EMSCRIPTEN) + if(sb_path_has_file_ext(filename, ".sav") || sb_path_has_file_ext(filename, ".code")) { + if(strncmp(filename, gui_state.recently_loaded_games[0].path, SB_FILE_PATH_SIZE) != 0) { + return se_load_rom(gui_state.recently_loaded_games[0].path); } - snprintf(emu_state.save_data_base_path, SB_FILE_PATH_SIZE,"/offline/%s", c); - #else - se_join_path(emu_state.save_data_base_path, SB_FILE_PATH_SIZE, base, c, NULL); - #endif - snprintf(save_file, SB_FILE_PATH_SIZE, "%s.sav",emu_state.save_data_base_path); - if(!sb_file_exists(save_file)){ - const char* base, *c, *ext; - sb_breakup_path(filename,&base, &c, &ext); + return; + } + snprintf(emu_state.save_data_base_path, SB_FILE_PATH_SIZE, "/offline/%s", c); +#else + se_join_path(emu_state.save_data_base_path, SB_FILE_PATH_SIZE, base, c, NULL); +#endif + snprintf(save_file, SB_FILE_PATH_SIZE, "%s.sav", emu_state.save_data_base_path); + if(!sb_file_exists(save_file)) { + const char *base, *c, *ext; + sb_breakup_path(filename, &base, &c, &ext); char tmp_path[SB_FILE_PATH_SIZE]; - se_join_path(tmp_path,SB_FILE_PATH_SIZE,gui_state.paths.save,c,".sav"); + se_join_path(tmp_path, SB_FILE_PATH_SIZE, gui_state.paths.save, c, ".sav"); - if(sb_file_exists(tmp_path)||gui_state.settings.save_to_path){ - se_join_path(emu_state.save_data_base_path,SB_FILE_PATH_SIZE,gui_state.paths.save,c,NULL); - strncpy(save_file,tmp_path,SB_FILE_PATH_SIZE); + if(sb_file_exists(tmp_path) || gui_state.settings.save_to_path) { + se_join_path(emu_state.save_data_base_path, SB_FILE_PATH_SIZE, gui_state.paths.save, c, NULL); + strncpy(save_file, tmp_path, SB_FILE_PATH_SIZE); } } } - //Compute Cheat Code File Path + // Compute Cheat Code File Path { - char *cheat_path=gui_state.cheat_path; + char *cheat_path = gui_state.cheat_path; cheat_path[0] = '\0'; - const char* base, *c, *ext; - sb_breakup_path(filename,&base, &c, &ext); - snprintf(cheat_path, SB_FILE_PATH_SIZE, "%s.code",emu_state.save_data_base_path); - if(!sb_file_exists(cheat_path)){ - const char* base, *c, *ext; - sb_breakup_path(filename,&base, &c, &ext); + const char *base, *c, *ext; + sb_breakup_path(filename, &base, &c, &ext); + snprintf(cheat_path, SB_FILE_PATH_SIZE, "%s.code", emu_state.save_data_base_path); + if(!sb_file_exists(cheat_path)) { + const char *base, *c, *ext; + sb_breakup_path(filename, &base, &c, &ext); char tmp_path[SB_FILE_PATH_SIZE]; - se_join_path(tmp_path,SB_FILE_PATH_SIZE,gui_state.paths.cheat_codes,c,".code"); - if(sb_file_exists(tmp_path)||gui_state.settings.save_to_path){ - strncpy(cheat_path,tmp_path,SB_FILE_PATH_SIZE); + se_join_path(tmp_path, SB_FILE_PATH_SIZE, gui_state.paths.cheat_codes, c, ".code"); + if(sb_file_exists(tmp_path) || gui_state.settings.save_to_path) { + strncpy(cheat_path, tmp_path, SB_FILE_PATH_SIZE); } } se_load_cheats(cheat_path); } strncpy(emu_state.rom_path, filename, sizeof(emu_state.rom_path)); - if(emu_state.rom_loaded){ - if(emu_state.system==SYSTEM_NDS)nds_unload(&core.nds, &scratch.nds); - else if(emu_state.system==SYSTEM_GBA)gba_unload(&core.gba,&scratch.gba); + if(emu_state.rom_loaded) { + if(emu_state.system == SYSTEM_NDS) + nds_unload(&core.nds, &scratch.nds); + else if(emu_state.system == SYSTEM_GBA) + gba_unload(&core.gba, &scratch.gba); } - if(emu_state.rom_data){ + if(emu_state.rom_data) { free(emu_state.rom_data); emu_state.rom_data = NULL; - emu_state.rom_size = 0; - emu_state.rom_loaded=false; + emu_state.rom_size = 0; + emu_state.rom_loaded = false; } - memset(&core,0,sizeof(core)); - printf("Loading ROM: %s\n", filename); + memset(&core, 0, sizeof(core)); + printf("Loading ROM: %s\n", filename); - if(sb_path_has_file_ext(filename,".zip")){ - printf("Loading Zip:%s \n",filename); + if(sb_path_has_file_ext(filename, ".zip")) { + printf("Loading Zip:%s \n", filename); mz_zip_archive zip = {0}; mz_zip_zero_struct(&zip); - if(mz_zip_reader_init_file(&zip, filename, 0)){ + if(mz_zip_reader_init_file(&zip, filename, 0)) { size_t total_files = mz_zip_reader_get_num_files(&zip); - for(size_t i=0;igb); - if(emu_state.system==SYSTEM_GBA)return gba_save_best_effort_state(&state->gba); - if(emu_state.system==SYSTEM_NDS)return nds_save_best_effort_state(&state->nds); - return -1; -} -static bool se_load_best_effort_state(se_core_state_t* state,uint8_t *save_state_data, uint32_t size, uint32_t bess_offset){ - if(emu_state.system==SYSTEM_GB)return sb_load_best_effort_state(&state->gb,save_state_data,size,bess_offset); - if(emu_state.system==SYSTEM_GBA)return gba_load_best_effort_state(&state->gba,save_state_data,size,bess_offset); - if(emu_state.system==SYSTEM_NDS)return nds_load_best_effort_state(&state->nds,save_state_data,size,bess_offset); +static bool se_sync_save_to_disk() { return se_write_save_to_disk(emu_state.save_file_path); } +// Returns offset into savestate where bess info can be found +static uint32_t se_save_best_effort_state(se_core_state_t *state) { + if(emu_state.system == SYSTEM_GB) return sb_save_best_effort_state(&state->gb); + if(emu_state.system == SYSTEM_GBA) return gba_save_best_effort_state(&state->gba); + if(emu_state.system == SYSTEM_NDS) return nds_save_best_effort_state(&state->nds); + return -1; +} +static bool se_load_best_effort_state(se_core_state_t *state, uint8_t *save_state_data, uint32_t size, uint32_t bess_offset) { + if(emu_state.system == SYSTEM_GB) return sb_load_best_effort_state(&state->gb, save_state_data, size, bess_offset); + if(emu_state.system == SYSTEM_GBA) return gba_load_best_effort_state(&state->gba, save_state_data, size, bess_offset); + if(emu_state.system == SYSTEM_NDS) return nds_load_best_effort_state(&state->nds, save_state_data, size, bess_offset); return false; } -static double se_get_sim_fps(){ - double sim_fps=1.0; - if(emu_state.system==SYSTEM_GB)sim_fps = 59.727; - else if(emu_state.system == SYSTEM_GBA) sim_fps = 59.727; - else if(emu_state.system == SYSTEM_NDS) sim_fps = 59.8261; +static double se_get_sim_fps() { + double sim_fps = 1.0; + if(emu_state.system == SYSTEM_GB) + sim_fps = 59.727; + else if(emu_state.system == SYSTEM_GBA) + sim_fps = 59.727; + else if(emu_state.system == SYSTEM_NDS) + sim_fps = 59.8261; return sim_fps; } -static size_t se_get_core_size(){ - if(emu_state.system==SYSTEM_GB)return sizeof(core.gb); - else if(emu_state.system == SYSTEM_GBA) return sizeof(core.gba); - else if(emu_state.system == SYSTEM_NDS) return sizeof(core.nds); - return 0; +static size_t se_get_core_size() { + if(emu_state.system == SYSTEM_GB) + return sizeof(core.gb); + else if(emu_state.system == SYSTEM_GBA) + return sizeof(core.gba); + else if(emu_state.system == SYSTEM_NDS) + return sizeof(core.nds); + return 0; } -typedef struct{ +typedef struct { float red_color[3]; float green_color[3]; float blue_color[3]; - float gamma; - bool is_grayscale; -}se_lcd_info_t; -se_lcd_info_t se_get_lcd_info(){ - if(emu_state.system==SYSTEM_GB){ - if(core.gb.model==SB_GBC){ + float gamma; + bool is_grayscale; +} se_lcd_info_t; +se_lcd_info_t se_get_lcd_info() { + if(emu_state.system == SYSTEM_GB) { + if(core.gb.model == SB_GBC) { return (se_lcd_info_t){ - .red_color ={26./32,0./32.,6./32.}, - .green_color={4./32,24/32.,4./32.}, - .blue_color ={2./32,8./32,22./32}, - .gamma = 2.2, + .red_color = {26. / 32, 0. / 32., 6. / 32.}, + .green_color = { 4. / 32, 24 / 32., 4. / 32.}, + .blue_color = { 2. / 32, 8. / 32, 22. / 32}, + .gamma = 2.2, }; - }else{ + } else { return (se_lcd_info_t){ - .red_color ={1,0,0}, - .green_color={0,1,0}, - .blue_color ={0,0,1}, - .gamma = 2.2, - .is_grayscale = true + .red_color = {1, 0, 0}, + .green_color = {0, 1, 0}, + .blue_color = {0, 0, 1}, + .gamma = 2.2, + .is_grayscale = true }; } - }else if(emu_state.system == SYSTEM_GBA){ - if(gui_state.settings.gba_color_correction_mode==GBA_HIGAN_CORRECTION){ + } else if(emu_state.system == SYSTEM_GBA) { + if(gui_state.settings.gba_color_correction_mode == GBA_HIGAN_CORRECTION) { return (se_lcd_info_t){ - .red_color ={1,0.039,0.196}, - .green_color={0.196 ,0.901,0.039}, - .blue_color ={0,0.117,0.862}, - .gamma = 4.0 + .red_color = { 1, 0.039, 0.196}, + .green_color = {0.196, 0.901, 0.039}, + .blue_color = { 0, 0.117, 0.862}, + .gamma = 4.0 }; } return (se_lcd_info_t){ - .red_color ={1,0.05,0.0}, - .green_color={0.05,1,0.05}, - .blue_color ={0,0.05,1.0}, - .gamma = 3.7 + .red_color = { 1, 0.05, 0.0}, + .green_color = {0.05, 1, 0.05}, + .blue_color = { 0, 0.05, 1.0}, + .gamma = 3.7 }; } return (se_lcd_info_t){ - .red_color ={1,0,0}, - .green_color={0,1,0}, - .blue_color ={0,0,1}, - .gamma = 2.2 + .red_color = {1, 0, 0}, + .green_color = {0, 1, 0}, + .blue_color = {0, 0, 1}, + .gamma = 2.2 }; } -static void se_emulate_single_frame(){ - if(emu_state.system == SYSTEM_GB){ - if(gui_state.test_runner_mode){ - uint8_t palette[4*3] = { 0xff,0xff,0xff,0xAA,0xAA,0xAA,0x55,0x55,0x55,0x00,0x00,0x00 }; - for(int i=0;i<12;++i)core.gb.dmg_palette[i]=palette[i]; - }else{ - for(int i=0;i<4;++i){ +static void se_emulate_single_frame() { + if(emu_state.system == SYSTEM_GB) { + if(gui_state.test_runner_mode) { + uint8_t palette[4 * 3] = {0xff, 0xff, 0xff, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00}; + for(int i = 0; i < 12; ++i) + core.gb.dmg_palette[i] = palette[i]; + } else { + for(int i = 0; i < 4; ++i) { uint32_t v = gui_state.settings.gb_palette[i]; - core.gb.dmg_palette[i*3+0]=SB_BFE(v,0,8); - core.gb.dmg_palette[i*3+1]=SB_BFE(v,8,8); - core.gb.dmg_palette[i*3+2]=SB_BFE(v,16,8); + core.gb.dmg_palette[i * 3 + 0] = SB_BFE(v, 0, 8); + core.gb.dmg_palette[i * 3 + 1] = SB_BFE(v, 8, 8); + core.gb.dmg_palette[i * 3 + 2] = SB_BFE(v, 16, 8); } } - sb_tick(&emu_state,&core.gb, &scratch.gb); - } - else if(emu_state.system == SYSTEM_GBA)gba_tick(&emu_state, &core.gba, &scratch.gba); - else if(emu_state.system == SYSTEM_NDS)nds_tick(&emu_state, &core.nds, &scratch.nds); + sb_tick(&emu_state, &core.gb, &scratch.gb); + } else if(emu_state.system == SYSTEM_GBA) + gba_tick(&emu_state, &core.gba, &scratch.gba); + else if(emu_state.system == SYSTEM_NDS) + nds_tick(&emu_state, &core.nds, &scratch.nds); se_run_all_ar_cheats(); } -static void se_screenshot(uint8_t * output_buffer, int * out_width, int * out_height){ - *out_height=*out_width=0; +static void se_screenshot(uint8_t *output_buffer, int *out_width, int *out_height) { + *out_height = *out_width = 0; // output_bufer is always SE_MAX_SCREENSHOT_SIZE bytes. RGB8 - if(emu_state.system==SYSTEM_GBA){ + if(emu_state.system == SYSTEM_GBA) { *out_width = GBA_LCD_W; *out_height = GBA_LCD_H; - memcpy(output_buffer,scratch.gba.framebuffer,GBA_LCD_W*GBA_LCD_H*4); - }else if (emu_state.system==SYSTEM_NDS){ + memcpy(output_buffer, scratch.gba.framebuffer, GBA_LCD_W * GBA_LCD_H * 4); + } else if(emu_state.system == SYSTEM_NDS) { *out_width = NDS_LCD_W; - *out_height = NDS_LCD_H*2; - memcpy(output_buffer,scratch.nds.framebuffer_top,NDS_LCD_W*NDS_LCD_H*4); - memcpy(output_buffer+NDS_LCD_W*NDS_LCD_H*4,scratch.nds.framebuffer_bottom,NDS_LCD_W*NDS_LCD_H*4); - }else if (emu_state.system==SYSTEM_GB){ + *out_height = NDS_LCD_H * 2; + memcpy(output_buffer, scratch.nds.framebuffer_top, NDS_LCD_W * NDS_LCD_H * 4); + memcpy(output_buffer + NDS_LCD_W * NDS_LCD_H * 4, scratch.nds.framebuffer_bottom, NDS_LCD_W * NDS_LCD_H * 4); + } else if(emu_state.system == SYSTEM_GB) { *out_width = SB_LCD_W; *out_height = SB_LCD_H; - memcpy(output_buffer,scratch.gb.framebuffer,SB_LCD_W*SB_LCD_H*4); + memcpy(output_buffer, scratch.gb.framebuffer, SB_LCD_W * SB_LCD_H * 4); } - for(int i=3;iUserCallbackData==NULL)return; - se_draw_lcd_callback_t *call = (se_draw_lcd_callback_t*)cmd->UserCallbackData; - se_draw_lcd(call->data,call->im_width,call->im_height,call->x,call->y,call->render_width,call->render_height,call->rotation,call->is_touch); + int im_width; + int im_height; + int x; + int y; + int render_width; + int render_height; + float rotation; + bool is_touch; +} se_draw_lcd_callback_t; +void se_draw_lcd_callback(const ImDrawList *parent_list, const ImDrawCmd *cmd) { + if(cmd->UserCallbackData == NULL) return; + se_draw_lcd_callback_t *call = (se_draw_lcd_callback_t *)cmd->UserCallbackData; + se_draw_lcd(call->data, call->im_width, call->im_height, call->x, call->y, call->render_width, call->render_height, call->rotation, call->is_touch); free(call); } -void se_draw_lcd_defer(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, float rotation,bool is_touch){ - se_draw_lcd_callback_t *call = (se_draw_lcd_callback_t*)malloc(sizeof(se_draw_lcd_callback_t)); +void se_draw_lcd_defer(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, float rotation, bool is_touch) { + se_draw_lcd_callback_t *call = (se_draw_lcd_callback_t *)malloc(sizeof(se_draw_lcd_callback_t)); call->data = data; - call->im_width=im_width; - call->im_height=im_height; + call->im_width = im_width; + call->im_height = im_height; call->x = x; call->y = y; - call->render_width=render_width; - call->render_height=render_height; - call->rotation=rotation; - call->is_touch=is_touch; - ImDrawList_AddCallback(igGetWindowDrawList(),se_draw_lcd_callback,call); + call->render_width = render_width; + call->render_height = render_height; + call->rotation = rotation; + call->is_touch = is_touch; + ImDrawList_AddCallback(igGetWindowDrawList(), se_draw_lcd_callback, call); } -static void se_draw_emulated_system_screen(bool preview){ - int lcd_render_x = 0, lcd_render_y = 0; - int lcd_render_w = 0, lcd_render_h = 0; +static void se_draw_emulated_system_screen(bool preview) { + int lcd_render_x = 0, lcd_render_y = 0; + int lcd_render_w = 0, lcd_render_h = 0; float scr_w = igGetWindowWidth(); float scr_h = igGetWindowHeight(); - if(preview==true){ - scr_w *=se_dpi_scale(); - scr_h *=se_dpi_scale(); + if(preview == true) { + scr_w *= se_dpi_scale(); + scr_h *= se_dpi_scale(); } float native_w = SB_LCD_W; float native_h = SB_LCD_H; - bool hybrid_nds=false; - float lcd_aspect = SB_LCD_H/(float)SB_LCD_W; - bool touch_controller_active = gui_state.last_touch_time>=0||gui_state.settings.auto_hide_touch_controls==false; - if(emu_state.system==SYSTEM_GBA){native_w = GBA_LCD_W; native_h = GBA_LCD_H;} - else if(emu_state.system==SYSTEM_NDS){ - native_w = NDS_LCD_W; native_h = NDS_LCD_H*2; - if(scr_w/scr_h>1&&!touch_controller_active){ - native_w = NDS_LCD_W+NDS_LCD_W*0.5; + bool hybrid_nds = false; + float lcd_aspect = SB_LCD_H / (float)SB_LCD_W; + bool touch_controller_active = gui_state.last_touch_time >= 0 || gui_state.settings.auto_hide_touch_controls == false; + if(emu_state.system == SYSTEM_GBA) { + native_w = GBA_LCD_W; + native_h = GBA_LCD_H; + } else if(emu_state.system == SYSTEM_NDS) { + native_w = NDS_LCD_W; + native_h = NDS_LCD_H * 2; + if(scr_w / scr_h > 1 && !touch_controller_active) { + native_w = NDS_LCD_W + NDS_LCD_W * 0.5; native_h = NDS_LCD_H; - hybrid_nds=true; + hybrid_nds = true; } } - float rotation = gui_state.settings.screen_rotation*0.5*3.14159; + float rotation = gui_state.settings.screen_rotation * 0.5 * 3.14159; - lcd_aspect= native_h/native_w; + lcd_aspect = native_h / native_w; - float height = scr_h; float render_w = native_w; float render_h = native_h; - switch(gui_state.settings.screen_rotation){ - case 1: case 3: - render_w = native_h; - render_h = native_w; + switch(gui_state.settings.screen_rotation) { + case 1: + case 3: + render_w = native_h; + render_h = native_w; } - float render_aspect = render_h/render_w; + float render_aspect = render_h / render_w; - float render_scale =1; - if(scr_w*render_aspect>height){ - render_scale = height/render_h; - }else{ - render_scale = scr_w/render_w; + float render_scale = 1; + if(scr_w * render_aspect > height) { + render_scale = height / render_h; + } else { + render_scale = scr_w / render_w; } - lcd_render_w = native_w*render_scale; - lcd_render_h = native_h*render_scale; - render_w*=render_scale; - render_h*=render_scale; - - float dpi_scale = se_dpi_scale(); + lcd_render_w = native_w * render_scale; + lcd_render_h = native_h * render_scale; + render_w *= render_scale; + render_h *= render_scale; - //Don't hide menubar if it doesn't make the screen smaller - if(gui_state.screen_height/dpi_scale-SE_MENU_BAR_HEIGHT>gui_state.screen_width/dpi_scale*render_aspect&&!preview){ - gui_state.menubar_hide_timer=se_time(); - } + float dpi_scale = se_dpi_scale(); - int controller_h = fmin(scr_h,scr_w*0.8); - int controller_y_pad = 0; - if(touch_controller_active){ - if(emu_state.system==SYSTEM_NDS && (gui_state.settings.screen_rotation==0)){ - if(render_h/height<0.7){ - controller_h = height-render_h; - lcd_render_y = -(height-render_h)*0.5; - controller_y_pad=0.00; - }else if(lcd_render_w/scr_w>=1.0-0.5*gui_state.settings.touch_controls_scale){ - if(gui_state.settings.avoid_overlaping_touchscreen){ - controller_h = height*0.5; - controller_y_pad=height*0.5+(1.0-gui_state.settings.touch_controls_scale)*height*0.25; + // Don't hide menubar if it doesn't make the screen smaller + if(gui_state.screen_height / dpi_scale - SE_MENU_BAR_HEIGHT > gui_state.screen_width / dpi_scale * render_aspect && !preview) { + gui_state.menubar_hide_timer = se_time(); + } + + int controller_h = fmin(scr_h, scr_w * 0.8); + int controller_y_pad = 0; + if(touch_controller_active) { + if(emu_state.system == SYSTEM_NDS && (gui_state.settings.screen_rotation == 0)) { + if(render_h / height < 0.7) { + controller_h = height - render_h; + lcd_render_y = -(height - render_h) * 0.5; + controller_y_pad = 0.00; + } else if(lcd_render_w / scr_w >= 1.0 - 0.5 * gui_state.settings.touch_controls_scale) { + if(gui_state.settings.avoid_overlaping_touchscreen) { + controller_h = height * 0.5; + controller_y_pad = height * 0.5 + (1.0 - gui_state.settings.touch_controls_scale) * height * 0.25; } - }else{ - controller_h = height*(1.0-lcd_render_w/scr_w)*1.25; - //controller_y_pad=(height-controller_h)*0.5+(1.0-gui_state.settings.touch_controls_scale)*height*0.25; + } else { + controller_h = height * (1.0 - lcd_render_w / scr_w) * 1.25; + // controller_y_pad=(height-controller_h)*0.5+(1.0-gui_state.settings.touch_controls_scale)*height*0.25; } - }else{ - lcd_render_y = -(height-render_h)*0.9*0.5; - if(controller_h+render_h=0){ - if(scr_w*render_aspect= 0) { + if(scr_w * render_aspect < scr_h - (controller_h + controller_y_pad * 2)) { + lcd_render_h = scr_h - (controller_h + controller_y_pad * 2); + lcd_render_y = scr_h - (controller_h + controller_y_pad * 2 + lcd_render_h * 0.5) - scr_h * 0.5; } - }else{ + } else { lcd_render_h = scr_h; lcd_render_w = scr_w; } - if(gui_state.settings.screen_rotation==1 || gui_state.settings.screen_rotation==3){ + if(gui_state.settings.screen_rotation == 1 || gui_state.settings.screen_rotation == 3) { int t = lcd_render_w; - lcd_render_w = lcd_render_h; - lcd_render_h= t; + lcd_render_w = lcd_render_h; + lcd_render_h = t; } } - bool portrait = scr_wipc[cpu].write_ptr); se_text("Read Pointer: %d\n", nds->ipc[cpu].read_ptr); - se_text("Size: %d\n", (nds->ipc[cpu].write_ptr-nds->ipc[cpu].read_ptr)&0x1f); + se_text("Size: %d\n", (nds->ipc[cpu].write_ptr - nds->ipc[cpu].read_ptr) & 0x1f); se_text("Error: %d\n", nds->ipc[cpu].error); - } } -se_debug_tool_desc_t gba_debug_tools[]={ - {ICON_FK_TELEVISION, ICON_FK_TELEVISION " CPU", gba_cpu_debugger}, - {ICON_FK_SITEMAP, ICON_FK_SITEMAP " MMIO", gba_mmio_debugger}, - {ICON_FK_PENCIL_SQUARE_O, ICON_FK_PENCIL_SQUARE_O " Memory",gba_memory_debugger}, - {ICON_FK_VOLUME_UP, ICON_FK_VOLUME_UP " PSG",se_psg_debugger}, - {ICON_FK_AREA_CHART, ICON_FK_AREA_CHART " Emulator Stats",se_draw_emu_stats, .allow_hardcore=true}, - {NULL,NULL,NULL} +se_debug_tool_desc_t gba_debug_tools[] = { + {ICON_FK_TELEVISION, ICON_FK_TELEVISION " CPU", gba_cpu_debugger}, + {ICON_FK_SITEMAP, ICON_FK_SITEMAP " MMIO", gba_mmio_debugger}, + {ICON_FK_PENCIL_SQUARE_O, ICON_FK_PENCIL_SQUARE_O " Memory", gba_memory_debugger}, + {ICON_FK_VOLUME_UP, ICON_FK_VOLUME_UP " PSG", se_psg_debugger}, + {ICON_FK_AREA_CHART, ICON_FK_AREA_CHART " Emulator Stats", se_draw_emu_stats, .allow_hardcore = true}, + {NULL, NULL, NULL} }; -se_debug_tool_desc_t gb_debug_tools[]={ - {ICON_FK_TELEVISION, ICON_FK_TELEVISION " CPU", gb_cpu_debugger}, - {ICON_FK_SITEMAP, ICON_FK_SITEMAP " MMIO", gb_mmio_debugger}, - {ICON_FK_PENCIL_SQUARE_O, ICON_FK_PENCIL_SQUARE_O " Memory",gb_memory_debugger}, - {ICON_FK_VOLUME_UP, ICON_FK_VOLUME_UP " PSG",se_psg_debugger}, - {ICON_FK_DELICIOUS, ICON_FK_DELICIOUS " Tile Map",gb_tile_map_debugger}, - {ICON_FK_TH, ICON_FK_TH " Tile Data",gb_tile_data_debugger}, - {ICON_FK_AREA_CHART, ICON_FK_AREA_CHART " Emulator Stats",se_draw_emu_stats, .allow_hardcore=true}, - {NULL,NULL,NULL} +se_debug_tool_desc_t gb_debug_tools[] = { + {ICON_FK_TELEVISION, ICON_FK_TELEVISION " CPU", gb_cpu_debugger}, + {ICON_FK_SITEMAP, ICON_FK_SITEMAP " MMIO", gb_mmio_debugger}, + {ICON_FK_PENCIL_SQUARE_O, ICON_FK_PENCIL_SQUARE_O " Memory", gb_memory_debugger}, + {ICON_FK_VOLUME_UP, ICON_FK_VOLUME_UP " PSG", se_psg_debugger}, + {ICON_FK_DELICIOUS, ICON_FK_DELICIOUS " Tile Map", gb_tile_map_debugger}, + {ICON_FK_TH, ICON_FK_TH " Tile Data", gb_tile_data_debugger}, + {ICON_FK_AREA_CHART, ICON_FK_AREA_CHART " Emulator Stats", se_draw_emu_stats, .allow_hardcore = true}, + {NULL, NULL, NULL} }; -se_debug_tool_desc_t nds_debug_tools[]={ - {ICON_FK_TELEVISION " 7", ICON_FK_TELEVISION " ARM7 CPU", nds7_cpu_debugger}, - {ICON_FK_TELEVISION " 9", ICON_FK_TELEVISION " ARM9 CPU", nds9_cpu_debugger}, - {ICON_FK_SITEMAP " 7", ICON_FK_SITEMAP " ARM7 MMIO", nds7_mmio_debugger}, - {ICON_FK_SITEMAP " 9", ICON_FK_SITEMAP " ARM9 MMIO", nds9_mmio_debugger}, - {ICON_FK_PENCIL_SQUARE_O " 7", ICON_FK_PENCIL_SQUARE_O " ARM7 Memory",nds7_mem_debugger}, - {ICON_FK_PENCIL_SQUARE_O " 9", ICON_FK_PENCIL_SQUARE_O " ARM9 Memory",nds9_mem_debugger}, - {ICON_FK_INFO_CIRCLE, ICON_FK_INFO_CIRCLE " NDS IO",nds_io_debugger}, - - {ICON_FK_AREA_CHART, ICON_FK_AREA_CHART " Emulator Stats",se_draw_emu_stats, .allow_hardcore=true}, - {NULL,NULL,NULL} +se_debug_tool_desc_t nds_debug_tools[] = { + {ICON_FK_TELEVISION " 7", ICON_FK_TELEVISION " ARM7 CPU", nds7_cpu_debugger}, + {ICON_FK_TELEVISION " 9", ICON_FK_TELEVISION " ARM9 CPU", nds9_cpu_debugger}, + {ICON_FK_SITEMAP " 7", ICON_FK_SITEMAP " ARM7 MMIO", nds7_mmio_debugger}, + {ICON_FK_SITEMAP " 9", ICON_FK_SITEMAP " ARM9 MMIO", nds9_mmio_debugger}, + {ICON_FK_PENCIL_SQUARE_O " 7", ICON_FK_PENCIL_SQUARE_O " ARM7 Memory", nds7_mem_debugger}, + {ICON_FK_PENCIL_SQUARE_O " 9", ICON_FK_PENCIL_SQUARE_O " ARM9 Memory", nds9_mem_debugger}, + {ICON_FK_INFO_CIRCLE, ICON_FK_INFO_CIRCLE " NDS IO", nds_io_debugger}, + + {ICON_FK_AREA_CHART, ICON_FK_AREA_CHART " Emulator Stats", se_draw_emu_stats, .allow_hardcore = true}, + {NULL, NULL, NULL} }; -static se_debug_tool_desc_t* se_get_debug_description(){ +static se_debug_tool_desc_t *se_get_debug_description() { se_debug_tool_desc_t *desc = NULL; - if(emu_state.system ==SYSTEM_GBA)desc = gba_debug_tools; - if(emu_state.system ==SYSTEM_GB)desc = gb_debug_tools; - if(emu_state.system ==SYSTEM_NDS)desc = nds_debug_tools; - return desc; -} -emu_byte_read_t se_read_byte_func(int addr_map){ - if(emu_state.system ==SYSTEM_GBA)return gba_byte_read; - if(emu_state.system ==SYSTEM_GB)return gb_byte_read; - if(emu_state.system ==SYSTEM_NDS)return addr_map==7? nds7_byte_read:nds9_byte_read; + if(emu_state.system == SYSTEM_GBA) desc = gba_debug_tools; + if(emu_state.system == SYSTEM_GB) desc = gb_debug_tools; + if(emu_state.system == SYSTEM_NDS) desc = nds_debug_tools; + return desc; +} +emu_byte_read_t se_read_byte_func(int addr_map) { + if(emu_state.system == SYSTEM_GBA) return gba_byte_read; + if(emu_state.system == SYSTEM_GB) return gb_byte_read; + if(emu_state.system == SYSTEM_NDS) return addr_map == 7 ? nds7_byte_read : nds9_byte_read; return null_byte_read; } -emu_byte_write_t se_write_byte_func(int addr_map){ - if(emu_state.system ==SYSTEM_GBA)return gba_byte_write; - if(emu_state.system ==SYSTEM_GB)return gb_byte_write; - if(emu_state.system ==SYSTEM_NDS)return addr_map==7? nds7_byte_write:nds9_byte_write; +emu_byte_write_t se_write_byte_func(int addr_map) { + if(emu_state.system == SYSTEM_GBA) return gba_byte_write; + if(emu_state.system == SYSTEM_GB) return gb_byte_write; + if(emu_state.system == SYSTEM_NDS) return addr_map == 7 ? nds7_byte_write : nds9_byte_write; return null_byte_write; } /////////////////////////////// // END UPDATE FOR NEW SYSTEM // /////////////////////////////// -void se_capture_state(se_core_state_t* core, se_save_state_t * save_state){ - save_state->state = *core; +void se_capture_state(se_core_state_t *core, se_save_state_t *save_state) { + save_state->state = *core; save_state->valid = true; save_state->system = emu_state.system; se_screenshot(save_state->screenshot, &save_state->screenshot_width, &save_state->screenshot_height); } -void se_restore_state(se_core_state_t* core, se_save_state_t * save_state){ - if(!save_state->valid || save_state->system != emu_state.system||gui_state.settings.hardcore_mode)return; - *core=save_state->state; +void se_restore_state(se_core_state_t *core, se_save_state_t *save_state) { + if(!save_state->valid || save_state->system != emu_state.system || gui_state.settings.hardcore_mode) return; + *core = save_state->state; emu_state.render_frame = true; se_emulate_single_frame(); } -void se_reset_save_states(){ - for(int i=0;i=SE_NUM_CHEATS)break; - continue; - } - se_cheat_t * ch = cheats+cheat_index; - if(state==0 && (c=='1'||c=='0')) ch->state = c=='1'; - if(c=='"'){ - state++; - if(state==4){ - se_convert_cheat_code(cheat_buffer,cheat_index); + if(cheat_index >= SE_NUM_CHEATS) break; + continue; + } + se_cheat_t *ch = cheats + cheat_index; + if(state == 0 && (c == '1' || c == '0')) ch->state = c == '1'; + if(c == '"') { + state++; + if(state == 4) { + se_convert_cheat_code(cheat_buffer, cheat_index); memset(cheat_buffer, 0, sizeof(cheat_buffer)); } continue; } - if(state == 1){ - if(cheat_name_sizename[cheat_name_size++]=c; + if(state == 1) { + if(cheat_name_size < SE_MAX_CHEAT_NAME_SIZE) ch->name[cheat_name_size++] = c; } - if(state == 3){ - if(cheat_name_sizelabel){ + if(igBeginCombo("##debug combo", " " ICON_FK_BUG, ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_HeightLarge)) { + while(desc->label) { bool is_selected = desc->visible; // You can store your selection however you want, outside or inside your objects - if (igSelectableBool(se_localize_and_cache(desc->label), is_selected,ImGuiSelectableFlags_None,(ImVec2){0,30})){ - desc->visible=!desc->visible; + if(igSelectableBool(se_localize_and_cache(desc->label), is_selected, ImGuiSelectableFlags_None, (ImVec2){0, 30})) { + desc->visible = !desc->visible; } char tmp_str[256]; - snprintf(tmp_str,sizeof(tmp_str),"Show/Hide %s Panel\n",desc->label); + snprintf(tmp_str, sizeof(tmp_str), "Show/Hide %s Panel\n", desc->label); se_tooltip(tmp_str); desc++; } igEndCombo(); } - igSameLine(0,1); - }else{ - while(desc->label){ + igSameLine(0, 1); + } else { + while(desc->label) { igPushIDInt(id++); - if(desc->visible){ + if(desc->visible) { igPushStyleColorVec4(ImGuiCol_Button, style->Colors[ImGuiCol_ButtonActive]); - if(se_button_themed(SE_REGION_BLANK_ACTIVE,desc->short_label,(ImVec2){SE_MENU_BAR_BUTTON_WIDTH,SE_MENU_BAR_HEIGHT},true)){desc->visible=!desc->visible;} + if(se_button_themed(SE_REGION_BLANK_ACTIVE, desc->short_label, (ImVec2){SE_MENU_BAR_BUTTON_WIDTH, SE_MENU_BAR_HEIGHT}, true)) { desc->visible = !desc->visible; } igPopStyleColor(1); - }else{ - if(se_button_themed(SE_REGION_BLANK,desc->short_label,(ImVec2){SE_MENU_BAR_BUTTON_WIDTH,SE_MENU_BAR_HEIGHT},true)){desc->visible=!desc->visible;} + } else { + if(se_button_themed(SE_REGION_BLANK, desc->short_label, (ImVec2){SE_MENU_BAR_BUTTON_WIDTH, SE_MENU_BAR_HEIGHT}, true)) { desc->visible = !desc->visible; } } - igSameLine(0,1); + igSameLine(0, 1); char tmp_str[256]; - snprintf(tmp_str,sizeof(tmp_str),"Show/Hide %s Panel\n",desc->label); + snprintf(tmp_str, sizeof(tmp_str), "Show/Hide %s Panel\n", desc->label); se_tooltip(tmp_str); desc++; igPopID(); } } } -static float se_draw_debug_panels(float screen_x, float sidebar_w, float y, float height){ - se_debug_tool_desc_t* desc= se_get_debug_description(); - if(!desc)return screen_x; - while(desc->label){ - if(desc->visible){ - gui_state.menubar_hide_timer=se_time(); - int w = sidebar_w+screen_x-(int)screen_x; - igSetNextWindowPos((ImVec2){screen_x,y}, ImGuiCond_Always, (ImVec2){0,0}); +static float se_draw_debug_panels(float screen_x, float sidebar_w, float y, float height) { + se_debug_tool_desc_t *desc = se_get_debug_description(); + if(!desc) return screen_x; + while(desc->label) { + if(desc->visible) { + gui_state.menubar_hide_timer = se_time(); + int w = sidebar_w + screen_x - (int)screen_x; + igSetNextWindowPos((ImVec2){screen_x, y}, ImGuiCond_Always, (ImVec2){0, 0}); igSetNextWindowSize((ImVec2){w, height}, ImGuiCond_Always); - igBegin(se_localize_and_cache(desc->label),&desc->visible, ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize); - if(gui_state.settings.hardcore_mode && desc->allow_hardcore == false){ + igBegin(se_localize_and_cache(desc->label), &desc->visible, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize); + if(gui_state.settings.hardcore_mode && desc->allow_hardcore == false) { se_text("Disabled in Hardcore Mode"); - }else desc->function(); - - float bottom_padding =0; - #ifdef PLATFORM_IOS - se_ios_get_safe_ui_padding(NULL,&bottom_padding,NULL,NULL); - #endif - igDummy((ImVec2){0,bottom_padding}); + } else + desc->function(); + + float bottom_padding = 0; +#ifdef PLATFORM_IOS + se_ios_get_safe_ui_padding(NULL, &bottom_padding, NULL, NULL); +#endif + igDummy((ImVec2){0, bottom_padding}); igEnd(); - screen_x+=sidebar_w; + screen_x += sidebar_w; } desc++; } return screen_x; } -void se_set_default_keybind(gui_state_t *gui){ - for(int i=0;ikey.bound_id[i]=-1; - gui->key.bound_id[SE_KEY_A] = SAPP_KEYCODE_J; - gui->key.bound_id[SE_KEY_B] = SAPP_KEYCODE_K; - gui->key.bound_id[SE_KEY_X] = SAPP_KEYCODE_N; - gui->key.bound_id[SE_KEY_Y] = SAPP_KEYCODE_M; - gui->key.bound_id[SE_KEY_UP] = SAPP_KEYCODE_W; - gui->key.bound_id[SE_KEY_DOWN] = SAPP_KEYCODE_S; - gui->key.bound_id[SE_KEY_LEFT] = SAPP_KEYCODE_A; - gui->key.bound_id[SE_KEY_RIGHT] = SAPP_KEYCODE_D; - gui->key.bound_id[SE_KEY_L] = SAPP_KEYCODE_U; - gui->key.bound_id[SE_KEY_R] = SAPP_KEYCODE_I; - gui->key.bound_id[SE_KEY_START] = SAPP_KEYCODE_ENTER; - gui->key.bound_id[SE_KEY_SELECT] = SAPP_KEYCODE_APOSTROPHE; - gui->key.bound_id[SE_KEY_FOLD_SCREEN]= SAPP_KEYCODE_B; - gui->key.bound_id[SE_KEY_PEN_DOWN]= SAPP_KEYCODE_V; - gui->key.bound_id[SE_KEY_EMU_PAUSE]= SAPP_KEYCODE_V; - - gui->key.bound_id[SE_KEY_EMU_PAUSE]= SAPP_KEYCODE_SPACE; - gui->key.bound_id[SE_KEY_EMU_REWIND]= SAPP_KEYCODE_R; - gui->key.bound_id[SE_KEY_EMU_FF_2X]= SAPP_KEYCODE_F; - gui->key.bound_id[SE_KEY_EMU_FF_MAX]= SAPP_KEYCODE_TAB; - gui->key.bound_id[SE_KEY_SOLAR_M]= SAPP_KEYCODE_MINUS; - gui->key.bound_id[SE_KEY_SOLAR_P]= SAPP_KEYCODE_EQUAL; +void se_set_default_keybind(gui_state_t *gui) { + for(int i = 0; i < SE_NUM_KEYBINDS; ++i) + gui->key.bound_id[i] = -1; + gui->key.bound_id[SE_KEY_A] = SAPP_KEYCODE_J; + gui->key.bound_id[SE_KEY_B] = SAPP_KEYCODE_K; + gui->key.bound_id[SE_KEY_X] = SAPP_KEYCODE_N; + gui->key.bound_id[SE_KEY_Y] = SAPP_KEYCODE_M; + gui->key.bound_id[SE_KEY_UP] = SAPP_KEYCODE_W; + gui->key.bound_id[SE_KEY_DOWN] = SAPP_KEYCODE_S; + gui->key.bound_id[SE_KEY_LEFT] = SAPP_KEYCODE_A; + gui->key.bound_id[SE_KEY_RIGHT] = SAPP_KEYCODE_D; + gui->key.bound_id[SE_KEY_L] = SAPP_KEYCODE_U; + gui->key.bound_id[SE_KEY_R] = SAPP_KEYCODE_I; + gui->key.bound_id[SE_KEY_START] = SAPP_KEYCODE_ENTER; + gui->key.bound_id[SE_KEY_SELECT] = SAPP_KEYCODE_APOSTROPHE; + gui->key.bound_id[SE_KEY_FOLD_SCREEN] = SAPP_KEYCODE_B; + gui->key.bound_id[SE_KEY_PEN_DOWN] = SAPP_KEYCODE_V; + gui->key.bound_id[SE_KEY_EMU_PAUSE] = SAPP_KEYCODE_V; + + gui->key.bound_id[SE_KEY_EMU_PAUSE] = SAPP_KEYCODE_SPACE; + gui->key.bound_id[SE_KEY_EMU_REWIND] = SAPP_KEYCODE_R; + gui->key.bound_id[SE_KEY_EMU_FF_2X] = SAPP_KEYCODE_F; + gui->key.bound_id[SE_KEY_EMU_FF_MAX] = SAPP_KEYCODE_TAB; + gui->key.bound_id[SE_KEY_SOLAR_M] = SAPP_KEYCODE_MINUS; + gui->key.bound_id[SE_KEY_SOLAR_P] = SAPP_KEYCODE_EQUAL; gui->key.bound_id[SE_KEY_TOGGLE_FULLSCREEN] = SAPP_KEYCODE_F11; - for(int i=0;ikey.bound_id[SE_KEY_CAPTURE_STATE(i)]=SAPP_KEYCODE_1+i; - gui->key.bound_id[SE_KEY_RESTORE_STATE(i)]=SAPP_KEYCODE_F1+i; + for(int i = 0; i < SE_NUM_SAVE_STATES; ++i) { + gui->key.bound_id[SE_KEY_CAPTURE_STATE(i)] = SAPP_KEYCODE_1 + i; + gui->key.bound_id[SE_KEY_RESTORE_STATE(i)] = SAPP_KEYCODE_F1 + i; } - } -void sb_poll_controller_input(sb_joy_t* joy){ - for(int i=0;iinputs[i] += 0.5inputs[i] += 0.5 < gui_state.key.value[i]; } } -void se_reset_joy(sb_joy_t*joy){ - for(int i=0;iinputs[i]=0; +void se_reset_joy(sb_joy_t *joy) { + for(int i = 0; i < SE_NUM_KEYBINDS; ++i) { + joy->inputs[i] = 0; } } -void se_draw_image_opacity(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, bool has_alpha,float opacity){ +void se_draw_image_opacity(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, bool has_alpha, float opacity) { sg_image *image = se_get_image(); - if(!image||!data){return; } - if(im_width<=0)im_width=1; - if(im_height<=0)im_height=1; - sg_image_data im_data={0}; - uint8_t * rgba8_data = data; - if(has_alpha==false){ - rgba8_data= malloc(im_width*im_height*4); - for(int i=0;iid, - (ImVec2){x/dpi_scale,y/dpi_scale}, - (ImVec2){(x+render_width)/dpi_scale,(y+render_height)/dpi_scale}, - (ImVec2){0,0},(ImVec2){1,1}, - tint); - if(has_alpha==false)free(rgba8_data); + (ImTextureID)(uintptr_t)image->id, + (ImVec2){x / dpi_scale, y / dpi_scale}, + (ImVec2){(x + render_width) / dpi_scale, (y + render_height) / dpi_scale}, + (ImVec2){0, 0}, (ImVec2){1, 1}, + tint); + if(has_alpha == false) free(rgba8_data); } -void se_draw_lcd(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, float rotation,bool is_touch){ +void se_draw_lcd(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, float rotation, bool is_touch) { sg_image *image = se_get_image(); - if(!image||!data){return; } - if(im_width<=0)im_width=1; - if(im_height<=0)im_height=1; - sg_image_data im_data={0}; - uint8_t * rgba8_data = data; + if(!image || !data) { return; } + if(im_width <= 0) im_width = 1; + if(im_height <= 0) im_height = 1; + sg_image_data im_data = {0}; + uint8_t *rgba8_data = data; /* Delta compression codec static uint8_t last_value[1024*1024]; @@ -2947,109 +3006,107 @@ void se_draw_lcd(uint8_t *data, int im_width, int im_height,int x, int y, int re printf("Compressed Size:%d\n",packet_count*2); */ im_data.subimage[0][0].ptr = rgba8_data; - im_data.subimage[0][0].size = im_width*im_height*4; - sg_image_desc desc={ - .type= SG_IMAGETYPE_2D, - .render_target= false, - .width= im_width, - .height= im_height, - .num_slices= 1, - .num_mipmaps= 1, - .usage= SG_USAGE_IMMUTABLE, - .pixel_format= SG_PIXELFORMAT_RGBA8, - .sample_count= 1, - .min_filter= SG_FILTER_NEAREST, - .mag_filter= SG_FILTER_NEAREST, - .wrap_u= SG_WRAP_CLAMP_TO_EDGE, - .wrap_v= SG_WRAP_CLAMP_TO_EDGE, - .wrap_w= SG_WRAP_CLAMP_TO_EDGE, - .border_color= SG_BORDERCOLOR_OPAQUE_BLACK, - .max_anisotropy= 1, - .min_lod= 0.0f, - .max_lod= 1e9f, - .data= im_data, + im_data.subimage[0][0].size = im_width * im_height * 4; + sg_image_desc desc = { + .type = SG_IMAGETYPE_2D, + .render_target = false, + .width = im_width, + .height = im_height, + .num_slices = 1, + .num_mipmaps = 1, + .usage = SG_USAGE_IMMUTABLE, + .pixel_format = SG_PIXELFORMAT_RGBA8, + .sample_count = 1, + .min_filter = SG_FILTER_NEAREST, + .mag_filter = SG_FILTER_NEAREST, + .wrap_u = SG_WRAP_CLAMP_TO_EDGE, + .wrap_v = SG_WRAP_CLAMP_TO_EDGE, + .wrap_w = SG_WRAP_CLAMP_TO_EDGE, + .border_color = SG_BORDERCOLOR_OPAQUE_BLACK, + .max_anisotropy = 1, + .min_lod = 0.0f, + .max_lod = 1e9f, + .data = im_data, }; - *image = sg_make_image(&desc); + *image = sg_make_image(&desc); float dpi_scale = se_dpi_scale(); - ImGuiIO* io = igGetIO(); + ImGuiIO *io = igGetIO(); - const int fb_width = (int) (io->DisplaySize.x * dpi_scale); - const int fb_height = (int) (io->DisplaySize.y * dpi_scale); + const int fb_width = (int)(io->DisplaySize.x * dpi_scale); + const int fb_height = (int)(io->DisplaySize.y * dpi_scale); sg_apply_pipeline(gui_state.lcd_pipeline); - se_lcd_info_t lcd_info=se_get_lcd_info(); - lcd_params_t lcd_params={ - .display_size[0] = fb_width, - .display_size[1] = fb_height, - .render_off[0] = x, - .render_off[1] = y, - .render_size[0]= render_width, - .render_size[1]= render_height, - .emu_lcd_size[0]= im_width, - .emu_lcd_size[1]= im_height, - .display_mode = gui_state.test_runner_mode?0:gui_state.settings.screen_shader, - .render_scale_x[0] = cos(rotation), - .render_scale_x[1] = sin(rotation), - .render_scale_y[0] = -sin(rotation), - .render_scale_y[1] = cos(rotation), - .lcd_is_grayscale = lcd_info.is_grayscale, - .input_gamma = lcd_info.gamma, - .red_color = {lcd_info.red_color[0],lcd_info.red_color[1],lcd_info.red_color[2]}, - .green_color = {lcd_info.green_color[0],lcd_info.green_color[1],lcd_info.green_color[2]}, - .blue_color = {lcd_info.blue_color[0],lcd_info.blue_color[1],lcd_info.blue_color[2]}, - .color_correction_strength=gui_state.test_runner_mode?0:gui_state.settings.color_correction + se_lcd_info_t lcd_info = se_get_lcd_info(); + lcd_params_t lcd_params = { + .display_size[0] = fb_width, + .display_size[1] = fb_height, + .render_off[0] = x, + .render_off[1] = y, + .render_size[0] = render_width, + .render_size[1] = render_height, + .emu_lcd_size[0] = im_width, + .emu_lcd_size[1] = im_height, + .display_mode = gui_state.test_runner_mode ? 0 : gui_state.settings.screen_shader, + .render_scale_x[0] = cos(rotation), + .render_scale_x[1] = sin(rotation), + .render_scale_y[0] = -sin(rotation), + .render_scale_y[1] = cos(rotation), + .lcd_is_grayscale = lcd_info.is_grayscale, + .input_gamma = lcd_info.gamma, + .red_color = { lcd_info.red_color[0], lcd_info.red_color[1], lcd_info.red_color[2]}, + .green_color = {lcd_info.green_color[0], lcd_info.green_color[1], lcd_info.green_color[2]}, + .blue_color = { lcd_info.blue_color[0], lcd_info.blue_color[1], lcd_info.blue_color[2]}, + .color_correction_strength = gui_state.test_runner_mode ? 0 : gui_state.settings.color_correction }; - if(is_touch){ + if(is_touch) { float tx = gui_state.mouse_pos[0]; float ty = gui_state.mouse_pos[1]; - tx-=x; - ty-=y; + tx -= x; + ty -= y; - float rx=cos(-rotation)*tx-sin(-rotation)*ty; - float ry=sin(-rotation)*tx+cos(-rotation)*ty; + float rx = cos(-rotation) * tx - sin(-rotation) * ty; + float ry = sin(-rotation) * tx + cos(-rotation) * ty; - rx/=render_width; - ry/=render_height; - rx+=0.5; - ry+=0.5; + rx /= render_width; + ry /= render_height; + rx += 0.5; + ry += 0.5; - emu_state.joy.touch_pos[0]=rx; - emu_state.joy.touch_pos[1]=ry; - if(gui_state.mouse_button[0]&&rx>=0&&rx<=1.0&&ry>=0.&&ry<=1.0)emu_state.joy.inputs[SE_KEY_PEN_DOWN]=true; + emu_state.joy.touch_pos[0] = rx; + emu_state.joy.touch_pos[1] = ry; + if(gui_state.mouse_button[0] && rx >= 0 && rx <= 1.0 && ry >= 0. && ry <= 1.0) emu_state.joy.inputs[SE_KEY_PEN_DOWN] = true; - for(int i=0;i=0&&rx<=1.0&&ry>=0.&&ry<=1.0){ - emu_state.joy.touch_pos[0]=rx; - emu_state.joy.touch_pos[1]=ry; - emu_state.joy.inputs[SE_KEY_PEN_DOWN]=true; + if(rx >= 0 && rx <= 1.0 && ry >= 0. && ry <= 1.0) { + emu_state.joy.touch_pos[0] = rx; + emu_state.joy.touch_pos[1] = ry; + emu_state.joy.inputs[SE_KEY_PEN_DOWN] = true; break; } } - } - sg_bindings bind={ - .vertex_buffers[0] = gui_state.quad_vb, - .fs_images[0] = *image - }; + sg_bindings bind = { + .vertex_buffers[0] = gui_state.quad_vb, + .fs_images[0] = *image}; sg_apply_bindings(&bind); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(lcd_params)); sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(lcd_params)); @@ -3057,1014 +3114,1024 @@ void se_draw_lcd(uint8_t *data, int im_width, int im_height,int x, int y, int re sg_draw(0, verts, 1); } -void se_draw_image(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, bool has_alpha){ - se_draw_image_opacity(data,im_width,im_height,x,y,render_width,render_height,has_alpha,1.0); +void se_draw_image(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, bool has_alpha) { + se_draw_image_opacity(data, im_width, im_height, x, y, render_width, render_height, has_alpha, 1.0); } -bool se_draw_image_button(uint8_t *data, int im_width, int im_height,int x, int y, int render_width, int render_height, bool has_alpha){ +bool se_draw_image_button(uint8_t *data, int im_width, int im_height, int x, int y, int render_width, int render_height, bool has_alpha) { float dpi_scale = se_dpi_scale(); igPushStyleColorVec4(ImGuiCol_Button, (ImVec4){0.f, 0.f, 0.f, 0.f}); igPushStyleColorVec4(ImGuiCol_ButtonActive, (ImVec4){0.f, 0.f, 0.f, 0.0f}); igPushStyleColorVec4(ImGuiCol_ButtonHovered, (ImVec4){0.f, 0.f, 0.f, 0.0f}); - igSetCursorScreenPos((ImVec2){x/dpi_scale,y/dpi_scale}); + igSetCursorScreenPos((ImVec2){x / dpi_scale, y / dpi_scale}); bool clicked = igButtonEx("", - (ImVec2){(render_width)/dpi_scale,(render_height)/dpi_scale}, - ImGuiButtonFlags_None); + (ImVec2){(render_width) / dpi_scale, (render_height) / dpi_scale}, + ImGuiButtonFlags_None); - float opacity = 1.0; - if(igIsItemActive())opacity=0.6; - else if(igIsItemHovered(ImGuiHoveredFlags_None))opacity=0.8; - se_draw_image_opacity(data,im_width,im_height,x,y,render_width,render_height,has_alpha,opacity); + float opacity = 1.0; + if(igIsItemActive()) + opacity = 0.6; + else if(igIsItemHovered(ImGuiHoveredFlags_None)) + opacity = 0.8; + se_draw_image_opacity(data, im_width, im_height, x, y, render_width, render_height, has_alpha, opacity); igPopStyleColor(3); - return clicked; + return clicked; } -float sb_distance(float * a, float* b, int dims){ +float sb_distance(float *a, float *b, int dims) { float v = 0; - for(int i=0;ibound_id[i]=-1; - state->value[i]=0; +void se_initialize_keybind(se_keybind_state_t *state) { + for(int i = 0; i < SE_NUM_BINDS_ALLOC; ++i) { + state->bound_id[i] = -1; + state->value[i] = 0; } - state->rebind_start_time= - SE_REBIND_TIMER_LENGTH; - state->bind_being_set=-1; - state->last_bind_activitiy=-1; - + state->rebind_start_time = -SE_REBIND_TIMER_LENGTH; + state->bind_being_set = -1; + state->last_bind_activitiy = -1; } #ifdef PLATFORM_ANDROID -const char* se_android_key_to_name(int key){ - switch(key){ - case AKEYCODE_UNKNOWN: return "UNKNOWN"; - case AKEYCODE_SOFT_LEFT: return "SOFT_LEFT"; - case AKEYCODE_SOFT_RIGHT: return "SOFT_RIGHT"; - case AKEYCODE_HOME: return "HOME"; - case AKEYCODE_BACK: return "BACK"; - case AKEYCODE_CALL: return "CALL"; - case AKEYCODE_ENDCALL: return "ENDCALL"; - case AKEYCODE_0: return "0"; - case AKEYCODE_1: return "1"; - case AKEYCODE_2: return "2"; - case AKEYCODE_3: return "3"; - case AKEYCODE_4: return "4"; - case AKEYCODE_5: return "5"; - case AKEYCODE_6: return "6"; - case AKEYCODE_7: return "7"; - case AKEYCODE_8: return "8"; - case AKEYCODE_9: return "9"; - case AKEYCODE_STAR: return "STAR"; - case AKEYCODE_POUND: return "POUND"; - case AKEYCODE_DPAD_UP: return "DPAD_UP"; - case AKEYCODE_DPAD_DOWN: return "DPAD_DOWN"; - case AKEYCODE_DPAD_LEFT: return "DPAD_LEFT"; - case AKEYCODE_DPAD_RIGHT: return "DPAD_RIGHT"; - case AKEYCODE_DPAD_CENTER: return "DPAD_CENTER"; - case AKEYCODE_VOLUME_UP: return "VOLUME_UP"; - case AKEYCODE_VOLUME_DOWN: return "VOLUME_DOWN"; - case AKEYCODE_POWER: return "POWER"; - case AKEYCODE_CAMERA: return "CAMERA"; - case AKEYCODE_CLEAR: return "CLEAR"; - case AKEYCODE_A: return "A"; - case AKEYCODE_B: return "B"; - case AKEYCODE_C: return "C"; - case AKEYCODE_D: return "D"; - case AKEYCODE_E: return "E"; - case AKEYCODE_F: return "F"; - case AKEYCODE_G: return "G"; - case AKEYCODE_H: return "H"; - case AKEYCODE_I: return "I"; - case AKEYCODE_J: return "J"; - case AKEYCODE_K: return "K"; - case AKEYCODE_L: return "L"; - case AKEYCODE_M: return "M"; - case AKEYCODE_N: return "N"; - case AKEYCODE_O: return "O"; - case AKEYCODE_P: return "P"; - case AKEYCODE_Q: return "Q"; - case AKEYCODE_R: return "R"; - case AKEYCODE_S: return "S"; - case AKEYCODE_T: return "T"; - case AKEYCODE_U: return "U"; - case AKEYCODE_V: return "V"; - case AKEYCODE_W: return "W"; - case AKEYCODE_X: return "X"; - case AKEYCODE_Y: return "Y"; - case AKEYCODE_Z: return "Z"; - case AKEYCODE_COMMA: return "COMMA"; - case AKEYCODE_PERIOD: return "PERIOD"; - case AKEYCODE_ALT_LEFT: return "ALT_LEFT"; - case AKEYCODE_ALT_RIGHT: return "ALT_RIGHT"; - case AKEYCODE_SHIFT_LEFT: return "SHIFT_LEFT"; - case AKEYCODE_SHIFT_RIGHT: return "SHIFT_RIGHT"; - case AKEYCODE_TAB: return "TAB"; - case AKEYCODE_SPACE: return "SPACE"; - case AKEYCODE_SYM: return "SYM"; - case AKEYCODE_EXPLORER: return "EXPLORER"; - case AKEYCODE_ENVELOPE: return "ENVELOPE"; - case AKEYCODE_ENTER: return "ENTER"; - case AKEYCODE_DEL: return "DEL"; - case AKEYCODE_GRAVE: return "GRAVE"; - case AKEYCODE_MINUS: return "MINUS"; - case AKEYCODE_EQUALS: return "EQUALS"; - case AKEYCODE_LEFT_BRACKET: return "LEFT_BRACKET"; - case AKEYCODE_RIGHT_BRACKET: return "RIGHT_BRACKET"; - case AKEYCODE_BACKSLASH: return "BACKSLASH"; - case AKEYCODE_SEMICOLON: return "SEMICOLON"; - case AKEYCODE_APOSTROPHE: return "APOSTROPHE"; - case AKEYCODE_SLASH: return "SLASH"; - case AKEYCODE_AT: return "AT"; - case AKEYCODE_NUM: return "NUM"; - case AKEYCODE_HEADSETHOOK: return "HEADSETHOOK"; - case AKEYCODE_FOCUS: return "FOCUS"; - case AKEYCODE_PLUS: return "PLUS"; - case AKEYCODE_MENU: return "MENU"; - case AKEYCODE_NOTIFICATION: return "NOTIFICATION"; - case AKEYCODE_SEARCH: return "SEARCH"; - case AKEYCODE_MEDIA_PLAY_PAUSE: return "MEDIA_PLAY_PAUSE"; - case AKEYCODE_MEDIA_STOP: return "MEDIA_STOP"; - case AKEYCODE_MEDIA_NEXT: return "MEDIA_NEXT"; - case AKEYCODE_MEDIA_PREVIOUS: return "MEDIA_PREVIOUS"; - case AKEYCODE_MEDIA_REWIND: return "MEDIA_REWIND"; - case AKEYCODE_MEDIA_FAST_FORWARD: return "MEDIA_FAST_FORWARD"; - case AKEYCODE_MUTE: return "MUTE"; - case AKEYCODE_PAGE_UP: return "PAGE_UP"; - case AKEYCODE_PAGE_DOWN: return "PAGE_DOWN"; - case AKEYCODE_PICTSYMBOLS: return "PICTSYMBOLS"; - case AKEYCODE_SWITCH_CHARSET: return "SWITCH_CHARSET"; - case AKEYCODE_BUTTON_A: return "BUTTON_A"; - case AKEYCODE_BUTTON_B: return "BUTTON_B"; - case AKEYCODE_BUTTON_C: return "BUTTON_C"; - case AKEYCODE_BUTTON_X: return "BUTTON_X"; - case AKEYCODE_BUTTON_Y: return "BUTTON_Y"; - case AKEYCODE_BUTTON_Z: return "BUTTON_Z"; - case AKEYCODE_BUTTON_L1: return "BUTTON_L1"; - case AKEYCODE_BUTTON_R1: return "BUTTON_R1"; - case AKEYCODE_BUTTON_L2: return "BUTTON_L2"; - case AKEYCODE_BUTTON_R2: return "BUTTON_R2"; - case AKEYCODE_BUTTON_THUMBL: return "BUTTON_THUMBL"; - case AKEYCODE_BUTTON_THUMBR: return "BUTTON_THUMBR"; - case AKEYCODE_BUTTON_START: return "BUTTON_START"; - case AKEYCODE_BUTTON_SELECT: return "BUTTON_SELECT"; - case AKEYCODE_BUTTON_MODE: return "BUTTON_MODE"; - case AKEYCODE_ESCAPE: return "ESCAPE"; - case AKEYCODE_FORWARD_DEL: return "FORWARD_DEL"; - case AKEYCODE_CTRL_LEFT: return "CTRL_LEFT"; - case AKEYCODE_CTRL_RIGHT: return "CTRL_RIGHT"; - case AKEYCODE_CAPS_LOCK: return "CAPS_LOCK"; - case AKEYCODE_SCROLL_LOCK: return "SCROLL_LOCK"; - case AKEYCODE_META_LEFT: return "META_LEFT"; - case AKEYCODE_META_RIGHT: return "META_RIGHT"; - case AKEYCODE_FUNCTION: return "FUNCTION"; - case AKEYCODE_SYSRQ: return "SYSRQ"; - case AKEYCODE_BREAK: return "BREAK"; - case AKEYCODE_MOVE_HOME: return "MOVE_HOME"; - case AKEYCODE_MOVE_END: return "MOVE_END"; - case AKEYCODE_INSERT: return "INSERT"; - case AKEYCODE_FORWARD: return "FORWARD"; - case AKEYCODE_MEDIA_PLAY: return "MEDIA_PLAY"; - case AKEYCODE_MEDIA_PAUSE: return "MEDIA_PAUSE"; - case AKEYCODE_MEDIA_CLOSE: return "MEDIA_CLOSE"; - case AKEYCODE_MEDIA_EJECT: return "MEDIA_EJECT"; - case AKEYCODE_MEDIA_RECORD: return "MEDIA_RECORD"; - case AKEYCODE_F1: return "F1"; - case AKEYCODE_F2: return "F2"; - case AKEYCODE_F3: return "F3"; - case AKEYCODE_F4: return "F4"; - case AKEYCODE_F5: return "F5"; - case AKEYCODE_F6: return "F6"; - case AKEYCODE_F7: return "F7"; - case AKEYCODE_F8: return "F8"; - case AKEYCODE_F9: return "F9"; - case AKEYCODE_F10: return "F10"; - case AKEYCODE_F11: return "F11"; - case AKEYCODE_F12: return "F12"; - case AKEYCODE_NUM_LOCK: return "NUM_LOCK"; - case AKEYCODE_NUMPAD_0: return "NUMPAD_0"; - case AKEYCODE_NUMPAD_1: return "NUMPAD_1"; - case AKEYCODE_NUMPAD_2: return "NUMPAD_2"; - case AKEYCODE_NUMPAD_3: return "NUMPAD_3"; - case AKEYCODE_NUMPAD_4: return "NUMPAD_4"; - case AKEYCODE_NUMPAD_5: return "NUMPAD_5"; - case AKEYCODE_NUMPAD_6: return "NUMPAD_6"; - case AKEYCODE_NUMPAD_7: return "NUMPAD_7"; - case AKEYCODE_NUMPAD_8: return "NUMPAD_8"; - case AKEYCODE_NUMPAD_9: return "NUMPAD_9"; - case AKEYCODE_NUMPAD_DIVIDE: return "NUMPAD_DIVIDE"; - case AKEYCODE_NUMPAD_MULTIPLY: return "NUMPAD_MULTIPLY"; - case AKEYCODE_NUMPAD_SUBTRACT: return "NUMPAD_SUBTRACT"; - case AKEYCODE_NUMPAD_ADD: return "NUMPAD_ADD"; - case AKEYCODE_NUMPAD_DOT: return "NUMPAD_DOT"; - case AKEYCODE_NUMPAD_COMMA: return "NUMPAD_COMMA"; - case AKEYCODE_NUMPAD_ENTER: return "NUMPAD_ENTER"; - case AKEYCODE_NUMPAD_EQUALS: return "NUMPAD_EQUALS"; - case AKEYCODE_NUMPAD_LEFT_PAREN: return "NUMPAD_LEFT_PAREN"; - case AKEYCODE_NUMPAD_RIGHT_PAREN: return "NUMPAD_RIGHT_PAREN"; - case AKEYCODE_VOLUME_MUTE: return "VOLUME_MUTE"; - case AKEYCODE_INFO: return "INFO"; - case AKEYCODE_CHANNEL_UP: return "CHANNEL_UP"; - case AKEYCODE_CHANNEL_DOWN: return "CHANNEL_DOWN"; - case AKEYCODE_ZOOM_IN: return "ZOOM_IN"; - case AKEYCODE_ZOOM_OUT: return "ZOOM_OUT"; - case AKEYCODE_TV: return "TV"; - case AKEYCODE_WINDOW: return "WINDOW"; - case AKEYCODE_GUIDE: return "GUIDE"; - case AKEYCODE_DVR: return "DVR"; - case AKEYCODE_BOOKMARK: return "BOOKMARK"; - case AKEYCODE_CAPTIONS: return "CAPTIONS"; - case AKEYCODE_SETTINGS: return "SETTINGS"; - case AKEYCODE_TV_POWER: return "TV_POWER"; - case AKEYCODE_TV_INPUT: return "TV_INPUT"; - case AKEYCODE_STB_POWER: return "STB_POWER"; - case AKEYCODE_STB_INPUT: return "STB_INPUT"; - case AKEYCODE_AVR_POWER: return "AVR_POWER"; - case AKEYCODE_AVR_INPUT: return "AVR_INPUT"; - case AKEYCODE_PROG_RED: return "PROG_RED"; - case AKEYCODE_PROG_GREEN: return "PROG_GREEN"; - case AKEYCODE_PROG_YELLOW: return "PROG_YELLOW"; - case AKEYCODE_PROG_BLUE: return "PROG_BLUE"; - case AKEYCODE_APP_SWITCH: return "APP_SWITCH"; - case AKEYCODE_BUTTON_1: return "BUTTON_1"; - case AKEYCODE_BUTTON_2: return "BUTTON_2"; - case AKEYCODE_BUTTON_3: return "BUTTON_3"; - case AKEYCODE_BUTTON_4: return "BUTTON_4"; - case AKEYCODE_BUTTON_5: return "BUTTON_5"; - case AKEYCODE_BUTTON_6: return "BUTTON_6"; - case AKEYCODE_BUTTON_7: return "BUTTON_7"; - case AKEYCODE_BUTTON_8: return "BUTTON_8"; - case AKEYCODE_BUTTON_9: return "BUTTON_9"; - case AKEYCODE_BUTTON_10: return "BUTTON_10"; - case AKEYCODE_BUTTON_11: return "BUTTON_11"; - case AKEYCODE_BUTTON_12: return "BUTTON_12"; - case AKEYCODE_BUTTON_13: return "BUTTON_13"; - case AKEYCODE_BUTTON_14: return "BUTTON_14"; - case AKEYCODE_BUTTON_15: return "BUTTON_15"; - case AKEYCODE_BUTTON_16: return "BUTTON_16"; - case AKEYCODE_LANGUAGE_SWITCH: return "LANGUAGE_SWITCH"; - case AKEYCODE_MANNER_MODE: return "MANNER_MODE"; - case AKEYCODE_3D_MODE: return "3D_MODE"; - case AKEYCODE_CONTACTS: return "CONTACTS"; - case AKEYCODE_CALENDAR: return "CALENDAR"; - case AKEYCODE_MUSIC: return "MUSIC"; - case AKEYCODE_CALCULATOR: return "CALCULATOR"; - case AKEYCODE_ZENKAKU_HANKAKU: return "ZENKAKU_HANKAKU"; - case AKEYCODE_EISU: return "EISU"; - case AKEYCODE_MUHENKAN: return "MUHENKAN"; - case AKEYCODE_HENKAN: return "HENKAN"; - case AKEYCODE_KATAKANA_HIRAGANA: return "KATAKANA_HIRAGANA"; - case AKEYCODE_YEN: return "YEN"; - case AKEYCODE_RO: return "RO"; - case AKEYCODE_KANA: return "KANA"; - case AKEYCODE_ASSIST: return "ASSIST"; - case AKEYCODE_BRIGHTNESS_DOWN: return "BRIGHTNESS_DOWN"; - case AKEYCODE_BRIGHTNESS_UP: return "BRIGHTNESS_UP"; - case AKEYCODE_MEDIA_AUDIO_TRACK: return "MEDIA_AUDIO_TRACK"; - case AKEYCODE_SLEEP: return "SLEEP"; - case AKEYCODE_WAKEUP: return "WAKEUP"; - case AKEYCODE_PAIRING: return "PAIRING"; - case AKEYCODE_MEDIA_TOP_MENU: return "MEDIA_TOP_MENU"; - case AKEYCODE_11: return "11"; - case AKEYCODE_12: return "12"; - case AKEYCODE_LAST_CHANNEL: return "LAST_CHANNEL"; - case AKEYCODE_TV_DATA_SERVICE: return "TV_DATA_SERVICE"; - case AKEYCODE_VOICE_ASSIST: return "VOICE_ASSIST"; - case AKEYCODE_TV_RADIO_SERVICE: return "TV_RADIO_SERVICE"; - case AKEYCODE_TV_TELETEXT: return "TV_TELETEXT"; - case AKEYCODE_TV_NUMBER_ENTRY: return "TV_NUMBER_ENTRY"; - case AKEYCODE_TV_TERRESTRIAL_ANALOG: return "TV_TERRESTRIAL_ANALOG"; - case AKEYCODE_TV_TERRESTRIAL_DIGITAL: return "TV_TERRESTRIAL_DIGITAL"; - case AKEYCODE_TV_SATELLITE: return "TV_SATELLITE"; - case AKEYCODE_TV_SATELLITE_BS: return "TV_SATELLITE_BS"; - case AKEYCODE_TV_SATELLITE_CS: return "TV_SATELLITE_CS"; - case AKEYCODE_TV_SATELLITE_SERVICE: return "TV_SATELLITE_SERVICE"; - case AKEYCODE_TV_NETWORK: return "TV_NETWORK"; - case AKEYCODE_TV_ANTENNA_CABLE: return "TV_ANTENNA_CABLE"; - case AKEYCODE_TV_INPUT_HDMI_1: return "TV_INPUT_HDMI_1"; - case AKEYCODE_TV_INPUT_HDMI_2: return "TV_INPUT_HDMI_2"; - case AKEYCODE_TV_INPUT_HDMI_3: return "TV_INPUT_HDMI_3"; - case AKEYCODE_TV_INPUT_HDMI_4: return "TV_INPUT_HDMI_4"; - case AKEYCODE_TV_INPUT_COMPOSITE_1: return "TV_INPUT_COMPOSITE_1"; - case AKEYCODE_TV_INPUT_COMPOSITE_2: return "TV_INPUT_COMPOSITE_2"; - case AKEYCODE_TV_INPUT_COMPONENT_1: return "TV_INPUT_COMPONENT_1"; - case AKEYCODE_TV_INPUT_COMPONENT_2: return "TV_INPUT_COMPONENT_2"; - case AKEYCODE_TV_INPUT_VGA_1: return "TV_INPUT_VGA_1"; - case AKEYCODE_TV_AUDIO_DESCRIPTION: return "TV_AUDIO_DESCRIPTION"; - case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: return "TV_AUDIO_DESCRIPTION_MIX_UP"; - case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: return "TV_AUDIO_DESCRIPTION_MIX_DOWN"; - case AKEYCODE_TV_ZOOM_MODE: return "TV_ZOOM_MODE"; - case AKEYCODE_TV_CONTENTS_MENU: return "TV_CONTENTS_MENU"; - case AKEYCODE_TV_MEDIA_CONTEXT_MENU: return "TV_MEDIA_CONTEXT_MENU"; - case AKEYCODE_TV_TIMER_PROGRAMMING: return "TV_TIMER_PROGRAMMING"; - case AKEYCODE_HELP: return "HELP"; - case AKEYCODE_NAVIGATE_PREVIOUS: return "NAVIGATE_PREVIOUS"; - case AKEYCODE_NAVIGATE_NEXT: return "NAVIGATE_NEXT"; - case AKEYCODE_NAVIGATE_IN: return "NAVIGATE_IN"; - case AKEYCODE_NAVIGATE_OUT: return "NAVIGATE_OUT"; - case AKEYCODE_STEM_PRIMARY: return "STEM_PRIMARY"; - case AKEYCODE_STEM_1: return "STEM_1"; - case AKEYCODE_STEM_2: return "STEM_2"; - case AKEYCODE_STEM_3: return "STEM_3"; - case AKEYCODE_DPAD_UP_LEFT: return "DPAD_UP_LEFT"; - case AKEYCODE_DPAD_DOWN_LEFT: return "DPAD_DOWN_LEFT"; - case AKEYCODE_DPAD_UP_RIGHT: return "DPAD_UP_RIGHT"; - case AKEYCODE_DPAD_DOWN_RIGHT: return "DPAD_DOWN_RIGHT"; - case AKEYCODE_MEDIA_SKIP_FORWARD: return "MEDIA_SKIP_FORWARD"; - case AKEYCODE_MEDIA_SKIP_BACKWARD: return "MEDIA_SKIP_BACKWARD"; - case AKEYCODE_MEDIA_STEP_FORWARD: return "MEDIA_STEP_FORWARD"; - case AKEYCODE_MEDIA_STEP_BACKWARD: return "MEDIA_STEP_BACKWARD"; - case AKEYCODE_SOFT_SLEEP: return "SOFT_SLEEP"; - case AKEYCODE_CUT: return "CUT"; - case AKEYCODE_COPY: return "COPY"; - case AKEYCODE_PASTE: return "PASTE"; - case AKEYCODE_SYSTEM_NAVIGATION_UP: return "SYSTEM_NAVIGATION_UP"; - case AKEYCODE_SYSTEM_NAVIGATION_DOWN: return "SYSTEM_NAVIGATION_DOWN"; - case AKEYCODE_SYSTEM_NAVIGATION_LEFT: return "SYSTEM_NAVIGATION_LEFT"; - case AKEYCODE_SYSTEM_NAVIGATION_RIGHT: return "SYSTEM_NAVIGATION_RIGHT"; - case AKEYCODE_ALL_APPS: return "ALL_APPS"; - case AKEYCODE_REFRESH: return "REFRESH"; - case AKEYCODE_THUMBS_UP: return "THUMBS_UP"; - case AKEYCODE_THUMBS_DOWN: return "THUMBS_DOWN"; - case AKEYCODE_PROFILE_SWITCH: return "PROFILE_SWITCH"; +const char *se_android_key_to_name(int key) { + switch(key) { + case AKEYCODE_UNKNOWN: return "UNKNOWN"; + case AKEYCODE_SOFT_LEFT: return "SOFT_LEFT"; + case AKEYCODE_SOFT_RIGHT: return "SOFT_RIGHT"; + case AKEYCODE_HOME: return "HOME"; + case AKEYCODE_BACK: return "BACK"; + case AKEYCODE_CALL: return "CALL"; + case AKEYCODE_ENDCALL: return "ENDCALL"; + case AKEYCODE_0: return "0"; + case AKEYCODE_1: return "1"; + case AKEYCODE_2: return "2"; + case AKEYCODE_3: return "3"; + case AKEYCODE_4: return "4"; + case AKEYCODE_5: return "5"; + case AKEYCODE_6: return "6"; + case AKEYCODE_7: return "7"; + case AKEYCODE_8: return "8"; + case AKEYCODE_9: return "9"; + case AKEYCODE_STAR: return "STAR"; + case AKEYCODE_POUND: return "POUND"; + case AKEYCODE_DPAD_UP: return "DPAD_UP"; + case AKEYCODE_DPAD_DOWN: return "DPAD_DOWN"; + case AKEYCODE_DPAD_LEFT: return "DPAD_LEFT"; + case AKEYCODE_DPAD_RIGHT: return "DPAD_RIGHT"; + case AKEYCODE_DPAD_CENTER: return "DPAD_CENTER"; + case AKEYCODE_VOLUME_UP: return "VOLUME_UP"; + case AKEYCODE_VOLUME_DOWN: return "VOLUME_DOWN"; + case AKEYCODE_POWER: return "POWER"; + case AKEYCODE_CAMERA: return "CAMERA"; + case AKEYCODE_CLEAR: return "CLEAR"; + case AKEYCODE_A: return "A"; + case AKEYCODE_B: return "B"; + case AKEYCODE_C: return "C"; + case AKEYCODE_D: return "D"; + case AKEYCODE_E: return "E"; + case AKEYCODE_F: return "F"; + case AKEYCODE_G: return "G"; + case AKEYCODE_H: return "H"; + case AKEYCODE_I: return "I"; + case AKEYCODE_J: return "J"; + case AKEYCODE_K: return "K"; + case AKEYCODE_L: return "L"; + case AKEYCODE_M: return "M"; + case AKEYCODE_N: return "N"; + case AKEYCODE_O: return "O"; + case AKEYCODE_P: return "P"; + case AKEYCODE_Q: return "Q"; + case AKEYCODE_R: return "R"; + case AKEYCODE_S: return "S"; + case AKEYCODE_T: return "T"; + case AKEYCODE_U: return "U"; + case AKEYCODE_V: return "V"; + case AKEYCODE_W: return "W"; + case AKEYCODE_X: return "X"; + case AKEYCODE_Y: return "Y"; + case AKEYCODE_Z: return "Z"; + case AKEYCODE_COMMA: return "COMMA"; + case AKEYCODE_PERIOD: return "PERIOD"; + case AKEYCODE_ALT_LEFT: return "ALT_LEFT"; + case AKEYCODE_ALT_RIGHT: return "ALT_RIGHT"; + case AKEYCODE_SHIFT_LEFT: return "SHIFT_LEFT"; + case AKEYCODE_SHIFT_RIGHT: return "SHIFT_RIGHT"; + case AKEYCODE_TAB: return "TAB"; + case AKEYCODE_SPACE: return "SPACE"; + case AKEYCODE_SYM: return "SYM"; + case AKEYCODE_EXPLORER: return "EXPLORER"; + case AKEYCODE_ENVELOPE: return "ENVELOPE"; + case AKEYCODE_ENTER: return "ENTER"; + case AKEYCODE_DEL: return "DEL"; + case AKEYCODE_GRAVE: return "GRAVE"; + case AKEYCODE_MINUS: return "MINUS"; + case AKEYCODE_EQUALS: return "EQUALS"; + case AKEYCODE_LEFT_BRACKET: return "LEFT_BRACKET"; + case AKEYCODE_RIGHT_BRACKET: return "RIGHT_BRACKET"; + case AKEYCODE_BACKSLASH: return "BACKSLASH"; + case AKEYCODE_SEMICOLON: return "SEMICOLON"; + case AKEYCODE_APOSTROPHE: return "APOSTROPHE"; + case AKEYCODE_SLASH: return "SLASH"; + case AKEYCODE_AT: return "AT"; + case AKEYCODE_NUM: return "NUM"; + case AKEYCODE_HEADSETHOOK: return "HEADSETHOOK"; + case AKEYCODE_FOCUS: return "FOCUS"; + case AKEYCODE_PLUS: return "PLUS"; + case AKEYCODE_MENU: return "MENU"; + case AKEYCODE_NOTIFICATION: return "NOTIFICATION"; + case AKEYCODE_SEARCH: return "SEARCH"; + case AKEYCODE_MEDIA_PLAY_PAUSE: return "MEDIA_PLAY_PAUSE"; + case AKEYCODE_MEDIA_STOP: return "MEDIA_STOP"; + case AKEYCODE_MEDIA_NEXT: return "MEDIA_NEXT"; + case AKEYCODE_MEDIA_PREVIOUS: return "MEDIA_PREVIOUS"; + case AKEYCODE_MEDIA_REWIND: return "MEDIA_REWIND"; + case AKEYCODE_MEDIA_FAST_FORWARD: return "MEDIA_FAST_FORWARD"; + case AKEYCODE_MUTE: return "MUTE"; + case AKEYCODE_PAGE_UP: return "PAGE_UP"; + case AKEYCODE_PAGE_DOWN: return "PAGE_DOWN"; + case AKEYCODE_PICTSYMBOLS: return "PICTSYMBOLS"; + case AKEYCODE_SWITCH_CHARSET: return "SWITCH_CHARSET"; + case AKEYCODE_BUTTON_A: return "BUTTON_A"; + case AKEYCODE_BUTTON_B: return "BUTTON_B"; + case AKEYCODE_BUTTON_C: return "BUTTON_C"; + case AKEYCODE_BUTTON_X: return "BUTTON_X"; + case AKEYCODE_BUTTON_Y: return "BUTTON_Y"; + case AKEYCODE_BUTTON_Z: return "BUTTON_Z"; + case AKEYCODE_BUTTON_L1: return "BUTTON_L1"; + case AKEYCODE_BUTTON_R1: return "BUTTON_R1"; + case AKEYCODE_BUTTON_L2: return "BUTTON_L2"; + case AKEYCODE_BUTTON_R2: return "BUTTON_R2"; + case AKEYCODE_BUTTON_THUMBL: return "BUTTON_THUMBL"; + case AKEYCODE_BUTTON_THUMBR: return "BUTTON_THUMBR"; + case AKEYCODE_BUTTON_START: return "BUTTON_START"; + case AKEYCODE_BUTTON_SELECT: return "BUTTON_SELECT"; + case AKEYCODE_BUTTON_MODE: return "BUTTON_MODE"; + case AKEYCODE_ESCAPE: return "ESCAPE"; + case AKEYCODE_FORWARD_DEL: return "FORWARD_DEL"; + case AKEYCODE_CTRL_LEFT: return "CTRL_LEFT"; + case AKEYCODE_CTRL_RIGHT: return "CTRL_RIGHT"; + case AKEYCODE_CAPS_LOCK: return "CAPS_LOCK"; + case AKEYCODE_SCROLL_LOCK: return "SCROLL_LOCK"; + case AKEYCODE_META_LEFT: return "META_LEFT"; + case AKEYCODE_META_RIGHT: return "META_RIGHT"; + case AKEYCODE_FUNCTION: return "FUNCTION"; + case AKEYCODE_SYSRQ: return "SYSRQ"; + case AKEYCODE_BREAK: return "BREAK"; + case AKEYCODE_MOVE_HOME: return "MOVE_HOME"; + case AKEYCODE_MOVE_END: return "MOVE_END"; + case AKEYCODE_INSERT: return "INSERT"; + case AKEYCODE_FORWARD: return "FORWARD"; + case AKEYCODE_MEDIA_PLAY: return "MEDIA_PLAY"; + case AKEYCODE_MEDIA_PAUSE: return "MEDIA_PAUSE"; + case AKEYCODE_MEDIA_CLOSE: return "MEDIA_CLOSE"; + case AKEYCODE_MEDIA_EJECT: return "MEDIA_EJECT"; + case AKEYCODE_MEDIA_RECORD: return "MEDIA_RECORD"; + case AKEYCODE_F1: return "F1"; + case AKEYCODE_F2: return "F2"; + case AKEYCODE_F3: return "F3"; + case AKEYCODE_F4: return "F4"; + case AKEYCODE_F5: return "F5"; + case AKEYCODE_F6: return "F6"; + case AKEYCODE_F7: return "F7"; + case AKEYCODE_F8: return "F8"; + case AKEYCODE_F9: return "F9"; + case AKEYCODE_F10: return "F10"; + case AKEYCODE_F11: return "F11"; + case AKEYCODE_F12: return "F12"; + case AKEYCODE_NUM_LOCK: return "NUM_LOCK"; + case AKEYCODE_NUMPAD_0: return "NUMPAD_0"; + case AKEYCODE_NUMPAD_1: return "NUMPAD_1"; + case AKEYCODE_NUMPAD_2: return "NUMPAD_2"; + case AKEYCODE_NUMPAD_3: return "NUMPAD_3"; + case AKEYCODE_NUMPAD_4: return "NUMPAD_4"; + case AKEYCODE_NUMPAD_5: return "NUMPAD_5"; + case AKEYCODE_NUMPAD_6: return "NUMPAD_6"; + case AKEYCODE_NUMPAD_7: return "NUMPAD_7"; + case AKEYCODE_NUMPAD_8: return "NUMPAD_8"; + case AKEYCODE_NUMPAD_9: return "NUMPAD_9"; + case AKEYCODE_NUMPAD_DIVIDE: return "NUMPAD_DIVIDE"; + case AKEYCODE_NUMPAD_MULTIPLY: return "NUMPAD_MULTIPLY"; + case AKEYCODE_NUMPAD_SUBTRACT: return "NUMPAD_SUBTRACT"; + case AKEYCODE_NUMPAD_ADD: return "NUMPAD_ADD"; + case AKEYCODE_NUMPAD_DOT: return "NUMPAD_DOT"; + case AKEYCODE_NUMPAD_COMMA: return "NUMPAD_COMMA"; + case AKEYCODE_NUMPAD_ENTER: return "NUMPAD_ENTER"; + case AKEYCODE_NUMPAD_EQUALS: return "NUMPAD_EQUALS"; + case AKEYCODE_NUMPAD_LEFT_PAREN: return "NUMPAD_LEFT_PAREN"; + case AKEYCODE_NUMPAD_RIGHT_PAREN: return "NUMPAD_RIGHT_PAREN"; + case AKEYCODE_VOLUME_MUTE: return "VOLUME_MUTE"; + case AKEYCODE_INFO: return "INFO"; + case AKEYCODE_CHANNEL_UP: return "CHANNEL_UP"; + case AKEYCODE_CHANNEL_DOWN: return "CHANNEL_DOWN"; + case AKEYCODE_ZOOM_IN: return "ZOOM_IN"; + case AKEYCODE_ZOOM_OUT: return "ZOOM_OUT"; + case AKEYCODE_TV: return "TV"; + case AKEYCODE_WINDOW: return "WINDOW"; + case AKEYCODE_GUIDE: return "GUIDE"; + case AKEYCODE_DVR: return "DVR"; + case AKEYCODE_BOOKMARK: return "BOOKMARK"; + case AKEYCODE_CAPTIONS: return "CAPTIONS"; + case AKEYCODE_SETTINGS: return "SETTINGS"; + case AKEYCODE_TV_POWER: return "TV_POWER"; + case AKEYCODE_TV_INPUT: return "TV_INPUT"; + case AKEYCODE_STB_POWER: return "STB_POWER"; + case AKEYCODE_STB_INPUT: return "STB_INPUT"; + case AKEYCODE_AVR_POWER: return "AVR_POWER"; + case AKEYCODE_AVR_INPUT: return "AVR_INPUT"; + case AKEYCODE_PROG_RED: return "PROG_RED"; + case AKEYCODE_PROG_GREEN: return "PROG_GREEN"; + case AKEYCODE_PROG_YELLOW: return "PROG_YELLOW"; + case AKEYCODE_PROG_BLUE: return "PROG_BLUE"; + case AKEYCODE_APP_SWITCH: return "APP_SWITCH"; + case AKEYCODE_BUTTON_1: return "BUTTON_1"; + case AKEYCODE_BUTTON_2: return "BUTTON_2"; + case AKEYCODE_BUTTON_3: return "BUTTON_3"; + case AKEYCODE_BUTTON_4: return "BUTTON_4"; + case AKEYCODE_BUTTON_5: return "BUTTON_5"; + case AKEYCODE_BUTTON_6: return "BUTTON_6"; + case AKEYCODE_BUTTON_7: return "BUTTON_7"; + case AKEYCODE_BUTTON_8: return "BUTTON_8"; + case AKEYCODE_BUTTON_9: return "BUTTON_9"; + case AKEYCODE_BUTTON_10: return "BUTTON_10"; + case AKEYCODE_BUTTON_11: return "BUTTON_11"; + case AKEYCODE_BUTTON_12: return "BUTTON_12"; + case AKEYCODE_BUTTON_13: return "BUTTON_13"; + case AKEYCODE_BUTTON_14: return "BUTTON_14"; + case AKEYCODE_BUTTON_15: return "BUTTON_15"; + case AKEYCODE_BUTTON_16: return "BUTTON_16"; + case AKEYCODE_LANGUAGE_SWITCH: return "LANGUAGE_SWITCH"; + case AKEYCODE_MANNER_MODE: return "MANNER_MODE"; + case AKEYCODE_3D_MODE: return "3D_MODE"; + case AKEYCODE_CONTACTS: return "CONTACTS"; + case AKEYCODE_CALENDAR: return "CALENDAR"; + case AKEYCODE_MUSIC: return "MUSIC"; + case AKEYCODE_CALCULATOR: return "CALCULATOR"; + case AKEYCODE_ZENKAKU_HANKAKU: return "ZENKAKU_HANKAKU"; + case AKEYCODE_EISU: return "EISU"; + case AKEYCODE_MUHENKAN: return "MUHENKAN"; + case AKEYCODE_HENKAN: return "HENKAN"; + case AKEYCODE_KATAKANA_HIRAGANA: return "KATAKANA_HIRAGANA"; + case AKEYCODE_YEN: return "YEN"; + case AKEYCODE_RO: return "RO"; + case AKEYCODE_KANA: return "KANA"; + case AKEYCODE_ASSIST: return "ASSIST"; + case AKEYCODE_BRIGHTNESS_DOWN: return "BRIGHTNESS_DOWN"; + case AKEYCODE_BRIGHTNESS_UP: return "BRIGHTNESS_UP"; + case AKEYCODE_MEDIA_AUDIO_TRACK: return "MEDIA_AUDIO_TRACK"; + case AKEYCODE_SLEEP: return "SLEEP"; + case AKEYCODE_WAKEUP: return "WAKEUP"; + case AKEYCODE_PAIRING: return "PAIRING"; + case AKEYCODE_MEDIA_TOP_MENU: return "MEDIA_TOP_MENU"; + case AKEYCODE_11: return "11"; + case AKEYCODE_12: return "12"; + case AKEYCODE_LAST_CHANNEL: return "LAST_CHANNEL"; + case AKEYCODE_TV_DATA_SERVICE: return "TV_DATA_SERVICE"; + case AKEYCODE_VOICE_ASSIST: return "VOICE_ASSIST"; + case AKEYCODE_TV_RADIO_SERVICE: return "TV_RADIO_SERVICE"; + case AKEYCODE_TV_TELETEXT: return "TV_TELETEXT"; + case AKEYCODE_TV_NUMBER_ENTRY: return "TV_NUMBER_ENTRY"; + case AKEYCODE_TV_TERRESTRIAL_ANALOG: return "TV_TERRESTRIAL_ANALOG"; + case AKEYCODE_TV_TERRESTRIAL_DIGITAL: return "TV_TERRESTRIAL_DIGITAL"; + case AKEYCODE_TV_SATELLITE: return "TV_SATELLITE"; + case AKEYCODE_TV_SATELLITE_BS: return "TV_SATELLITE_BS"; + case AKEYCODE_TV_SATELLITE_CS: return "TV_SATELLITE_CS"; + case AKEYCODE_TV_SATELLITE_SERVICE: return "TV_SATELLITE_SERVICE"; + case AKEYCODE_TV_NETWORK: return "TV_NETWORK"; + case AKEYCODE_TV_ANTENNA_CABLE: return "TV_ANTENNA_CABLE"; + case AKEYCODE_TV_INPUT_HDMI_1: return "TV_INPUT_HDMI_1"; + case AKEYCODE_TV_INPUT_HDMI_2: return "TV_INPUT_HDMI_2"; + case AKEYCODE_TV_INPUT_HDMI_3: return "TV_INPUT_HDMI_3"; + case AKEYCODE_TV_INPUT_HDMI_4: return "TV_INPUT_HDMI_4"; + case AKEYCODE_TV_INPUT_COMPOSITE_1: return "TV_INPUT_COMPOSITE_1"; + case AKEYCODE_TV_INPUT_COMPOSITE_2: return "TV_INPUT_COMPOSITE_2"; + case AKEYCODE_TV_INPUT_COMPONENT_1: return "TV_INPUT_COMPONENT_1"; + case AKEYCODE_TV_INPUT_COMPONENT_2: return "TV_INPUT_COMPONENT_2"; + case AKEYCODE_TV_INPUT_VGA_1: return "TV_INPUT_VGA_1"; + case AKEYCODE_TV_AUDIO_DESCRIPTION: return "TV_AUDIO_DESCRIPTION"; + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: return "TV_AUDIO_DESCRIPTION_MIX_UP"; + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: return "TV_AUDIO_DESCRIPTION_MIX_DOWN"; + case AKEYCODE_TV_ZOOM_MODE: return "TV_ZOOM_MODE"; + case AKEYCODE_TV_CONTENTS_MENU: return "TV_CONTENTS_MENU"; + case AKEYCODE_TV_MEDIA_CONTEXT_MENU: return "TV_MEDIA_CONTEXT_MENU"; + case AKEYCODE_TV_TIMER_PROGRAMMING: return "TV_TIMER_PROGRAMMING"; + case AKEYCODE_HELP: return "HELP"; + case AKEYCODE_NAVIGATE_PREVIOUS: return "NAVIGATE_PREVIOUS"; + case AKEYCODE_NAVIGATE_NEXT: return "NAVIGATE_NEXT"; + case AKEYCODE_NAVIGATE_IN: return "NAVIGATE_IN"; + case AKEYCODE_NAVIGATE_OUT: return "NAVIGATE_OUT"; + case AKEYCODE_STEM_PRIMARY: return "STEM_PRIMARY"; + case AKEYCODE_STEM_1: return "STEM_1"; + case AKEYCODE_STEM_2: return "STEM_2"; + case AKEYCODE_STEM_3: return "STEM_3"; + case AKEYCODE_DPAD_UP_LEFT: return "DPAD_UP_LEFT"; + case AKEYCODE_DPAD_DOWN_LEFT: return "DPAD_DOWN_LEFT"; + case AKEYCODE_DPAD_UP_RIGHT: return "DPAD_UP_RIGHT"; + case AKEYCODE_DPAD_DOWN_RIGHT: return "DPAD_DOWN_RIGHT"; + case AKEYCODE_MEDIA_SKIP_FORWARD: return "MEDIA_SKIP_FORWARD"; + case AKEYCODE_MEDIA_SKIP_BACKWARD: return "MEDIA_SKIP_BACKWARD"; + case AKEYCODE_MEDIA_STEP_FORWARD: return "MEDIA_STEP_FORWARD"; + case AKEYCODE_MEDIA_STEP_BACKWARD: return "MEDIA_STEP_BACKWARD"; + case AKEYCODE_SOFT_SLEEP: return "SOFT_SLEEP"; + case AKEYCODE_CUT: return "CUT"; + case AKEYCODE_COPY: return "COPY"; + case AKEYCODE_PASTE: return "PASTE"; + case AKEYCODE_SYSTEM_NAVIGATION_UP: return "SYSTEM_NAVIGATION_UP"; + case AKEYCODE_SYSTEM_NAVIGATION_DOWN: return "SYSTEM_NAVIGATION_DOWN"; + case AKEYCODE_SYSTEM_NAVIGATION_LEFT: return "SYSTEM_NAVIGATION_LEFT"; + case AKEYCODE_SYSTEM_NAVIGATION_RIGHT: return "SYSTEM_NAVIGATION_RIGHT"; + case AKEYCODE_ALL_APPS: return "ALL_APPS"; + case AKEYCODE_REFRESH: return "REFRESH"; + case AKEYCODE_THUMBS_UP: return "THUMBS_UP"; + case AKEYCODE_THUMBS_DOWN: return "THUMBS_DOWN"; + case AKEYCODE_PROFILE_SWITCH: return "PROFILE_SWITCH"; } return NULL; } #endif -//Returns true if modifed -bool se_handle_keybind_settings(int keybind_type, se_keybind_state_t * state){ - double rebind_timer = SE_REBIND_TIMER_LENGTH-(se_time()-state->rebind_start_time); - int num_keybinds = SE_NUM_KEYBINDS; - const char ** button_labels = se_keybind_names; - const char * action = "Press new button " ICON_FK_SIGN_IN; - if(keybind_type==SE_BIND_ANALOG){ +// Returns true if modifed +bool se_handle_keybind_settings(int keybind_type, se_keybind_state_t *state) { + double rebind_timer = SE_REBIND_TIMER_LENGTH - (se_time() - state->rebind_start_time); + int num_keybinds = SE_NUM_KEYBINDS; + const char **button_labels = se_keybind_names; + const char *action = "Press new button " ICON_FK_SIGN_IN; + if(keybind_type == SE_BIND_ANALOG) { num_keybinds = SE_NUM_ANALOGBINDS; button_labels = se_analog_bind_names; action = "Move Axis " ICON_FK_SIGN_IN; } action = se_localize(action); - if(rebind_timer<0){state->bind_being_set=-1;} + if(rebind_timer < 0) { state->bind_being_set = -1; } igPushIDInt(keybind_type); - ImGuiStyle* style = igGetStyle(); - bool settings_changed = false; - for(int k=0;kvalue[k])>0.4; - igSameLine(SE_FIELD_INDENT,0); - if(state->bind_being_set==k)active=true; - if(active)igPushStyleColorVec4(ImGuiCol_Button, style->Colors[ImGuiCol_ButtonActive]); - const char* button_label = "Not bound"; - char buff[32]; - if(state->bound_id[k]!=-1){ - switch(keybind_type){ - case SE_BIND_KEYBOARD: button_label=se_keycode_to_string(state->bound_id[k]);break; - #if defined(USE_SDL) || defined(PLATFORM_ANDROID) - case SE_BIND_KEY: - { - int key = state->bound_id[k]; - bool is_hat = key&SE_HAT_MASK; - bool is_joy = key&(SE_JOY_NEG_MASK|SE_JOY_POS_MASK); - #ifdef USE_SDL - if(is_hat){ - int hat_id = SB_BFE(key,8,8); - int hat_val = SB_BFE(key,0,8); - const char * dir = ""; - if(hat_val == SDL_HAT_UP)dir="UP"; - if(hat_val == SDL_HAT_DOWN)dir="DOWN"; - if(hat_val == SDL_HAT_LEFT)dir="LEFT"; - if(hat_val == SDL_HAT_RIGHT)dir="RIGHT"; - - snprintf(buff, sizeof(buff),se_localize("Hat %d %s"), hat_id, dir); - button_label=buff; - }else - #endif - if(is_joy){ - int joy_id = SB_BFE(key,0,16); - const char* dir = (key&SE_JOY_NEG_MASK)? "<-0.3": ">0.3"; - snprintf(buff, sizeof(buff),se_localize("Analog %d %s"),joy_id,dir); - }else { - #ifdef PLATFORM_ANDROID - const char* android_name = se_android_key_to_name(state->bound_id[k]); - if(android_name) { - android_name = se_localize_and_cache(android_name); - button_label = android_name; - break; - } - #endif - snprintf(buff, sizeof(buff),se_localize("Key %d"), state->bound_id[k]);button_label=buff; - } + se_text("%s", se_localize_and_cache(button_labels[k])); + float active = (state->value[k]) > 0.4; + igSameLine(SE_FIELD_INDENT, 0); + if(state->bind_being_set == k) active = true; + if(active) igPushStyleColorVec4(ImGuiCol_Button, style->Colors[ImGuiCol_ButtonActive]); + const char *button_label = "Not bound"; + char buff[32]; + if(state->bound_id[k] != -1) { + switch(keybind_type) { + case SE_BIND_KEYBOARD: button_label = se_keycode_to_string(state->bound_id[k]); break; +#if defined(USE_SDL) || defined(PLATFORM_ANDROID) + case SE_BIND_KEY: { + int key = state->bound_id[k]; + bool is_hat = key & SE_HAT_MASK; + bool is_joy = key & (SE_JOY_NEG_MASK | SE_JOY_POS_MASK); +#ifdef USE_SDL + if(is_hat) { + int hat_id = SB_BFE(key, 8, 8); + int hat_val = SB_BFE(key, 0, 8); + const char *dir = ""; + if(hat_val == SDL_HAT_UP) dir = "UP"; + if(hat_val == SDL_HAT_DOWN) dir = "DOWN"; + if(hat_val == SDL_HAT_LEFT) dir = "LEFT"; + if(hat_val == SDL_HAT_RIGHT) dir = "RIGHT"; + + snprintf(buff, sizeof(buff), se_localize("Hat %d %s"), hat_id, dir); + button_label = buff; + } else +#endif + if(is_joy) { + int joy_id = SB_BFE(key, 0, 16); + const char *dir = (key & SE_JOY_NEG_MASK) ? "<-0.3" : ">0.3"; + snprintf(buff, sizeof(buff), se_localize("Analog %d %s"), joy_id, dir); + } else { +#ifdef PLATFORM_ANDROID + const char *android_name = se_android_key_to_name(state->bound_id[k]); + if(android_name) { + android_name = se_localize_and_cache(android_name); + button_label = android_name; + break; } - button_label=buff; - break; - case SE_BIND_ANALOG: - snprintf(buff, sizeof(buff),se_localize("Analog %d (%0.2f)"), state->bound_id[k],state->value[k]);button_label=buff; - button_label=buff; - break; - #endif +#endif + snprintf(buff, sizeof(buff), se_localize("Key %d"), state->bound_id[k]); + button_label = buff; + } + } + button_label = buff; + break; + case SE_BIND_ANALOG: + snprintf(buff, sizeof(buff), se_localize("Analog %d (%0.2f)"), state->bound_id[k], state->value[k]); + button_label = buff; + button_label = buff; + break; +#endif } } - if(state->bind_being_set==k){ - button_label = buff; - snprintf(buff,sizeof(buff),"%s (%d)",action,(int)(rebind_timer+1)); - if(state->last_bind_activitiy!=-1){ - state->bound_id[k]=state->last_bind_activitiy; - state->bind_being_set=-1; + if(state->bind_being_set == k) { + button_label = buff; + snprintf(buff, sizeof(buff), "%s (%d)", action, (int)(rebind_timer + 1)); + if(state->last_bind_activitiy != -1) { + state->bound_id[k] = state->last_bind_activitiy; + state->bind_being_set = -1; settings_changed = true; } } - if(se_button(button_label,(ImVec2){-25, 0})){ + if(se_button(button_label, (ImVec2){-25, 0})) { state->bind_being_set = k; state->rebind_start_time = se_time(); } - igSameLine(0,1); - if(se_button(ICON_FK_TIMES,(ImVec2){-1, 0})){ - state->bound_id[k]=-1; - state->bind_being_set=-1; + igSameLine(0, 1); + if(se_button(ICON_FK_TIMES, (ImVec2){-1, 0})) { + state->bound_id[k] = -1; + state->bind_being_set = -1; settings_changed = true; } - if(active)igPopStyleColor(1); + if(active) igPopStyleColor(1); igPopID(); - } + } igPopID(); return settings_changed; } -void sb_draw_onscreen_controller(sb_emu_state_t*state, int controller_h, int controller_y_pad,bool preview){ - if(state->run_mode!=SB_MODE_RUN&&preview==false)return; - controller_h*=gui_state.settings.touch_controls_scale; +void sb_draw_onscreen_controller(sb_emu_state_t *state, int controller_h, int controller_y_pad, bool preview) { + if(state->run_mode != SB_MODE_RUN && preview == false) return; + controller_h *= gui_state.settings.touch_controls_scale; float win_w = igGetWindowWidth(); float win_h = igGetWindowHeight(); - if(preview==false){ - win_w /=se_dpi_scale(); - win_h /=se_dpi_scale(); + if(preview == false) { + win_w /= se_dpi_scale(); + win_h /= se_dpi_scale(); } - controller_h/=se_dpi_scale(); - controller_y_pad/=se_dpi_scale(); + controller_h /= se_dpi_scale(); + controller_y_pad /= se_dpi_scale(); - ImVec2 pos; + ImVec2 pos; igGetWindowPos(&pos); float win_x = pos.x; - float win_y = pos.y+win_h-controller_h-controller_y_pad; - win_h=controller_h; + float win_y = pos.y + win_h - controller_h - controller_y_pad; + win_h = controller_h; float size_scalar = win_w; - if(controller_h*1.41||preview)opacity=1; - if(!gui_state.settings.auto_hide_touch_controls)opacity=1; - if(opacity<=0){opacity=0;} - opacity*=gui_state.settings.touch_controls_opacity; - - if(gui_state.settings.theme==SE_THEME_CUSTOM){ - line_color|=(int)(opacity*0xff)<<24; - line_color2|=(int)(opacity*0xff)<<24; - sel_color|=(int)(opacity*0x80)<<24; - hold_color|=(uint32_t)(0xffu)<<24; - turbo_color|=(int)(fmin(opacity+turbo_t*0.5,1)*0xffu)<<24; - }else{ - line_color|=(int)(opacity*0x8f)<<24; - line_color2|=(int)(opacity*0x8f)<<24; - sel_color|=(int)(opacity*0x8f)<<24; - hold_color|=(uint32_t)(0xffu)<<24; - turbo_color|=(int)(fmin(opacity+turbo_t*0.5,1)*0xffu)<<24; - } - + ImU32 line_color = 0xffffff; + ImU32 line_color2 = 0x000000; + ImU32 sel_color = 0x000000; + double turbo_t = se_time() * 5; + turbo_t -= floor(turbo_t); + ImU32 turbo_color = 0x0070ff; + ImU32 hold_color = 0xff4000; + + float opacity = 3. - (se_time() - gui_state.last_touch_time); + if(opacity > 1 || preview) opacity = 1; + if(!gui_state.settings.auto_hide_touch_controls) opacity = 1; + if(opacity <= 0) { opacity = 0; } + opacity *= gui_state.settings.touch_controls_opacity; + + if(gui_state.settings.theme == SE_THEME_CUSTOM) { + line_color |= (int)(opacity * 0xff) << 24; + line_color2 |= (int)(opacity * 0xff) << 24; + sel_color |= (int)(opacity * 0x80) << 24; + hold_color |= (uint32_t)(0xffu) << 24; + turbo_color |= (int)(fmin(opacity + turbo_t * 0.5, 1) * 0xffu) << 24; + } else { + line_color |= (int)(opacity * 0x8f) << 24; + line_color2 |= (int)(opacity * 0x8f) << 24; + sel_color |= (int)(opacity * 0x8f) << 24; + hold_color |= (uint32_t)(0xffu) << 24; + turbo_color |= (int)(fmin(opacity + turbo_t * 0.5, 1) * 0xffu) << 24; + } + float themed_scale = 1.1; - int line_w0 = 1; - int line_w1 = 3; - float button_r = size_scalar*0.0815; - - float dpad_sz0 = size_scalar*0.051; - float dpad_sz1 = size_scalar*0.180; - - float a_pos[2] = {win_w-button_r*1.5,face_button_h*0.48+face_button_y}; - float b_pos[2] = {win_w-button_r*3.8,face_button_h*0.54+face_button_y}; - - //Only have the x and y buttons on screen if the emulated system uses them. - float x_pos[2] = {10e9,10e9}; - float y_pos[2] = {10e9,10e9}; - float dpad_pos[2] = {dpad_sz1+button_padding*2,face_button_h*0.5+face_button_y}; - if(emu_state.system==SYSTEM_GB){ - dpad_pos[1]*=0.8; - a_pos[1]*=0.8; - b_pos[1]*=0.8; - } - - char * button_name[] ={"Start", "Hold", "Turbo", "Select"}; - int num_buttons = sizeof(button_name)/sizeof(button_name[0]); - int button_x_off = button_padding+win_x; - int button_w = dpad_sz1*2+dpad_pos[0]-dpad_sz1-button_padding; - int button_y = win_y+win_h-button_h-button_padding; - typedef struct{const char* button_name; float x; float width; int theme_region;}button_row_t; - button_row_t bottom_row[]={ - {"Select" , button_x_off,button_w*0.67-button_padding, SE_REGION_KEY_SELECT}, - {"Hold" , button_x_off+button_w*0.67,button_w*0.33,SE_REGION_KEY_HOLD}, - {"Turbo", b_pos[0]+win_x-button_r,button_w*0.33,SE_REGION_KEY_TURBO}, - {"Start" , b_pos[0]+win_x-button_r+button_w*0.33+button_padding,button_w*0.67-button_padding,SE_REGION_KEY_START}, + int line_w0 = 1; + int line_w1 = 3; + float button_r = size_scalar * 0.0815; + + float dpad_sz0 = size_scalar * 0.051; + float dpad_sz1 = size_scalar * 0.180; + + float a_pos[2] = {win_w - button_r * 1.5, face_button_h * 0.48 + face_button_y}; + float b_pos[2] = {win_w - button_r * 3.8, face_button_h * 0.54 + face_button_y}; + + // Only have the x and y buttons on screen if the emulated system uses them. + float x_pos[2] = {10e9, 10e9}; + float y_pos[2] = {10e9, 10e9}; + float dpad_pos[2] = {dpad_sz1 + button_padding * 2, face_button_h * 0.5 + face_button_y}; + if(emu_state.system == SYSTEM_GB) { + dpad_pos[1] *= 0.8; + a_pos[1] *= 0.8; + b_pos[1] *= 0.8; + } + + char *button_name[] = {"Start", "Hold", "Turbo", "Select"}; + int num_buttons = sizeof(button_name) / sizeof(button_name[0]); + int button_x_off = button_padding + win_x; + int button_w = dpad_sz1 * 2 + dpad_pos[0] - dpad_sz1 - button_padding; + int button_y = win_y + win_h - button_h - button_padding; + typedef struct { + const char *button_name; + float x; + float width; + int theme_region; + } button_row_t; + button_row_t bottom_row[] = { + {"Select", button_x_off, button_w * 0.67 - button_padding, SE_REGION_KEY_SELECT}, + { "Hold", button_x_off + button_w * 0.67, button_w * 0.33, SE_REGION_KEY_HOLD}, + { "Turbo", b_pos[0] + win_x - button_r, button_w * 0.33, SE_REGION_KEY_TURBO}, + { "Start", b_pos[0] + win_x - button_r + button_w * 0.33 + button_padding, button_w * 0.67 - button_padding, SE_REGION_KEY_START}, }; - button_row_t top_row[]={ - {"L" , button_x_off,button_w,SE_REGION_KEY_L}, - {"R" ,b_pos[0]+win_x-button_r,button_w,SE_REGION_KEY_R}, + button_row_t top_row[] = { + {"L", button_x_off, button_w, SE_REGION_KEY_L}, + {"R", b_pos[0] + win_x - button_r, button_w, SE_REGION_KEY_R}, }; + bool abxy = emu_state.system == SYSTEM_NDS; - bool abxy= emu_state.system==SYSTEM_NDS; - - if(abxy){ - float fx = win_w-button_r*2.65; - float fy = face_button_h*0.5+face_button_y; - a_pos[0] = fx+button_r*1.5; + if(abxy) { + float fx = win_w - button_r * 2.65; + float fy = face_button_h * 0.5 + face_button_y; + a_pos[0] = fx + button_r * 1.5; a_pos[1] = fy; b_pos[0] = fx; - b_pos[1] = fy+button_r*1.5; - + b_pos[1] = fy + button_r * 1.5; + x_pos[0] = fx; - x_pos[1] = fy-button_r*1.5; - - y_pos[0] = fx-button_r*1.5; + x_pos[1] = fy - button_r * 1.5; + + y_pos[0] = fx - button_r * 1.5; y_pos[1] = fy; } - a_pos[0]+=win_x; - b_pos[0]+=win_x; - x_pos[0]+=win_x; - y_pos[0]+=win_x; - dpad_pos[0]+=win_x; + a_pos[0] += win_x; + b_pos[0] += win_x; + x_pos[0] += win_x; + y_pos[0] += win_x; + dpad_pos[0] += win_x; + + a_pos[1] += win_y; + b_pos[1] += win_y; + x_pos[1] += win_y; + y_pos[1] += win_y; + dpad_pos[1] += win_y; - a_pos[1]+=win_y; - b_pos[1]+=win_y; - x_pos[1]+=win_y; - y_pos[1]+=win_y; - dpad_pos[1]+=win_y; + bool a = false, b = false, x = false, y = false, up = false, down = false, left = false, right = false; - bool a=false,b=false, x=false, y=false,up=false,down=false, left=false,right=false; - - enum{max_points = 5}; - float points[max_points][2]={0}; + enum { max_points = 5 }; + float points[max_points][2] = {0}; int p = 0; - //if(IsMouseButtonDown(0))points[p++] = GetMousePosition(); - for(int i=0; i=-dpad_sz1*1.15 && dx<=dpad_sz1*1.15 && dy>=-dpad_sz1*1.15 && dy<=dpad_sz1*1.15 ){ - if(dy>dpad_sz0)down=true; - if(dy<-dpad_sz0)up=true; + int dx = points[i][0] - dpad_pos[0]; + int dy = points[i][1] - dpad_pos[1]; + if(dx >= -dpad_sz1 * 1.15 && dx <= dpad_sz1 * 1.15 && dy >= -dpad_sz1 * 1.15 && dy <= dpad_sz1 * 1.15) { + if(dy > dpad_sz0) down = true; + if(dy < -dpad_sz0) up = true; - if(dx>dpad_sz0)right=true; - if(dx<-dpad_sz0)left=true; + if(dx > dpad_sz0) right = true; + if(dx < -dpad_sz0) left = true; } - if(sb_distance(points[i],a_pos,2)prev_frame_joy.inputs[SE_KEY_A]) prev_pressed |= 1<<0; - if(state->prev_frame_joy.inputs[SE_KEY_B]) prev_pressed |= 1<<1; - if(state->prev_frame_joy.inputs[SE_KEY_X]) prev_pressed |= 1<<2; - if(state->prev_frame_joy.inputs[SE_KEY_Y]) prev_pressed |= 1<<3; - - if(state->prev_frame_joy.inputs[SE_KEY_L]) prev_pressed |= 1<<4; - if(state->prev_frame_joy.inputs[SE_KEY_R]) prev_pressed |= 1<<5; - if(state->prev_frame_joy.inputs[SE_KEY_SELECT]) prev_pressed |= 1<<6; - if(state->prev_frame_joy.inputs[SE_KEY_START]) prev_pressed |= 1<<9; - - float* key_pos[]={ - a_pos, - b_pos, - x_pos, - y_pos - }; - - ImDrawList*dl= igGetWindowDrawList(); - for(int i=0;i<4;++i){ - ImU32 col = SB_BFE(gui_state.touch_controls.hold_toggle,i,1)?hold_color: SB_BFE(gui_state.touch_controls.turbo_toggle,i,1)? turbo_color: line_color; - bool pressed = SB_BFE(button_press|prev_pressed,i,1); - float * pos = key_pos[i]; - - if(se_draw_theme_region_tint(SE_REGION_KEY_A+i*2+(pressed?1:0), - pos[0]-button_r*themed_scale, - pos[1]-button_r*themed_scale, - button_r*2*themed_scale, - button_r*2*themed_scale, - col)); - else if(se_draw_theme_region_tint(SE_REGION_KEY_A+i*2, - pos[0]-button_r*themed_scale, - pos[1]-button_r*themed_scale, - button_r*2*themed_scale, - button_r*2*themed_scale, - col)){ - if(pressed) ImDrawList_AddCircleFilled(dl,(ImVec2){pos[0],pos[1]},button_r,sel_color,128); - - }else if(se_draw_theme_region_tint(SE_REGION_KEY_BLANK+(pressed?1:0), - pos[0]-button_r*themed_scale, - pos[1]-button_r*themed_scale, - button_r*2*themed_scale, - button_r*2*themed_scale, - col)); + int button_press = 0; + + button_press |= a << 0; + button_press |= b << 1; + button_press |= x << 2; + button_press |= y << 3; + + int prev_pressed = 0; + + if(state->prev_frame_joy.inputs[SE_KEY_A]) prev_pressed |= 1 << 0; + if(state->prev_frame_joy.inputs[SE_KEY_B]) prev_pressed |= 1 << 1; + if(state->prev_frame_joy.inputs[SE_KEY_X]) prev_pressed |= 1 << 2; + if(state->prev_frame_joy.inputs[SE_KEY_Y]) prev_pressed |= 1 << 3; + + if(state->prev_frame_joy.inputs[SE_KEY_L]) prev_pressed |= 1 << 4; + if(state->prev_frame_joy.inputs[SE_KEY_R]) prev_pressed |= 1 << 5; + if(state->prev_frame_joy.inputs[SE_KEY_SELECT]) prev_pressed |= 1 << 6; + if(state->prev_frame_joy.inputs[SE_KEY_START]) prev_pressed |= 1 << 9; + + float *key_pos[] = { + a_pos, + b_pos, + x_pos, + y_pos}; + + ImDrawList *dl = igGetWindowDrawList(); + for(int i = 0; i < 4; ++i) { + ImU32 col = SB_BFE(gui_state.touch_controls.hold_toggle, i, 1) ? hold_color : SB_BFE(gui_state.touch_controls.turbo_toggle, i, 1) ? turbo_color + : line_color; + bool pressed = SB_BFE(button_press | prev_pressed, i, 1); + float *pos = key_pos[i]; + + if(se_draw_theme_region_tint(SE_REGION_KEY_A + i * 2 + (pressed ? 1 : 0), + pos[0] - button_r * themed_scale, + pos[1] - button_r * themed_scale, + button_r * 2 * themed_scale, + button_r * 2 * themed_scale, + col)) + ; + else if(se_draw_theme_region_tint(SE_REGION_KEY_A + i * 2, + pos[0] - button_r * themed_scale, + pos[1] - button_r * themed_scale, + button_r * 2 * themed_scale, + button_r * 2 * themed_scale, + col)) { + if(pressed) ImDrawList_AddCircleFilled(dl, (ImVec2){pos[0], pos[1]}, button_r, sel_color, 128); + + } else if(se_draw_theme_region_tint(SE_REGION_KEY_BLANK + (pressed ? 1 : 0), + pos[0] - button_r * themed_scale, + pos[1] - button_r * themed_scale, + button_r * 2 * themed_scale, + button_r * 2 * themed_scale, + col)) + ; else if(se_draw_theme_region_tint(SE_REGION_KEY_BLANK, - pos[0]-button_r*themed_scale, - pos[1]-button_r*themed_scale, - button_r*2*themed_scale, - button_r*2*themed_scale, - col)){ - if(pressed) ImDrawList_AddCircleFilled(dl,(ImVec2){pos[0],pos[1]},button_r,sel_color,128); - }else{ - if(pressed) ImDrawList_AddCircleFilled(dl,(ImVec2){pos[0],pos[1]},button_r,sel_color,128); - ImDrawList_AddCircle(dl,(ImVec2){pos[0],pos[1]},button_r,line_color2,128,line_w1); - ImDrawList_AddCircle(dl,(ImVec2){pos[0],pos[1]},button_r,col,128,line_w0); - } - } - - int dpad_code = up ? 0: down? 6: 3; - dpad_code += left? 0: right? 2: 1; - if(dpad_code==4){ - dpad_code = state->prev_frame_joy.inputs[SE_KEY_UP]>0.2 ? 0: state->prev_frame_joy.inputs[SE_KEY_DOWN]>0.2? 6: 3; - dpad_code += state->prev_frame_joy.inputs[SE_KEY_LEFT]>0.2? 0: state->prev_frame_joy.inputs[SE_KEY_RIGHT]>0.2? 2: 1; - } - bool draw_dpad = !se_draw_theme_region_tint(SE_REGION_DPAD_UL+dpad_code,dpad_pos[0]-dpad_sz1*themed_scale, - dpad_pos[1]-dpad_sz1*themed_scale, - dpad_sz1*2*themed_scale, - dpad_sz1*2*themed_scale, + pos[0] - button_r * themed_scale, + pos[1] - button_r * themed_scale, + button_r * 2 * themed_scale, + button_r * 2 * themed_scale, + col)) { + if(pressed) ImDrawList_AddCircleFilled(dl, (ImVec2){pos[0], pos[1]}, button_r, sel_color, 128); + } else { + if(pressed) ImDrawList_AddCircleFilled(dl, (ImVec2){pos[0], pos[1]}, button_r, sel_color, 128); + ImDrawList_AddCircle(dl, (ImVec2){pos[0], pos[1]}, button_r, line_color2, 128, line_w1); + ImDrawList_AddCircle(dl, (ImVec2){pos[0], pos[1]}, button_r, col, 128, line_w0); + } + } + + int dpad_code = up ? 0 : down ? 6 + : 3; + dpad_code += left ? 0 : right ? 2 + : 1; + if(dpad_code == 4) { + dpad_code = state->prev_frame_joy.inputs[SE_KEY_UP] > 0.2 ? 0 : state->prev_frame_joy.inputs[SE_KEY_DOWN] > 0.2 ? 6 + : 3; + dpad_code += state->prev_frame_joy.inputs[SE_KEY_LEFT] > 0.2 ? 0 : state->prev_frame_joy.inputs[SE_KEY_RIGHT] > 0.2 ? 2 + : 1; + } + bool draw_dpad = !se_draw_theme_region_tint(SE_REGION_DPAD_UL + dpad_code, dpad_pos[0] - dpad_sz1 * themed_scale, + dpad_pos[1] - dpad_sz1 * themed_scale, + dpad_sz1 * 2 * themed_scale, + dpad_sz1 * 2 * themed_scale, line_color); - if(draw_dpad){ - if(!se_draw_theme_region_tint(SE_REGION_DPAD_UL+4,dpad_pos[0]-dpad_sz1*themed_scale, - dpad_pos[1]-dpad_sz1*themed_scale, - dpad_sz1*2*themed_scale, - dpad_sz1*2*themed_scale, - line_color)){ - ImVec2 dpad_points[12]={ - //Up - {dpad_pos[0]-dpad_sz0,dpad_pos[1]+dpad_sz0}, - {dpad_pos[0]-dpad_sz0,dpad_pos[1]+dpad_sz1}, - {dpad_pos[0]+dpad_sz0,dpad_pos[1]+dpad_sz1}, - //right - {dpad_pos[0]+dpad_sz0,dpad_pos[1]+dpad_sz0}, - {dpad_pos[0]+dpad_sz1,dpad_pos[1]+dpad_sz0}, - {dpad_pos[0]+dpad_sz1,dpad_pos[1]-dpad_sz0}, - //Down - {dpad_pos[0]+dpad_sz0,dpad_pos[1]-dpad_sz0}, - {dpad_pos[0]+dpad_sz0,dpad_pos[1]-dpad_sz1}, - {dpad_pos[0]-dpad_sz0,dpad_pos[1]-dpad_sz1}, - //left - {dpad_pos[0]-dpad_sz0,dpad_pos[1]-dpad_sz0}, - {dpad_pos[0]-dpad_sz1,dpad_pos[1]-dpad_sz0}, - {dpad_pos[0]-dpad_sz1,dpad_pos[1]+dpad_sz0}, + if(draw_dpad) { + if(!se_draw_theme_region_tint(SE_REGION_DPAD_UL + 4, dpad_pos[0] - dpad_sz1 * themed_scale, + dpad_pos[1] - dpad_sz1 * themed_scale, + dpad_sz1 * 2 * themed_scale, + dpad_sz1 * 2 * themed_scale, + line_color)) { + ImVec2 dpad_points[12] = { + // Up + {dpad_pos[0] - dpad_sz0, dpad_pos[1] + dpad_sz0}, + {dpad_pos[0] - dpad_sz0, dpad_pos[1] + dpad_sz1}, + {dpad_pos[0] + dpad_sz0, dpad_pos[1] + dpad_sz1}, + // right + {dpad_pos[0] + dpad_sz0, dpad_pos[1] + dpad_sz0}, + {dpad_pos[0] + dpad_sz1, dpad_pos[1] + dpad_sz0}, + {dpad_pos[0] + dpad_sz1, dpad_pos[1] - dpad_sz0}, + // Down + {dpad_pos[0] + dpad_sz0, dpad_pos[1] - dpad_sz0}, + {dpad_pos[0] + dpad_sz0, dpad_pos[1] - dpad_sz1}, + {dpad_pos[0] - dpad_sz0, dpad_pos[1] - dpad_sz1}, + // left + {dpad_pos[0] - dpad_sz0, dpad_pos[1] - dpad_sz0}, + {dpad_pos[0] - dpad_sz1, dpad_pos[1] - dpad_sz0}, + {dpad_pos[0] - dpad_sz1, dpad_pos[1] + dpad_sz0}, }; - ImDrawList_AddPolyline(dl,dpad_points,12,line_color2,true,line_w1); - ImDrawList_AddPolyline(dl,dpad_points,12,line_color,true,line_w0); + ImDrawList_AddPolyline(dl, dpad_points, 12, line_color2, true, line_w1); + ImDrawList_AddPolyline(dl, dpad_points, 12, line_color, true, line_w0); } - - if(dpad_code>=6) ImDrawList_AddRectFilled(dl,(ImVec2){dpad_pos[0]-dpad_sz0,dpad_pos[1]+dpad_sz0},(ImVec2){dpad_pos[0]+dpad_sz0,dpad_pos[1]+dpad_sz1},sel_color,0,ImDrawCornerFlags_None); - if(dpad_code<3) ImDrawList_AddRectFilled(dl,(ImVec2){dpad_pos[0]-dpad_sz0,dpad_pos[1]-dpad_sz1},(ImVec2){dpad_pos[0]+dpad_sz0,dpad_pos[1]-dpad_sz0},sel_color,0,ImDrawCornerFlags_None); + if(dpad_code >= 6) ImDrawList_AddRectFilled(dl, (ImVec2){dpad_pos[0] - dpad_sz0, dpad_pos[1] + dpad_sz0}, (ImVec2){dpad_pos[0] + dpad_sz0, dpad_pos[1] + dpad_sz1}, sel_color, 0, ImDrawCornerFlags_None); + if(dpad_code < 3) ImDrawList_AddRectFilled(dl, (ImVec2){dpad_pos[0] - dpad_sz0, dpad_pos[1] - dpad_sz1}, (ImVec2){dpad_pos[0] + dpad_sz0, dpad_pos[1] - dpad_sz0}, sel_color, 0, ImDrawCornerFlags_None); - if((dpad_code%3)==0) ImDrawList_AddRectFilled(dl,(ImVec2){dpad_pos[0]-dpad_sz1,dpad_pos[1]-dpad_sz0},(ImVec2){dpad_pos[0]-dpad_sz0,dpad_pos[1]+dpad_sz0},sel_color,0,ImDrawCornerFlags_None); - if((dpad_code%3)==2)ImDrawList_AddRectFilled(dl,(ImVec2){dpad_pos[0]+dpad_sz0,dpad_pos[1]-dpad_sz0},(ImVec2){dpad_pos[0]+dpad_sz1,dpad_pos[1]+dpad_sz0},sel_color,0,ImDrawCornerFlags_None); + if((dpad_code % 3) == 0) ImDrawList_AddRectFilled(dl, (ImVec2){dpad_pos[0] - dpad_sz1, dpad_pos[1] - dpad_sz0}, (ImVec2){dpad_pos[0] - dpad_sz0, dpad_pos[1] + dpad_sz0}, sel_color, 0, ImDrawCornerFlags_None); + if((dpad_code % 3) == 2) ImDrawList_AddRectFilled(dl, (ImVec2){dpad_pos[0] + dpad_sz0, dpad_pos[1] - dpad_sz0}, (ImVec2){dpad_pos[0] + dpad_sz1, dpad_pos[1] + dpad_sz0}, sel_color, 0, ImDrawCornerFlags_None); } - - int hold_button =1; - int turbo_button =2; - if(gui_state.settings.touch_controls_show_turbo==false){ + + int hold_button = 1; + int turbo_button = 2; + if(gui_state.settings.touch_controls_show_turbo == false) { bottom_row[0].width = button_w; - bottom_row[1].width = 0; - bottom_row[2].width = 0; - bottom_row[3].width = button_w; + bottom_row[1].width = 0; + bottom_row[2].width = 0; + bottom_row[3].width = button_w; bottom_row[3].x = bottom_row[2].x; - gui_state.touch_controls.hold_toggle=gui_state.touch_controls.turbo_toggle=0; - gui_state.touch_controls.last_hold_toggle_presses= gui_state.touch_controls.last_turbo_toggle_presses=0; + gui_state.touch_controls.hold_toggle = gui_state.touch_controls.turbo_toggle = 0; + gui_state.touch_controls.last_hold_toggle_presses = gui_state.touch_controls.last_turbo_toggle_presses = 0; } - for(int b=0;b=-(x_max-x_min)*0.05 && dx<=(x_max-x_min)*1.05 && dy>=0 && dy<=button_h ){ - button_press|=1<<(b+6); - pressed=true; - region+=1; + int x_max = bottom_row[b].x + bottom_row[b].width; + if(bottom_row[b].width == 0) continue; + int region = bottom_row[b].theme_region; + bool pressed = SB_BFE(prev_pressed, 6 + b, 1); + for(int i = 0; i < p; ++i) { + int dx = points[i][0] - x_min; + int dy = points[i][1] - button_y; + if(dx >= -(x_max - x_min) * 0.05 && dx <= (x_max - x_min) * 1.05 && dy >= 0 && dy <= button_h) { + button_press |= 1 << (b + 6); + pressed = true; + region += 1; } } ImU32 col = line_color; - if(b==turbo_button&&(pressed || gui_state.touch_controls.turbo_toggle))col=turbo_color; - if(b==hold_button&&(pressed || gui_state.touch_controls.hold_toggle))col=hold_color; - if(SB_BFE(gui_state.touch_controls.hold_toggle,b+6,1))col = hold_color; - if(SB_BFE(gui_state.touch_controls.turbo_toggle,b+6,1))col = turbo_color; - if(!se_draw_theme_region_tint(region+pressed,x_min,button_y,x_max-x_min,button_h,col)){ - if(!se_draw_theme_region_tint(region,x_min,button_y,x_max-x_min,button_h,col)){ - ImDrawList_AddRect(dl,(ImVec2){x_min,button_y},(ImVec2){x_max,button_y+button_h},line_color2,0,ImDrawCornerFlags_None,line_w1); - ImDrawList_AddRect(dl,(ImVec2){x_min,button_y},(ImVec2){x_max,button_y+button_h},col,0,ImDrawCornerFlags_None,line_w0); + if(b == turbo_button && (pressed || gui_state.touch_controls.turbo_toggle)) col = turbo_color; + if(b == hold_button && (pressed || gui_state.touch_controls.hold_toggle)) col = hold_color; + if(SB_BFE(gui_state.touch_controls.hold_toggle, b + 6, 1)) col = hold_color; + if(SB_BFE(gui_state.touch_controls.turbo_toggle, b + 6, 1)) col = turbo_color; + if(!se_draw_theme_region_tint(region + pressed, x_min, button_y, x_max - x_min, button_h, col)) { + if(!se_draw_theme_region_tint(region, x_min, button_y, x_max - x_min, button_h, col)) { + ImDrawList_AddRect(dl, (ImVec2){x_min, button_y}, (ImVec2){x_max, button_y + button_h}, line_color2, 0, ImDrawCornerFlags_None, line_w1); + ImDrawList_AddRect(dl, (ImVec2){x_min, button_y}, (ImVec2){x_max, button_y + button_h}, col, 0, ImDrawCornerFlags_None, line_w0); } - if(pressed){ - ImDrawList_AddRectFilled(dl,(ImVec2){x_min,button_y},(ImVec2){x_max,button_y+button_h},sel_color,0,ImDrawCornerFlags_None); + if(pressed) { + ImDrawList_AddRectFilled(dl, (ImVec2){x_min, button_y}, (ImVec2){x_max, button_y + button_h}, sel_color, 0, ImDrawCornerFlags_None); } } } - button_y=win_y+button_padding; - if(emu_state.system!=SYSTEM_GB){ - for(int b=0;b=-(x_max-x_min)*0.05 && dx<=(x_max-x_min)*1.05 && dy>=0 && dy<=button_h ){ - button_press|=1<<(b+4); - pressed=true; + button_y = win_y + button_padding; + if(emu_state.system != SYSTEM_GB) { + for(int b = 0; b < sizeof(top_row) / sizeof(top_row[0]); ++b) { + int state = 0; + int x_min = top_row[b].x; + ; + int x_max = top_row[b].x + top_row[b].width; + bool pressed = SB_BFE(prev_pressed, 4 + b, 1); + int region = top_row[b].theme_region; + for(int i = 0; i < p; ++i) { + int dx = points[i][0] - x_min; + int dy = points[i][1] - button_y; + if(dx >= -(x_max - x_min) * 0.05 && dx <= (x_max - x_min) * 1.05 && dy >= 0 && dy <= button_h) { + button_press |= 1 << (b + 4); + pressed = true; region++; } } ImU32 col = line_color; - if(SB_BFE(gui_state.touch_controls.hold_toggle,b+4,1))col = hold_color; - if(SB_BFE(gui_state.touch_controls.turbo_toggle,b+4,1))col = turbo_color; - if(!se_draw_theme_region_tint(region+pressed,x_min,button_y,x_max-x_min,button_h,col)){ - if(!se_draw_theme_region_tint(region,x_min,button_y,x_max-x_min,button_h,col)){ - ImDrawList_AddRect(dl,(ImVec2){x_min,button_y},(ImVec2){x_max,button_y+button_h},line_color2,0,ImDrawCornerFlags_None,line_w1); - ImDrawList_AddRect(dl,(ImVec2){x_min,button_y},(ImVec2){x_max,button_y+button_h},col,0,ImDrawCornerFlags_None,line_w0); + if(SB_BFE(gui_state.touch_controls.hold_toggle, b + 4, 1)) col = hold_color; + if(SB_BFE(gui_state.touch_controls.turbo_toggle, b + 4, 1)) col = turbo_color; + if(!se_draw_theme_region_tint(region + pressed, x_min, button_y, x_max - x_min, button_h, col)) { + if(!se_draw_theme_region_tint(region, x_min, button_y, x_max - x_min, button_h, col)) { + ImDrawList_AddRect(dl, (ImVec2){x_min, button_y}, (ImVec2){x_max, button_y + button_h}, line_color2, 0, ImDrawCornerFlags_None, line_w1); + ImDrawList_AddRect(dl, (ImVec2){x_min, button_y}, (ImVec2){x_max, button_y + button_h}, col, 0, ImDrawCornerFlags_None, line_w0); } - if(pressed)ImDrawList_AddRectFilled(dl,(ImVec2){x_min,button_y},(ImVec2){x_max,button_y+button_h},sel_color,0,ImDrawCornerFlags_None); + if(pressed) ImDrawList_AddRectFilled(dl, (ImVec2){x_min, button_y}, (ImVec2){x_max, button_y + button_h}, sel_color, 0, ImDrawCornerFlags_None); } } } + bool hold = SB_BFE(button_press, 7, 1); + bool turbo = SB_BFE(button_press, 8, 1); + state->joy.inputs[SE_KEY_START] += SB_BFE(button_press, 9, 1); - bool hold = SB_BFE(button_press,7,1); - bool turbo = SB_BFE(button_press,8,1); - state->joy.inputs[SE_KEY_START] += SB_BFE(button_press,9,1); - - if(hold)turbo=false; + if(hold) turbo = false; - uint32_t hold_mask = hold? button_press:0; - uint32_t turbo_mask = turbo? button_press: 0; + uint32_t hold_mask = hold ? button_press : 0; + uint32_t turbo_mask = turbo ? button_press : 0; - //Prevent the hold and turbo buttons from being held or turbo'd - uint32_t valid_hold_turbo_mask = ~((1<<7)|(1<<8)); - hold_mask&=valid_hold_turbo_mask; - turbo_mask&=valid_hold_turbo_mask; + // Prevent the hold and turbo buttons from being held or turbo'd + uint32_t valid_hold_turbo_mask = ~((1 << 7) | (1 << 8)); + hold_mask &= valid_hold_turbo_mask; + turbo_mask &= valid_hold_turbo_mask; - gui_state.touch_controls.hold_toggle^= hold_mask&~gui_state.touch_controls.last_hold_toggle_presses; - gui_state.touch_controls.turbo_toggle^= turbo_mask&~gui_state.touch_controls.last_turbo_toggle_presses; - gui_state.touch_controls.turbo_toggle&= ~(hold_mask&~gui_state.touch_controls.last_hold_toggle_presses); - gui_state.touch_controls.hold_toggle&= ~(turbo_mask&~gui_state.touch_controls.last_turbo_toggle_presses); + gui_state.touch_controls.hold_toggle ^= hold_mask & ~gui_state.touch_controls.last_hold_toggle_presses; + gui_state.touch_controls.turbo_toggle ^= turbo_mask & ~gui_state.touch_controls.last_turbo_toggle_presses; + gui_state.touch_controls.turbo_toggle &= ~(hold_mask & ~gui_state.touch_controls.last_hold_toggle_presses); + gui_state.touch_controls.hold_toggle &= ~(turbo_mask & ~gui_state.touch_controls.last_turbo_toggle_presses); - if(!hold&&!turbo){ - gui_state.touch_controls.turbo_toggle&= ~(button_press); - gui_state.touch_controls.hold_toggle&= ~(button_press); + if(!hold && !turbo) { + gui_state.touch_controls.turbo_toggle &= ~(button_press); + gui_state.touch_controls.hold_toggle &= ~(button_press); } gui_state.touch_controls.last_hold_toggle_presses = hold_mask; gui_state.touch_controls.last_turbo_toggle_presses = turbo_mask; - if(turbo_t>0.5)button_press|=gui_state.touch_controls.turbo_toggle; - button_press|=gui_state.touch_controls.hold_toggle; + if(turbo_t > 0.5) button_press |= gui_state.touch_controls.turbo_toggle; + button_press |= gui_state.touch_controls.hold_toggle; - state->joy.inputs[SE_KEY_LEFT] += left; + state->joy.inputs[SE_KEY_LEFT] += left; state->joy.inputs[SE_KEY_RIGHT] += right; - state->joy.inputs[SE_KEY_UP] += up; - state->joy.inputs[SE_KEY_DOWN] += down; - - state->joy.inputs[SE_KEY_A] += SB_BFE(button_press,0,1); - state->joy.inputs[SE_KEY_B] += SB_BFE(button_press,1,1); - state->joy.inputs[SE_KEY_X] += SB_BFE(button_press,2,1); - state->joy.inputs[SE_KEY_Y] += SB_BFE(button_press,3,1); - - state->joy.inputs[SE_KEY_L] += SB_BFE(button_press,4,1); - state->joy.inputs[SE_KEY_R] += SB_BFE(button_press,5,1); - state->joy.inputs[SE_KEY_SELECT] += SB_BFE(button_press,6,1); -} -void se_update_key_turbo(sb_emu_state_t *state){ - double t = se_time()*15; - bool turbo_press = (t-(int)t)>0.5; - if(turbo_press){ - state->joy.inputs[SE_KEY_A]+=state->joy.inputs[SE_KEY_TURBO_A]; - state->joy.inputs[SE_KEY_B]+=state->joy.inputs[SE_KEY_TURBO_B]; - state->joy.inputs[SE_KEY_X]+=state->joy.inputs[SE_KEY_TURBO_X]; - state->joy.inputs[SE_KEY_Y]+=state->joy.inputs[SE_KEY_TURBO_Y]; - state->joy.inputs[SE_KEY_L]+=state->joy.inputs[SE_KEY_TURBO_L]; - state->joy.inputs[SE_KEY_R]+=state->joy.inputs[SE_KEY_TURBO_R]; - } -} -void se_update_solar_sensor(sb_emu_state_t*state){ - static double last_t =0; - double dt = se_time()-last_t; - - state->joy.solar_sensor-=state->joy.inputs[SE_KEY_SOLAR_M]*dt*0.5; - state->joy.solar_sensor+=state->joy.inputs[SE_KEY_SOLAR_P]*dt*0.5; - if(state->joy.solar_sensor>1.0)state->joy.solar_sensor=1.0; - if(state->joy.solar_sensor<0.0)state->joy.solar_sensor=0.0; + state->joy.inputs[SE_KEY_UP] += up; + state->joy.inputs[SE_KEY_DOWN] += down; + + state->joy.inputs[SE_KEY_A] += SB_BFE(button_press, 0, 1); + state->joy.inputs[SE_KEY_B] += SB_BFE(button_press, 1, 1); + state->joy.inputs[SE_KEY_X] += SB_BFE(button_press, 2, 1); + state->joy.inputs[SE_KEY_Y] += SB_BFE(button_press, 3, 1); + + state->joy.inputs[SE_KEY_L] += SB_BFE(button_press, 4, 1); + state->joy.inputs[SE_KEY_R] += SB_BFE(button_press, 5, 1); + state->joy.inputs[SE_KEY_SELECT] += SB_BFE(button_press, 6, 1); +} +void se_update_key_turbo(sb_emu_state_t *state) { + double t = se_time() * 15; + bool turbo_press = (t - (int)t) > 0.5; + if(turbo_press) { + state->joy.inputs[SE_KEY_A] += state->joy.inputs[SE_KEY_TURBO_A]; + state->joy.inputs[SE_KEY_B] += state->joy.inputs[SE_KEY_TURBO_B]; + state->joy.inputs[SE_KEY_X] += state->joy.inputs[SE_KEY_TURBO_X]; + state->joy.inputs[SE_KEY_Y] += state->joy.inputs[SE_KEY_TURBO_Y]; + state->joy.inputs[SE_KEY_L] += state->joy.inputs[SE_KEY_TURBO_L]; + state->joy.inputs[SE_KEY_R] += state->joy.inputs[SE_KEY_TURBO_R]; + } +} +void se_update_solar_sensor(sb_emu_state_t *state) { + static double last_t = 0; + double dt = se_time() - last_t; + + state->joy.solar_sensor -= state->joy.inputs[SE_KEY_SOLAR_M] * dt * 0.5; + state->joy.solar_sensor += state->joy.inputs[SE_KEY_SOLAR_P] * dt * 0.5; + if(state->joy.solar_sensor > 1.0) state->joy.solar_sensor = 1.0; + if(state->joy.solar_sensor < 0.0) state->joy.solar_sensor = 0.0; last_t = se_time(); } -void se_text_centered_in_box(ImVec2 p, ImVec2 size, const char* text){ +void se_text_centered_in_box(ImVec2 p, ImVec2 size, const char *text) { ImVec2 curr_cursor; igGetCursorPos(&curr_cursor); ImVec2 backup_cursor = curr_cursor; ImVec2 curr_cursor_screen; igGetCursorScreenPos(&curr_cursor_screen); - curr_cursor.x+=p.x; - curr_cursor.y+=p.y; - curr_cursor_screen.x+=p.x; - curr_cursor_screen.y+=p.y; + curr_cursor.x += p.x; + curr_cursor.y += p.y; + curr_cursor_screen.x += p.x; + curr_cursor_screen.y += p.y; ImU32 color = igColorConvertFloat4ToU32(igGetStyle()->Colors[ImGuiCol_ButtonActive]); - ImDrawList_AddRectFilled(igGetWindowDrawList(),curr_cursor_screen,(ImVec2){curr_cursor_screen.x+size.x,curr_cursor_screen.y+size.y},color,0,ImDrawCornerFlags_None); + ImDrawList_AddRectFilled(igGetWindowDrawList(), curr_cursor_screen, (ImVec2){curr_cursor_screen.x + size.x, curr_cursor_screen.y + size.y}, color, 0, ImDrawCornerFlags_None); - ImVec2 text_sz; - igCalcTextSize(&text_sz, text,NULL,0,0); + ImVec2 text_sz; + igCalcTextSize(&text_sz, text, NULL, 0, 0); - curr_cursor.x+=(size.x-text_sz.x)*0.5; - curr_cursor.y+=(size.y-text_sz.y)*0.5; + curr_cursor.x += (size.x - text_sz.x) * 0.5; + curr_cursor.y += (size.y - text_sz.y) * 0.5; igSetCursorPos(curr_cursor); se_text(text); igSetCursorPos(backup_cursor); } -//CPU: 73%->48 -bool se_selectable_with_box(const char * first_label, const char* second_label, const char* box, bool force_hover, int reduce_width){ - ImVec2 win_min,win_sz,win_max; - win_min.x=0; - win_min.y=0; // content boundaries min (roughly (0,0)-Scroll), in window coordinates +// CPU: 73%->48 +bool se_selectable_with_box(const char *first_label, const char *second_label, const char *box, bool force_hover, int reduce_width) { + ImVec2 win_min, win_sz, win_max; + win_min.x = 0; + win_min.y = 0; // content boundaries min (roughly (0,0)-Scroll), in window coordinates igGetWindowSize(&win_sz); - win_min.y+=igGetScrollY(); - win_max.x = win_min.x+win_sz.x; - win_max.y = win_min.y+win_sz.y; + win_min.y += igGetScrollY(); + win_max.x = win_min.x + win_sz.x; + win_max.y = win_min.y + win_sz.y; - int item_height = 40; - int padding = 4; + int item_height = 40; + int padding = 4; float disp_y_min = igGetCursorPosY(); - float disp_y_max = disp_y_min+item_height+padding*2; - //Early out if not visible (helps for long lists) - if(disp_y_maxwin_max.y){ + float disp_y_max = disp_y_min + item_height + padding * 2; + // Early out if not visible (helps for long lists) + if(disp_y_max < win_min.y || disp_y_min > win_max.y) { igSetCursorPosY(disp_y_max); return false; } #ifdef UNICODE_GUI - first_label= (const char*)utf8proc_NFC((const utf8proc_uint8_t *)first_label); - second_label= (const char*)utf8proc_NFC((const utf8proc_uint8_t *)second_label); + first_label = (const char *)utf8proc_NFC((const utf8proc_uint8_t *)first_label); + second_label = (const char *)utf8proc_NFC((const utf8proc_uint8_t *)second_label); #endif - int box_h = item_height-padding*2; - int box_w = box_h; + int box_h = item_height - padding * 2; + int box_w = box_h; bool clicked = false; igPushIDStr(second_label); - ImVec2 curr_pos; + ImVec2 curr_pos; igGetCursorPos(&curr_pos); - curr_pos.y+=padding; - curr_pos.x+=padding; - if(igSelectableBool("",force_hover,ImGuiSelectableFlags_None, (ImVec2){igGetWindowContentRegionWidth()-reduce_width,item_height}))clicked=true; + curr_pos.y += padding; + curr_pos.x += padding; + if(igSelectableBool("", force_hover, ImGuiSelectableFlags_None, (ImVec2){igGetWindowContentRegionWidth() - reduce_width, item_height})) clicked = true; ImVec2 next_pos; igGetCursorPos(&next_pos); igSetCursorPos(curr_pos); - ImVec2 rect_p = (ImVec2){0,0}; - se_text_centered_in_box((ImVec2){0,0}, (ImVec2){box_w,box_h},box); - igSetCursorPosY(curr_pos.y-padding*0.5); - igSetCursorPosX(curr_pos.x+box_w); - igBeginChildFrame(igGetIDStr(first_label),(ImVec2){igGetWindowContentRegionWidth()-box_w-padding-reduce_width,item_height},ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoBackground|ImGuiWindowFlags_NoInputs); + ImVec2 rect_p = (ImVec2){0, 0}; + se_text_centered_in_box((ImVec2){0, 0}, (ImVec2){box_w, box_h}, box); + igSetCursorPosY(curr_pos.y - padding * 0.5); + igSetCursorPosX(curr_pos.x + box_w); + igBeginChildFrame(igGetIDStr(first_label), (ImVec2){igGetWindowContentRegionWidth() - box_w - padding - reduce_width, item_height}, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs); se_text(first_label); se_text_disabled(second_label); igEndChildFrame(); igSetCursorPos(next_pos); igPopID(); #ifdef UNICODE_GUI - free((void*)first_label); - free((void*)second_label); + free((void *)first_label); + free((void *)second_label); #endif - return clicked; + return clicked; } #ifdef PLATFORM_ANDROID #include #define TAG "SkyEmu" -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) -#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) -void se_android_open_file_picker(){ - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); +void se_android_open_file_picker() { + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); - if ( nResult != JNI_ERR ) - { - // Retrieves NativeActivity. - jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity ); - jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "openFile", "()V" ); - (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard ); - + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); + if(nResult != JNI_ERR) { + // Retrieves NativeActivity. + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "openFile", "()V"); + (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard); - // Finished with the JVM. - (*pJavaVM)->DetachCurrentThread(pJavaVM); + // Finished with the JVM. + (*pJavaVM)->DetachCurrentThread(pJavaVM); } } -float se_android_get_display_dpi_scale(){ - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); +float se_android_get_display_dpi_scale() { + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); float result = 1.0; - if ( nResult != JNI_ERR ){ + if(nResult != JNI_ERR) { // Retrieves NativeActivity. - jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity ); - jmethodID MethodDPI= (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getDPIScale", "()F" ); - result = (*pJNIEnv)->CallFloatMethod(pJNIEnv, nativeActivity, MethodDPI ); + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + jmethodID MethodDPI = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getDPIScale", "()F"); + result = (*pJNIEnv)->CallFloatMethod(pJNIEnv, nativeActivity, MethodDPI); // Finished with the JVM. (*pJavaVM)->DetachCurrentThread(pJavaVM); } return result; } -void se_android_get_visible_rect(float * top, float * bottom){ - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); +void se_android_get_visible_rect(float *top, float *bottom) { + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); - if ( nResult != JNI_ERR ){ + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); + if(nResult != JNI_ERR) { // Retrieves NativeActivity. - jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity ); - jmethodID MethodBottom= (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getVisibleBottom", "()F" ); - *bottom = (*pJNIEnv)->CallFloatMethod(pJNIEnv, nativeActivity, MethodBottom )/se_dpi_scale(); - jmethodID MethodTop= (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getVisibleTop", "()F" ); - *top = (*pJNIEnv)->CallFloatMethod(pJNIEnv, nativeActivity, MethodTop )/se_dpi_scale(); + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + jmethodID MethodBottom = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getVisibleBottom", "()F"); + *bottom = (*pJNIEnv)->CallFloatMethod(pJNIEnv, nativeActivity, MethodBottom) / se_dpi_scale(); + jmethodID MethodTop = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getVisibleTop", "()F"); + *top = (*pJNIEnv)->CallFloatMethod(pJNIEnv, nativeActivity, MethodTop) / se_dpi_scale(); // Finished with the JVM. (*pJavaVM)->DetachCurrentThread(pJavaVM); } } -void se_android_get_language(char* language_buffer, size_t buffer_size){ +void se_android_get_language(char *language_buffer, size_t buffer_size) { - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); - if ( nResult != JNI_ERR ){ + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); + if(nResult != JNI_ERR) { // Retrieves NativeActivity. - jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity ); - jmethodID getLanguageMethod= (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getLanguage", "()Ljava/lang/String;" ); + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + jmethodID getLanguageMethod = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getLanguage", "()Ljava/lang/String;"); if(getLanguageMethod) { - jstring joStringPropVal = (jstring) (*pJNIEnv)->CallStaticObjectMethod(pJNIEnv,ClassNativeActivity,getLanguageMethod); - const jchar *jcVal = (*pJNIEnv)->GetStringUTFChars(pJNIEnv, joStringPropVal, JNI_FALSE); - LOGD("Android Language is %s", jcVal); - strncpy(language_buffer, jcVal, buffer_size); - (*pJNIEnv)->ReleaseStringChars(pJNIEnv, joStringPropVal, jcVal); - }else LOGE("Failed to find getLanguage() method in JNIEnv"); + jstring joStringPropVal = (jstring)(*pJNIEnv)->CallStaticObjectMethod(pJNIEnv, ClassNativeActivity, getLanguageMethod); + const jchar *jcVal = (*pJNIEnv)->GetStringUTFChars(pJNIEnv, joStringPropVal, JNI_FALSE); + LOGD("Android Language is %s", jcVal); + strncpy(language_buffer, jcVal, buffer_size); + (*pJNIEnv)->ReleaseStringChars(pJNIEnv, joStringPropVal, jcVal); + } else + LOGE("Failed to find getLanguage() method in JNIEnv"); // Finished with the JVM. (*pJavaVM)->DetachCurrentThread(pJavaVM); } @@ -4072,35 +4139,34 @@ void se_android_get_language(char* language_buffer, size_t buffer_size){ void se_android_send_controller_key(uint32_t bound_id, bool value) { se_controller_state_t *cont = &gui_state.controller; - for(int k= 0; kkey.bound_id[k]; - if(key!=bound_id)continue; + if(key != bound_id) continue; cont->key.value[k] = value; } } -void se_android_poll_events(bool visible){ +void se_android_poll_events(bool visible) { se_controller_state_t *cont = &gui_state.controller; - cont->key.last_bind_activitiy=-1; - cont->analog.last_bind_activitiy=-1; + cont->key.last_bind_activitiy = -1; + cont->analog.last_bind_activitiy = -1; static bool last_visible = false; - if(visible!=last_visible){ - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); + if(visible != last_visible) { + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); - if ( nResult != JNI_ERR ) - { + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); + if(nResult != JNI_ERR) { // Retrieves NativeActivity. jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity ); - if(visible){ - jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "showKeyboard", "()V" ); - (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard ); - }else{ - jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "hideKeyboard", "()V" ); - (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard ); + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + if(visible) { + jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "showKeyboard", "()V"); + (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard); + } else { + jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "hideKeyboard", "()V"); + (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard); } // Finished with the JVM. (*pJavaVM)->DetachCurrentThread(pJavaVM); @@ -4110,64 +4176,63 @@ void se_android_poll_events(bool visible){ float top = 0; float bottom = 0; se_android_get_visible_rect(&top, &bottom); - float size = (bottom-top); - gui_state.screen_height= (bottom-top)*se_dpi_scale(); + float size = (bottom - top); + gui_state.screen_height = (bottom - top) * se_dpi_scale(); - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); - if ( nResult != JNI_ERR ) { + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); + if(nResult != JNI_ERR) { // Retrieves NativeActivity. - jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); - jmethodID getEvent= (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getEvent", "()I" ); - jmethodID pollKeyboard= (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "pollKeyboard", "()V" ); - (*pJNIEnv)->CallIntMethod(pJNIEnv, nativeActivity, pollKeyboard ); - ImGuiIO* io= igGetIO(); - - io->KeysDown[io->KeyMap[ImGuiKey_Backspace]]=false; - io->KeysDown[io->KeyMap[ImGuiKey_LeftArrow]]=false; - io->KeysDown[io->KeyMap[ImGuiKey_RightArrow]]=false; - io->KeysDown[io->KeyMap[ImGuiKey_Enter]]=false; - while (true) { - int32_t event = (*pJNIEnv)->CallIntMethod(pJNIEnv, nativeActivity, getEvent ); - if(event==-1)break; - if(!(event&0xF0000000)) - ImGuiIO_AddInputCharacter(igGetIO(),event&0x0fffffff); - else if(event&0x40000000){ - int imgui_key = io->KeyMap[event&0xff]; - io->KeysDown[imgui_key] = (event&0x80000000)==0; - io->KeysDownDuration[imgui_key]=0; - }else if(event&0x20000000){ - //Controller keypad - int keycode = SB_BFE(event,0,16); - int pressed = SB_BFE(event,16,1); + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + jmethodID getEvent = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "getEvent", "()I"); + jmethodID pollKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "pollKeyboard", "()V"); + (*pJNIEnv)->CallIntMethod(pJNIEnv, nativeActivity, pollKeyboard); + ImGuiIO *io = igGetIO(); + + io->KeysDown[io->KeyMap[ImGuiKey_Backspace]] = false; + io->KeysDown[io->KeyMap[ImGuiKey_LeftArrow]] = false; + io->KeysDown[io->KeyMap[ImGuiKey_RightArrow]] = false; + io->KeysDown[io->KeyMap[ImGuiKey_Enter]] = false; + while(true) { + int32_t event = (*pJNIEnv)->CallIntMethod(pJNIEnv, nativeActivity, getEvent); + if(event == -1) break; + if(!(event & 0xF0000000)) + ImGuiIO_AddInputCharacter(igGetIO(), event & 0x0fffffff); + else if(event & 0x40000000) { + int imgui_key = io->KeyMap[event & 0xff]; + io->KeysDown[imgui_key] = (event & 0x80000000) == 0; + io->KeysDownDuration[imgui_key] = 0; + } else if(event & 0x20000000) { + // Controller keypad + int keycode = SB_BFE(event, 0, 16); + int pressed = SB_BFE(event, 16, 1); cont->key.last_bind_activitiy = keycode; - se_android_send_controller_key(keycode,pressed); - }else if(event&0x10000000){ - //Controller joy axis - int16_t value = SB_BFE(event,0,16); - float fv = value/32768.; - int axis = SB_BFE(event,16,8); - - if(fv<0.2&&fv>-0.2 && (int)axis < sizeof(cont->axis_last_zero_time)/sizeof(cont->axis_last_zero_time[0])){ - cont->axis_last_zero_time[axis]=se_time(); + se_android_send_controller_key(keycode, pressed); + } else if(event & 0x10000000) { + // Controller joy axis + int16_t value = SB_BFE(event, 0, 16); + float fv = value / 32768.; + int axis = SB_BFE(event, 16, 8); + + if(fv < 0.2 && fv > -0.2 && (int)axis < sizeof(cont->axis_last_zero_time) / sizeof(cont->axis_last_zero_time[0])) { + cont->axis_last_zero_time[axis] = se_time(); } - if((fv>0.3)||(fv<-0.3&&fv>-0.6))cont->analog.last_bind_activitiy = axis; - double delta = se_time()-cont->axis_last_zero_time[axis]; - - if(fv>0.4&&delta<2)cont->key.last_bind_activitiy = axis|SE_JOY_POS_MASK; - if(fv<-0.4&&delta<2)cont->key.last_bind_activitiy = axis|SE_JOY_NEG_MASK; - se_android_send_controller_key(axis|SE_JOY_POS_MASK,fv>0.3); - se_android_send_controller_key(axis|SE_JOY_NEG_MASK,fv<-0.3); - for(int a= 0; aanalog.bound_id[a]; - if(axis==bound_id){ - cont->analog.value[a]= fv; + if((fv > 0.3) || (fv < -0.3 && fv > -0.6)) cont->analog.last_bind_activitiy = axis; + double delta = se_time() - cont->axis_last_zero_time[axis]; + + if(fv > 0.4 && delta < 2) cont->key.last_bind_activitiy = axis | SE_JOY_POS_MASK; + if(fv < -0.4 && delta < 2) cont->key.last_bind_activitiy = axis | SE_JOY_NEG_MASK; + se_android_send_controller_key(axis | SE_JOY_POS_MASK, fv > 0.3); + se_android_send_controller_key(axis | SE_JOY_NEG_MASK, fv < -0.3); + for(int a = 0; a < SE_NUM_ANALOGBINDS; ++a) { + int bound_id = cont->analog.bound_id[a]; + if(axis == bound_id) { + cont->analog.value[a] = fv; break; } } @@ -4176,46 +4241,45 @@ void se_android_poll_events(bool visible){ (*pJavaVM)->DetachCurrentThread(pJavaVM); } - for(int i=0;ikey.value[i]>0.5; + for(int i = 0; i < SE_NUM_KEYBINDS; ++i) + emu_state.joy.inputs[i] += cont->key.value[i] > 0.5; - emu_state.joy.inputs[SE_KEY_LEFT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT]<-0.3; - emu_state.joy.inputs[SE_KEY_RIGHT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT]> 0.3; - emu_state.joy.inputs[SE_KEY_UP] += cont->analog.value[SE_ANALOG_UP_DOWN]<-0.3; - emu_state.joy.inputs[SE_KEY_DOWN] += cont->analog.value[SE_ANALOG_UP_DOWN]>0.3; + emu_state.joy.inputs[SE_KEY_LEFT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT] < -0.3; + emu_state.joy.inputs[SE_KEY_RIGHT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT] > 0.3; + emu_state.joy.inputs[SE_KEY_UP] += cont->analog.value[SE_ANALOG_UP_DOWN] < -0.3; + emu_state.joy.inputs[SE_KEY_DOWN] += cont->analog.value[SE_ANALOG_UP_DOWN] > 0.3; - emu_state.joy.inputs[SE_KEY_L] += cont->analog.value[SE_ANALOG_L]>0.1; - emu_state.joy.inputs[SE_KEY_R] += cont->analog.value[SE_ANALOG_R]>0.1; + emu_state.joy.inputs[SE_KEY_L] += cont->analog.value[SE_ANALOG_L] > 0.1; + emu_state.joy.inputs[SE_KEY_R] += cont->analog.value[SE_ANALOG_R] > 0.1; } -void se_android_request_permissions(){ - ANativeActivity* activity =(ANativeActivity*)sapp_android_get_native_activity(); +void se_android_request_permissions() { + ANativeActivity *activity = (ANativeActivity *)sapp_android_get_native_activity(); // Attaches the current thread to the JVM. JavaVM *pJavaVM = activity->vm; JNIEnv *pJNIEnv = activity->env; - jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL ); - if ( nResult != JNI_ERR ) - { - // Retrieves NativeActivity. - jobject nativeActivity = activity->clazz; - jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity ); - jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "requestPermissions", "()V" ); - (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard ); - + jint nResult = (*pJavaVM)->AttachCurrentThread(pJavaVM, &pJNIEnv, NULL); + if(nResult != JNI_ERR) { + // Retrieves NativeActivity. + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = (*pJNIEnv)->GetObjectClass(pJNIEnv, nativeActivity); + jmethodID MethodShowKeyboard = (*pJNIEnv)->GetMethodID(pJNIEnv, ClassNativeActivity, "requestPermissions", "()V"); + (*pJNIEnv)->CallVoidMethod(pJNIEnv, nativeActivity, MethodShowKeyboard); - // Finished with the JVM. - (*pJavaVM)->DetachCurrentThread(pJavaVM); + // Finished with the JVM. + (*pJavaVM)->DetachCurrentThread(pJavaVM); } } #endif #ifdef EMSCRIPTEN -void se_download_emscripten_file(const char * path){ - const char * base,*file, *ext; - sb_breakup_path(path,&base,&file,&ext); +void se_download_emscripten_file(const char *path) { + const char *base, *file, *ext; + sb_breakup_path(path, &base, &file, &ext); char name[SB_FILE_PATH_SIZE]; - snprintf(name,SB_FILE_PATH_SIZE,"%s.%s",file,ext); - size_t data_size; - uint8_t*data = sb_load_file_data(path,&data_size); + snprintf(name, SB_FILE_PATH_SIZE, "%s.%s", file, ext); + size_t data_size; + uint8_t *data = sb_load_file_data(path, &data_size); EM_ASM_({ name = $0; @@ -4238,55 +4302,55 @@ void se_download_emscripten_file(const char * path){ }, name, data, data_size); free(data); } -#endif +#endif -void se_bring_text_field_into_view(){ - if(igGetIO()->WantTextInput){ - - ImGuiWindow* window = igGetCurrentContext()->HoveredWindow; - if(igGetCurrentContext()->ActiveIdWindow)window=igGetCurrentContext()->ActiveIdWindow; - - if (window!=NULL) { - float size = gui_state.screen_height/se_dpi_scale(); - float y = igGetCurrentContext()->PlatformImeLastPos.y+30; - if (y >= size) igSetScrollYWindowPtr(window, window->Scroll.y + (y - size)); +void se_bring_text_field_into_view() { + if(igGetIO()->WantTextInput) { + + ImGuiWindow *window = igGetCurrentContext()->HoveredWindow; + if(igGetCurrentContext()->ActiveIdWindow) window = igGetCurrentContext()->ActiveIdWindow; + + if(window != NULL) { + float size = gui_state.screen_height / se_dpi_scale(); + float y = igGetCurrentContext()->PlatformImeLastPos.y + 30; + if(y >= size) igSetScrollYWindowPtr(window, window->Scroll.y + (y - size)); } } } -int file_sorter (const void * a, const void * b) { - tinydir_file*af = (tinydir_file*)a; - tinydir_file*bf = (tinydir_file*)b; - if(af->is_dir!=bf->is_dir)return af->is_dir?-1:1; - int i=0; - for(i = 0; af->path[i];++i){ - if(af->path[i]!=bf->path[i]){ +int file_sorter(const void *a, const void *b) { + tinydir_file *af = (tinydir_file *)a; + tinydir_file *bf = (tinydir_file *)b; + if(af->is_dir != bf->is_dir) return af->is_dir ? -1 : 1; + int i = 0; + for(i = 0; af->path[i]; ++i) { + if(af->path[i] != bf->path[i]) { char ac = af->path[i]; char bc = bf->path[i]; - if(ac>='A'&&ac<='Z')ac=ac-'A'+'a'; - if(bc>='A'&&bc<='Z')bc=bc-'A'+'a'; - if(ac!=bc)return ac>bc?1:-1; + if(ac >= 'A' && ac <= 'Z') ac = ac - 'A' + 'a'; + if(bc >= 'A' && bc <= 'Z') bc = bc - 'A' + 'a'; + if(ac != bc) return ac > bc ? 1 : -1; } } - return bf->path[i]=='\0'?0:-1; + return bf->path[i] == '\0' ? 0 : -1; } -void se_file_browser_accept(const char * path){ - se_file_browser_state_t* file_browse = &gui_state.file_browser; - if(file_browse->file_open_fn){ - gui_state.file_browser.state=SE_FILE_BROWSER_CLOSED; +void se_file_browser_accept(const char *path) { + se_file_browser_state_t *file_browse = &gui_state.file_browser; + if(file_browse->file_open_fn) { + gui_state.file_browser.state = SE_FILE_BROWSER_CLOSED; file_browse->file_open_fn(path); } - if(file_browse->output_path){ - strncpy(file_browse->output_path,path,SB_FILE_PATH_SIZE); - gui_state.file_browser.state=SE_FILE_BROWSER_CLOSED; + if(file_browse->output_path) { + strncpy(file_browse->output_path, path, SB_FILE_PATH_SIZE); + gui_state.file_browser.state = SE_FILE_BROWSER_CLOSED; } } -static void se_file_picker_click_region(int x, int y, int w, int h, void (*accept_func)(const char*)){ - float delta_dpi_scale = se_dpi_scale()/sapp_dpi_scale(); +static void se_file_picker_click_region(int x, int y, int w, int h, void (*accept_func)(const char *)) { + float delta_dpi_scale = se_dpi_scale() / sapp_dpi_scale(); - #ifdef EMSCRIPTEN - while(gui_state.current_click_region_id>=gui_state.max_click_region_id){ - EM_ASM({ +#ifdef EMSCRIPTEN + while(gui_state.current_click_region_id >= gui_state.max_click_region_id) { + EM_ASM({ var input = document.createElement('input'); input.id = 'fileInput'+$0; input.value = ''; @@ -4306,56 +4370,57 @@ static void se_file_picker_click_region(int x, int y, int w, int h, void (*accep document.getElementById('canvas').dispatchEvent(mouseMoveEvent); }; },gui_state.current_click_region_id); - gui_state.max_click_region_id++; - } - char * new_path = (char*)EM_ASM_INT({ - var input = document.getElementById('fileInput'+$0); - input.style.left = $1 +'px'; - input.style.top = $2 +'px'; - input.style.width = $3 +'px'; - input.style.height= $4 +'px'; - input.style.visibility = 'visible'; - input = document.getElementById('fileInput'+$0); - if(input.value!= ''){ - console.log(input.value); - var reader= new FileReader(); - var file = input.files[0]; - function print_file(e){ - var result=reader.result; - const uint8_view = new Uint8Array(result); - var out_file = '/offline/'+filename; - if(FS.analyzePath(out_file)["exists"])FS.unlink(out_file); - FS.writeFile(out_file, uint8_view); - FS.syncfs(function (err) {}); - var input_stage = document.getElementById('fileStaging'+$0); - input_stage.value = out_file; - } - reader.addEventListener('loadend', print_file); - reader.readAsArrayBuffer(file); - var filename = file.name; - input.value = ''; - } - var input_stage = document.getElementById('fileStaging'+$0); - var ret_path = ''; - if(input_stage.value !=''){ - ret_path = input_stage.value; - input_stage.value = ''; + gui_state.max_click_region_id++; + } + char *new_path = (char *)EM_ASM_INT({ + var input = document.getElementById('fileInput' + $0); + input.style.left = $1 + 'px'; + input.style.top = $2 + 'px'; + input.style.width = $3 + 'px'; + input.style.height = $4 + 'px'; + input.style.visibility = 'visible'; + input = document.getElementById('fileInput' + $0); + if(input.value != '') { + console.log(input.value); + var reader = new FileReader(); + var file = input.files[0]; + function print_file(e) { + var result = reader.result; + const uint8_view = new Uint8Array(result); + var out_file = '/offline/' + filename; + if(FS.analyzePath(out_file)["exists"]) FS.unlink(out_file); + FS.writeFile(out_file, uint8_view); + FS.syncfs(function(err){}); + var input_stage = document.getElementById('fileStaging' + $0); + input_stage.value = out_file; } - var sz = lengthBytesUTF8(ret_path)+1; - var string_on_heap = _malloc(sz); - stringToUTF8(ret_path, string_on_heap, sz); - return string_on_heap; - },gui_state.current_click_region_id,x*delta_dpi_scale,y*delta_dpi_scale,w*delta_dpi_scale,h*delta_dpi_scale); - - if(new_path&&new_path[0]){ - se_file_browser_accept(new_path); - } - free(new_path); - #endif + reader.addEventListener('loadend', print_file); + reader.readAsArrayBuffer(file); + var filename = file.name; + input.value = ''; + } + var input_stage = document.getElementById('fileStaging' + $0); + var ret_path = ''; + if(input_stage.value !='') { + ret_path = input_stage.value; + input_stage.value = ''; + } + var sz = lengthBytesUTF8(ret_path) + 1; + var string_on_heap = _malloc(sz); + stringToUTF8(ret_path, string_on_heap, sz); + return string_on_heap; + }, + gui_state.current_click_region_id, x * delta_dpi_scale, y * delta_dpi_scale, w * delta_dpi_scale, h * delta_dpi_scale); + + if(new_path && new_path[0]) { + se_file_browser_accept(new_path); + } + free(new_path); +#endif ++gui_state.current_click_region_id; } -static void se_reset_html_click_regions(){ - while(gui_state.current_click_region_id=SE_NUM_CHEATS)return; - se_cheat_t *cheat = cheats+cheat_index; - int char_count = 0; - uint8_t code_buffer_truncated[SE_MAX_CHEAT_CODE_SIZE*8]; +#ifdef EMSCRIPTEN + gui_state.file_browser.state = SE_FILE_BROWSER_CLOSED; + se_file_picker_click_region(x, y, w, h, file_open_fn); + return; +#endif + +#ifdef USE_BUILT_IN_FILEBROWSER + gui_state.file_browser.state = SE_FILE_BROWSER_OPEN; +#endif +#ifdef USE_TINY_FILE_DIALOGS + if(tinyfd_openFileDialog("tinyfd_query", "", num_file_types, file_types, NULL, 0)) { + gui_state.file_browser.state = SE_FILE_BROWSER_CLOSED; + } + char *outPath = NULL; + if(allow_directory) + outPath = tinyfd_selectFolderDialog(se_localize_and_cache("Select Folder"), output_path ? output_path : ""); + else + outPath = tinyfd_openFileDialog(se_localize_and_cache("Open ROM"), "", num_file_types, file_types, NULL, 0); + if(outPath) { + se_file_browser_accept(outPath); + } +#endif +#ifdef PLATFORM_IOS + gui_state.file_browser.state = SE_FILE_BROWSER_CLOSED; + se_ios_open_file_picker(num_file_types, file_types); +#endif +#ifdef PLATFORM_ANDROID + gui_state.file_browser.state = SE_FILE_BROWSER_CLOSED; + se_android_open_file_picker(); +#endif +} +void se_convert_cheat_code(char *text_code, int cheat_index) { + if(cheat_index >= SE_NUM_CHEATS) return; + se_cheat_t *cheat = cheats + cheat_index; + int char_count = 0; + uint8_t code_buffer_truncated[SE_MAX_CHEAT_CODE_SIZE * 8]; // Remove all the non-hex characters - for(int i=0;i='0' && text_code[i]<='9') || (text_code[i]>='A' && text_code[i]<='F') || (text_code[i]>='a' && text_code[i]<='f')){ - code_buffer_truncated[char_count]=text_code[i]; + for(int i = 0; i < SE_MAX_CHEAT_CODE_SIZE * 8; ++i) { + if(text_code[i] == '\0') + break; + else if((text_code[i] >= '0' && text_code[i] <= '9') || (text_code[i] >= 'A' && text_code[i] <= 'F') || (text_code[i] >= 'a' && text_code[i] <= 'f')) { + code_buffer_truncated[char_count] = text_code[i]; char_count++; } } - cheat->size = char_count/8; - if(cheat->size>=SE_MAX_CHEAT_CODE_SIZE)cheat->size=SE_MAX_CHEAT_CODE_SIZE; - for(int i=0;isize;++i)cheat->buffer[i]=0; - for(int i=0;isize;i++){ + cheat->size = char_count / 8; + if(cheat->size >= SE_MAX_CHEAT_CODE_SIZE) cheat->size = SE_MAX_CHEAT_CODE_SIZE; + for(int i = 0; i < cheat->size; ++i) + cheat->buffer[i] = 0; + for(int i = 0; i < cheat->size; i++) { char hex[9]; - memcpy(hex,code_buffer_truncated+i*8,8); - for(int h=0;h<8;++h)if(hex[h]==0)hex[h]='0'; - hex[8]='\0'; - cheat->buffer[i]=strtoul(hex,NULL,16); + memcpy(hex, code_buffer_truncated + i * 8, 8); + for(int h = 0; h < 8; ++h) + if(hex[h] == 0) hex[h] = '0'; + hex[8] = '\0'; + cheat->buffer[i] = strtoul(hex, NULL, 16); } - } -bool se_process_file_browser(){ +bool se_process_file_browser() { const char *home_dir = sb_get_home_path(); - - if(gui_state.file_browser.state==SE_FILE_BROWSER_CLOSED)return false; - if(gui_state.file_browser.current_path[0]=='\0')strncpy(gui_state.file_browser.current_path,home_dir,SB_FILE_PATH_SIZE); - - ImVec2 w_pos={0,0}; - ImVec2 w_size={gui_state.screen_width,gui_state.screen_height}; - - w_size.x/=se_dpi_scale(); - w_size.y/=se_dpi_scale(); - igSetNextWindowPos(w_pos, ImGuiCond_Always, (ImVec2){0,0}); - igSetNextWindowSize((ImVec2){w_size.x,0}, ImGuiCond_Always); - bool file_browser_open =true; - se_file_browser_state_t* file_browse = &gui_state.file_browser; - - igBegin(se_localize_and_cache(ICON_FK_FILE_O " File Browser"),&file_browser_open,ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize); - if(!file_browser_open)gui_state.file_browser.state=SE_FILE_BROWSER_CLOSED; - if(se_selectable_with_box("Exit File Browser","Go back to recently loaded games",ICON_FK_BAN,false,0)){ - gui_state.file_browser.state=SE_FILE_BROWSER_CLOSED; - } - if(file_browse->allow_directory){ - if(se_selectable_with_box("Select Folder",gui_state.file_browser.current_path,ICON_FK_CHECK,false,0)){ - size_t len = strnlen(gui_state.file_browser.current_path,SB_FILE_PATH_SIZE); - if(lenallow_directory) { + if(se_selectable_with_box("Select Folder", gui_state.file_browser.current_path, ICON_FK_CHECK, false, 0)) { + size_t len = strnlen(gui_state.file_browser.current_path, SB_FILE_PATH_SIZE); + if(len < SB_FILE_PATH_SIZE - 2) { + if(gui_state.file_browser.current_path[len - 1] != '\\' && gui_state.file_browser.current_path[len - 1] != '/') { + gui_state.file_browser.current_path[len] = '/'; + gui_state.file_browser.current_path[len + 1] = 0; } } se_file_browser_accept(gui_state.file_browser.current_path); } } - if(se_selectable_with_box("Go to home directory",home_dir,ICON_FK_HOME,false,0)){ + if(se_selectable_with_box("Go to home directory", home_dir, ICON_FK_HOME, false, 0)) { strncpy(gui_state.file_browser.current_path, home_dir, SB_FILE_PATH_SIZE); } - const char* parent_dir = sb_parent_path(gui_state.file_browser.current_path); - if(se_selectable_with_box("Go to parent directory",parent_dir,ICON_FK_ARROW_UP,false,0)){ + const char *parent_dir = sb_parent_path(gui_state.file_browser.current_path); + if(se_selectable_with_box("Go to parent directory", parent_dir, ICON_FK_ARROW_UP, false, 0)) { strncpy(gui_state.file_browser.current_path, parent_dir, SB_FILE_PATH_SIZE); } - float list_y_off = igGetWindowHeight(); + float list_y_off = igGetWindowHeight(); igEnd(); - igSetNextWindowPos((ImVec2){w_pos.x,w_pos.y+list_y_off}, ImGuiCond_Always, (ImVec2){0,0}); - igSetNextWindowSize((ImVec2){w_size.x,w_size.y-list_y_off}, ImGuiCond_Always); + igSetNextWindowPos((ImVec2){w_pos.x, w_pos.y + list_y_off}, ImGuiCond_Always, (ImVec2){0, 0}); + igSetNextWindowSize((ImVec2){w_size.x, w_size.y - list_y_off}, ImGuiCond_Always); - igBegin(se_localize_and_cache(ICON_FK_FOLDER_OPEN " Open File From Disk"),NULL,ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize); - bool update_cache = file_browse->has_cache==false||file_browse->cached_time+5.cached_path,file_browse->current_path,SB_FILE_PATH_SIZE)!=0; - if(update_cache){ - strncpy(file_browse->cached_path,file_browse->current_path,SB_FILE_PATH_SIZE); - file_browse->cached_time=se_time(); - if(file_browse->has_cache){ - if(file_browse->cached_files){ + igBegin(se_localize_and_cache(ICON_FK_FOLDER_OPEN " Open File From Disk"), NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize); + bool update_cache = file_browse->has_cache == false || file_browse->cached_time + 5. < se_time() || strncmp(file_browse->cached_path, file_browse->current_path, SB_FILE_PATH_SIZE) != 0; + if(update_cache) { + strncpy(file_browse->cached_path, file_browse->current_path, SB_FILE_PATH_SIZE); + file_browse->cached_time = se_time(); + if(file_browse->has_cache) { + if(file_browse->cached_files) { free(file_browse->cached_files); file_browse->cached_files = NULL; - file_browse->num_cached_files=0; + file_browse->num_cached_files = 0; } tinydir_close(&file_browse->cached_dir); - file_browse->has_cache=false; + file_browse->has_cache = false; } - if(tinydir_open(&file_browse->cached_dir, gui_state.file_browser.current_path)==-1){ - printf("Error opening %s\n",gui_state.file_browser.current_path); - }else{ + if(tinydir_open(&file_browse->cached_dir, gui_state.file_browser.current_path) == -1) { + printf("Error opening %s\n", gui_state.file_browser.current_path); + } else { int max_files = 4096; - file_browse->cached_files= (tinydir_file*)malloc(sizeof(tinydir_file)*max_files); - int f = 0; - while(file_browse->cached_dir.has_next&&fcached_files = (tinydir_file *)malloc(sizeof(tinydir_file) * max_files); + int f = 0; + while(file_browse->cached_dir.has_next && f < max_files) { tinydir_readfile(&file_browse->cached_dir, &file_browse->cached_files[f]); char *ext = file_browse->cached_files[f].extension; - bool show_item = true; - if(!file_browse->cached_files[f].is_dir){ - show_item=false; - for(int i=0;inum_file_types;++i){ - if(sb_path_has_file_ext(file_browse->cached_files[f].path,file_browse->file_types[i])){show_item=true;break;} + bool show_item = true; + if(!file_browse->cached_files[f].is_dir) { + show_item = false; + for(int i = 0; i < file_browse->num_file_types; ++i) { + if(sb_path_has_file_ext(file_browse->cached_files[f].path, file_browse->file_types[i])) { + show_item = true; + break; + } } - if(file_browse->num_file_types==0)show_item=true; - }else{ - const char* name = file_browse->cached_files[f].name; - if(strcmp(name,".")==0||strcmp(name,"..")==0)show_item=false; + if(file_browse->num_file_types == 0) show_item = true; + } else { + const char *name = file_browse->cached_files[f].name; + if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) show_item = false; } - if(show_item)++f; + if(show_item) ++f; tinydir_next(&file_browse->cached_dir); } file_browse->num_cached_files = f; - qsort(file_browse->cached_files,f,sizeof(tinydir_file),file_sorter); + qsort(file_browse->cached_files, f, sizeof(tinydir_file), file_sorter); } - file_browse->has_cache=true; + file_browse->has_cache = true; } - for(int f = 0;fnum_cached_files;++f) { - const char *ext = file_browse->cached_files[f].is_link ? ICON_FK_FOLDER_OPEN_O:ICON_FK_FOLDER_OPEN; - if (!file_browse->cached_files[f].is_dir) { - const char* base, *file; + for(int f = 0; f < file_browse->num_cached_files; ++f) { + const char *ext = file_browse->cached_files[f].is_link ? ICON_FK_FOLDER_OPEN_O : ICON_FK_FOLDER_OPEN; + if(!file_browse->cached_files[f].is_dir) { + const char *base, *file; sb_breakup_path(file_browse->cached_files[f].path, &base, &file, &ext); } - if (se_selectable_with_box(file_browse->cached_files[f].name, file_browse->cached_files[f].path, ext, false, 0)) { - if (file_browse->cached_files[f].is_dir) + if(se_selectable_with_box(file_browse->cached_files[f].name, file_browse->cached_files[f].path, ext, false, 0)) { + if(file_browse->cached_files[f].is_dir) strncpy(gui_state.file_browser.current_path, file_browse->cached_files[f].path, SB_FILE_PATH_SIZE); else { se_file_browser_accept(file_browse->cached_files[f].path); @@ -4548,581 +4620,580 @@ bool se_process_file_browser(){ igEnd(); return true; } -bool se_load_rom_file_browser_callback(const char* path){ +bool se_load_rom_file_browser_callback(const char *path) { se_load_rom(path); return emu_state.rom_loaded; } bool se_string_contains_string_case_insensitive(char *canidate, char *search) { int len1 = strlen(canidate); int len2 = strlen(search); - if(len2==0)return true; - for (int i = 0; i < len1 - len2; i++) { - int j=0; - for (j = 0; j < len2; j++) { - if (tolower(canidate[i+j]) != tolower(search[j]))break; + if(len2 == 0) return true; + for(int i = 0; i < len1 - len2; i++) { + int j = 0; + for(j = 0; j < len2; j++) { + if(tolower(canidate[i + j]) != tolower(search[j])) break; } - if (j == len2) return true; + if(j == len2) return true; } return false; } -void se_load_rom_overlay(bool visible){ - if(visible==false)return; +void se_load_rom_overlay(bool visible) { + if(visible == false) return; ImVec2 w_pos, w_size; igGetWindowPos(&w_pos); igGetWindowSize(&w_size); - w_size.x/=se_dpi_scale(); - w_size.y/=se_dpi_scale(); - igSetNextWindowSize((ImVec2){w_size.x,0},ImGuiCond_Always); - igSetNextWindowPos((ImVec2){w_pos.x,w_pos.y},ImGuiCond_Always,(ImVec2){0,0}); - igSetNextWindowBgAlpha(gui_state.settings.hardcore_mode? 1.0: SE_TRANSPARENT_BG_ALPHA); - igBegin(se_localize_and_cache(ICON_FK_FILE_O " Load Game"),gui_state.settings.hardcore_mode?NULL:&gui_state.overlay_open,ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize); - - float list_y_off = igGetWindowHeight(); - int x, y, w, h; - ImVec2 win_p,win_max; + w_size.x /= se_dpi_scale(); + w_size.y /= se_dpi_scale(); + igSetNextWindowSize((ImVec2){w_size.x, 0}, ImGuiCond_Always); + igSetNextWindowPos((ImVec2){w_pos.x, w_pos.y}, ImGuiCond_Always, (ImVec2){0, 0}); + igSetNextWindowBgAlpha(gui_state.settings.hardcore_mode ? 1.0 : SE_TRANSPARENT_BG_ALPHA); + igBegin(se_localize_and_cache(ICON_FK_FILE_O " Load Game"), gui_state.settings.hardcore_mode ? NULL : &gui_state.overlay_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize); + + float list_y_off = igGetWindowHeight(); + int x, y, w, h; + ImVec2 win_p, win_max; igGetWindowContentRegionMin(&win_p); igGetWindowContentRegionMax(&win_max); x = win_p.x; y = win_p.y; - w = win_max.x-win_p.x; - h = win_max.y-win_p.y; - y+=w_pos.y; - x+=w_pos.x; - const char * prompt1 = "Load ROM from file (.gb, .gbc, .gba, .zip)"; - const char * prompt2= "You can also drag & drop a ROM to load it"; - if(gui_state.ui_type==SE_UI_ANDROID||gui_state.ui_type==SE_UI_IOS){ + w = win_max.x - win_p.x; + h = win_max.y - win_p.y; + y += w_pos.y; + x += w_pos.x; + const char *prompt1 = "Load ROM from file (.gb, .gbc, .gba, .zip)"; + const char *prompt2 = "You can also drag & drop a ROM to load it"; + if(gui_state.ui_type == SE_UI_ANDROID || gui_state.ui_type == SE_UI_IOS) { prompt2 = ""; - }else if (gui_state.ui_type==SE_UI_WEB){ + } else if(gui_state.ui_type == SE_UI_WEB) { prompt1 = "Load ROM(.gb, .gbc, .gba, .zip), save(.sav), or GBA bios (gba_bios.bin) from file"; prompt2 = "You can also drag & drop a ROM/save file to load it"; } - bool clicked = se_selectable_with_box(prompt1,prompt2,ICON_FK_FOLDER_OPEN,false,0); - se_open_file_browser(clicked, x,y,w,h, se_load_rom,valid_rom_file_types,NULL); - + bool clicked = se_selectable_with_box(prompt1, prompt2, ICON_FK_FOLDER_OPEN, false, 0); + se_open_file_browser(clicked, x, y, w, h, se_load_rom, valid_rom_file_types, NULL); + igEnd(); - ImVec2 child_size; + ImVec2 child_size; child_size.x = w_size.x; - child_size.y = w_size.y-list_y_off; - igSetNextWindowSize(child_size,ImGuiCond_Always); - igSetNextWindowPos((ImVec2){(w_pos.x),list_y_off+w_pos.y},ImGuiCond_Always,(ImVec2){0,0}); - igSetNextWindowBgAlpha(gui_state.settings.hardcore_mode? 1.0: SE_TRANSPARENT_BG_ALPHA); - igBegin(se_localize_and_cache(ICON_FK_CLOCK_O " Load Recently Played Game"),NULL,ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize); - - igSameLine(0,5); - se_text("%s ",ICON_FK_SEARCH); - igSameLine(0,5); + child_size.y = w_size.y - list_y_off; + igSetNextWindowSize(child_size, ImGuiCond_Always); + igSetNextWindowPos((ImVec2){(w_pos.x), list_y_off + w_pos.y}, ImGuiCond_Always, (ImVec2){0, 0}); + igSetNextWindowBgAlpha(gui_state.settings.hardcore_mode ? 1.0 : SE_TRANSPARENT_BG_ALPHA); + igBegin(se_localize_and_cache(ICON_FK_CLOCK_O " Load Recently Played Game"), NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize); + + igSameLine(0, 5); + se_text("%s ", ICON_FK_SEARCH); + igSameLine(0, 5); igPushItemWidth(-55); - igInputText("##search",gui_state.search_buffer,sizeof(gui_state.search_buffer),ImGuiInputTextFlags_None, NULL,NULL); + igInputText("##search", gui_state.search_buffer, sizeof(gui_state.search_buffer), ImGuiInputTextFlags_None, NULL, NULL); igPopItemWidth(); - igSameLine(0,5); - - const char* icon=ICON_FK_LONG_ARROW_DOWN ICON_FK_CLOCK_O; - switch(gui_state.recent_games_sort_type){ - case SE_NO_SORT: icon=ICON_FK_LONG_ARROW_DOWN ICON_FK_CLOCK_O ;break; - case SE_SORT_ALPHA_ASC: icon=ICON_FK_SORT_ALPHA_ASC;break; - case SE_SORT_ALPHA_DESC:icon=ICON_FK_SORT_ALPHA_DESC;break; - default: - gui_state.recent_games_sort_type = SE_NO_SORT; - se_sort_recent_games_list(); - } - if(se_button(icon,(ImVec2){50,0})){ + igSameLine(0, 5); + + const char *icon = ICON_FK_LONG_ARROW_DOWN ICON_FK_CLOCK_O; + switch(gui_state.recent_games_sort_type) { + case SE_NO_SORT: icon = ICON_FK_LONG_ARROW_DOWN ICON_FK_CLOCK_O; break; + case SE_SORT_ALPHA_ASC: icon = ICON_FK_SORT_ALPHA_ASC; break; + case SE_SORT_ALPHA_DESC: icon = ICON_FK_SORT_ALPHA_DESC; break; + default: + gui_state.recent_games_sort_type = SE_NO_SORT; + se_sort_recent_games_list(); + } + if(se_button(icon, (ImVec2){50, 0})) { gui_state.recent_games_sort_type++; - if(gui_state.recent_games_sort_type>SE_SORT_ALPHA_DESC)gui_state.recent_games_sort_type=SE_NO_SORT; + if(gui_state.recent_games_sort_type > SE_SORT_ALPHA_DESC) gui_state.recent_games_sort_type = SE_NO_SORT; se_sort_recent_games_list(); } igSeparator(); - int num_entries=0; - for(int i=0;ipath,"")==0)break; + int num_entries = 0; + for(int i = 0; i < SE_NUM_RECENT_PATHS; ++i) { + if(gui_state.sorted_recently_loaded_games[i] == -1) break; + se_game_info_t *info = gui_state.recently_loaded_games + gui_state.sorted_recently_loaded_games[i]; + if(strcmp(info->path, "") == 0) break; igPushIDInt(i); - const char* base, *file_name, *ext; - sb_breakup_path(info->path,&base,&file_name,&ext); - char ext_upper[8]={0}; - for(int i=0;i<7&&ext[i];++i)ext_upper[i]=toupper(ext[i]); - int reduce_width = 0; - #ifdef EMSCRIPTEN + const char *base, *file_name, *ext; + sb_breakup_path(info->path, &base, &file_name, &ext); + char ext_upper[8] = {0}; + for(int i = 0; i < 7 && ext[i]; ++i) + ext_upper[i] = toupper(ext[i]); + int reduce_width = 0; +#ifdef EMSCRIPTEN char save_file_path[SB_FILE_PATH_SIZE]; - snprintf(save_file_path,SB_FILE_PATH_SIZE,"%s/%s.sav",base,file_name); + snprintf(save_file_path, SB_FILE_PATH_SIZE, "%s/%s.sav", base, file_name); bool save_exists = sb_file_exists(save_file_path); - if(save_exists)reduce_width=85; - #endif - if(!se_string_contains_string_case_insensitive(info->path,gui_state.search_buffer))continue; - if(se_selectable_with_box(file_name,se_replace_fake_path(info->path),ext_upper,false,reduce_width)){ + if(save_exists) reduce_width = 85; +#endif + if(!se_string_contains_string_case_insensitive(info->path, gui_state.search_buffer)) continue; + if(se_selectable_with_box(file_name, se_replace_fake_path(info->path), ext_upper, false, reduce_width)) { se_load_rom(info->path); } - #ifdef EMSCRIPTEN - if(save_exists){ - igSameLine(0,4); - if(se_button(ICON_FK_DOWNLOAD " Export Save",(ImVec2){reduce_width-4,40}))se_download_emscripten_file(save_file_path); +#ifdef EMSCRIPTEN + if(save_exists) { + igSameLine(0, 4); + if(se_button(ICON_FK_DOWNLOAD " Export Save", (ImVec2){reduce_width - 4, 40})) se_download_emscripten_file(save_file_path); } - #endif +#endif igSeparator(); num_entries++; igPopID(); } - if(num_entries==0)se_text("No recently played games"); + if(num_entries == 0) se_text("No recently played games"); igEnd(); return; } #ifdef USE_SDL -static void se_poll_sdl(){ - SDL_Event sdlEvent; +static void se_poll_sdl() { + SDL_Event sdlEvent; se_controller_state_t *cont = &gui_state.controller; - cont->key.last_bind_activitiy=-1; - cont->analog.last_bind_activitiy=-1; - - while( SDL_PollEvent( &sdlEvent ) ) { - switch( sdlEvent.type ) { - case SDL_JOYDEVICEADDED:{ - if(!cont->sdl_joystick){ - se_set_new_controller(cont,sdlEvent.jdevice.which); - } - break; + cont->key.last_bind_activitiy = -1; + cont->analog.last_bind_activitiy = -1; + + while(SDL_PollEvent(&sdlEvent)) { + switch(sdlEvent.type) { + case SDL_JOYDEVICEADDED: { + if(!cont->sdl_joystick) { + se_set_new_controller(cont, sdlEvent.jdevice.which); } - case SDL_JOYDEVICEREMOVED: - if(cont->sdl_joystick==SDL_JoystickFromInstanceID(sdlEvent.jdevice.which)){ - SDL_JoystickClose(cont->sdl_joystick); - SDL_GameControllerClose(cont->sdl_gc); - cont->sdl_joystick = NULL; - cont->sdl_gc = NULL; - } - break; - case SDL_JOYHATMOTION:{ - int value = 0; - if(sdlEvent.jhat.value==SDL_HAT_UP)value = SDL_HAT_UP; - if(sdlEvent.jhat.value==SDL_HAT_DOWN)value = SDL_HAT_DOWN; - if(sdlEvent.jhat.value==SDL_HAT_LEFT)value = SDL_HAT_LEFT; - if(sdlEvent.jhat.value==SDL_HAT_RIGHT)value = SDL_HAT_RIGHT; - if(value){ - value |= sdlEvent.jhat.hat<<8; - value |= SE_HAT_MASK; - cont->key.last_bind_activitiy = value; - } - }break; - case SDL_JOYBUTTONDOWN: - if(SDL_JoystickFromInstanceID(sdlEvent.jbutton.which)==cont->sdl_joystick) - cont->key.last_bind_activitiy = sdlEvent.jbutton.button; - break; - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - //OnControllerButton( sdlEvent.cbutton ); - break; - case SDL_JOYAXISMOTION: - if(SDL_JoystickFromInstanceID(sdlEvent.jaxis.which)==cont->sdl_joystick){ - float v = sdlEvent.jaxis.value/32768.f; - if(v<0.2&&v>-0.2 && (int)sdlEvent.jaxis.axis < sizeof(cont->axis_last_zero_time)/sizeof(cont->axis_last_zero_time[0])){ - cont->axis_last_zero_time[sdlEvent.jaxis.axis]=se_time(); - } - if((v>0.3)||(v<-0.3&&v>-0.6)) - cont->analog.last_bind_activitiy = sdlEvent.jaxis.axis; - double delta = se_time()-cont->axis_last_zero_time[sdlEvent.jaxis.axis]; - if(v>0.4&&delta<2)cont->key.last_bind_activitiy = sdlEvent.jaxis.axis|SE_JOY_POS_MASK; - if(v<-0.4&&delta<2)cont->key.last_bind_activitiy = sdlEvent.jaxis.axis|SE_JOY_NEG_MASK; + break; + } + case SDL_JOYDEVICEREMOVED: + if(cont->sdl_joystick == SDL_JoystickFromInstanceID(sdlEvent.jdevice.which)) { + SDL_JoystickClose(cont->sdl_joystick); + SDL_GameControllerClose(cont->sdl_gc); + cont->sdl_joystick = NULL; + cont->sdl_gc = NULL; + } + break; + case SDL_JOYHATMOTION: { + int value = 0; + if(sdlEvent.jhat.value == SDL_HAT_UP) value = SDL_HAT_UP; + if(sdlEvent.jhat.value == SDL_HAT_DOWN) value = SDL_HAT_DOWN; + if(sdlEvent.jhat.value == SDL_HAT_LEFT) value = SDL_HAT_LEFT; + if(sdlEvent.jhat.value == SDL_HAT_RIGHT) value = SDL_HAT_RIGHT; + if(value) { + value |= sdlEvent.jhat.hat << 8; + value |= SE_HAT_MASK; + cont->key.last_bind_activitiy = value; + } + } break; + case SDL_JOYBUTTONDOWN: + if(SDL_JoystickFromInstanceID(sdlEvent.jbutton.which) == cont->sdl_joystick) + cont->key.last_bind_activitiy = sdlEvent.jbutton.button; + break; + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + // OnControllerButton( sdlEvent.cbutton ); + break; + case SDL_JOYAXISMOTION: + if(SDL_JoystickFromInstanceID(sdlEvent.jaxis.which) == cont->sdl_joystick) { + float v = sdlEvent.jaxis.value / 32768.f; + if(v < 0.2 && v > -0.2 && (int)sdlEvent.jaxis.axis < sizeof(cont->axis_last_zero_time) / sizeof(cont->axis_last_zero_time[0])) { + cont->axis_last_zero_time[sdlEvent.jaxis.axis] = se_time(); } - break; + if((v > 0.3) || (v < -0.3 && v > -0.6)) + cont->analog.last_bind_activitiy = sdlEvent.jaxis.axis; + double delta = se_time() - cont->axis_last_zero_time[sdlEvent.jaxis.axis]; + if(v > 0.4 && delta < 2) cont->key.last_bind_activitiy = sdlEvent.jaxis.axis | SE_JOY_POS_MASK; + if(v < -0.4 && delta < 2) cont->key.last_bind_activitiy = sdlEvent.jaxis.axis | SE_JOY_NEG_MASK; } + break; + } } - if(cont->sdl_joystick){ - for(int k= 0; ksdl_joystick) { + for(int k = 0; k < SE_NUM_KEYBINDS; ++k) { int key = cont->key.bound_id[k]; - if(key==-1)continue; - bool val = false; - bool is_hat = key&(SE_HAT_MASK); - bool is_joy = key&(SE_JOY_NEG_MASK|SE_JOY_POS_MASK); - if(is_hat){ - int hat_id = SB_BFE(key,8,8); - if(hat_idsdl_joystick)){ - int hat_value = SDL_JoystickGetHat(cont->sdl_joystick,hat_id); - int match_value = SB_BFE(key,0,8); - if(match_value==SDL_HAT_UP)val |= (hat_value==SDL_HAT_UP)|(hat_value==SDL_HAT_RIGHTUP)|(hat_value==SDL_HAT_LEFTUP); - if(match_value==SDL_HAT_DOWN)val |= (hat_value==SDL_HAT_DOWN)|(hat_value==SDL_HAT_RIGHTDOWN)|(hat_value==SDL_HAT_LEFTDOWN); - if(match_value==SDL_HAT_LEFT)val |= (hat_value==SDL_HAT_LEFT)|(hat_value==SDL_HAT_LEFTDOWN)|(hat_value==SDL_HAT_LEFTUP); - if(match_value==SDL_HAT_RIGHT)val |= (hat_value==SDL_HAT_RIGHT)|(hat_value==SDL_HAT_RIGHTDOWN)|(hat_value==SDL_HAT_RIGHTUP); + if(key == -1) continue; + bool val = false; + bool is_hat = key & (SE_HAT_MASK); + bool is_joy = key & (SE_JOY_NEG_MASK | SE_JOY_POS_MASK); + if(is_hat) { + int hat_id = SB_BFE(key, 8, 8); + if(hat_id < SDL_JoystickNumHats(cont->sdl_joystick)) { + int hat_value = SDL_JoystickGetHat(cont->sdl_joystick, hat_id); + int match_value = SB_BFE(key, 0, 8); + if(match_value == SDL_HAT_UP) val |= (hat_value == SDL_HAT_UP) | (hat_value == SDL_HAT_RIGHTUP) | (hat_value == SDL_HAT_LEFTUP); + if(match_value == SDL_HAT_DOWN) val |= (hat_value == SDL_HAT_DOWN) | (hat_value == SDL_HAT_RIGHTDOWN) | (hat_value == SDL_HAT_LEFTDOWN); + if(match_value == SDL_HAT_LEFT) val |= (hat_value == SDL_HAT_LEFT) | (hat_value == SDL_HAT_LEFTDOWN) | (hat_value == SDL_HAT_LEFTUP); + if(match_value == SDL_HAT_RIGHT) val |= (hat_value == SDL_HAT_RIGHT) | (hat_value == SDL_HAT_RIGHTDOWN) | (hat_value == SDL_HAT_RIGHTUP); } - }else if(is_joy){ - int joy_id = SB_BFE(key,0,16); - if(joy_idsdl_joystick)){ - float v = SDL_JoystickGetAxis(cont->sdl_joystick,joy_id)/32768.f; - val = false; - if(key&SE_JOY_NEG_MASK)val|= v<-0.3; - if(key&SE_JOY_POS_MASK)val|= v>0.3; + } else if(is_joy) { + int joy_id = SB_BFE(key, 0, 16); + if(joy_id < SDL_JoystickNumAxes(cont->sdl_joystick)) { + float v = SDL_JoystickGetAxis(cont->sdl_joystick, joy_id) / 32768.f; + val = false; + if(key & SE_JOY_NEG_MASK) val |= v < -0.3; + if(key & SE_JOY_POS_MASK) val |= v > 0.3; } - }else{ - if(keysdl_joystick)){ - val = SDL_JoystickGetButton(cont->sdl_joystick,key); + } else { + if(key < SDL_JoystickNumButtons(cont->sdl_joystick)) { + val = SDL_JoystickGetButton(cont->sdl_joystick, key); } } - + cont->key.value[k] = val; } - for(int a= 0; aanalog.bound_id[a]; - float val = 0; - if(axissdl_joystick)&&axis!=-1){ - val = SDL_JoystickGetAxis(cont->sdl_joystick,axis)/32768.f; + for(int a = 0; a < SE_NUM_ANALOGBINDS; ++a) { + int axis = cont->analog.bound_id[a]; + float val = 0; + if(axis < SDL_JoystickNumAxes(cont->sdl_joystick) && axis != -1) { + val = SDL_JoystickGetAxis(cont->sdl_joystick, axis) / 32768.f; } - cont->analog.value[a]= val; + cont->analog.value[a] = val; } - float intensity= emu_state.joy.rumble*65000; + float intensity = emu_state.joy.rumble * 65000; SDL_JoystickRumble(cont->sdl_joystick, intensity, intensity, 100); - for(int i=0;ikey.value[i]>0.5; + for(int i = 0; i < SE_NUM_KEYBINDS; ++i) + emu_state.joy.inputs[i] += cont->key.value[i] > 0.5; - emu_state.joy.inputs[SE_KEY_LEFT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT]<-0.3; - emu_state.joy.inputs[SE_KEY_RIGHT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT]> 0.3; - emu_state.joy.inputs[SE_KEY_UP] += cont->analog.value[SE_ANALOG_UP_DOWN]<-0.3; - emu_state.joy.inputs[SE_KEY_DOWN] += cont->analog.value[SE_ANALOG_UP_DOWN]>0.3; + emu_state.joy.inputs[SE_KEY_LEFT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT] < -0.3; + emu_state.joy.inputs[SE_KEY_RIGHT] += cont->analog.value[SE_ANALOG_LEFT_RIGHT] > 0.3; + emu_state.joy.inputs[SE_KEY_UP] += cont->analog.value[SE_ANALOG_UP_DOWN] < -0.3; + emu_state.joy.inputs[SE_KEY_DOWN] += cont->analog.value[SE_ANALOG_UP_DOWN] > 0.3; - emu_state.joy.inputs[SE_KEY_L] += cont->analog.value[SE_ANALOG_L]>0.1; - emu_state.joy.inputs[SE_KEY_R] += cont->analog.value[SE_ANALOG_R]>0.1; + emu_state.joy.inputs[SE_KEY_L] += cont->analog.value[SE_ANALOG_L] > 0.1; + emu_state.joy.inputs[SE_KEY_R] += cont->analog.value[SE_ANALOG_R] > 0.1; } } #endif void se_update_frame() { - #ifdef ENABLE_HTTP_CONTROL_SERVER - hcs_update(gui_state.settings.http_control_server_enable,gui_state.settings.http_control_server_port,se_hcs_callback); - if(gui_state.settings.http_control_server_enable){ - for(int i=0;i10){ + if(frames_since_last_save > 10) { bool saved = se_sync_save_to_disk(); - if(saved){ - frames_since_last_save=0; + if(saved) { + frames_since_last_save = 0; se_emscripten_flush_fs(); } } emu_state.screen_ghosting_strength = gui_state.settings.ghosting; - const int frames_per_rewind_state = 8; + const int frames_per_rewind_state = 8; static double simulation_time = -1; - double curr_time = se_time(); + double curr_time = se_time(); - if(fabs(curr_time-simulation_time)>1.0/60.*10||emu_state.run_mode==SB_MODE_PAUSE)simulation_time = curr_time; - if(emu_state.run_mode==SB_MODE_RUN||emu_state.run_mode==SB_MODE_STEP||emu_state.run_mode==SB_MODE_REWIND){ - emu_state.frame=0; - int max_frames_per_tick =1+ emu_state.step_frames; - if(emu_state.run_mode==SB_MODE_STEP)max_frames_per_tick= emu_state.step_frames; + if(fabs(curr_time - simulation_time) > 1.0 / 60. * 10 || emu_state.run_mode == SB_MODE_PAUSE) simulation_time = curr_time; + if(emu_state.run_mode == SB_MODE_RUN || emu_state.run_mode == SB_MODE_STEP || emu_state.run_mode == SB_MODE_REWIND) { + emu_state.frame = 0; + int max_frames_per_tick = 1 + emu_state.step_frames; + if(emu_state.run_mode == SB_MODE_STEP) max_frames_per_tick = emu_state.step_frames; emu_state.render_frame = true; - double sim_fps= se_get_sim_fps(); - double sim_time_increment = 1./sim_fps/emu_state.step_frames; - if(emu_state.run_mode==SB_MODE_REWIND)sim_time_increment*=frames_per_rewind_state/2; - if(emu_state.step_frames<0){ - max_frames_per_tick =1; - sim_time_increment = 1./sim_fps*-emu_state.step_frames; - } - bool unlocked_mode = emu_state.step_frames==0; - if(gui_state.test_runner_mode)unlocked_mode=true; - if(unlocked_mode&&emu_state.run_mode!=SB_MODE_STEP){ - sim_time_increment=0; - max_frames_per_tick=1000; - simulation_time=curr_time+1./30.; - } - while(max_frames_per_tick--){ + double sim_fps = se_get_sim_fps(); + double sim_time_increment = 1. / sim_fps / emu_state.step_frames; + if(emu_state.run_mode == SB_MODE_REWIND) sim_time_increment *= frames_per_rewind_state / 2; + if(emu_state.step_frames < 0) { + max_frames_per_tick = 1; + sim_time_increment = 1. / sim_fps * -emu_state.step_frames; + } + bool unlocked_mode = emu_state.step_frames == 0; + if(gui_state.test_runner_mode) unlocked_mode = true; + if(unlocked_mode && emu_state.run_mode != SB_MODE_STEP) { + sim_time_increment = 0; + max_frames_per_tick = 1000; + simulation_time = curr_time + 1. / 30.; + } + while(max_frames_per_tick--) { // On steps emulate all frames, but only render the last frame of the step // and don't allow screen ghosting - if(emu_state.run_mode==SB_MODE_STEP){ - emu_state.render_frame = max_frames_per_tick==0; - emu_state.screen_ghosting_strength=0; - }else{ - if(unlocked_mode){ - if(simulation_timecurr_time)break; - if(emu_state.frame&&curr_time-simulation_time curr_time) break; + if(emu_state.frame && curr_time - simulation_time < sim_time_increment * 0.8) { break; } } } - if(emu_state.run_mode==SB_MODE_REWIND){ + if(emu_state.run_mode == SB_MODE_REWIND) { se_rewind_state_single_tick(&core, &rewind_buffer); emu_state.render_frame = true; se_emulate_single_frame(); se_emulate_single_frame(); - simulation_time+=sim_time_increment*2; - }else{ + simulation_time += sim_time_increment * 2; + } else { se_emulate_single_frame(); ++emu_state.frames_since_rewind_push; - if(emu_state.frames_since_rewind_push>frames_per_rewind_state-1 ){ - se_push_rewind_state(&core,&rewind_buffer); - emu_state.frames_since_rewind_push=0; + if(emu_state.frames_since_rewind_push > frames_per_rewind_state - 1) { + se_push_rewind_state(&core, &rewind_buffer); + emu_state.frames_since_rewind_push = 0; } - simulation_time+=sim_time_increment; + simulation_time += sim_time_increment; } emu_state.frame++; emu_state.render_frame = false; curr_time = se_time(); - if(emu_state.run_mode==SB_MODE_PAUSE)break; + if(emu_state.run_mode == SB_MODE_PAUSE) break; } } - if(emu_state.run_mode==SB_MODE_STEP)printf("Emulated %d frames\n",emu_state.frame); - if(emu_state.run_mode==SB_MODE_STEP)emu_state.run_mode = SB_MODE_PAUSE; - if(emu_state.run_mode==SB_MODE_PAUSE)emu_state.frame = 0; - if(emu_state.run_mode==SB_MODE_REWIND)emu_state.frame = - emu_state.frame*frames_per_rewind_state; + if(emu_state.run_mode == SB_MODE_STEP) printf("Emulated %d frames\n", emu_state.frame); + if(emu_state.run_mode == SB_MODE_STEP) emu_state.run_mode = SB_MODE_PAUSE; + if(emu_state.run_mode == SB_MODE_PAUSE) emu_state.frame = 0; + if(emu_state.run_mode == SB_MODE_REWIND) emu_state.frame = -emu_state.frame * frames_per_rewind_state; - emu_state.prev_frame_joy = emu_state.joy; + emu_state.prev_frame_joy = emu_state.joy; se_reset_joy(&emu_state.joy); - #ifdef ENABLE_HTTP_CONTROL_SERVER - hcs_resume_callbacks(); - #endif -} -void se_imgui_theme() -{ - ImVec4* colors = igGetStyle()->Colors; - colors[ImGuiCol_Text] = (ImVec4){1.00f, 1.00f, 1.00f, 1.00f}; - colors[ImGuiCol_TextDisabled] = (ImVec4){0.6f, 0.6f, 0.6f, 0.5f}; - colors[ImGuiCol_WindowBg] = (ImVec4){0.14f, 0.14f, 0.14f, 1.00f}; - colors[ImGuiCol_ChildBg] = (ImVec4){0.14f, 0.14f, 0.14f, 0.40f}; - colors[ImGuiCol_PopupBg] = (ImVec4){0.19f, 0.19f, 0.19f, 0.92f}; - colors[ImGuiCol_Border] = (ImVec4){0.1f, 0.1f, 0.1f, 1.0f}; - colors[ImGuiCol_BorderShadow] = (ImVec4){0.00f, 0.00f, 0.00f, 0.24f}; - colors[ImGuiCol_FrameBg] = (ImVec4){0.2f, 0.2f, 0.2f, 0.9f}; - colors[ImGuiCol_FrameBgHovered] = (ImVec4){0.1f, 0.1f, 0.1f, 1.0f}; - colors[ImGuiCol_FrameBgActive] = (ImVec4){0.29f, 0.29f, 0.29f, 1.00f}; - colors[ImGuiCol_TitleBg] = (ImVec4){0.00f, 0.00f, 0.00f, 1.00f}; - colors[ImGuiCol_TitleBgActive] = (ImVec4){0.06f, 0.06f, 0.06f, 1.00f}; - colors[ImGuiCol_TitleBgCollapsed] = (ImVec4){0.00f, 0.00f, 0.00f, 1.00f}; - colors[ImGuiCol_MenuBarBg] = (ImVec4){0.10f, 0.10f, 0.10f, 1.00f}; - colors[ImGuiCol_ScrollbarBg] = (ImVec4){0.05f, 0.05f, 0.05f, 0.54f}; - colors[ImGuiCol_ScrollbarGrab] = (ImVec4){0.34f, 0.34f, 0.34f, 0.54f}; - colors[ImGuiCol_ScrollbarGrabHovered] = (ImVec4){0.40f, 0.40f, 0.40f, 0.54f}; - colors[ImGuiCol_ScrollbarGrabActive] = (ImVec4){0.56f, 0.56f, 0.56f, 0.54f}; - colors[ImGuiCol_CheckMark] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; - colors[ImGuiCol_SliderGrab] = (ImVec4){0.34f, 0.34f, 0.34f, 0.8f}; - colors[ImGuiCol_SliderGrabActive] = (ImVec4){0.56f, 0.56f, 0.56f, 0.8f}; - colors[ImGuiCol_Button] = (ImVec4){0.25f, 0.25f, 0.25f, 1.00f}; - colors[ImGuiCol_ButtonHovered] = (ImVec4){0.19f, 0.19f, 0.19f, 0.54f}; - colors[ImGuiCol_ButtonActive] = (ImVec4){0.4f, 0.4f, 0.4f, 1.00f}; - colors[ImGuiCol_Header] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; - colors[ImGuiCol_HeaderHovered] = (ImVec4){0.00f, 0.00f, 0.00f, 0.36f}; - colors[ImGuiCol_HeaderActive] = (ImVec4){0.20f, 0.22f, 0.23f, 0.33f}; - colors[ImGuiCol_Separator] = (ImVec4){0.28f, 0.28f, 0.28f, 0.9f}; - colors[ImGuiCol_SeparatorHovered] = (ImVec4){0.44f, 0.44f, 0.44f, 0.29f}; - colors[ImGuiCol_SeparatorActive] = (ImVec4){0.40f, 0.44f, 0.47f, 1.00f}; - colors[ImGuiCol_ResizeGrip] = (ImVec4){0.28f, 0.28f, 0.28f, 0.29f}; - colors[ImGuiCol_ResizeGripHovered] = (ImVec4){0.44f, 0.44f, 0.44f, 0.29f}; - colors[ImGuiCol_ResizeGripActive] = (ImVec4){0.40f, 0.44f, 0.47f, 1.00f}; - colors[ImGuiCol_Tab] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; - colors[ImGuiCol_TabHovered] = (ImVec4){0.14f, 0.14f, 0.14f, 1.00f}; - colors[ImGuiCol_TabActive] = (ImVec4){0.20f, 0.20f, 0.20f, 0.36f}; - colors[ImGuiCol_TabUnfocused] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; - colors[ImGuiCol_TabUnfocusedActive] = (ImVec4){0.14f, 0.14f, 0.14f, 1.00f}; - //colors[ImGuiCol_DockingPreview] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; - //colors[ImGuiCol_DockingEmptyBg] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; - colors[ImGuiCol_PlotLines] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; - colors[ImGuiCol_PlotLinesHovered] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; - colors[ImGuiCol_PlotHistogram] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; - colors[ImGuiCol_PlotHistogramHovered] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; - colors[ImGuiCol_TableHeaderBg] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; - colors[ImGuiCol_TableBorderStrong] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; - colors[ImGuiCol_TableBorderLight] = (ImVec4){0.28f, 0.28f, 0.28f, 0.29f}; - colors[ImGuiCol_TableRowBg] = (ImVec4){0.00f, 0.00f, 0.00f, 0.00f}; - colors[ImGuiCol_TableRowBgAlt] = (ImVec4){1.00f, 1.00f, 1.00f, 0.06f}; - colors[ImGuiCol_TextSelectedBg] = (ImVec4){0.20f, 0.22f, 0.23f, 1.00f}; - colors[ImGuiCol_DragDropTarget] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; - colors[ImGuiCol_NavHighlight] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; - colors[ImGuiCol_NavWindowingHighlight] = (ImVec4){1.00f, 0.00f, 0.00f, 0.70f}; - colors[ImGuiCol_NavWindowingDimBg] = (ImVec4){1.00f, 0.00f, 0.00f, 0.20f}; - colors[ImGuiCol_ModalWindowDimBg] = (ImVec4){1.00f, 0.00f, 0.00f, 0.35f}; - - if(gui_state.settings.theme == SE_THEME_CUSTOM){ +#ifdef ENABLE_HTTP_CONTROL_SERVER + hcs_resume_callbacks(); +#endif +} +void se_imgui_theme() { + ImVec4 *colors = igGetStyle()->Colors; + colors[ImGuiCol_Text] = (ImVec4){1.00f, 1.00f, 1.00f, 1.00f}; + colors[ImGuiCol_TextDisabled] = (ImVec4){0.6f, 0.6f, 0.6f, 0.5f}; + colors[ImGuiCol_WindowBg] = (ImVec4){0.14f, 0.14f, 0.14f, 1.00f}; + colors[ImGuiCol_ChildBg] = (ImVec4){0.14f, 0.14f, 0.14f, 0.40f}; + colors[ImGuiCol_PopupBg] = (ImVec4){0.19f, 0.19f, 0.19f, 0.92f}; + colors[ImGuiCol_Border] = (ImVec4){0.1f, 0.1f, 0.1f, 1.0f}; + colors[ImGuiCol_BorderShadow] = (ImVec4){0.00f, 0.00f, 0.00f, 0.24f}; + colors[ImGuiCol_FrameBg] = (ImVec4){0.2f, 0.2f, 0.2f, 0.9f}; + colors[ImGuiCol_FrameBgHovered] = (ImVec4){0.1f, 0.1f, 0.1f, 1.0f}; + colors[ImGuiCol_FrameBgActive] = (ImVec4){0.29f, 0.29f, 0.29f, 1.00f}; + colors[ImGuiCol_TitleBg] = (ImVec4){0.00f, 0.00f, 0.00f, 1.00f}; + colors[ImGuiCol_TitleBgActive] = (ImVec4){0.06f, 0.06f, 0.06f, 1.00f}; + colors[ImGuiCol_TitleBgCollapsed] = (ImVec4){0.00f, 0.00f, 0.00f, 1.00f}; + colors[ImGuiCol_MenuBarBg] = (ImVec4){0.10f, 0.10f, 0.10f, 1.00f}; + colors[ImGuiCol_ScrollbarBg] = (ImVec4){0.05f, 0.05f, 0.05f, 0.54f}; + colors[ImGuiCol_ScrollbarGrab] = (ImVec4){0.34f, 0.34f, 0.34f, 0.54f}; + colors[ImGuiCol_ScrollbarGrabHovered] = (ImVec4){0.40f, 0.40f, 0.40f, 0.54f}; + colors[ImGuiCol_ScrollbarGrabActive] = (ImVec4){0.56f, 0.56f, 0.56f, 0.54f}; + colors[ImGuiCol_CheckMark] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; + colors[ImGuiCol_SliderGrab] = (ImVec4){0.34f, 0.34f, 0.34f, 0.8f}; + colors[ImGuiCol_SliderGrabActive] = (ImVec4){0.56f, 0.56f, 0.56f, 0.8f}; + colors[ImGuiCol_Button] = (ImVec4){0.25f, 0.25f, 0.25f, 1.00f}; + colors[ImGuiCol_ButtonHovered] = (ImVec4){0.19f, 0.19f, 0.19f, 0.54f}; + colors[ImGuiCol_ButtonActive] = (ImVec4){0.4f, 0.4f, 0.4f, 1.00f}; + colors[ImGuiCol_Header] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; + colors[ImGuiCol_HeaderHovered] = (ImVec4){0.00f, 0.00f, 0.00f, 0.36f}; + colors[ImGuiCol_HeaderActive] = (ImVec4){0.20f, 0.22f, 0.23f, 0.33f}; + colors[ImGuiCol_Separator] = (ImVec4){0.28f, 0.28f, 0.28f, 0.9f}; + colors[ImGuiCol_SeparatorHovered] = (ImVec4){0.44f, 0.44f, 0.44f, 0.29f}; + colors[ImGuiCol_SeparatorActive] = (ImVec4){0.40f, 0.44f, 0.47f, 1.00f}; + colors[ImGuiCol_ResizeGrip] = (ImVec4){0.28f, 0.28f, 0.28f, 0.29f}; + colors[ImGuiCol_ResizeGripHovered] = (ImVec4){0.44f, 0.44f, 0.44f, 0.29f}; + colors[ImGuiCol_ResizeGripActive] = (ImVec4){0.40f, 0.44f, 0.47f, 1.00f}; + colors[ImGuiCol_Tab] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; + colors[ImGuiCol_TabHovered] = (ImVec4){0.14f, 0.14f, 0.14f, 1.00f}; + colors[ImGuiCol_TabActive] = (ImVec4){0.20f, 0.20f, 0.20f, 0.36f}; + colors[ImGuiCol_TabUnfocused] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; + colors[ImGuiCol_TabUnfocusedActive] = (ImVec4){0.14f, 0.14f, 0.14f, 1.00f}; + // colors[ImGuiCol_DockingPreview] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; + // colors[ImGuiCol_DockingEmptyBg] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; + colors[ImGuiCol_PlotLines] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; + colors[ImGuiCol_PlotLinesHovered] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; + colors[ImGuiCol_PlotHistogram] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; + colors[ImGuiCol_PlotHistogramHovered] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; + colors[ImGuiCol_TableHeaderBg] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; + colors[ImGuiCol_TableBorderStrong] = (ImVec4){0.00f, 0.00f, 0.00f, 0.52f}; + colors[ImGuiCol_TableBorderLight] = (ImVec4){0.28f, 0.28f, 0.28f, 0.29f}; + colors[ImGuiCol_TableRowBg] = (ImVec4){0.00f, 0.00f, 0.00f, 0.00f}; + colors[ImGuiCol_TableRowBgAlt] = (ImVec4){1.00f, 1.00f, 1.00f, 0.06f}; + colors[ImGuiCol_TextSelectedBg] = (ImVec4){0.20f, 0.22f, 0.23f, 1.00f}; + colors[ImGuiCol_DragDropTarget] = (ImVec4){0.33f, 0.67f, 0.86f, 1.00f}; + colors[ImGuiCol_NavHighlight] = (ImVec4){1.00f, 0.00f, 0.00f, 1.00f}; + colors[ImGuiCol_NavWindowingHighlight] = (ImVec4){1.00f, 0.00f, 0.00f, 0.70f}; + colors[ImGuiCol_NavWindowingDimBg] = (ImVec4){1.00f, 0.00f, 0.00f, 0.20f}; + colors[ImGuiCol_ModalWindowDimBg] = (ImVec4){1.00f, 0.00f, 0.00f, 0.35f}; + + if(gui_state.settings.theme == SE_THEME_CUSTOM) { uint8_t *palette = gui_state.theme.palettes; - //Base color - if(palette[0*4+3]){ - float r = palette[0*4+0]/255.; - float g = palette[0*4+1]/255.; - float b = palette[0*4+2]/255.; - float a = palette[0*4+3]/255.; - colors[ImGuiCol_WindowBg] = (ImVec4){r, g, b, a}; - colors[ImGuiCol_ChildBg] = (ImVec4){r, g, b, a}; - colors[ImGuiCol_PopupBg] = (ImVec4){r, g, b, a}; - colors[ImGuiCol_MenuBarBg] = (ImVec4){r, g, b, a}; - } - //Text Color - if(palette[1*4+3]){ - float r = palette[1*4+0]/255.; - float g = palette[1*4+1]/255.; - float b = palette[1*4+2]/255.; - float a = palette[1*4+3]/255.; - colors[ImGuiCol_PlotLinesHovered] = - colors[ImGuiCol_PlotHistogramHovered] = - colors[ImGuiCol_Text] = (ImVec4){r,g,b,a}; - colors[ImGuiCol_TextDisabled] = (ImVec4){r,g,b,a*0.4f}; - colors[ImGuiCol_ScrollbarGrabHovered] = (ImVec4){r,g,b,a*0.6f}; - colors[ImGuiCol_SliderGrabActive] = colors[ImGuiCol_ScrollbarGrabActive] = (ImVec4){r,g,b,a*0.8f}; - } - //Second Color - if(palette[2*4+3]){ - float r = palette[2*4+0]/255.; - float g = palette[2*4+1]/255.; - float b = palette[2*4+2]/255.; - float a = palette[2*4+3]/255.; - colors[ImGuiCol_FrameBg] = (ImVec4){r,g,b,a*0.5}; - colors[ImGuiCol_ScrollbarBg] = (ImVec4){r,g,b,a}; + // Base color + if(palette[0 * 4 + 3]) { + float r = palette[0 * 4 + 0] / 255.; + float g = palette[0 * 4 + 1] / 255.; + float b = palette[0 * 4 + 2] / 255.; + float a = palette[0 * 4 + 3] / 255.; + colors[ImGuiCol_WindowBg] = (ImVec4){r, g, b, a}; + colors[ImGuiCol_ChildBg] = (ImVec4){r, g, b, a}; + colors[ImGuiCol_PopupBg] = (ImVec4){r, g, b, a}; + colors[ImGuiCol_MenuBarBg] = (ImVec4){r, g, b, a}; + } + // Text Color + if(palette[1 * 4 + 3]) { + float r = palette[1 * 4 + 0] / 255.; + float g = palette[1 * 4 + 1] / 255.; + float b = palette[1 * 4 + 2] / 255.; + float a = palette[1 * 4 + 3] / 255.; + colors[ImGuiCol_PlotLinesHovered] = + colors[ImGuiCol_PlotHistogramHovered] = + colors[ImGuiCol_Text] = (ImVec4){r, g, b, a}; + colors[ImGuiCol_TextDisabled] = (ImVec4){r, g, b, a * 0.4f}; + colors[ImGuiCol_ScrollbarGrabHovered] = (ImVec4){r, g, b, a * 0.6f}; + colors[ImGuiCol_SliderGrabActive] = colors[ImGuiCol_ScrollbarGrabActive] = (ImVec4){r, g, b, a * 0.8f}; + } + // Second Color + if(palette[2 * 4 + 3]) { + float r = palette[2 * 4 + 0] / 255.; + float g = palette[2 * 4 + 1] / 255.; + float b = palette[2 * 4 + 2] / 255.; + float a = palette[2 * 4 + 3] / 255.; + colors[ImGuiCol_FrameBg] = (ImVec4){r, g, b, a * 0.5}; + colors[ImGuiCol_ScrollbarBg] = (ImVec4){r, g, b, a}; colors[ImGuiCol_Button] = (ImVec4){r, g, b, a}; - colors[ImGuiCol_ButtonHovered] = (ImVec4){r,g,b, a*0.54f}; - colors[ImGuiCol_ButtonActive] = (ImVec4){r*2,g*2,b*2, a*1.00f}; - } - //Tab/Header - if(palette[3*4+3]){ - float r = palette[3*4+0]/255.; - float g = palette[3*4+1]/255.; - float b = palette[3*4+2]/255.; - float a = palette[3*4+3]/255.; - colors[ImGuiCol_TitleBg] = - colors[ImGuiCol_TitleBgActive] = - colors[ImGuiCol_TitleBgCollapsed] = - colors[ImGuiCol_TableHeaderBg] = - colors[ImGuiCol_TableBorderStrong] = (ImVec4){r,g,b,a}; - - colors[ImGuiCol_SliderGrab] = colors[ImGuiCol_ScrollbarGrab] = (ImVec4){r,g,b,a}; - - colors[ImGuiCol_FrameBgHovered] = (ImVec4){r,g,b,a*0.75}; - colors[ImGuiCol_FrameBgActive] = (ImVec4){r,g,b,a}; - - colors[ImGuiCol_Tab] = - colors[ImGuiCol_Header] = (ImVec4){r,g,b,a*0.5}; - colors[ImGuiCol_TabHovered] = - colors[ImGuiCol_HeaderHovered] = (ImVec4){r,g,b,a*0.75}; - colors[ImGuiCol_TabActive] = - colors[ImGuiCol_HeaderActive] = (ImVec4){r,g,b,a}; - - } - //Accent color (checkmark, bar/line graph) - if(palette[4*4+3]){ - float r = palette[4*4+0]/255.; - float g = palette[4*4+1]/255.; - float b = palette[4*4+2]/255.; - float a = palette[4*4+3]/255.; - colors[ImGuiCol_PlotLines] = - colors[ImGuiCol_PlotHistogram] = - colors[ImGuiCol_CheckMark] = (ImVec4){r,g,b,a}; - } - } - - if(gui_state.settings.theme == SE_THEME_LIGHT){ - int invert_list[]={ - ImGuiCol_Text, - ImGuiCol_TextDisabled, - ImGuiCol_WindowBg, - ImGuiCol_ChildBg, - ImGuiCol_PopupBg, - ImGuiCol_Border, - ImGuiCol_BorderShadow, - ImGuiCol_FrameBg, - ImGuiCol_FrameBgHovered, - ImGuiCol_FrameBgActive, - ImGuiCol_TitleBg, - ImGuiCol_TitleBgActive, - ImGuiCol_TitleBgCollapsed, - ImGuiCol_MenuBarBg, - ImGuiCol_ScrollbarBg, - ImGuiCol_ScrollbarGrab, - ImGuiCol_ScrollbarGrabHovered, - ImGuiCol_ScrollbarGrabActive, - ImGuiCol_SliderGrab, - ImGuiCol_SliderGrabActive, - ImGuiCol_Button, - ImGuiCol_ButtonHovered, - ImGuiCol_ButtonActive, - ImGuiCol_Header, - ImGuiCol_HeaderHovered, - ImGuiCol_HeaderActive, - ImGuiCol_Separator, - ImGuiCol_SeparatorHovered, - ImGuiCol_SeparatorActive, - ImGuiCol_ResizeGrip, - ImGuiCol_ResizeGripHovered, - ImGuiCol_ResizeGripActive, - ImGuiCol_Tab, - ImGuiCol_TabHovered, - ImGuiCol_TabActive, - ImGuiCol_TabUnfocused, - ImGuiCol_TabUnfocusedActive, - ImGuiCol_TableHeaderBg, - ImGuiCol_TableBorderStrong, - ImGuiCol_TableBorderLight, - ImGuiCol_TableRowBg, - ImGuiCol_TableRowBgAlt, - ImGuiCol_TextSelectedBg, - ImGuiCol_DragDropTarget, - ImGuiCol_NavHighlight, - ImGuiCol_NavWindowingHighlight, - ImGuiCol_NavWindowingDimBg, - ImGuiCol_ModalWindowDimBg, + colors[ImGuiCol_ButtonHovered] = (ImVec4){r, g, b, a * 0.54f}; + colors[ImGuiCol_ButtonActive] = (ImVec4){r * 2, g * 2, b * 2, a * 1.00f}; + } + // Tab/Header + if(palette[3 * 4 + 3]) { + float r = palette[3 * 4 + 0] / 255.; + float g = palette[3 * 4 + 1] / 255.; + float b = palette[3 * 4 + 2] / 255.; + float a = palette[3 * 4 + 3] / 255.; + colors[ImGuiCol_TitleBg] = + colors[ImGuiCol_TitleBgActive] = + colors[ImGuiCol_TitleBgCollapsed] = + colors[ImGuiCol_TableHeaderBg] = + colors[ImGuiCol_TableBorderStrong] = (ImVec4){r, g, b, a}; + + colors[ImGuiCol_SliderGrab] = colors[ImGuiCol_ScrollbarGrab] = (ImVec4){r, g, b, a}; + + colors[ImGuiCol_FrameBgHovered] = (ImVec4){r, g, b, a * 0.75}; + colors[ImGuiCol_FrameBgActive] = (ImVec4){r, g, b, a}; + + colors[ImGuiCol_Tab] = + colors[ImGuiCol_Header] = (ImVec4){r, g, b, a * 0.5}; + colors[ImGuiCol_TabHovered] = + colors[ImGuiCol_HeaderHovered] = (ImVec4){r, g, b, a * 0.75}; + colors[ImGuiCol_TabActive] = + colors[ImGuiCol_HeaderActive] = (ImVec4){r, g, b, a}; + } + // Accent color (checkmark, bar/line graph) + if(palette[4 * 4 + 3]) { + float r = palette[4 * 4 + 0] / 255.; + float g = palette[4 * 4 + 1] / 255.; + float b = palette[4 * 4 + 2] / 255.; + float a = palette[4 * 4 + 3] / 255.; + colors[ImGuiCol_PlotLines] = + colors[ImGuiCol_PlotHistogram] = + colors[ImGuiCol_CheckMark] = (ImVec4){r, g, b, a}; + } + } + + if(gui_state.settings.theme == SE_THEME_LIGHT) { + int invert_list[] = { + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, + ImGuiCol_ChildBg, + ImGuiCol_PopupBg, + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_TableHeaderBg, + ImGuiCol_TableBorderStrong, + ImGuiCol_TableBorderLight, + ImGuiCol_TableRowBg, + ImGuiCol_TableRowBgAlt, + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, + ImGuiCol_NavWindowingHighlight, + ImGuiCol_NavWindowingDimBg, + ImGuiCol_ModalWindowDimBg, }; - for(int i=0;iWindowPadding = (ImVec2){8.00f, 8.00f}; - style->FramePadding = (ImVec2){5.00f, 2.00f}; - //style->CellPadding = (ImVec2){6.00f, 6.00f}; - style->ItemSpacing = (ImVec2){6.00f, 6.00f}; - //style->ItemInnerSpacing = (ImVec2){6.00f, 6.00f}; - style->TouchExtraPadding = (ImVec2){2.00f, 4.00f}; - style->IndentSpacing = 25; - style->ScrollbarSize = 15; - style->GrabMinSize = 10; - style->WindowBorderSize = 0; - style->ChildBorderSize = 0; - style->PopupBorderSize = 0; - style->FrameBorderSize = 0; - style->TabBorderSize = 1; - style->WindowRounding = 0; - style->ChildRounding = 4; - style->FrameRounding = 0; - style->PopupRounding = 0; - style->ScrollbarRounding = 9; - style->GrabRounding = 100; - style->LogSliderDeadzone = 4; - style->TabRounding = 4; - style->ButtonTextAlign = (ImVec2){0.5,0.5}; - - if(gui_state.settings.theme == SE_THEME_BLACK){ - int black_list[]={ - ImGuiCol_WindowBg, - ImGuiCol_ChildBg, - ImGuiCol_PopupBg, - //ImGuiCol_FrameBg, - ImGuiCol_TitleBg, - ImGuiCol_MenuBarBg, - //ImGuiCol_ScrollbarBg, + for(int i = 0; i < sizeof(invert_list) / sizeof(invert_list[0]); ++i) { + colors[invert_list[i]].x = 1.0 - colors[invert_list[i]].x; + colors[invert_list[i]].y = 1.0 - colors[invert_list[i]].y; + colors[invert_list[i]].z = 1.0 - colors[invert_list[i]].z; + } + } + + ImGuiStyle *style = igGetStyle(); + style->WindowPadding = (ImVec2){8.00f, 8.00f}; + style->FramePadding = (ImVec2){5.00f, 2.00f}; + // style->CellPadding = (ImVec2){6.00f, 6.00f}; + style->ItemSpacing = (ImVec2){6.00f, 6.00f}; + // style->ItemInnerSpacing = (ImVec2){6.00f, 6.00f}; + style->TouchExtraPadding = (ImVec2){2.00f, 4.00f}; + style->IndentSpacing = 25; + style->ScrollbarSize = 15; + style->GrabMinSize = 10; + style->WindowBorderSize = 0; + style->ChildBorderSize = 0; + style->PopupBorderSize = 0; + style->FrameBorderSize = 0; + style->TabBorderSize = 1; + style->WindowRounding = 0; + style->ChildRounding = 4; + style->FrameRounding = 0; + style->PopupRounding = 0; + style->ScrollbarRounding = 9; + style->GrabRounding = 100; + style->LogSliderDeadzone = 4; + style->TabRounding = 4; + style->ButtonTextAlign = (ImVec2){0.5, 0.5}; + + if(gui_state.settings.theme == SE_THEME_BLACK) { + int black_list[] = { + ImGuiCol_WindowBg, + ImGuiCol_ChildBg, + ImGuiCol_PopupBg, + // ImGuiCol_FrameBg, + ImGuiCol_TitleBg, + ImGuiCol_MenuBarBg, + // ImGuiCol_ScrollbarBg, }; - colors[ImGuiCol_Button] = (ImVec4){0.18f, 0.18f, 0.18f, 1.00f}; - colors[ImGuiCol_FrameBg] = (ImVec4){0.15f, 0.15f, 0.15f, 0.9f}; - colors[ImGuiCol_ScrollbarBg] = (ImVec4){0.1f, 0.1f, 0.1f, 0.6f}; + colors[ImGuiCol_Button] = (ImVec4){0.18f, 0.18f, 0.18f, 1.00f}; + colors[ImGuiCol_FrameBg] = (ImVec4){0.15f, 0.15f, 0.15f, 0.9f}; + colors[ImGuiCol_ScrollbarBg] = (ImVec4){0.1f, 0.1f, 0.1f, 0.6f}; - for(int i=0;ikey.bound_id[i]=-1; - cont->key.bound_id[SE_KEY_A]= AKEYCODE_BUTTON_A; - cont->key.bound_id[SE_KEY_B]= AKEYCODE_BUTTON_B; - cont->key.bound_id[SE_KEY_X]= AKEYCODE_BUTTON_X; - cont->key.bound_id[SE_KEY_Y]= AKEYCODE_BUTTON_Y; - cont->key.bound_id[SE_KEY_L]= AKEYCODE_BUTTON_L1; - cont->key.bound_id[SE_KEY_R]= AKEYCODE_BUTTON_R1; - cont->key.bound_id[SE_KEY_UP]= AKEYCODE_DPAD_UP; - cont->key.bound_id[SE_KEY_DOWN]= AKEYCODE_DPAD_DOWN; - cont->key.bound_id[SE_KEY_LEFT]= AKEYCODE_DPAD_LEFT; - cont->key.bound_id[SE_KEY_RIGHT]= AKEYCODE_DPAD_RIGHT; - cont->key.bound_id[SE_KEY_START]= AKEYCODE_BUTTON_START; - cont->key.bound_id[SE_KEY_SELECT]= AKEYCODE_BUTTON_SELECT; - - cont->key.bound_id[SE_KEY_EMU_PAUSE]= AKEYCODE_BUTTON_MODE; - cont->key.bound_id[SE_KEY_RESET_GAME]= AKEYCODE_R; - cont->key.bound_id[SE_KEY_CAPTURE_STATE(0)]= AKEYCODE_1; - cont->key.bound_id[SE_KEY_CAPTURE_STATE(1)]= AKEYCODE_2; - cont->key.bound_id[SE_KEY_CAPTURE_STATE(2)]= AKEYCODE_3; - cont->key.bound_id[SE_KEY_CAPTURE_STATE(3)]= AKEYCODE_4; - cont->key.bound_id[SE_KEY_RESTORE_STATE(0)]= AKEYCODE_F1; - cont->key.bound_id[SE_KEY_RESTORE_STATE(1)]= AKEYCODE_F2; - cont->key.bound_id[SE_KEY_RESTORE_STATE(2)]= AKEYCODE_F3; - cont->key.bound_id[SE_KEY_RESTORE_STATE(3)]= AKEYCODE_F4; - - cont->key.bound_id[SE_KEY_SOLAR_P]= AKEYCODE_PLUS; - cont->key.bound_id[SE_KEY_SOLAR_M]= AKEYCODE_MINUS; +void se_set_default_controller_binds(se_controller_state_t *cont) { + if(!cont) return; + for(int i = 0; i < SE_NUM_KEYBINDS; ++i) + cont->key.bound_id[i] = -1; + cont->key.bound_id[SE_KEY_A] = AKEYCODE_BUTTON_A; + cont->key.bound_id[SE_KEY_B] = AKEYCODE_BUTTON_B; + cont->key.bound_id[SE_KEY_X] = AKEYCODE_BUTTON_X; + cont->key.bound_id[SE_KEY_Y] = AKEYCODE_BUTTON_Y; + cont->key.bound_id[SE_KEY_L] = AKEYCODE_BUTTON_L1; + cont->key.bound_id[SE_KEY_R] = AKEYCODE_BUTTON_R1; + cont->key.bound_id[SE_KEY_UP] = AKEYCODE_DPAD_UP; + cont->key.bound_id[SE_KEY_DOWN] = AKEYCODE_DPAD_DOWN; + cont->key.bound_id[SE_KEY_LEFT] = AKEYCODE_DPAD_LEFT; + cont->key.bound_id[SE_KEY_RIGHT] = AKEYCODE_DPAD_RIGHT; + cont->key.bound_id[SE_KEY_START] = AKEYCODE_BUTTON_START; + cont->key.bound_id[SE_KEY_SELECT] = AKEYCODE_BUTTON_SELECT; + + cont->key.bound_id[SE_KEY_EMU_PAUSE] = AKEYCODE_BUTTON_MODE; + cont->key.bound_id[SE_KEY_RESET_GAME] = AKEYCODE_R; + cont->key.bound_id[SE_KEY_CAPTURE_STATE(0)] = AKEYCODE_1; + cont->key.bound_id[SE_KEY_CAPTURE_STATE(1)] = AKEYCODE_2; + cont->key.bound_id[SE_KEY_CAPTURE_STATE(2)] = AKEYCODE_3; + cont->key.bound_id[SE_KEY_CAPTURE_STATE(3)] = AKEYCODE_4; + cont->key.bound_id[SE_KEY_RESTORE_STATE(0)] = AKEYCODE_F1; + cont->key.bound_id[SE_KEY_RESTORE_STATE(1)] = AKEYCODE_F2; + cont->key.bound_id[SE_KEY_RESTORE_STATE(2)] = AKEYCODE_F3; + cont->key.bound_id[SE_KEY_RESTORE_STATE(3)] = AKEYCODE_F4; + + cont->key.bound_id[SE_KEY_SOLAR_P] = AKEYCODE_PLUS; + cont->key.bound_id[SE_KEY_SOLAR_M] = AKEYCODE_MINUS; /* cont->key.bound_id[SE_KEY_EMU_PAUSE] = se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_GUIDE,SE_JOY_POS_MASK); cont->key.bound_id[SE_KEY_EMU_REWIND] = se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_PADDLE1,SE_JOY_POS_MASK); @@ -5175,378 +5247,393 @@ void se_set_default_controller_binds(se_controller_state_t* cont){ cont->analog.bound_id[SE_ANALOG_R] = AMOTION_EVENT_AXIS_RTRIGGER; } #endif -//Returns true if loaded successfully -bool se_load_controller_settings(se_controller_state_t * cont){ - if(!cont)return false; +// Returns true if loaded successfully +bool se_load_controller_settings(se_controller_state_t *cont) { + if(!cont) return false; #ifdef USE_SDL - if(!cont->sdl_joystick)return false; + if(!cont->sdl_joystick) return false; #endif #ifdef PLATFORM_ANDROID - strncpy(cont->name,SE_ANDROID_CONTROLLER_NAME, sizeof(cont->name) ); + strncpy(cont->name, SE_ANDROID_CONTROLLER_NAME, sizeof(cont->name)); #endif - int32_t bind_map[SE_NUM_BINDS_ALLOC*2]; - char settings_path[SB_FILE_PATH_SIZE]; - snprintf(settings_path,SB_FILE_PATH_SIZE,"%s%s-bindings.bin",se_get_pref_path(),cont->name); - bool load_old_settings = sb_load_file_data_into_buffer(settings_path,(uint8_t*)bind_map,sizeof(bind_map)); - if(load_old_settings){ - for(int i=0;ikey.bound_id[i]=bind_map[i]; - cont->analog.bound_id[i]=bind_map[i+SE_NUM_BINDS_ALLOC]; + int32_t bind_map[SE_NUM_BINDS_ALLOC * 2]; + char settings_path[SB_FILE_PATH_SIZE]; + snprintf(settings_path, SB_FILE_PATH_SIZE, "%s%s-bindings.bin", se_get_pref_path(), cont->name); + bool load_old_settings = sb_load_file_data_into_buffer(settings_path, (uint8_t *)bind_map, sizeof(bind_map)); + if(load_old_settings) { + for(int i = 0; i < SE_NUM_BINDS_ALLOC; ++i) { + cont->key.bound_id[i] = bind_map[i]; + cont->analog.bound_id[i] = bind_map[i + SE_NUM_BINDS_ALLOC]; } } return load_old_settings; } #ifdef USE_SDL -int se_get_sdl_key_bind(SDL_GameController* gc, int button, int joystick_direction_mask){ +int se_get_sdl_key_bind(SDL_GameController *gc, int button, int joystick_direction_mask) { SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(gc, button); - if(bind.bindType==SDL_CONTROLLER_BINDTYPE_HAT){ + if(bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { int hat_id = bind.value.hat.hat; int hat_mask = bind.value.hat.hat_mask; int mask = 0; - if(hat_mask&SDL_HAT_UP)mask = SDL_HAT_UP; - if(hat_mask&SDL_HAT_DOWN)mask = SDL_HAT_DOWN; - if(hat_mask&SDL_HAT_LEFT)mask = SDL_HAT_LEFT; - if(hat_mask&SDL_HAT_RIGHT)mask = SDL_HAT_RIGHT; - if(!mask)return -1; - return SE_HAT_MASK| (hat_id<<8)|mask; + if(hat_mask & SDL_HAT_UP) mask = SDL_HAT_UP; + if(hat_mask & SDL_HAT_DOWN) mask = SDL_HAT_DOWN; + if(hat_mask & SDL_HAT_LEFT) mask = SDL_HAT_LEFT; + if(hat_mask & SDL_HAT_RIGHT) mask = SDL_HAT_RIGHT; + if(!mask) return -1; + return SE_HAT_MASK | (hat_id << 8) | mask; }; - if(bind.bindType==SDL_CONTROLLER_BINDTYPE_AXIS){ - return bind.value.axis|joystick_direction_mask; + if(bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { + return bind.value.axis | joystick_direction_mask; } - if(bind.bindType!=SDL_CONTROLLER_BINDTYPE_BUTTON)return -1; - else return bind.value.button; + if(bind.bindType != SDL_CONTROLLER_BINDTYPE_BUTTON) + return -1; + else + return bind.value.button; } -int se_get_sdl_axis_bind(SDL_GameController* gc, int button){ +int se_get_sdl_axis_bind(SDL_GameController *gc, int button) { SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(gc, button); - if(bind.bindType!=SDL_CONTROLLER_BINDTYPE_AXIS)return -1; - else return bind.value.axis; -} -void se_set_default_controller_binds(se_controller_state_t* cont){ - if(!cont ||!cont->sdl_gc)return; - SDL_GameController * gc = cont->sdl_gc; + if(bind.bindType != SDL_CONTROLLER_BINDTYPE_AXIS) + return -1; + else + return bind.value.axis; +} +void se_set_default_controller_binds(se_controller_state_t *cont) { + if(!cont || !cont->sdl_gc) return; + SDL_GameController *gc = cont->sdl_gc; SDL_GameControllerUpdate(); - for(int i=0;ikey.bound_id[i]=-1; - cont->key.bound_id[SE_KEY_A]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_A,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_B]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_B,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_X]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_X,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_Y]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_Y,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_L]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_LEFTSHOULDER,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_R]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_UP]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_DPAD_UP,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_DOWN]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_DPAD_DOWN,SE_JOY_NEG_MASK); - cont->key.bound_id[SE_KEY_LEFT]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_DPAD_LEFT,SE_JOY_NEG_MASK); - cont->key.bound_id[SE_KEY_RIGHT]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_DPAD_RIGHT,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_START]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_START,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_SELECT]= se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_BACK,SE_JOY_POS_MASK); - - cont->key.bound_id[SE_KEY_EMU_PAUSE] = se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_GUIDE,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_EMU_REWIND] = se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_PADDLE1,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_EMU_FF_2X] = se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_PADDLE2,SE_JOY_POS_MASK); - cont->key.bound_id[SE_KEY_EMU_FF_MAX] = se_get_sdl_key_bind(gc,SDL_CONTROLLER_BUTTON_PADDLE3,SE_JOY_POS_MASK); - - cont->analog.bound_id[SE_ANALOG_UP_DOWN] = se_get_sdl_axis_bind(gc,SDL_CONTROLLER_AXIS_LEFTY); - cont->analog.bound_id[SE_ANALOG_LEFT_RIGHT] = se_get_sdl_axis_bind(gc,SDL_CONTROLLER_AXIS_LEFTX); - cont->analog.bound_id[SE_ANALOG_L] = se_get_sdl_axis_bind(gc,SDL_CONTROLLER_AXIS_TRIGGERLEFT); - cont->analog.bound_id[SE_ANALOG_R] = se_get_sdl_axis_bind(gc,SDL_CONTROLLER_AXIS_TRIGGERRIGHT); -} -void se_set_new_controller(se_controller_state_t* cont, int index){ - SDL_Joystick*joy = SDL_JoystickOpen(index); - if(joy==cont->sdl_joystick)return; - if(cont->sdl_joystick)SDL_JoystickClose(cont->sdl_joystick); - if(cont->sdl_gc)SDL_GameControllerClose(cont->sdl_gc); + for(int i = 0; i < SE_NUM_KEYBINDS; ++i) + cont->key.bound_id[i] = -1; + cont->key.bound_id[SE_KEY_A] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_A, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_B] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_B, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_X] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_X, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_Y] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_Y, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_L] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_R] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_UP] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_DPAD_UP, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_DOWN] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_DPAD_DOWN, SE_JOY_NEG_MASK); + cont->key.bound_id[SE_KEY_LEFT] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_DPAD_LEFT, SE_JOY_NEG_MASK); + cont->key.bound_id[SE_KEY_RIGHT] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_START] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_START, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_SELECT] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_BACK, SE_JOY_POS_MASK); + + cont->key.bound_id[SE_KEY_EMU_PAUSE] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_GUIDE, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_EMU_REWIND] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_PADDLE1, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_EMU_FF_2X] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_PADDLE2, SE_JOY_POS_MASK); + cont->key.bound_id[SE_KEY_EMU_FF_MAX] = se_get_sdl_key_bind(gc, SDL_CONTROLLER_BUTTON_PADDLE3, SE_JOY_POS_MASK); + + cont->analog.bound_id[SE_ANALOG_UP_DOWN] = se_get_sdl_axis_bind(gc, SDL_CONTROLLER_AXIS_LEFTY); + cont->analog.bound_id[SE_ANALOG_LEFT_RIGHT] = se_get_sdl_axis_bind(gc, SDL_CONTROLLER_AXIS_LEFTX); + cont->analog.bound_id[SE_ANALOG_L] = se_get_sdl_axis_bind(gc, SDL_CONTROLLER_AXIS_TRIGGERLEFT); + cont->analog.bound_id[SE_ANALOG_R] = se_get_sdl_axis_bind(gc, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); +} +void se_set_new_controller(se_controller_state_t *cont, int index) { + SDL_Joystick *joy = SDL_JoystickOpen(index); + if(joy == cont->sdl_joystick) return; + if(cont->sdl_joystick) SDL_JoystickClose(cont->sdl_joystick); + if(cont->sdl_gc) SDL_GameControllerClose(cont->sdl_gc); cont->sdl_gc = SDL_GameControllerOpen(index); SDL_GameControllerUpdate(); - cont->sdl_joystick = joy; - if(cont->sdl_joystick==NULL)return; - strncpy(cont->name, SDL_JoystickName(cont->sdl_joystick),sizeof(cont->name)); + cont->sdl_joystick = joy; + if(cont->sdl_joystick == NULL) return; + strncpy(cont->name, SDL_JoystickName(cont->sdl_joystick), sizeof(cont->name)); SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), cont->guid, sizeof(cont->guid)); se_initialize_keybind(&cont->key); se_initialize_keybind(&cont->analog); - if(!se_load_controller_settings(cont))se_set_default_controller_binds(cont); + if(!se_load_controller_settings(cont)) se_set_default_controller_binds(cont); } #endif -void se_draw_controller_config(gui_state_t* gui){ +void se_draw_controller_config(gui_state_t *gui) { se_text(ICON_FK_GAMEPAD " Controllers"); igSeparator(); - ImGuiStyle* style = igGetStyle(); + ImGuiStyle *style = igGetStyle(); se_controller_state_t *cont = &gui->controller; #if USE_SDL - const char* cont_name = "No Controller"; - if(cont->sdl_joystick){ + const char *cont_name = "No Controller"; + if(cont->sdl_joystick) { cont_name = SDL_JoystickName(cont->sdl_joystick); } - if(igBeginCombo(se_localize_and_cache("Controller"), se_localize_and_cache(cont_name), ImGuiComboFlags_None)){ + if(igBeginCombo(se_localize_and_cache("Controller"), se_localize_and_cache(cont_name), ImGuiComboFlags_None)) { { - bool is_selected=cont->sdl_joystick==NULL; - if(igSelectableBool(se_localize_and_cache("No Controller"),is_selected,ImGuiSelectableFlags_None, (ImVec2){0,0})){ - if(cont->sdl_joystick)SDL_JoystickClose(cont->sdl_joystick); - if(cont->sdl_gc)SDL_GameControllerClose(cont->sdl_gc); - cont->sdl_joystick=NULL; + bool is_selected = cont->sdl_joystick == NULL; + if(igSelectableBool(se_localize_and_cache("No Controller"), is_selected, ImGuiSelectableFlags_None, (ImVec2){0, 0})) { + if(cont->sdl_joystick) SDL_JoystickClose(cont->sdl_joystick); + if(cont->sdl_gc) SDL_GameControllerClose(cont->sdl_gc); + cont->sdl_joystick = NULL; cont->sdl_gc = NULL; } - if(is_selected)igSetItemDefaultFocus(); + if(is_selected) igSetItemDefaultFocus(); } - for(int j= 0;jsdl_joystick)return; + if(!cont->sdl_joystick) return; #else - const char* cont_name = SE_ANDROID_CONTROLLER_NAME; + const char *cont_name = SE_ANDROID_CONTROLLER_NAME; #endif - bool modified = se_handle_keybind_settings(SE_BIND_KEY,&(cont->key)); - modified |= se_handle_keybind_settings(SE_BIND_ANALOG,&(cont->analog)); - if(se_button("Reset Default Controller Bindings",(ImVec2){0,0})){ + bool modified = se_handle_keybind_settings(SE_BIND_KEY, &(cont->key)); + modified |= se_handle_keybind_settings(SE_BIND_ANALOG, &(cont->analog)); + if(se_button("Reset Default Controller Bindings", (ImVec2){0, 0})) { se_set_default_controller_binds(cont); - modified=true; + modified = true; } - if(modified){ - int32_t bind_map[SE_NUM_BINDS_ALLOC*2]; - for(int i=0;ikey.bound_id[i]; - bind_map[i+SE_NUM_BINDS_ALLOC]= cont->analog.bound_id[i]; + if(modified) { + int32_t bind_map[SE_NUM_BINDS_ALLOC * 2]; + for(int i = 0; i < SE_NUM_BINDS_ALLOC; ++i) { + bind_map[i] = cont->key.bound_id[i]; + bind_map[i + SE_NUM_BINDS_ALLOC] = cont->analog.bound_id[i]; } char settings_path[SB_FILE_PATH_SIZE]; - snprintf(settings_path,SB_FILE_PATH_SIZE,"%s%s-bindings.bin",se_get_pref_path(),cont_name); - sb_save_file_data(settings_path,(uint8_t*)bind_map,sizeof(bind_map)); + snprintf(settings_path, SB_FILE_PATH_SIZE, "%s%s-bindings.bin", se_get_pref_path(), cont_name); + sb_save_file_data(settings_path, (uint8_t *)bind_map, sizeof(bind_map)); se_emscripten_flush_fs(); } #ifdef USE_SDL - if(SDL_JoystickHasRumble(cont->sdl_joystick)){se_text("Rumble Supported"); - }else se_text("Rumble Not Supported"); + if(SDL_JoystickHasRumble(cont->sdl_joystick)) { + se_text("Rumble Supported"); + } else + se_text("Rumble Not Supported"); #endif } -void se_reset_default_gb_palette(){ - uint8_t palette[4*3] = { 0x81,0x8F,0x38,0x64,0x7D,0x43,0x56,0x6D,0x3F,0x31,0x4A,0x2D }; - for(int i=0;i<4;++i){ - gui_state.settings.gb_palette[i]=palette[i*3]|(palette[i*3+1]<<8)|(palette[i*3+2]<<16); +void se_reset_default_gb_palette() { + uint8_t palette[4 * 3] = {0x81, 0x8F, 0x38, 0x64, 0x7D, 0x43, 0x56, 0x6D, 0x3F, 0x31, 0x4A, 0x2D}; + for(int i = 0; i < 4; ++i) { + gui_state.settings.gb_palette[i] = palette[i * 3] | (palette[i * 3 + 1] << 8) | (palette[i * 3 + 2] << 16); } } -void se_capture_state_slot(int slot){ - se_capture_state(&core, save_states+slot); +void se_capture_state_slot(int slot) { + se_capture_state(&core, save_states + slot); char save_state_path[SB_FILE_PATH_SIZE]; - snprintf(save_state_path,SB_FILE_PATH_SIZE,"%s.slot%d.state.png",emu_state.save_data_base_path,slot); - se_save_state_to_disk(save_states+slot,save_state_path); + snprintf(save_state_path, SB_FILE_PATH_SIZE, "%s.slot%d.state.png", emu_state.save_data_base_path, slot); + se_save_state_to_disk(save_states + slot, save_state_path); } -void se_restore_state_slot(int slot){ - if(save_states[slot].valid)se_restore_state(&core, save_states+slot); +void se_restore_state_slot(int slot) { + if(save_states[slot].valid) se_restore_state(&core, save_states + slot); } -void se_push_disabled(){ +void se_push_disabled() { ImGuiStyle *style = igGetStyle(); igPushStyleColorVec4(ImGuiCol_Text, style->Colors[ImGuiCol_TextDisabled]); igPushItemFlag(ImGuiItemFlags_Disabled, true); } -void se_pop_disabled(){ - igPopStyleColor(1); - igPopItemFlag(); +void se_pop_disabled() { + igPopStyleColor(1); + igPopItemFlag(); } -void se_draw_touch_controls_settings(){ +void se_draw_touch_controls_settings() { se_text(ICON_FK_HAND_O_RIGHT " Touch Control Settings"); igSeparator(); - float aspect_ratio = gui_state.screen_width/(float)gui_state.screen_height; - float scale = (igGetWindowContentRegionWidth()-2)/(aspect_ratio+1.0/aspect_ratio); + float aspect_ratio = gui_state.screen_width / (float)gui_state.screen_height; + float scale = (igGetWindowContentRegionWidth() - 2) / (aspect_ratio + 1.0 / aspect_ratio); - igDummy((ImVec2){0,(igGetWindowContentRegionWidth()*0.5-2-scale)*0.5}); - if(igBeginChildFrame(1,(ImVec2){scale*aspect_ratio,scale},ImGuiWindowFlags_None)){ + igDummy((ImVec2){0, (igGetWindowContentRegionWidth() * 0.5 - 2 - scale) * 0.5}); + if(igBeginChildFrame(1, (ImVec2){scale * aspect_ratio, scale}, ImGuiWindowFlags_None)) { se_draw_emulated_system_screen(true); } igEndChildFrame(); - igSameLine(0,2); + igSameLine(0, 2); - if(igBeginChildFrame(2,(ImVec2){scale/aspect_ratio,scale},ImGuiWindowFlags_None)){ + if(igBeginChildFrame(2, (ImVec2){scale / aspect_ratio, scale}, ImGuiWindowFlags_None)) { se_draw_emulated_system_screen(true); } igEndChildFrame(); - igDummy((ImVec2){0,(igGetWindowContentRegionWidth()*0.5-2-scale)*0.5}); + igDummy((ImVec2){0, (igGetWindowContentRegionWidth() * 0.5 - 2 - scale) * 0.5}); - se_text("Scale");igSameLine(SE_FIELD_INDENT,0); + se_text("Scale"); + igSameLine(SE_FIELD_INDENT, 0); igPushItemWidth(-1); - se_slider_float("##TouchControlsScale",&gui_state.settings.touch_controls_scale,0.3,1.0,"Scale: %.2f"); + se_slider_float("##TouchControlsScale", &gui_state.settings.touch_controls_scale, 0.3, 1.0, "Scale: %.2f"); - se_text("Opacity");igSameLine(SE_FIELD_INDENT,0); + se_text("Opacity"); + igSameLine(SE_FIELD_INDENT, 0); igPushItemWidth(-1); - se_slider_float("##TouchControlsOpacity",&gui_state.settings.touch_controls_opacity,0,1.0,"Opacity: %.2f"); + se_slider_float("##TouchControlsOpacity", &gui_state.settings.touch_controls_opacity, 0, 1.0, "Opacity: %.2f"); igPopItemWidth(); bool auto_hide = gui_state.settings.auto_hide_touch_controls; - se_checkbox("Hide when inactive",&auto_hide); + se_checkbox("Hide when inactive", &auto_hide); gui_state.settings.auto_hide_touch_controls = auto_hide; bool show_turbo = gui_state.settings.touch_controls_show_turbo; - se_checkbox("Enable Turbo and Hold Button Modifiers",&show_turbo); + se_checkbox("Enable Turbo and Hold Button Modifiers", &show_turbo); gui_state.settings.touch_controls_show_turbo = show_turbo; - + bool avoid_touchscreen = gui_state.settings.avoid_overlaping_touchscreen; - se_checkbox("Avoid NDS Touchscreen",&avoid_touchscreen); + se_checkbox("Avoid NDS Touchscreen", &avoid_touchscreen); gui_state.settings.avoid_overlaping_touchscreen = avoid_touchscreen; - } -void se_draw_menu_panel(){ +void se_draw_menu_panel() { ImGuiStyle *style = igGetStyle(); - int win_w = igGetWindowContentRegionWidth(); - ImDrawList*dl= igGetWindowDrawList(); + int win_w = igGetWindowContentRegionWidth(); + ImDrawList *dl = igGetWindowDrawList(); se_text(ICON_FK_FLOPPY_O " Save States"); igSeparator(); - if(gui_state.settings.hardcore_mode)se_text("Disabled in Hardcore Mode"); - else{ - if(!emu_state.rom_loaded)se_push_disabled(); - for(int i=0;iFramePadding.x)*0.5; - int slot_h = 64; - if(i%2)igSameLine(0,style->FramePadding.x); + int slot_w = (win_w - style->FramePadding.x) * 0.5; + int slot_h = 64; + if(i % 2) igSameLine(0, style->FramePadding.x); - igBeginChildFrame(i+100, (ImVec2){slot_w,slot_h},ImGuiWindowFlags_None); + igBeginChildFrame(i + 100, (ImVec2){slot_w, slot_h}, ImGuiWindowFlags_None); ImVec2 screen_p; igGetCursorScreenPos(&screen_p); int screen_x = screen_p.x; int screen_y = screen_p.y; int screen_w = 64; - int screen_h = 64+style->FramePadding.y*2; - int button_w = 55; - se_text(se_localize_and_cache("Save Slot %d"),i); - if(se_button(se_localize_and_cache("Capture"),(ImVec2){button_w,0}))se_capture_state_slot(i); - if(!save_states[i].valid)se_push_disabled(); - if(se_button(se_localize_and_cache("Restore"),(ImVec2){button_w,0}))se_restore_state_slot(i); - if(!save_states[i].valid)se_pop_disabled(); - - if(save_states[i].valid){ + int screen_h = 64 + style->FramePadding.y * 2; + int button_w = 55; + se_text(se_localize_and_cache("Save Slot %d"), i); + if(se_button(se_localize_and_cache("Capture"), (ImVec2){button_w, 0})) se_capture_state_slot(i); + if(!save_states[i].valid) se_push_disabled(); + if(se_button(se_localize_and_cache("Restore"), (ImVec2){button_w, 0})) se_restore_state_slot(i); + if(!save_states[i].valid) se_pop_disabled(); + + if(save_states[i].valid) { float w_scale = 1.0; float h_scale = 1.0; - if(save_states[i].screenshot_width>save_states[i].screenshot_height){ - h_scale = (float)save_states[i].screenshot_height/(float)save_states[i].screenshot_width; - }else{ - w_scale = (float)save_states[i].screenshot_width/(float)save_states[i].screenshot_height; + if(save_states[i].screenshot_width > save_states[i].screenshot_height) { + h_scale = (float)save_states[i].screenshot_height / (float)save_states[i].screenshot_width; + } else { + w_scale = (float)save_states[i].screenshot_width / (float)save_states[i].screenshot_height; } - screen_w*=w_scale; - screen_h*=h_scale; - screen_x+=button_w+(slot_w-screen_w-button_w)*0.5; - screen_y+=(slot_h-screen_h)*0.5-style->FramePadding.y; - - se_draw_image(save_states[i].screenshot,save_states[i].screenshot_width,save_states[i].screenshot_height, - screen_x*se_dpi_scale(),screen_y*se_dpi_scale(),screen_w*se_dpi_scale(),screen_h*se_dpi_scale(), true); - if(save_states[i].valid==2){ - igSetCursorScreenPos((ImVec2){screen_x+screen_w*0.5-15,screen_y+screen_h*0.5-15}); - se_button(ICON_FK_EXCLAMATION_TRIANGLE,(ImVec2){30,30}); + screen_w *= w_scale; + screen_h *= h_scale; + screen_x += button_w + (slot_w - screen_w - button_w) * 0.5; + screen_y += (slot_h - screen_h) * 0.5 - style->FramePadding.y; + + se_draw_image(save_states[i].screenshot, save_states[i].screenshot_width, save_states[i].screenshot_height, + screen_x * se_dpi_scale(), screen_y * se_dpi_scale(), screen_w * se_dpi_scale(), screen_h * se_dpi_scale(), true); + if(save_states[i].valid == 2) { + igSetCursorScreenPos((ImVec2){screen_x + screen_w * 0.5 - 15, screen_y + screen_h * 0.5 - 15}); + se_button(ICON_FK_EXCLAMATION_TRIANGLE, (ImVec2){30, 30}); se_tooltip("This save state came from an incompatible build. SkyEmu has attempted to recover it, but there may be issues"); } - }else{ - screen_h*=0.85; - screen_x+=button_w+(slot_w-screen_w-button_w)*0.5; - screen_y+=(slot_h-screen_h)*0.5-style->FramePadding.y; + } else { + screen_h *= 0.85; + screen_x += button_w + (slot_w - screen_w - button_w) * 0.5; + screen_y += (slot_h - screen_h) * 0.5 - style->FramePadding.y; ImU32 color = igColorConvertFloat4ToU32(style->Colors[ImGuiCol_MenuBarBg]); - ImDrawList_AddRectFilled(igGetWindowDrawList(),(ImVec2){screen_x,screen_y},(ImVec2){screen_x+screen_w,screen_y+screen_h},color,0,ImDrawCornerFlags_None); + ImDrawList_AddRectFilled(igGetWindowDrawList(), (ImVec2){screen_x, screen_y}, (ImVec2){screen_x + screen_w, screen_y + screen_h}, color, 0, ImDrawCornerFlags_None); ImVec2 anchor; - igSetCursorScreenPos((ImVec2){screen_x+screen_w*0.5-5,screen_y+screen_h*0.5-5}); + igSetCursorScreenPos((ImVec2){screen_x + screen_w * 0.5 - 5, screen_y + screen_h * 0.5 - 5}); se_text(ICON_FK_BAN); } igEndChildFrame(); } - if(!emu_state.rom_loaded)se_pop_disabled(); + if(!emu_state.rom_loaded) se_pop_disabled(); } - if(emu_state.system==SYSTEM_NDS || emu_state.system == SYSTEM_GBA || emu_state.system == SYSTEM_GB){ + if(emu_state.system == SYSTEM_NDS || emu_state.system == SYSTEM_GBA || emu_state.system == SYSTEM_GB) { se_text(ICON_FK_KEY " Action Replay Codes"); igSeparator(); - if(gui_state.settings.hardcore_mode) se_text("Disabled in Hardcore Mode"); - else{ - int free_cheat_index = -1; - for(int i=0;istate==-1){free_cheat_index=i; continue;} + if(gui_state.settings.hardcore_mode) + se_text("Disabled in Hardcore Mode"); + else { + int free_cheat_index = -1; + for(int i = 0; i < SE_NUM_CHEATS; i++) { + se_cheat_t *cheat = &cheats[i]; + if(cheat->state == -1) { + free_cheat_index = i; + continue; + } igPushIDInt(i); - if(gui_state.editing_cheat_index==i){ - igSetNextItemWidth(win_w-55); - igInputText("##Name",cheat->name,SE_MAX_CHEAT_NAME_SIZE-1,ImGuiInputTextFlags_None,NULL,NULL); - cheat->state = 0; - igSameLine(win_w-40,0); - if(se_button(ICON_FK_CHECK, (ImVec2){0,0})) { + if(gui_state.editing_cheat_index == i) { + igSetNextItemWidth(win_w - 55); + igInputText("##Name", cheat->name, SE_MAX_CHEAT_NAME_SIZE - 1, ImGuiInputTextFlags_None, NULL, NULL); + cheat->state = 0; + igSameLine(win_w - 40, 0); + if(se_button(ICON_FK_CHECK, (ImVec2){0, 0})) { gui_state.editing_cheat_index = -1; se_save_cheats(gui_state.cheat_path); } - }else{ + } else { bool active = cheat->state; - if(se_checkbox(cheat->name, &active)){ - cheat->state = active ? 1:0; + if(se_checkbox(cheat->name, &active)) { + cheat->state = active ? 1 : 0; se_save_cheats(gui_state.cheat_path); } - igSameLine(win_w-40,0); - if(se_button(ICON_FK_WRENCH, (ImVec2){0,0})) { + igSameLine(win_w - 40, 0); + if(se_button(ICON_FK_WRENCH, (ImVec2){0, 0})) { gui_state.editing_cheat_index = i; } } - igSameLine(win_w-15,0); - if(se_button(ICON_FK_TRASH, (ImVec2){-1,0})){ - if(gui_state.editing_cheat_index == i)gui_state.editing_cheat_index=-1; + igSameLine(win_w - 15, 0); + if(se_button(ICON_FK_TRASH, (ImVec2){-1, 0})) { + if(gui_state.editing_cheat_index == i) gui_state.editing_cheat_index = -1; cheat->state = -1; se_save_cheats(gui_state.cheat_path); } - if(gui_state.editing_cheat_index==i){ + if(gui_state.editing_cheat_index == i) { igPushFont(gui_state.mono_font); - char code_buffer[SE_MAX_CHEAT_CODE_SIZE*8] = { 0 }; - int off=0; - for(int i=0;isize;i+=1){ - off+=snprintf(code_buffer+off,sizeof(code_buffer)-off,"%08X",cheat->buffer[i]); - if(i%2)off+=snprintf(code_buffer+off,sizeof(code_buffer)-off,"\n"); - else off+=snprintf(code_buffer+off,sizeof(code_buffer)-off," "); + char code_buffer[SE_MAX_CHEAT_CODE_SIZE * 8] = {0}; + int off = 0; + for(int i = 0; i < cheat->size; i += 1) { + off += snprintf(code_buffer + off, sizeof(code_buffer) - off, "%08X", cheat->buffer[i]); + if(i % 2) + off += snprintf(code_buffer + off, sizeof(code_buffer) - off, "\n"); + else + off += snprintf(code_buffer + off, sizeof(code_buffer) - off, " "); } igSetNextItemWidth(win_w); // Not setting ImGuiInputTextFlags_CharsHexadecimal as it doesn't allow whitespace - if(igInputTextMultiline("##CheatCode",code_buffer,sizeof(code_buffer),(ImVec2){0,300},ImGuiInputTextFlags_CharsUppercase,NULL,NULL)){ - se_convert_cheat_code(code_buffer,gui_state.editing_cheat_index); + if(igInputTextMultiline("##CheatCode", code_buffer, sizeof(code_buffer), (ImVec2){0, 300}, ImGuiInputTextFlags_CharsUppercase, NULL, NULL)) { + se_convert_cheat_code(code_buffer, gui_state.editing_cheat_index); } igPopFont(); } igPopID(); } - if(free_cheat_index!=-1){ - if(se_button(ICON_FK_PLUS " New", (ImVec2){0,0})){ + if(free_cheat_index != -1) { + if(se_button(ICON_FK_PLUS " New", (ImVec2){0, 0})) { gui_state.editing_cheat_index = free_cheat_index; - se_cheat_t * cheat = cheats+gui_state.editing_cheat_index; - cheat->state = 0; - strcpy(cheat->name,"Untitled Code"); - memset(cheat->buffer,0,sizeof(cheat->buffer)); + se_cheat_t *cheat = cheats + gui_state.editing_cheat_index; + cheat->state = 0; + strcpy(cheat->name, "Untitled Code"); + memset(cheat->buffer, 0, sizeof(cheat->buffer)); } } } } { - se_bios_info_t * info = &gui_state.bios_info; - if(emu_state.rom_loaded){ + se_bios_info_t *info = &gui_state.bios_info; + if(emu_state.rom_loaded) { se_text(ICON_FK_CROSSHAIRS " Located BIOS/Firmware Files"); igSeparator(); bool missing_bios = false; - for(int i=0;iname)/sizeof(info->name[0]);++i){ - if(info->name[i][0]){ - if(info->success[i]){ - igPushStyleColorU32(ImGuiCol_Text,0xff00ff00); + for(int i = 0; i < sizeof(info->name) / sizeof(info->name[0]); ++i) { + if(info->name[i][0]) { + if(info->success[i]) { + igPushStyleColorU32(ImGuiCol_Text, 0xff00ff00); se_text(ICON_FK_CHECK); - }else{ - igPushStyleColorU32(ImGuiCol_Text,0xff0000ff); + } else { + igPushStyleColorU32(ImGuiCol_Text, 0xff0000ff); se_text(ICON_FK_TIMES); - missing_bios=true; + missing_bios = true; } igPopStyleColor(1); - igSameLine(0,2); - igSetNextItemWidth(win_w-55); - const char* bios_types[]={NULL}; - se_input_file_callback(info->name[i],info->path[i],bios_types,se_bios_file_open_fn,ImGuiInputTextFlags_None); + igSameLine(0, 2); + igSetNextItemWidth(win_w - 55); + const char *bios_types[] = {NULL}; + se_input_file_callback(info->name[i], info->path[i], bios_types, se_bios_file_open_fn, ImGuiInputTextFlags_None); } } - if(missing_bios){ - igPushStyleColorU32(ImGuiCol_Text,0xff0000ff); + if(missing_bios) { + igPushStyleColorU32(ImGuiCol_Text, 0xff0000ff); se_text("Can't find all needed BIOS/Boot ROM/Firmware Files."); se_text("Accuracy will suffer and some features won't work."); igPopStyleColor(1); @@ -5557,24 +5644,28 @@ void se_draw_menu_panel(){ igSeparator(); int v = gui_state.settings.screen_shader; igPushItemWidth(-1); - se_text("Screen Shader");igSameLine(SE_FIELD_INDENT,0); - se_combo_str("##Screen Shader",&v,"Pixelate\0Bilinear\0LCD\0LCD & Subpixels\0Smooth Upscale (xBRZ)\0",0); - gui_state.settings.screen_shader=v; + se_text("Screen Shader"); + igSameLine(SE_FIELD_INDENT, 0); + se_combo_str("##Screen Shader", &v, "Pixelate\0Bilinear\0LCD\0LCD & Subpixels\0Smooth Upscale (xBRZ)\0", 0); + gui_state.settings.screen_shader = v; v = gui_state.settings.screen_rotation; - se_text("Screen Rotation");igSameLine(SE_FIELD_INDENT,0); - se_combo_str("##Screen Rotation",&v,"0 degrees\00090 degrees\000180 degrees\000270 degrees\0",0); - gui_state.settings.screen_rotation=v; - se_text("Color Correction");igSameLine(SE_FIELD_INDENT,0); - se_slider_float("##Color Correction",&gui_state.settings.color_correction,0,1.0,"Strength: %.2f"); + se_text("Screen Rotation"); + igSameLine(SE_FIELD_INDENT, 0); + se_combo_str("##Screen Rotation", &v, "0 degrees\00090 degrees\000180 degrees\000270 degrees\0", 0); + gui_state.settings.screen_rotation = v; + se_text("Color Correction"); + igSameLine(SE_FIELD_INDENT, 0); + se_slider_float("##Color Correction", &gui_state.settings.color_correction, 0, 1.0, "Strength: %.2f"); int color_correct = gui_state.settings.gba_color_correction_mode; - se_text("GBA Color Correction Type");igSameLine(180,0); - se_combo_str("##ColorAlgorithm",&color_correct,"SkyEmu\0Higan\0",0); + se_text("GBA Color Correction Type"); + igSameLine(180, 0); + se_combo_str("##ColorAlgorithm", &color_correct, "SkyEmu\0Higan\0", 0); igPopItemWidth(); - gui_state.settings.gba_color_correction_mode=color_correct; + gui_state.settings.gba_color_correction_mode = color_correct; { bool b = gui_state.settings.ghosting; se_checkbox("Screen Ghosting", &b); - gui_state.settings.ghosting=b; + gui_state.settings.ghosting = b; } { bool b = gui_state.settings.integer_scaling; @@ -5587,605 +5678,626 @@ void se_draw_menu_panel(){ gui_state.settings.stretch_to_fit = b; } se_text("Game Boy Color Palette"); - for(int i=0;i<4;++i){ + for(int i = 0; i < 4; ++i) { char buff[60]; - snprintf(buff,60,se_localize_and_cache("GB Palette %d"),i); - float color[3]; + snprintf(buff, 60, se_localize_and_cache("GB Palette %d"), i); + float color[3]; uint32_t col = gui_state.settings.gb_palette[i]; - color[0]= SB_BFE(col,0,8)/255.; - color[1]= SB_BFE(col,8,8)/255.; - color[2]= SB_BFE(col,16,8)/255.; - igColorEdit3(buff,color,ImGuiColorEditFlags_None); - col = (((int)(color[0]*255))&0xff); - col |= (((int)(color[1]*255))&0xff)<<8; - col |= (((int)(color[2]*255))&0xff)<<16; - gui_state.settings.gb_palette[i]=col; - } - if(se_button("Reset Palette to Defaults",(ImVec2){0,0}))se_reset_default_gb_palette(); - if(gui_state.ui_type==SE_UI_ANDROID||gui_state.ui_type==SE_UI_IOS){ + color[0] = SB_BFE(col, 0, 8) / 255.; + color[1] = SB_BFE(col, 8, 8) / 255.; + color[2] = SB_BFE(col, 16, 8) / 255.; + igColorEdit3(buff, color, ImGuiColorEditFlags_None); + col = (((int)(color[0] * 255)) & 0xff); + col |= (((int)(color[1] * 255)) & 0xff) << 8; + col |= (((int)(color[2] * 255)) & 0xff) << 16; + gui_state.settings.gb_palette[i] = col; + } + if(se_button("Reset Palette to Defaults", (ImVec2){0, 0})) se_reset_default_gb_palette(); + if(gui_state.ui_type == SE_UI_ANDROID || gui_state.ui_type == SE_UI_IOS) { se_draw_touch_controls_settings(); - }else{ + } else { se_text(ICON_FK_KEYBOARD_O " Keybinds"); igSeparator(); - bool value= true; - bool modified = se_handle_keybind_settings(SE_BIND_KEYBOARD,&gui_state.key); - if(se_button("Reset Default Keybinds",(ImVec2){0,0})){ + bool value = true; + bool modified = se_handle_keybind_settings(SE_BIND_KEYBOARD, &gui_state.key); + if(se_button("Reset Default Keybinds", (ImVec2){0, 0})) { se_set_default_keybind(&gui_state); - modified=true; + modified = true; } - if(modified){ + if(modified) { char settings_path[SB_FILE_PATH_SIZE]; - snprintf(settings_path,SB_FILE_PATH_SIZE,"%skeyboard-bindings.bin",se_get_pref_path()); - sb_save_file_data(settings_path,(uint8_t*)gui_state.key.bound_id,sizeof(gui_state.key.bound_id)); + snprintf(settings_path, SB_FILE_PATH_SIZE, "%skeyboard-bindings.bin", se_get_pref_path()); + sb_save_file_data(settings_path, (uint8_t *)gui_state.key.bound_id, sizeof(gui_state.key.bound_id)); se_emscripten_flush_fs(); } } - #if defined( USE_SDL) ||defined(PLATFORM_ANDROID) +#if defined(USE_SDL) || defined(PLATFORM_ANDROID) se_draw_controller_config(&gui_state); - #endif +#endif - if(gui_state.ui_type!=SE_UI_ANDROID&&gui_state.ui_type!=SE_UI_IOS){ + if(gui_state.ui_type != SE_UI_ANDROID && gui_state.ui_type != SE_UI_IOS) { se_draw_touch_controls_settings(); } se_text(ICON_FK_TEXT_HEIGHT " GUI"); igSeparator(); - se_text("Language");igSameLine(SE_FIELD_INDENT,0); + se_text("Language"); + igSameLine(SE_FIELD_INDENT, 0); igPushItemWidth(-1); - if(igBeginCombo("##Language", se_language_string(gui_state.settings.language), ImGuiComboFlags_HeightLargest)){ - int lang_id = 0; - for(int lang_id=0;lang_idregions[SE_REGION_NAME].h/theme->regions[SE_REGION_NAME].w; - ImVec2 p,v; + se_custom_theme_t *theme = &gui_state.theme; + float w = igGetWindowContentRegionWidth(); + float h = w * theme->regions[SE_REGION_NAME].h / theme->regions[SE_REGION_NAME].w; + ImVec2 p, v; - if(theme->regions[SE_REGION_NAME].active){ + if(theme->regions[SE_REGION_NAME].active) { se_text("Custom Theme Name"); igGetCursorPos(&p); igGetWindowPos(&v); - p.x+=v.x-igGetScrollX(); - p.y+=v.y-igGetScrollY(); + p.x += v.x - igGetScrollX(); + p.y += v.y - igGetScrollY(); - se_draw_theme_region(SE_REGION_NAME, p.x,p.y,w,h); - igDummy((ImVec2){0,h}); + se_draw_theme_region(SE_REGION_NAME, p.x, p.y, w, h); + igDummy((ImVec2){0, h}); } - if(theme->regions[SE_REGION_AUTHOR].active){ + if(theme->regions[SE_REGION_AUTHOR].active) { se_text("Custom Theme Author"); igGetCursorPos(&p); igGetWindowPos(&v); - p.x+=v.x-igGetScrollX(); - p.y+=v.y-igGetScrollY(); - se_draw_theme_region(SE_REGION_AUTHOR, p.x,p.y,w,h); - igDummy((ImVec2){0,h}); + p.x += v.x - igGetScrollX(); + p.y += v.y - igGetScrollY(); + se_draw_theme_region(SE_REGION_AUTHOR, p.x, p.y, w, h); + igDummy((ImVec2){0, h}); } } gui_state.settings.theme = theme; bool always_show_menubar = gui_state.settings.always_show_menubar; - se_checkbox("Always Show Menu/Nav Bar",&always_show_menubar); + se_checkbox("Always Show Menu/Nav Bar", &always_show_menubar); gui_state.settings.always_show_menubar = always_show_menubar; - if(gui_state.ui_type==SE_UI_DESKTOP){ + if(gui_state.ui_type == SE_UI_DESKTOP) { bool fullscreen = sapp_is_fullscreen(); - se_checkbox("Full Screen",&fullscreen); - if(fullscreen!=sapp_is_fullscreen())sapp_toggle_fullscreen(); + se_checkbox("Full Screen", &fullscreen); + if(fullscreen != sapp_is_fullscreen()) sapp_toggle_fullscreen(); se_text(ICON_FK_CODE_FORK " Additional Search Paths"); igSeparator(); - se_input_path("Save File/State Path", gui_state.paths.save,ImGuiInputTextFlags_None); - se_input_path("BIOS/Firmware Path", gui_state.paths.bios,ImGuiInputTextFlags_None); - se_input_path("Cheat Code Path", gui_state.paths.cheat_codes,ImGuiInputTextFlags_None); - bool save_to_path=gui_state.settings.save_to_path; - se_checkbox("Create new files in paths",&save_to_path); - gui_state.settings.save_to_path=save_to_path; - if(memcmp(&gui_state.last_saved_paths, &gui_state.paths,sizeof(gui_state.paths))){ + se_input_path("Save File/State Path", gui_state.paths.save, ImGuiInputTextFlags_None); + se_input_path("BIOS/Firmware Path", gui_state.paths.bios, ImGuiInputTextFlags_None); + se_input_path("Cheat Code Path", gui_state.paths.cheat_codes, ImGuiInputTextFlags_None); + bool save_to_path = gui_state.settings.save_to_path; + se_checkbox("Create new files in paths", &save_to_path); + gui_state.settings.save_to_path = save_to_path; + if(memcmp(&gui_state.last_saved_paths, &gui_state.paths, sizeof(gui_state.paths))) { se_save_search_paths(); - gui_state.last_saved_paths=gui_state.paths; + gui_state.last_saved_paths = gui_state.paths; } } se_text(ICON_FK_WRENCH " Advanced"); igSeparator(); - se_text("Solar Sensor");igSameLine(SE_FIELD_INDENT,0); + se_text("Solar Sensor"); + igSameLine(SE_FIELD_INDENT, 0); igPushItemWidth(-1); - se_slider_float("##Solar Sensor",&emu_state.joy.solar_sensor,0.,1.,"Brightness: %.2f"); + se_slider_float("##Solar Sensor", &emu_state.joy.solar_sensor, 0., 1., "Brightness: %.2f"); bool force_dmg_mode = gui_state.settings.force_dmg_mode; - se_checkbox("Force GB games to run in DMG mode",&force_dmg_mode); - gui_state.settings.force_dmg_mode=force_dmg_mode; + se_checkbox("Force GB games to run in DMG mode", &force_dmg_mode); + gui_state.settings.force_dmg_mode = force_dmg_mode; bool draw_debug_menu = gui_state.settings.draw_debug_menu; - se_checkbox("Show Debug Tools",&draw_debug_menu); + se_checkbox("Show Debug Tools", &draw_debug_menu); gui_state.settings.draw_debug_menu = draw_debug_menu; bool hardcore_mode = gui_state.settings.hardcore_mode; - se_checkbox("Hardcore Mode",&hardcore_mode); - if(gui_state.settings.hardcore_mode!=hardcore_mode){ + se_checkbox("Hardcore Mode", &hardcore_mode); + if(gui_state.settings.hardcore_mode != hardcore_mode) { gui_state.settings.hardcore_mode = hardcore_mode; se_reset_core(); } #ifdef ENABLE_HTTP_CONTROL_SERVER bool enable_hcs = gui_state.settings.http_control_server_enable; - se_checkbox("Enable HTTP Control Server",&enable_hcs); - gui_state.settings.http_control_server_enable =enable_hcs; - if(enable_hcs){ + se_checkbox("Enable HTTP Control Server", &enable_hcs); + gui_state.settings.http_control_server_enable = enable_hcs; + if(enable_hcs) { int port = gui_state.settings.http_control_server_port; - se_text("Server Port");igSameLine(SE_FIELD_INDENT,0); + se_text("Server Port"); + igSameLine(SE_FIELD_INDENT, 0); igPushItemWidth(-1); - se_input_int("##Server Port",&port,1,10,ImGuiInputTextFlags_None); - if(igIsItemDeactivated())gui_state.settings.http_control_server_port=port; + se_input_int("##Server Port", &port, 1, 10, ImGuiInputTextFlags_None); + if(igIsItemDeactivated()) gui_state.settings.http_control_server_port = port; igPopItemWidth(); } -#endif +#endif - float bottom_padding =0; - #ifdef PLATFORM_IOS - se_ios_get_safe_ui_padding(NULL,&bottom_padding,NULL,NULL); - #endif - igDummy((ImVec2){0,bottom_padding}); + float bottom_padding = 0; +#ifdef PLATFORM_IOS + se_ios_get_safe_ui_padding(NULL, &bottom_padding, NULL, NULL); +#endif + igDummy((ImVec2){0, bottom_padding}); } -static void se_reset_audio_ring(){ - //Reset the audio ring to 50% full with empty samples to avoid crackles while the buffer fills back up. +static void se_reset_audio_ring() { + // Reset the audio ring to 50% full with empty samples to avoid crackles while the buffer fills back up. emu_state.audio_ring_buff.read_ptr = 0; - emu_state.audio_ring_buff.write_ptr=4096; - for(int i=0;iIO.DisplaySize.x, g->NextWindowData.MenuBarOffsetMinVal.y + SE_MENU_BAR_HEIGHT}; - float y_off = (3+gui_state.menubar_hide_timer-se_time())*2.; - if(y_off>0)y_off=0; - if(gui_state.settings.always_show_menubar)y_off=0; - y_off = y_off*menu_bar_size.y+style->DisplaySafeAreaPadding.y; - if(y_off<-menu_bar_size.y)y_off=-menu_bar_size.y; +bool se_begin_menu_bar() { + ImGuiContext *g = igGetCurrentContext(); + ImGuiStyle *style = igGetStyle(); + ImVec2 menu_bar_size = {g->IO.DisplaySize.x, g->NextWindowData.MenuBarOffsetMinVal.y + SE_MENU_BAR_HEIGHT}; + float y_off = (3 + gui_state.menubar_hide_timer - se_time()) * 2.; + if(y_off > 0) y_off = 0; + if(gui_state.settings.always_show_menubar) y_off = 0; + y_off = y_off * menu_bar_size.y + style->DisplaySafeAreaPadding.y; + if(y_off < -menu_bar_size.y) y_off = -menu_bar_size.y; float y_pos = g->Style.DisplaySafeAreaPadding.y - g->Style.FramePadding.y; - if(y_pos<0)y_pos=0; + if(y_pos < 0) y_pos = 0; g->NextWindowData.MenuBarOffsetMinVal = (ImVec2){g->Style.DisplaySafeAreaPadding.x, y_pos}; - igSetNextWindowPos((ImVec2){0.0f, y_off},ImGuiCond_Always,(ImVec2){0,0}); - igSetNextWindowSize(menu_bar_size,ImGuiCond_Always); + igSetNextWindowPos((ImVec2){0.0f, y_off}, ImGuiCond_Always, (ImVec2){0, 0}); + igSetNextWindowSize(menu_bar_size, ImGuiCond_Always); igPushStyleVarFloat(ImGuiStyleVar_WindowRounding, 0.0f); igPushStyleVarVec2(ImGuiStyleVar_WindowMinSize, (ImVec2){0, 0}); ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoSavedSettings; - bool is_open = igBegin("##MainMenuBar", NULL, window_flags); + bool is_open = igBegin("##MainMenuBar", NULL, window_flags); igPopStyleVar(2); g->NextWindowData.MenuBarOffsetMinVal = (ImVec2){0.0f, 0.0f}; - if (!is_open){ - igEnd(); - return false; + if(!is_open) { + igEnd(); + return false; } igSetCursorPosY(0); igSetCursorPosX(style->DisplaySafeAreaPadding.x); - se_draw_theme_region(SE_REGION_MENUBAR,0,y_off,menu_bar_size.x,menu_bar_size.y); + se_draw_theme_region(SE_REGION_MENUBAR, 0, y_off, menu_bar_size.x, menu_bar_size.y); return true; //-V1020 } -void se_end_menu_bar(){ +void se_end_menu_bar() { igEnd(); } #ifdef ENABLE_HTTP_CONTROL_SERVER -typedef struct{ - uint8_t* data; - size_t size; -}se_png_write_context_t; -void se_png_write_mem(void *context, void *data, int size){ - se_png_write_context_t * cont =(se_png_write_context_t*)context; - cont->data = realloc(cont->data,size+cont->size); - memcpy(cont->data+cont->size,data,size); - cont->size+=size; -} -uint64_t se_hex_string_to_int(const char* s){ - uint64_t num = 0; - while(*s){ - num<<=4; - if(s[0]>='a'&&s[0]<='f')num+=s[0]-'a'+10; - if(s[0]>='A'&&s[0]<='F')num+=s[0]-'A'+10; - if(s[0]>='0'&&s[0]<='9')num+=s[0]-'0'; +typedef struct { + uint8_t *data; + size_t size; +} se_png_write_context_t; +void se_png_write_mem(void *context, void *data, int size) { + se_png_write_context_t *cont = (se_png_write_context_t *)context; + cont->data = realloc(cont->data, size + cont->size); + memcpy(cont->data + cont->size, data, size); + cont->size += size; +} +uint64_t se_hex_string_to_int(const char *s) { + uint64_t num = 0; + while(*s) { + num <<= 4; + if(s[0] >= 'a' && s[0] <= 'f') num += s[0] - 'a' + 10; + if(s[0] >= 'A' && s[0] <= 'F') num += s[0] - 'A' + 10; + if(s[0] >= '0' && s[0] <= '9') num += s[0] - '0'; ++s; } return num; } -void se_append_char_to_string(char** str, uint64_t* size, char c){ - if(*size==0)*size=1; - *str = realloc(*str,*size+1); - (*str)[*size-1]=c; - (*str)[*size]='\0'; - *size+=1; +void se_append_char_to_string(char **str, uint64_t *size, char c) { + if(*size == 0) *size = 1; + *str = realloc(*str, *size + 1); + (*str)[*size - 1] = c; + (*str)[*size] = '\0'; + *size += 1; } -uint8_t* se_hcs_callback(const char* cmd, const char** params, uint64_t* result_size, const char** mime_type){ +uint8_t *se_hcs_callback(const char *cmd, const char **params, uint64_t *result_size, const char **mime_type) { *result_size = 0; *mime_type = "text/html"; - printf("Got HCS Cmd: %s\n",cmd); - const char* str_result = NULL; - if(strcmp(cmd,"/ping")==0)str_result="pong"; - else if(strcmp(cmd,"/load_rom")==0){ - while(*params){ - if(strcmp(params[0],"path")==0)se_load_rom(params[1]); - if(strcmp(params[0],"pause")==0){ - if(atoi(params[1]))emu_state.run_mode=SB_MODE_PAUSE; + printf("Got HCS Cmd: %s\n", cmd); + const char *str_result = NULL; + if(strcmp(cmd, "/ping") == 0) + str_result = "pong"; + else if(strcmp(cmd, "/load_rom") == 0) { + while(*params) { + if(strcmp(params[0], "path") == 0) se_load_rom(params[1]); + if(strcmp(params[0], "pause") == 0) { + if(atoi(params[1])) emu_state.run_mode = SB_MODE_PAUSE; }; - params+=2; - } - str_result=emu_state.rom_loaded?"ok":"Failed to load ROM"; - }else if(strcmp(cmd,"/setting")==0){ - while(*params){ - if(strcmp(params[0],"ui_type")==0){ - if(strcmp(params[1],"DESKTOP")==0)gui_state.ui_type = SE_UI_DESKTOP; - if(strcmp(params[1],"ANDROID")==0)gui_state.ui_type = SE_UI_ANDROID; - if(strcmp(params[1],"IOS")==0)gui_state.ui_type = SE_UI_IOS; - if(strcmp(params[1],"WEB")==0)gui_state.ui_type = SE_UI_WEB; - }else if(strcmp(params[0],"menu")==0)gui_state.sidebar_open=atoi(params[1]); - else if(strcmp(params[0],"dpi")==0)gui_state.dpi_override=atof(params[1]); - else if(strcmp(params[0],"touch_controls_scale")==0)gui_state.settings.touch_controls_scale=atof(params[1]); - else if(strcmp(params[0],"language")==0)gui_state.settings.language=se_convert_locale_to_enum(params[1]); - else if(strcmp(params[0],"shader")==0)gui_state.settings.screen_shader=atof(params[1]); - else if(strcmp(params[0],"load_slot")==0)se_restore_state_slot(atoi(params[1])); - else if(strcmp(params[0],"capture_slot")==0)se_capture_state_slot(atoi(params[1])); - else if(strcmp(params[0],"edit_cheat_index")==0)gui_state.editing_cheat_index = atoi(params[1]); - else if(strcmp(params[0],"debug_tools")==0)gui_state.settings.draw_debug_menu = atoi(params[1]); - else if(strcmp(params[0],"fake_paths")==0)gui_state.fake_paths = atoi(params[1]); - else if(strcmp(params[0],"theme")==0)gui_state.settings.theme = atoi(params[1]); - else if(strcmp(params[0],"menu_bar")==0){ - if(atoi(params[1])){ - gui_state.settings.always_show_menubar=true; - }else{ - gui_state.settings.always_show_menubar=false; - gui_state.menubar_hide_timer = 0; + params += 2; + } + str_result = emu_state.rom_loaded ? "ok" : "Failed to load ROM"; + } else if(strcmp(cmd, "/setting") == 0) { + while(*params) { + if(strcmp(params[0], "ui_type") == 0) { + if(strcmp(params[1], "DESKTOP") == 0) gui_state.ui_type = SE_UI_DESKTOP; + if(strcmp(params[1], "ANDROID") == 0) gui_state.ui_type = SE_UI_ANDROID; + if(strcmp(params[1], "IOS") == 0) gui_state.ui_type = SE_UI_IOS; + if(strcmp(params[1], "WEB") == 0) gui_state.ui_type = SE_UI_WEB; + } else if(strcmp(params[0], "menu") == 0) + gui_state.sidebar_open = atoi(params[1]); + else if(strcmp(params[0], "dpi") == 0) + gui_state.dpi_override = atof(params[1]); + else if(strcmp(params[0], "touch_controls_scale") == 0) + gui_state.settings.touch_controls_scale = atof(params[1]); + else if(strcmp(params[0], "language") == 0) + gui_state.settings.language = se_convert_locale_to_enum(params[1]); + else if(strcmp(params[0], "shader") == 0) + gui_state.settings.screen_shader = atof(params[1]); + else if(strcmp(params[0], "load_slot") == 0) + se_restore_state_slot(atoi(params[1])); + else if(strcmp(params[0], "capture_slot") == 0) + se_capture_state_slot(atoi(params[1])); + else if(strcmp(params[0], "edit_cheat_index") == 0) + gui_state.editing_cheat_index = atoi(params[1]); + else if(strcmp(params[0], "debug_tools") == 0) + gui_state.settings.draw_debug_menu = atoi(params[1]); + else if(strcmp(params[0], "fake_paths") == 0) + gui_state.fake_paths = atoi(params[1]); + else if(strcmp(params[0], "theme") == 0) + gui_state.settings.theme = atoi(params[1]); + else if(strcmp(params[0], "menu_bar") == 0) { + if(atoi(params[1])) { + gui_state.settings.always_show_menubar = true; + } else { + gui_state.settings.always_show_menubar = false; + gui_state.menubar_hide_timer = 0; } } - params+=2; + params += 2; } - str_result=emu_state.rom_loaded?"ok":"Failed to load ROM"; - }else if(strcmp(cmd,"/step")==0){ - int step_frames = 1; + str_result = emu_state.rom_loaded ? "ok" : "Failed to load ROM"; + } else if(strcmp(cmd, "/step") == 0) { + int step_frames = 1; int old_step = emu_state.step_frames; - while(*params){ - if(strcmp(params[0],"frames")==0)step_frames=atoi(params[1]); - params+=2; + while(*params) { + if(strcmp(params[0], "frames") == 0) step_frames = atoi(params[1]); + params += 2; } - emu_state.step_frames=step_frames; + emu_state.step_frames = step_frames; emu_state.run_mode = SB_MODE_STEP; - se_update_frame(); - emu_state.step_frames=old_step; - str_result="ok"; - }else if(strcmp(cmd,"/run")==0){ - emu_state.step_frames=1; + se_update_frame(); + emu_state.step_frames = old_step; + str_result = "ok"; + } else if(strcmp(cmd, "/run") == 0) { + emu_state.step_frames = 1; emu_state.run_mode = SB_MODE_RUN; - str_result="ok"; - }else if(strcmp(cmd,"/screen")==0){ - if(emu_state.rom_loaded){ + str_result = "ok"; + } else if(strcmp(cmd, "/screen") == 0) { + if(emu_state.rom_loaded) { bool embed_state = false; - int format = 0; - while(*params){ - if(strcmp(params[0],"embed_state")==0)embed_state=atoi(params[1])!=0; - if(strcmp(params[0],"format")==0){ - if(strcmp(params[1],"BMP")==0||strcmp(params[1],"bmp")==0)format = 1; - if(strcmp(params[1],"JPG")==0||strcmp(params[1],"jpg")==0)format = 2; + int format = 0; + while(*params) { + if(strcmp(params[0], "embed_state") == 0) embed_state = atoi(params[1]) != 0; + if(strcmp(params[0], "format") == 0) { + if(strcmp(params[1], "BMP") == 0 || strcmp(params[1], "bmp") == 0) format = 1; + if(strcmp(params[1], "JPG") == 0 || strcmp(params[1], "jpg") == 0) format = 2; } - params+=2; + params += 2; } - uint8_t* imdata = NULL; - uint32_t width=0, height=0; - if(embed_state){ - se_save_state_t* save_state = (se_save_state_t*)malloc(sizeof(se_save_state_t)); - se_capture_state(&core,save_state); - imdata = se_save_state_to_image(save_state, &width,&height); + uint8_t *imdata = NULL; + uint32_t width = 0, height = 0; + if(embed_state) { + se_save_state_t *save_state = (se_save_state_t *)malloc(sizeof(se_save_state_t)); + se_capture_state(&core, save_state); + imdata = se_save_state_to_image(save_state, &width, &height); free(save_state); - }else{ - imdata = (uint8_t*)malloc(SE_MAX_SCREENSHOT_SIZE); - int out_width=0, out_height=0; + } else { + imdata = (uint8_t *)malloc(SE_MAX_SCREENSHOT_SIZE); + int out_width = 0, out_height = 0; se_screenshot(imdata, &out_width, &out_height); width = out_width; height = out_height; } - if(format==0){ - se_png_write_context_t cont ={0}; - stbi_write_png_to_func(se_png_write_mem, &cont,width,height,4, imdata, 0); + if(format == 0) { + se_png_write_context_t cont = {0}; + stbi_write_png_to_func(se_png_write_mem, &cont, width, height, 4, imdata, 0); free(imdata); *result_size = cont.size; - *mime_type="image/png"; + *mime_type = "image/png"; return cont.data; - }else if(format==1){ - se_png_write_context_t cont ={0}; - stbi_write_bmp_to_func(se_png_write_mem, &cont,width,height,4, imdata); + } else if(format == 1) { + se_png_write_context_t cont = {0}; + stbi_write_bmp_to_func(se_png_write_mem, &cont, width, height, 4, imdata); free(imdata); *result_size = cont.size; - *mime_type="image/bmp"; + *mime_type = "image/bmp"; return cont.data; - }else if(format==2){ - se_png_write_context_t cont ={0}; - stbi_write_jpg_to_func(se_png_write_mem, &cont,width,height,4, imdata,95); + } else if(format == 2) { + se_png_write_context_t cont = {0}; + stbi_write_jpg_to_func(se_png_write_mem, &cont, width, height, 4, imdata, 95); free(imdata); *result_size = cont.size; - *mime_type="image/jpg"; + *mime_type = "image/jpg"; return cont.data; } - }else str_result = "Failed (no ROM loaded)"; - }else if(strcmp(cmd,"/read_byte")==0){ - uint64_t response_size = 0; - char *response = NULL; - int address_map=0; - while(*params){ - if(strcmp(params[0],"map")==0) address_map = atoi(params[1]); - else if(strcmp(params[0],"addr")==0){ - uint64_t addr = se_hex_string_to_int(params[1]); - uint8_t byte = se_read_byte_func(address_map)(addr); - const char *map="0123456789abcdef"; - se_append_char_to_string(&response,&response_size,map[SB_BFE(byte,4,4)]); - se_append_char_to_string(&response,&response_size,map[SB_BFE(byte,0,4)]); + } else + str_result = "Failed (no ROM loaded)"; + } else if(strcmp(cmd, "/read_byte") == 0) { + uint64_t response_size = 0; + char *response = NULL; + int address_map = 0; + while(*params) { + if(strcmp(params[0], "map") == 0) + address_map = atoi(params[1]); + else if(strcmp(params[0], "addr") == 0) { + uint64_t addr = se_hex_string_to_int(params[1]); + uint8_t byte = se_read_byte_func(address_map)(addr); + const char *map = "0123456789abcdef"; + se_append_char_to_string(&response, &response_size, map[SB_BFE(byte, 4, 4)]); + se_append_char_to_string(&response, &response_size, map[SB_BFE(byte, 0, 4)]); } - params+=2; + params += 2; } - if(response){ + if(response) { *result_size = response_size; - return (uint8_t*)response; - } - }else if(strcmp(cmd,"/write_byte")==0){ - uint64_t response_size = 0; - char *response = NULL; - int address_map = 0; - while(*params){ - if(strcmp(params[0],"map")==0) address_map = atoi(params[1]); - else{ + return (uint8_t *)response; + } + } else if(strcmp(cmd, "/write_byte") == 0) { + uint64_t response_size = 0; + char *response = NULL; + int address_map = 0; + while(*params) { + if(strcmp(params[0], "map") == 0) + address_map = atoi(params[1]); + else { uint64_t addr = se_hex_string_to_int(params[0]); - uint8_t data = se_hex_string_to_int(params[1]); - se_write_byte_func(address_map)(addr,data); + uint8_t data = se_hex_string_to_int(params[1]); + se_write_byte_func(address_map)(addr, data); } - params+=2; - } - str_result="ok"; - }else if(strcmp(cmd,"/input")==0){ - while(*params){ - for(int i=0; i=0&&id= 0 && id < SE_NUM_CHEATS) { + cheats[id].state = -1; + okay = true; + } else { + okay = false; } } - params+=2; - } - str_result=okay? "ok":"failed"; - }else if(strcmp(cmd,"/edit_cheat")==0){ - bool okay=true; - int editing_id=-1; - bool name_changed=false, code_changed=false, enabled_changed=false; - char new_name[SE_MAX_CHEAT_NAME_SIZE+1] = {0}; - char new_code[SE_MAX_CHEAT_CODE_SIZE+1] = {0}; - int new_enabled=1; - while(*params){ - if(strcmp(params[0],"id")==0){ - int result=sscanf(params[1],"%d",&editing_id); - if(result==EOF||(editing_id<0||editing_id>=SE_NUM_CHEATS)){ - okay=false; + params += 2; + } + str_result = okay ? "ok" : "failed"; + } else if(strcmp(cmd, "/edit_cheat") == 0) { + bool okay = true; + int editing_id = -1; + bool name_changed = false, code_changed = false, enabled_changed = false; + char new_name[SE_MAX_CHEAT_NAME_SIZE + 1] = {0}; + char new_code[SE_MAX_CHEAT_CODE_SIZE + 1] = {0}; + int new_enabled = 1; + while(*params) { + if(strcmp(params[0], "id") == 0) { + int result = sscanf(params[1], "%d", &editing_id); + if(result == EOF || (editing_id < 0 || editing_id >= SE_NUM_CHEATS)) { + okay = false; break; } - }else if(strcmp(params[0],"name")==0){ - name_changed=true; - strncpy(new_name,params[1],SE_MAX_CHEAT_NAME_SIZE); - }else if(strcmp(params[0],"code")==0){ - code_changed=true; - strncpy(new_code,params[1],SE_MAX_CHEAT_CODE_SIZE); - }else if(strcmp(params[0],"enabled")==0){ - int result=sscanf(params[1],"%d",&new_enabled); - if(result==EOF){ - okay=false; + } else if(strcmp(params[0], "name") == 0) { + name_changed = true; + strncpy(new_name, params[1], SE_MAX_CHEAT_NAME_SIZE); + } else if(strcmp(params[0], "code") == 0) { + code_changed = true; + strncpy(new_code, params[1], SE_MAX_CHEAT_CODE_SIZE); + } else if(strcmp(params[0], "enabled") == 0) { + int result = sscanf(params[1], "%d", &new_enabled); + if(result == EOF) { + okay = false; break; } - enabled_changed=true; + enabled_changed = true; } - params+=2; + params += 2; } - if(okay){ + if(okay) { // Find an empty slot if an id wasn't specified - if(editing_id==-1){ - okay=false; - for(int i=0;iDisplaySafeAreaPadding.x = style->DisplaySafeAreaPadding.y =0; + igPushStyleVarVec2(ImGuiStyleVar_FramePadding, (ImVec2){5, 5}); + igPushStyleVarVec2(ImGuiStyleVar_WindowPadding, (ImVec2){0, 5}); + ImGuiStyle *style = igGetStyle(); + float top_padding = 0; + float left_padding = 0, right_padding = 0; + style->DisplaySafeAreaPadding.x = style->DisplaySafeAreaPadding.y = 0; #ifdef PLATFORM_IOS - se_ios_get_safe_ui_padding(&top_padding,NULL,&left_padding,&right_padding); + se_ios_get_safe_ui_padding(&top_padding, NULL, &left_padding, &right_padding); style->DisplaySafeAreaPadding.x = left_padding; style->DisplaySafeAreaPadding.y = top_padding; #endif @@ -6238,377 +6354,390 @@ static void frame(void) { #endif sb_poll_controller_input(&emu_state.joy); - if(gui_state.ui_type==SE_UI_ANDROID || gui_state.ui_type == SE_UI_IOS){ - style->ScrollbarSize=4; + if(gui_state.ui_type == SE_UI_ANDROID || gui_state.ui_type == SE_UI_IOS) { + style->ScrollbarSize = 4; } se_bring_text_field_into_view(); - if (gui_state.test_runner_mode==false&&se_begin_menu_bar()) - { + if(gui_state.test_runner_mode == false && se_begin_menu_bar()) { float menu_bar_y = igGetCursorPosY(); - if(gui_state.sidebar_open){ + if(gui_state.sidebar_open) { igPushStyleColorVec4(ImGuiCol_Button, style->Colors[ImGuiCol_ButtonActive]); - if(se_button_themed(SE_REGION_MENU+2,ICON_FK_TIMES,(ImVec2){SE_MENU_BAR_BUTTON_WIDTH,SE_MENU_BAR_HEIGHT},false)){gui_state.sidebar_open=!gui_state.sidebar_open;} + if(se_button_themed(SE_REGION_MENU + 2, ICON_FK_TIMES, (ImVec2){SE_MENU_BAR_BUTTON_WIDTH, SE_MENU_BAR_HEIGHT}, false)) { gui_state.sidebar_open = !gui_state.sidebar_open; } igPopStyleColor(1); - }else{ - if(se_button_themed(SE_REGION_MENU,ICON_FK_BARS,(ImVec2){SE_MENU_BAR_BUTTON_WIDTH,SE_MENU_BAR_HEIGHT},false)){gui_state.sidebar_open=!gui_state.sidebar_open;} + } else { + if(se_button_themed(SE_REGION_MENU, ICON_FK_BARS, (ImVec2){SE_MENU_BAR_BUTTON_WIDTH, SE_MENU_BAR_HEIGHT}, false)) { gui_state.sidebar_open = !gui_state.sidebar_open; } } - igSameLine(0,1); + igSameLine(0, 1); se_tooltip("Show/Hide Menu Panel"); - if(gui_state.settings.draw_debug_menu)se_draw_debug_menu(); - + if(gui_state.settings.draw_debug_menu) se_draw_debug_menu(); - int orig_x = igGetCursorPosX(); - int v = (gui_state.settings.volume*100); - float volume_width = SE_VOLUME_SLIDER_WIDTH+5; - - if(gui_state.ui_type==SE_UI_ANDROID||gui_state.ui_type==SE_UI_IOS){ - gui_state.settings.volume=1.; - volume_width = 0; + int orig_x = igGetCursorPosX(); + int v = (gui_state.settings.volume * 100); + float volume_width = SE_VOLUME_SLIDER_WIDTH + 5; + + if(gui_state.ui_type == SE_UI_ANDROID || gui_state.ui_type == SE_UI_IOS) { + gui_state.settings.volume = 1.; + volume_width = 0; } - int num_toggles = 4; - int sel_width =SE_TOGGLE_WIDTH; - igPushStyleVarVec2(ImGuiStyleVar_ItemSpacing,(ImVec2){1,1}); - int toggle_x = ((float)width/2)/se_dpi_scale()-(float)sel_width*num_toggles/2; - if((width)/se_dpi_scale()-toggle_x-(sel_width+1)*num_togglesinputs[SE_KEY_RESET_GAME]){ - emu_state.run_mode=SB_MODE_RESET; + if(curr->inputs[SE_KEY_RESET_GAME]) { + emu_state.run_mode = SB_MODE_RESET; } - for(int i=0;iinputs[SE_KEY_CAPTURE_STATE(i)])se_capture_state_slot(i); - if(curr->inputs[SE_KEY_RESTORE_STATE(i)])se_restore_state_slot(i); + for(int i = 0; i < SE_NUM_SAVE_STATES; ++i) { + if(curr->inputs[SE_KEY_CAPTURE_STATE(i)]) se_capture_state_slot(i); + if(curr->inputs[SE_KEY_RESTORE_STATE(i)]) se_restore_state_slot(i); } if(!emu_state.rom_loaded) emu_state.run_mode = SB_MODE_PAUSE; int curr_toggle = 3; - if(emu_state.run_mode==SB_MODE_REWIND)curr_toggle=0; - if(emu_state.run_mode==SB_MODE_RUN && (emu_state.step_frames<0))curr_toggle=1; - if(emu_state.run_mode==SB_MODE_PAUSE)curr_toggle=2; - if(emu_state.run_mode==SB_MODE_RUN && emu_state.step_frames==1)curr_toggle=2; - if(emu_state.run_mode==SB_MODE_RUN && (emu_state.step_frames>1 || emu_state.step_frames==0))curr_toggle=3; - - if(emu_state.run_mode==SB_MODE_PAUSE)gui_state.menubar_hide_timer=se_time(); - - const char* fast_forward_label = ICON_FK_FORWARD; - if(emu_state.run_mode==SB_MODE_RUN){ - if(emu_state.step_frames==0)fast_forward_label=ICON_FK_UNLOCK; - if(emu_state.step_frames>1){ - static char buffer[3]="2X"; - buffer[0]='0'+emu_state.step_frames; - fast_forward_label=buffer; + if(emu_state.run_mode == SB_MODE_REWIND) curr_toggle = 0; + if(emu_state.run_mode == SB_MODE_RUN && (emu_state.step_frames < 0)) curr_toggle = 1; + if(emu_state.run_mode == SB_MODE_PAUSE) curr_toggle = 2; + if(emu_state.run_mode == SB_MODE_RUN && emu_state.step_frames == 1) curr_toggle = 2; + if(emu_state.run_mode == SB_MODE_RUN && (emu_state.step_frames > 1 || emu_state.step_frames == 0)) curr_toggle = 3; + + if(emu_state.run_mode == SB_MODE_PAUSE) gui_state.menubar_hide_timer = se_time(); + + const char *fast_forward_label = ICON_FK_FORWARD; + if(emu_state.run_mode == SB_MODE_RUN) { + if(emu_state.step_frames == 0) fast_forward_label = ICON_FK_UNLOCK; + if(emu_state.step_frames > 1) { + static char buffer[3] = "2X"; + buffer[0] = '0' + emu_state.step_frames; + fast_forward_label = buffer; } } - const char* rewind_label = ICON_FK_BACKWARD; - if(emu_state.run_mode==SB_MODE_REWIND){ - if(emu_state.step_frames<0)rewind_label=ICON_FK_UNLOCK; - else if(emu_state.step_frames>=1){ - static char buffer[3]="2X"; - buffer[0]='0'+emu_state.step_frames; - rewind_label=buffer; + const char *rewind_label = ICON_FK_BACKWARD; + if(emu_state.run_mode == SB_MODE_REWIND) { + if(emu_state.step_frames < 0) + rewind_label = ICON_FK_UNLOCK; + else if(emu_state.step_frames >= 1) { + static char buffer[3] = "2X"; + buffer[0] = '0' + emu_state.step_frames; + rewind_label = buffer; } } - const char* slow_label = ICON_FK_HOURGLASS; - if(emu_state.run_mode==SB_MODE_RUN && emu_state.step_frames<0){ - static char buffer[4]="1/X"; - buffer[2]='0'-emu_state.step_frames; - slow_label=buffer; - } - const char* toggle_labels[]={ - rewind_label, - slow_label, - ICON_FK_PLAY, - fast_forward_label + const char *slow_label = ICON_FK_HOURGLASS; + if(emu_state.run_mode == SB_MODE_RUN && emu_state.step_frames < 0) { + static char buffer[4] = "1/X"; + buffer[2] = '0' - emu_state.step_frames; + slow_label = buffer; + } + const char *toggle_labels[] = { + rewind_label, + slow_label, + ICON_FK_PLAY, + fast_forward_label}; + + const char *toggle_tooltips[] = { + "Rewind", + "Slow", + "Toggle pause/play.\n When paused, the rom selection screen will be shown.", + "Fast Forward", }; - - const char* toggle_tooltips[]={ - "Rewind", - "Slow", - "Toggle pause/play.\n When paused, the rom selection screen will be shown.", - "Fast Forward", - }; - if(emu_state.run_mode==SB_MODE_RUN && emu_state.step_frames==1){ - toggle_labels[2]=ICON_FK_PAUSE; + if(emu_state.run_mode == SB_MODE_RUN && emu_state.step_frames == 1) { + toggle_labels[2] = ICON_FK_PAUSE; } - int next_toggle_id = -1; + int next_toggle_id = -1; int first_hardcore_toggle = 2; - if(emu_state.run_mode!=SB_MODE_PAUSE){ - if(curr->inputs[SE_KEY_EMU_REWIND] && !prev->inputs[SE_KEY_EMU_REWIND]){ - emu_state.run_mode=SB_MODE_REWIND; - emu_state.step_frames=2; + if(emu_state.run_mode != SB_MODE_PAUSE) { + if(curr->inputs[SE_KEY_EMU_REWIND] && !prev->inputs[SE_KEY_EMU_REWIND]) { + emu_state.run_mode = SB_MODE_REWIND; + emu_state.step_frames = 2; } if( (!curr->inputs[SE_KEY_EMU_REWIND] && prev->inputs[SE_KEY_EMU_REWIND]) || (!curr->inputs[SE_KEY_EMU_FF_2X] && prev->inputs[SE_KEY_EMU_FF_2X]) || - (!curr->inputs[SE_KEY_EMU_FF_MAX] && prev->inputs[SE_KEY_EMU_FF_MAX]) - ){ - emu_state.run_mode=SB_MODE_RUN; - emu_state.step_frames=1; + (!curr->inputs[SE_KEY_EMU_FF_MAX] && prev->inputs[SE_KEY_EMU_FF_MAX])) { + emu_state.run_mode = SB_MODE_RUN; + emu_state.step_frames = 1; } - if(curr->inputs[SE_KEY_EMU_FF_2X] && !prev->inputs[SE_KEY_EMU_FF_2X]){ - emu_state.run_mode=SB_MODE_RUN; - emu_state.step_frames=2; + if(curr->inputs[SE_KEY_EMU_FF_2X] && !prev->inputs[SE_KEY_EMU_FF_2X]) { + emu_state.run_mode = SB_MODE_RUN; + emu_state.step_frames = 2; } - if(curr->inputs[SE_KEY_EMU_FF_MAX] && !prev->inputs[SE_KEY_EMU_FF_MAX]){ - emu_state.run_mode=SB_MODE_RUN; - emu_state.step_frames=-1; + if(curr->inputs[SE_KEY_EMU_FF_MAX] && !prev->inputs[SE_KEY_EMU_FF_MAX]) { + emu_state.run_mode = SB_MODE_RUN; + emu_state.step_frames = -1; } } - if(!emu_state.rom_loaded)se_push_disabled(); - for(int i=0;iColors[ImGuiCol_ButtonActive]); - if(se_button_themed(SE_REGION_BLANK+ (active_button? 2:0),toggle_labels[i],(ImVec2){sel_width, SE_MENU_BAR_HEIGHT},true))next_toggle_id = i; - igSameLine(0,1); - if(hardcore_disabled) se_tooltip("Disabled in Hardcore Mode"); - else se_tooltip(toggle_tooltips[i]); - - if(active_button)igPopStyleColor(1); - - if(i==num_toggles-1)igPopStyleVar(1); - if(hardcore_disabled)se_pop_disabled(); - } - if(!emu_state.rom_loaded)se_pop_disabled(); - - switch(next_toggle_id){ - case 0: { - emu_state.run_mode=SB_MODE_REWIND; - if(emu_state.step_frames==2 && curr_toggle == next_toggle_id)emu_state.step_frames=4; - else if(emu_state.step_frames==4 && curr_toggle == next_toggle_id)emu_state.step_frames=8; - else emu_state.step_frames=2; - } ;break; - case 1: { - emu_state.run_mode=SB_MODE_RUN; - if(emu_state.step_frames==-2&& curr_toggle == next_toggle_id)emu_state.step_frames=-4; - else if(emu_state.step_frames==-4&& curr_toggle == next_toggle_id)emu_state.step_frames=-8; - else emu_state.step_frames=-2; - } ;break; - case 2: {emu_state.run_mode=emu_state.run_mode==SB_MODE_RUN&&emu_state.step_frames==1?SB_MODE_PAUSE: SB_MODE_RUN;emu_state.step_frames=1;} ;break; - case 3: { - emu_state.run_mode=SB_MODE_RUN; - if(emu_state.step_frames==2 && curr_toggle == next_toggle_id)emu_state.step_frames=4; - else if(emu_state.step_frames==4&& curr_toggle == next_toggle_id)emu_state.step_frames=8; - else if(emu_state.step_frames==8&& curr_toggle == next_toggle_id)emu_state.step_frames=0; - else emu_state.step_frames=2; - break; - } + if(!emu_state.rom_loaded) se_push_disabled(); + for(int i = 0; i < num_toggles; ++i) { + bool hardcore_disabled = gui_state.settings.hardcore_mode && i < first_hardcore_toggle; + if(hardcore_disabled) se_push_disabled(); + bool active_button = i == curr_toggle; + if(active_button) igPushStyleColorVec4(ImGuiCol_Button, style->Colors[ImGuiCol_ButtonActive]); + if(se_button_themed(SE_REGION_BLANK + (active_button ? 2 : 0), toggle_labels[i], (ImVec2){sel_width, SE_MENU_BAR_HEIGHT}, true)) next_toggle_id = i; + igSameLine(0, 1); + if(hardcore_disabled) + se_tooltip("Disabled in Hardcore Mode"); + else + se_tooltip(toggle_tooltips[i]); + + if(active_button) igPopStyleColor(1); + + if(i == num_toggles - 1) igPopStyleVar(1); + if(hardcore_disabled) se_pop_disabled(); + } + if(!emu_state.rom_loaded) se_pop_disabled(); + + switch(next_toggle_id) { + case 0: { + emu_state.run_mode = SB_MODE_REWIND; + if(emu_state.step_frames == 2 && curr_toggle == next_toggle_id) + emu_state.step_frames = 4; + else if(emu_state.step_frames == 4 && curr_toggle == next_toggle_id) + emu_state.step_frames = 8; + else + emu_state.step_frames = 2; + }; break; + case 1: { + emu_state.run_mode = SB_MODE_RUN; + if(emu_state.step_frames == -2 && curr_toggle == next_toggle_id) + emu_state.step_frames = -4; + else if(emu_state.step_frames == -4 && curr_toggle == next_toggle_id) + emu_state.step_frames = -8; + else + emu_state.step_frames = -2; + }; break; + case 2: { + emu_state.run_mode = emu_state.run_mode == SB_MODE_RUN && emu_state.step_frames == 1 ? SB_MODE_PAUSE : SB_MODE_RUN; + emu_state.step_frames = 1; + }; break; + case 3: { + emu_state.run_mode = SB_MODE_RUN; + if(emu_state.step_frames == 2 && curr_toggle == next_toggle_id) + emu_state.step_frames = 4; + else if(emu_state.step_frames == 4 && curr_toggle == next_toggle_id) + emu_state.step_frames = 8; + else if(emu_state.step_frames == 8 && curr_toggle == next_toggle_id) + emu_state.step_frames = 0; + else + emu_state.step_frames = 2; + break; + } } - if(gui_state.settings.hardcore_mode){ - if(emu_state.run_mode==SB_MODE_REWIND||emu_state.run_mode==SB_MODE_STEP){ - emu_state.run_mode= SB_MODE_RUN; - emu_state.step_frames=1; + if(gui_state.settings.hardcore_mode) { + if(emu_state.run_mode == SB_MODE_REWIND || emu_state.run_mode == SB_MODE_STEP) { + emu_state.run_mode = SB_MODE_RUN; + emu_state.step_frames = 1; } - if(emu_state.step_frames<1&&emu_state.step_frames!=-1)emu_state.step_frames=1; + if(emu_state.step_frames < 1 && emu_state.step_frames != -1) emu_state.step_frames = 1; } - if(curr->inputs[SE_KEY_EMU_PAUSE] && !prev->inputs[SE_KEY_EMU_PAUSE]){ - if(emu_state.run_mode!=SB_MODE_RUN){emu_state.run_mode=SB_MODE_RUN;emu_state.step_frames=1;} - else emu_state.run_mode = SB_MODE_PAUSE; + if(curr->inputs[SE_KEY_EMU_PAUSE] && !prev->inputs[SE_KEY_EMU_PAUSE]) { + if(emu_state.run_mode != SB_MODE_RUN) { + emu_state.run_mode = SB_MODE_RUN; + emu_state.step_frames = 1; + } else + emu_state.run_mode = SB_MODE_PAUSE; } igPopItemWidth(); - - ImVec2 menu_p; igGetWindowPos(&menu_p); - menu_height= igGetWindowHeight()+menu_p.y; + + ImVec2 menu_p; + igGetWindowPos(&menu_p); + menu_height = igGetWindowHeight() + menu_p.y; se_end_menu_bar(); } igPopStyleVar(2); bool active = se_process_file_browser(); - if(!active){ - float screen_x = 0; - float screen_width = width; - float scaled_screen_width = screen_width/se_dpi_scale(); - - float sidebar_w = 300; - int num_sidebars_open = gui_state.sidebar_open; - if(gui_state.settings.draw_debug_menu){ - se_debug_tool_desc_t* desc=se_get_debug_description(); - while(desc&&desc->label){ - num_sidebars_open+=desc->visible; + if(!active) { + float screen_x = 0; + float screen_width = width; + float scaled_screen_width = screen_width / se_dpi_scale(); + + float sidebar_w = 300; + int num_sidebars_open = gui_state.sidebar_open; + if(gui_state.settings.draw_debug_menu) { + se_debug_tool_desc_t *desc = se_get_debug_description(); + while(desc && desc->label) { + num_sidebars_open += desc->visible; ++desc; } } - bool draw_sidebars_over_screen = scaled_screen_width-sidebar_w*num_sidebars_openColors[ImGuiCol_WindowBg]; - window_bg.w = SE_TRANSPARENT_BG_ALPHA; + window_bg.w = SE_TRANSPARENT_BG_ALPHA; igPushStyleColorVec4(ImGuiCol_WindowBg, window_bg); } screen_x = left_padding; - screen_width-=(left_padding+right_padding)*se_dpi_scale(); - if(gui_state.sidebar_open){ - igSetNextWindowPos((ImVec2){screen_x,menu_height}, ImGuiCond_Always, (ImVec2){0,0}); - igSetNextWindowSize((ImVec2){sidebar_w, (gui_state.screen_height-menu_height*se_dpi_scale())/se_dpi_scale()}, ImGuiCond_Always); - igBegin(se_localize_and_cache("Menu"),&gui_state.sidebar_open, ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize); + screen_width -= (left_padding + right_padding) * se_dpi_scale(); + if(gui_state.sidebar_open) { + igSetNextWindowPos((ImVec2){screen_x, menu_height}, ImGuiCond_Always, (ImVec2){0, 0}); + igSetNextWindowSize((ImVec2){sidebar_w, (gui_state.screen_height - menu_height * se_dpi_scale()) / se_dpi_scale()}, ImGuiCond_Always); + igBegin(se_localize_and_cache("Menu"), &gui_state.sidebar_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize); se_draw_menu_panel(); igEnd(); screen_x += sidebar_w; - screen_width -=sidebar_w*se_dpi_scale(); + screen_width -= sidebar_w * se_dpi_scale(); gui_state.key.last_bind_activitiy = -1; - gui_state.menubar_hide_timer=se_time(); + gui_state.menubar_hide_timer = se_time(); } - if(gui_state.settings.draw_debug_menu){ + if(gui_state.settings.draw_debug_menu) { int orig_screen_x = screen_x; - screen_x = se_draw_debug_panels(screen_x, sidebar_w,menu_height,(height-menu_height*se_dpi_scale())/se_dpi_scale()); - screen_width -=(screen_x-orig_screen_x)*se_dpi_scale(); + screen_x = se_draw_debug_panels(screen_x, sidebar_w, menu_height, (height - menu_height * se_dpi_scale()) / se_dpi_scale()); + screen_width -= (screen_x - orig_screen_x) * se_dpi_scale(); } - if(draw_sidebars_over_screen){ + if(draw_sidebars_over_screen) { screen_x = 0; screen_width = width; igPopStyleColor(1); } gui_state.block_touchscreen = draw_sidebars_over_screen; - igSetNextWindowPos((ImVec2){screen_x,menu_height}, ImGuiCond_Always, (ImVec2){0,0}); - igSetNextWindowSize((ImVec2){screen_width, height-menu_height*se_dpi_scale()}, ImGuiCond_Always); + igSetNextWindowPos((ImVec2){screen_x, menu_height}, ImGuiCond_Always, (ImVec2){0, 0}); + igSetNextWindowSize((ImVec2){screen_width, height - menu_height * se_dpi_scale()}, ImGuiCond_Always); igPushStyleVarFloat(ImGuiStyleVar_WindowBorderSize, 0.0f); - igPushStyleVarVec2(ImGuiStyleVar_WindowPadding,(ImVec2){0}); - igPushStyleColorVec4(ImGuiCol_WindowBg, (ImVec4){0,0,0,0.}); + igPushStyleVarVec2(ImGuiStyleVar_WindowPadding, (ImVec2){0}); + igPushStyleColorVec4(ImGuiCol_WindowBg, (ImVec4){0, 0, 0, 0.}); + + igBegin("Screen", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); - igBegin("Screen", 0,ImGuiWindowFlags_NoDecoration - |ImGuiWindowFlags_NoBringToFrontOnFocus); - se_update_frame(); se_draw_emulated_system_screen(false); - for(int i=0;iFonts; + if(gui_state.update_font_atlas) { + gui_state.update_font_atlas = false; + ImFontAtlas *atlas = igGetIO()->Fonts; ImFont *font = NULL; - float font_scale=1.0; - - if(gui_state.settings.theme==SE_THEME_CUSTOM){ - size_t size =0; + float font_scale = 1.0; + + if(gui_state.settings.theme == SE_THEME_CUSTOM) { + size_t size = 0; font_scale = gui_state.settings.custom_font_scale; - uint8_t* data = sb_load_file_data(gui_state.paths.custom_font,&size); - if(data){ - font =ImFontAtlas_AddFontFromMemoryTTF( - atlas,data,size,13*se_dpi_scale()*font_scale,NULL,NULL); + uint8_t *data = sb_load_file_data(gui_state.paths.custom_font, &size); + if(data) { + font = ImFontAtlas_AddFontFromMemoryTTF( + atlas, data, size, 13 * se_dpi_scale() * font_scale, NULL, NULL); } } - - if(!font){ - uint64_t karla_compressed_size; - const uint8_t* karla_compressed_data = se_get_resource(SE_KARLA,&karla_compressed_size); - font =ImFontAtlas_AddFontFromMemoryCompressedTTF( - atlas,karla_compressed_data,karla_compressed_size,13*se_dpi_scale()*font_scale,NULL,NULL); + + if(!font) { + uint64_t karla_compressed_size; + const uint8_t *karla_compressed_data = se_get_resource(SE_KARLA, &karla_compressed_size); + font = ImFontAtlas_AddFontFromMemoryCompressedTTF( + atlas, karla_compressed_data, karla_compressed_size, 13 * se_dpi_scale() * font_scale, NULL, NULL); } - - uint64_t forkawesome_compressed_size; - const uint8_t* forkawesome_compressed_data = se_get_resource(SE_FORKAWESOME,&forkawesome_compressed_size); - static const ImWchar icons_ranges[] = { ICON_MIN_FK, ICON_MAX_FK, 0 }; // Will not be copied by AddFont* so keep in scope. - ImFontConfig* config=ImFontConfig_ImFontConfig(); + uint64_t forkawesome_compressed_size; + const uint8_t *forkawesome_compressed_data = se_get_resource(SE_FORKAWESOME, &forkawesome_compressed_size); + + static const ImWchar icons_ranges[] = {ICON_MIN_FK, ICON_MAX_FK, 0}; // Will not be copied by AddFont* so keep in scope. + ImFontConfig *config = ImFontConfig_ImFontConfig(); config->MergeMode = true; config->GlyphMinAdvanceX = 13.0f; - ImFont* font2 =ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas, - forkawesome_compressed_data,forkawesome_compressed_size,13*se_dpi_scale()*font_scale,config,icons_ranges); + ImFont *font2 = ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas, + forkawesome_compressed_data, forkawesome_compressed_size, 13 * se_dpi_scale() * font_scale, config, icons_ranges); ImFontConfig_destroy(config); - igGetIO()->FontDefault=font2; - - #ifdef UNICODE_GUI - uint64_t notosans_cjksc_compressed_size; - const uint8_t* notosans_cjksc_compressed_data = se_get_resource(SE_NOTO,¬osans_cjksc_compressed_size); - ImFontConfig* config3=ImFontConfig_ImFontConfig(); - config3->MergeMode = true; - config3->OversampleH=1; - config3->PixelSnapH = true; - - static ImWchar ranges[((SE_MAX_UNICODE_CODE_POINT+1)/SE_FONT_CACHE_PAGE_SIZE)*2+1] = {0}; - int index = 0; - for(int i = 0; i<((SE_MAX_UNICODE_CODE_POINT+1)/SE_FONT_CACHE_PAGE_SIZE);++i){ - if(gui_state.font_cache_page_valid[i]==0x1){ - ranges[index*2] = i*SE_FONT_CACHE_PAGE_SIZE; - if(ranges[index*2]==0)ranges[index*2]=1; - ranges[index*2+1] = i*SE_FONT_CACHE_PAGE_SIZE+SE_FONT_CACHE_PAGE_SIZE; - index++; - } + igGetIO()->FontDefault = font2; + +#ifdef UNICODE_GUI + uint64_t notosans_cjksc_compressed_size; + const uint8_t *notosans_cjksc_compressed_data = se_get_resource(SE_NOTO, ¬osans_cjksc_compressed_size); + ImFontConfig *config3 = ImFontConfig_ImFontConfig(); + config3->MergeMode = true; + config3->OversampleH = 1; + config3->PixelSnapH = true; + + static ImWchar ranges[((SE_MAX_UNICODE_CODE_POINT + 1) / SE_FONT_CACHE_PAGE_SIZE) * 2 + 1] = {0}; + int index = 0; + for(int i = 0; i < ((SE_MAX_UNICODE_CODE_POINT + 1) / SE_FONT_CACHE_PAGE_SIZE); ++i) { + if(gui_state.font_cache_page_valid[i] == 0x1) { + ranges[index * 2] = i * SE_FONT_CACHE_PAGE_SIZE; + if(ranges[index * 2] == 0) ranges[index * 2] = 1; + ranges[index * 2 + 1] = i * SE_FONT_CACHE_PAGE_SIZE + SE_FONT_CACHE_PAGE_SIZE; + index++; } - ImFont* font3 =ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas,notosans_cjksc_compressed_data,notosans_cjksc_compressed_size,14*se_dpi_scale()*font_scale,config3,ranges); - uint64_t noto_armenian_size; - const uint8_t *noto_armenian = se_get_resource(SE_NOTO_ARMENIAN,¬o_armenian_size); - ImFont* font4 =ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas,noto_armenian,noto_armenian_size,14*se_dpi_scale()*font_scale,config3,ranges); - uint64_t noto_sans_size=0; - const uint8_t *noto_sans = se_get_resource(SE_NOTO_SANS,¬o_sans_size); - ImFont* font5 =ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas,noto_sans,noto_sans_size,14*se_dpi_scale()*font_scale,config3,ranges); - ImFontConfig_destroy(config3); - igGetIO()->FontDefault=font3; - #endif + } + ImFont *font3 = ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas, notosans_cjksc_compressed_data, notosans_cjksc_compressed_size, 14 * se_dpi_scale() * font_scale, config3, ranges); + uint64_t noto_armenian_size; + const uint8_t *noto_armenian = se_get_resource(SE_NOTO_ARMENIAN, ¬o_armenian_size); + ImFont *font4 = ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas, noto_armenian, noto_armenian_size, 14 * se_dpi_scale() * font_scale, config3, ranges); + uint64_t noto_sans_size = 0; + const uint8_t *noto_sans = se_get_resource(SE_NOTO_SANS, ¬o_sans_size); + ImFont *font5 = ImFontAtlas_AddFontFromMemoryCompressedTTF(atlas, noto_sans, noto_sans_size, 14 * se_dpi_scale() * font_scale, config3, ranges); + ImFontConfig_destroy(config3); + igGetIO()->FontDefault = font3; +#endif { - uint64_t karla_compressed_size; - const uint8_t* karla_compressed_data = se_get_resource(SE_SV_BASIC_MANUAL,&karla_compressed_size); - gui_state.mono_font =ImFontAtlas_AddFontFromMemoryCompressedTTF( - atlas,karla_compressed_data,karla_compressed_size,13*se_dpi_scale()*font_scale,NULL,NULL); + uint64_t karla_compressed_size; + const uint8_t *karla_compressed_data = se_get_resource(SE_SV_BASIC_MANUAL, &karla_compressed_size); + gui_state.mono_font = ImFontAtlas_AddFontFromMemoryCompressedTTF( + atlas, karla_compressed_data, karla_compressed_size, 13 * se_dpi_scale() * font_scale, NULL, NULL); } - - unsigned char* font_pixels; - int font_width, font_height; - int bytes_per_pixel; + unsigned char *font_pixels; + int font_width, font_height; + int bytes_per_pixel; ImFontAtlas_GetTexDataAsRGBA32(atlas, &font_pixels, &font_width, &font_height, &bytes_per_pixel); sg_image_desc img_desc; memset(&img_desc, 0, sizeof(img_desc)); @@ -6623,419 +6752,429 @@ static void frame(void) { img_desc.data.subimage[0][0].size = (size_t)(font_width * font_height) * sizeof(uint32_t); img_desc.label = "sokol-imgui-font"; static bool has_atlas_image = false; - if(has_atlas_image)sg_destroy_image(gui_state.font_atlas_image); + if(has_atlas_image) sg_destroy_image(gui_state.font_atlas_image); has_atlas_image = true; gui_state.font_atlas_image = sg_make_image(&img_desc); atlas->TexID = (ImTextureID)(uintptr_t)gui_state.font_atlas_image.id; ImFontAtlas_ClearTexData(atlas); ImFontAtlas_ClearInputData(atlas); - - igGetIO()->Fonts=atlas; - igGetIO()->FontGlobalScale=1./se_dpi_scale(); + + igGetIO()->Fonts = atlas; + igGetIO()->FontGlobalScale = 1. / se_dpi_scale(); } sg_commit(); - int num_samples_to_push = saudio_expect()*2; - enum{samples_to_push=128}; - float volume_sq = gui_state.settings.volume*gui_state.settings.volume/32768.; - int sample_copies = 1; - if(emu_state.step_frames<0)sample_copies = -emu_state.step_frames; - int sample_copy_index = sample_copies; - for(int s = 0; s100){ - gui_state.audio_watchdog_timer=0; + if(gui_state.audio_watchdog_timer > 100) { + gui_state.audio_watchdog_timer = 0; saudio_shutdown(); se_init_audio(); gui_state.audio_watchdog_triggered++; } se_free_all_images(); - if(memcmp(&gui_state.last_saved_settings, &gui_state.settings,sizeof(gui_state.settings))){ + if(memcmp(&gui_state.last_saved_settings, &gui_state.settings, sizeof(gui_state.settings))) { char settings_path[SB_FILE_PATH_SIZE]; - snprintf(settings_path,SB_FILE_PATH_SIZE,"%suser_settings.bin",se_get_pref_path()); - sb_save_file_data(settings_path,(uint8_t*)&gui_state.settings,sizeof(gui_state.settings)); + snprintf(settings_path, SB_FILE_PATH_SIZE, "%suser_settings.bin", se_get_pref_path()); + sb_save_file_data(settings_path, (uint8_t *)&gui_state.settings, sizeof(gui_state.settings)); se_emscripten_flush_fs(); - gui_state.last_saved_settings=gui_state.settings; + gui_state.last_saved_settings = gui_state.settings; } } -void se_load_settings(){ +void se_load_settings() { se_load_recent_games_list(); se_load_search_paths(); - + { char keybind_path[SB_FILE_PATH_SIZE]; - snprintf(keybind_path,SB_FILE_PATH_SIZE,"%skeyboard-bindings.bin",se_get_pref_path()); - if(!sb_load_file_data_into_buffer(keybind_path,(uint8_t*)gui_state.key.bound_id,sizeof(gui_state.key.bound_id))){ + snprintf(keybind_path, SB_FILE_PATH_SIZE, "%skeyboard-bindings.bin", se_get_pref_path()); + if(!sb_load_file_data_into_buffer(keybind_path, (uint8_t *)gui_state.key.bound_id, sizeof(gui_state.key.bound_id))) { se_set_default_keybind(&gui_state); } } #if defined(USE_SDL) || defined(PLATFORM_ANDROID) - if(!se_load_controller_settings(&gui_state.controller)){ + if(!se_load_controller_settings(&gui_state.controller)) { se_set_default_controller_binds(&gui_state.controller); } #endif { char settings_path[SB_FILE_PATH_SIZE]; - snprintf(settings_path,SB_FILE_PATH_SIZE,"%suser_settings.bin",se_get_pref_path()); - if(!sb_load_file_data_into_buffer(settings_path,(void*)&gui_state.settings,sizeof(gui_state.settings))){gui_state.settings.settings_file_version=-1;} - int max_settings_version_supported =3; - if(gui_state.settings.settings_file_version>max_settings_version_supported){ - gui_state.settings.volume=0.8; - gui_state.settings.draw_debug_menu = false; + snprintf(settings_path, SB_FILE_PATH_SIZE, "%suser_settings.bin", se_get_pref_path()); + if(!sb_load_file_data_into_buffer(settings_path, (void *)&gui_state.settings, sizeof(gui_state.settings))) { gui_state.settings.settings_file_version = -1; } + int max_settings_version_supported = 3; + if(gui_state.settings.settings_file_version > max_settings_version_supported) { + gui_state.settings.volume = 0.8; + gui_state.settings.draw_debug_menu = false; gui_state.settings.settings_file_version = 0; } - if(gui_state.settings.settings_file_version<1){ - gui_state.settings.settings_file_version=1; + if(gui_state.settings.settings_file_version < 1) { + gui_state.settings.settings_file_version = 1; se_reset_default_gb_palette(); gui_state.settings.ghosting = 1.0; - gui_state.settings.color_correction=1.0; - gui_state.settings.integer_scaling=false; - gui_state.settings.screen_shader=3; - gui_state.settings.screen_rotation=0; - gui_state.settings.stretch_to_fit = 0; - } - if(gui_state.settings.screen_shader>4)gui_state.settings.screen_shader=4; - if(gui_state.settings.settings_file_version<2){ - gui_state.settings.settings_file_version = 2; - gui_state.settings.auto_hide_touch_controls=true; + gui_state.settings.color_correction = 1.0; + gui_state.settings.integer_scaling = false; + gui_state.settings.screen_shader = 3; + gui_state.settings.screen_rotation = 0; + gui_state.settings.stretch_to_fit = 0; + } + if(gui_state.settings.screen_shader > 4) gui_state.settings.screen_shader = 4; + if(gui_state.settings.settings_file_version < 2) { + gui_state.settings.settings_file_version = 2; + gui_state.settings.auto_hide_touch_controls = true; gui_state.settings.touch_controls_opacity = 0.5; - gui_state.settings.always_show_menubar=false; - gui_state.settings.language=SE_LANG_DEFAULT; - gui_state.settings.touch_controls_scale=1.0; - gui_state.settings.touch_controls_show_turbo = 1; + gui_state.settings.always_show_menubar = false; + gui_state.settings.language = SE_LANG_DEFAULT; + gui_state.settings.touch_controls_scale = 1.0; + gui_state.settings.touch_controls_show_turbo = 1; gui_state.settings.save_to_path = false; - gui_state.settings.http_control_server_enable = false; - gui_state.settings.http_control_server_port=8080; + gui_state.settings.http_control_server_enable = false; + gui_state.settings.http_control_server_port = 8080; gui_state.settings.avoid_overlaping_touchscreen = true; } - if(gui_state.settings.settings_file_version<3){ + if(gui_state.settings.settings_file_version < 3) { gui_state.settings.settings_file_version = 3; - gui_state.settings.hardcore_mode=0; + gui_state.settings.hardcore_mode = 0; } - if(gui_state.settings.custom_font_scale<0.5)gui_state.settings.custom_font_scale=1.0; - if(gui_state.settings.custom_font_scale>2.0)gui_state.settings.custom_font_scale=1.0; - if(gui_state.settings.touch_controls_scale<0.1)gui_state.settings.touch_controls_scale=1.0; - if(gui_state.settings.touch_controls_opacity<0||gui_state.settings.touch_controls_opacity>1.0)gui_state.settings.touch_controls_opacity=0.5; - if(gui_state.settings.gba_color_correction_mode> GBA_HIGAN_CORRECTION)gui_state.settings.gba_color_correction_mode=GBA_SKYEMU_CORRECTION; - gui_state.last_saved_settings=gui_state.settings; - if(gui_state.settings.theme==SE_THEME_CUSTOM)se_load_theme_from_file(gui_state.paths.theme); + if(gui_state.settings.custom_font_scale < 0.5) gui_state.settings.custom_font_scale = 1.0; + if(gui_state.settings.custom_font_scale > 2.0) gui_state.settings.custom_font_scale = 1.0; + if(gui_state.settings.touch_controls_scale < 0.1) gui_state.settings.touch_controls_scale = 1.0; + if(gui_state.settings.touch_controls_opacity < 0 || gui_state.settings.touch_controls_opacity > 1.0) gui_state.settings.touch_controls_opacity = 0.5; + if(gui_state.settings.gba_color_correction_mode > GBA_HIGAN_CORRECTION) gui_state.settings.gba_color_correction_mode = GBA_SKYEMU_CORRECTION; + gui_state.last_saved_settings = gui_state.settings; + if(gui_state.settings.theme == SE_THEME_CUSTOM) se_load_theme_from_file(gui_state.paths.theme); } } -static void se_compute_draw_lcd_rect(float *lcd_render_w, float *lcd_render_h, bool *hybrid_nds){ - *hybrid_nds = false; - float rotation = gui_state.settings.screen_rotation*0.5*3.14159; - if(!gui_state.settings.stretch_to_fit){ +static void se_compute_draw_lcd_rect(float *lcd_render_w, float *lcd_render_h, bool *hybrid_nds) { + *hybrid_nds = false; + float rotation = gui_state.settings.screen_rotation * 0.5 * 3.14159; + if(!gui_state.settings.stretch_to_fit) { float scr_w = *lcd_render_w; float scr_h = *lcd_render_h; float native_w = SB_LCD_W; float native_h = SB_LCD_H; - bool touch_controller_active = gui_state.last_touch_time>=0||gui_state.settings.auto_hide_touch_controls==false; - if(emu_state.system==SYSTEM_GBA){native_w = GBA_LCD_W; native_h = GBA_LCD_H;} - else if(emu_state.system==SYSTEM_NDS){ - native_w = NDS_LCD_W; native_h = NDS_LCD_H*2; - if(scr_w/scr_h>1&&!touch_controller_active){ - native_w = NDS_LCD_W+NDS_LCD_W*0.5; + bool touch_controller_active = gui_state.last_touch_time >= 0 || gui_state.settings.auto_hide_touch_controls == false; + if(emu_state.system == SYSTEM_GBA) { + native_w = GBA_LCD_W; + native_h = GBA_LCD_H; + } else if(emu_state.system == SYSTEM_NDS) { + native_w = NDS_LCD_W; + native_h = NDS_LCD_H * 2; + if(scr_w / scr_h > 1 && !touch_controller_active) { + native_w = NDS_LCD_W + NDS_LCD_W * 0.5; native_h = NDS_LCD_H; - *hybrid_nds=true; + *hybrid_nds = true; } } - float lcd_aspect= native_h/native_w; + float lcd_aspect = native_h / native_w; float height = scr_h; float render_w = native_w; float render_h = native_h; - switch(gui_state.settings.screen_rotation){ - case 1: case 3: - render_w = native_h; - render_h = native_w; + switch(gui_state.settings.screen_rotation) { + case 1: + case 3: + render_w = native_h; + render_h = native_w; } - float render_aspect = render_h/render_w; + float render_aspect = render_h / render_w; - float render_scale =1; - if(scr_w*render_aspect>height) render_scale = height/render_h; - else render_scale = scr_w/render_w; + float render_scale = 1; + if(scr_w * render_aspect > height) + render_scale = height / render_h; + else + render_scale = scr_w / render_w; - *lcd_render_w = native_w*render_scale; - *lcd_render_h = native_h*render_scale; + *lcd_render_w = native_w * render_scale; + *lcd_render_h = native_h * render_scale; - if(gui_state.settings.integer_scaling){ + if(gui_state.settings.integer_scaling) { float old_w = *lcd_render_w; float old_h = *lcd_render_h; float dpi_scale = se_dpi_scale(); - *lcd_render_h = ((int)((*lcd_render_h)/(native_h/dpi_scale)))*native_h/dpi_scale; - *lcd_render_w = ((int)((*lcd_render_w)/(native_w/dpi_scale)))*native_w/dpi_scale; - if(*lcd_render_w==0)*lcd_render_w=old_w; - if(*lcd_render_h==0)*lcd_render_h=old_h; + *lcd_render_h = ((int)((*lcd_render_h) / (native_h / dpi_scale))) * native_h / dpi_scale; + *lcd_render_w = ((int)((*lcd_render_w) / (native_w / dpi_scale))) * native_w / dpi_scale; + if(*lcd_render_w == 0) *lcd_render_w = old_w; + if(*lcd_render_h == 0) *lcd_render_h = old_h; } } - switch(gui_state.settings.screen_rotation){ - case 1: case 3:{ - float tmp = *lcd_render_w; - *lcd_render_w = *lcd_render_h; - *lcd_render_h = tmp; - } + switch(gui_state.settings.screen_rotation) { + case 1: + case 3: { + float tmp = *lcd_render_w; + *lcd_render_w = *lcd_render_h; + *lcd_render_h = tmp; + } } } -static void se_draw_lcd_in_rect(float lcd_render_x, float lcd_render_y, float lcd_render_w, float lcd_render_h, bool hybrid_nds){ +static void se_draw_lcd_in_rect(float lcd_render_x, float lcd_render_y, float lcd_render_w, float lcd_render_h, bool hybrid_nds) { float dpi_scale = se_dpi_scale(); - float lx = lcd_render_x*dpi_scale; - float ly = lcd_render_y*dpi_scale; - float lw = lcd_render_w*dpi_scale; - float lh = lcd_render_h*dpi_scale; - float rotation = gui_state.settings.screen_rotation*0.5*3.14159; - - if(emu_state.system==SYSTEM_GBA){ - se_draw_lcd_defer(core.gba.framebuffer,GBA_LCD_W,GBA_LCD_H,lx,ly, lw, lh,rotation,false); - }else if (emu_state.system==SYSTEM_NDS){ - if(hybrid_nds){ - float p[6]={ - 0.3333* lw,- lh*0.25, - 0.3333* lw, lh*0.25, - -0.1666* lw,0, + float lx = lcd_render_x * dpi_scale; + float ly = lcd_render_y * dpi_scale; + float lw = lcd_render_w * dpi_scale; + float lh = lcd_render_h * dpi_scale; + float rotation = gui_state.settings.screen_rotation * 0.5 * 3.14159; + + if(emu_state.system == SYSTEM_GBA) { + se_draw_lcd_defer(core.gba.framebuffer, GBA_LCD_W, GBA_LCD_H, lx, ly, lw, lh, rotation, false); + } else if(emu_state.system == SYSTEM_NDS) { + if(hybrid_nds) { + float p[6] = { + 0.3333 * lw, + -lh * 0.25, + 0.3333 * lw, + lh * 0.25, + -0.1666 * lw, + 0, }; - for(int i=0;i<3;++i){ - float x = p[i*2+0]; - float y = p[i*2+1]; - p[i*2+0] = x*cos(-rotation)+y*sin(-rotation); - p[i*2+1] = x*-sin(-rotation)+y*cos(-rotation); + for(int i = 0; i < 3; ++i) { + float x = p[i * 2 + 0]; + float y = p[i * 2 + 1]; + p[i * 2 + 0] = x * cos(-rotation) + y * sin(-rotation); + p[i * 2 + 1] = x * -sin(-rotation) + y * cos(-rotation); } - se_draw_lcd_defer(core.nds.framebuffer_top,NDS_LCD_W,NDS_LCD_H,lx+p[0],ly+p[1], lw/3, lh*0.5,rotation,false); - se_draw_lcd_defer(core.nds.framebuffer_bottom,NDS_LCD_W,NDS_LCD_H,lx+p[2],ly+p[3], lw/3, lh*0.5,rotation,true); - se_draw_lcd_defer(core.nds.framebuffer_top,NDS_LCD_W,NDS_LCD_H,lx+p[4],ly+p[5], lw*2/3, lh,rotation,false); - }else{ - float p[4]={ - 0,- lh*0.25, - 0,lh*0.25 - }; - for(int i=0;i<2;++i){ - float x = p[i*2+0]; - float y = p[i*2+1]; - p[i*2+0] = x*cos(-rotation)+y*sin(-rotation); - p[i*2+1] = x*-sin(-rotation)+y*cos(-rotation); + se_draw_lcd_defer(core.nds.framebuffer_top, NDS_LCD_W, NDS_LCD_H, lx + p[0], ly + p[1], lw / 3, lh * 0.5, rotation, false); + se_draw_lcd_defer(core.nds.framebuffer_bottom, NDS_LCD_W, NDS_LCD_H, lx + p[2], ly + p[3], lw / 3, lh * 0.5, rotation, true); + se_draw_lcd_defer(core.nds.framebuffer_top, NDS_LCD_W, NDS_LCD_H, lx + p[4], ly + p[5], lw * 2 / 3, lh, rotation, false); + } else { + float p[4] = { + 0, -lh * 0.25, + 0, lh * 0.25}; + for(int i = 0; i < 2; ++i) { + float x = p[i * 2 + 0]; + float y = p[i * 2 + 1]; + p[i * 2 + 0] = x * cos(-rotation) + y * sin(-rotation); + p[i * 2 + 1] = x * -sin(-rotation) + y * cos(-rotation); } - se_draw_lcd_defer(core.nds.framebuffer_top,NDS_LCD_W,NDS_LCD_H,lx+p[0],ly+p[1], lw, lh*0.5,rotation,false); - se_draw_lcd_defer(core.nds.framebuffer_bottom,NDS_LCD_W,NDS_LCD_H,lx+p[2],ly+p[3], lw, lh*0.5,rotation,true); + se_draw_lcd_defer(core.nds.framebuffer_top, NDS_LCD_W, NDS_LCD_H, lx + p[0], ly + p[1], lw, lh * 0.5, rotation, false); + se_draw_lcd_defer(core.nds.framebuffer_bottom, NDS_LCD_W, NDS_LCD_H, lx + p[2], ly + p[3], lw, lh * 0.5, rotation, true); } - }else if (emu_state.system==SYSTEM_GB){ - se_draw_lcd_defer(core.gb.lcd.framebuffer,SB_LCD_W,SB_LCD_H,lx,ly, lw, lh,rotation,false); + } else if(emu_state.system == SYSTEM_GB) { + se_draw_lcd_defer(core.gb.lcd.framebuffer, SB_LCD_W, SB_LCD_H, lx, ly, lw, lh, rotation, false); } } -static bool se_draw_theme_region_tint_partial(int region, float x, float y, float w, float h, float w_ratio, float h_ratio, uint32_t tint){ - if(gui_state.settings.theme!=SE_THEME_CUSTOM)return false; - se_theme_region_t* r = &gui_state.theme.regions[region]; - if(!r->active)return false; - if(gui_state.theme.image.id==SG_INVALID_ID)return false; - if(w==0||h==0)return false; +static bool se_draw_theme_region_tint_partial(int region, float x, float y, float w, float h, float w_ratio, float h_ratio, uint32_t tint) { + if(gui_state.settings.theme != SE_THEME_CUSTOM) return false; + se_theme_region_t *r = &gui_state.theme.regions[region]; + if(!r->active) return false; + if(gui_state.theme.image.id == SG_INVALID_ID) return false; + if(w == 0 || h == 0) return false; float tex_w = gui_state.theme.im_w; float tex_h = gui_state.theme.im_h; - float fixed_pixels[2]={0,0}; - float screen_pixels[2]={0,0}; - float fixed_screen_pixels[2]={0,0}; - //Categorize pixels - for(int axis=0;axis<2;++axis) - for(int i=0;icontrol_points_y+i:r->control_points_x+i; - bool fixed = cp->resize_control== SE_RESIZE_FIXED; - bool screen = cp->screen_control== SE_SCREEN_BOTH; - if(fixed&& cp->screen_control==0)fixed_pixels[axis] +=cp->end_pixel-cp->start_pixel; - if(screen) screen_pixels[axis]+=cp->end_pixel-cp->start_pixel; - if(fixed&&screen) fixed_screen_pixels[axis]+=cp->end_pixel-cp->start_pixel; - } - - float uniform_scale_factor = fmin(w/r->w, h/r->h); - for(int r=0;r<2;++r){ - fixed_pixels[r]*=uniform_scale_factor; - screen_pixels[r]*=uniform_scale_factor; - fixed_screen_pixels[r]*=uniform_scale_factor; - } - float dims[2]={w,h}; - - float lcd_dims[2]; - SE_RPT2 lcd_dims[r]=screen_pixels[r]? dims[r]-fixed_pixels[r]:0; - bool hybrid_nds = false; - se_compute_draw_lcd_rect(&lcd_dims[0],&lcd_dims[1],&hybrid_nds); - float lcd_non_fixed_scale[2]; - SE_RPT2 lcd_non_fixed_scale[r]=(lcd_dims[r]-fixed_screen_pixels[r])/(screen_pixels[r]-fixed_screen_pixels[r]); - - float non_fixed_pixels[2]; - SE_RPT2 non_fixed_pixels[r]= dims[r]-fixed_pixels[r]-lcd_dims[r]; - float non_fixed_pixels_scale[2]; - int rdims[2]={r->w,r->h}; - SE_RPT2 non_fixed_pixels_scale[r]= (non_fixed_pixels[r])/(rdims[r]*uniform_scale_factor-fixed_pixels[r]-screen_pixels[r]); - - float x_clamp = x+w*w_ratio; - float y_clamp = y+h*h_ratio; - ImVec2 pmin = {x,y}; - ImVec2 pmax = {x,y}; - bool first_screen = true; - for(int yc=0;yccontrol_points_y + i : r->control_points_x + i; + bool fixed = cp->resize_control == SE_RESIZE_FIXED; + bool screen = cp->screen_control == SE_SCREEN_BOTH; + if(fixed && cp->screen_control == 0) fixed_pixels[axis] += cp->end_pixel - cp->start_pixel; + if(screen) screen_pixels[axis] += cp->end_pixel - cp->start_pixel; + if(fixed && screen) fixed_screen_pixels[axis] += cp->end_pixel - cp->start_pixel; + } + + float uniform_scale_factor = fmin(w / r->w, h / r->h); + for(int r = 0; r < 2; ++r) { + fixed_pixels[r] *= uniform_scale_factor; + screen_pixels[r] *= uniform_scale_factor; + fixed_screen_pixels[r] *= uniform_scale_factor; + } + float dims[2] = {w, h}; + + float lcd_dims[2]; + SE_RPT2 lcd_dims[r] = screen_pixels[r] ? dims[r] - fixed_pixels[r] : 0; + bool hybrid_nds = false; + se_compute_draw_lcd_rect(&lcd_dims[0], &lcd_dims[1], &hybrid_nds); + float lcd_non_fixed_scale[2]; + SE_RPT2 lcd_non_fixed_scale[r] = (lcd_dims[r] - fixed_screen_pixels[r]) / (screen_pixels[r] - fixed_screen_pixels[r]); + + float non_fixed_pixels[2]; + SE_RPT2 non_fixed_pixels[r] = dims[r] - fixed_pixels[r] - lcd_dims[r]; + float non_fixed_pixels_scale[2]; + int rdims[2] = {r->w, r->h}; + SE_RPT2 non_fixed_pixels_scale[r] = (non_fixed_pixels[r]) / (rdims[r] * uniform_scale_factor - fixed_pixels[r] - screen_pixels[r]); + + float x_clamp = x + w * w_ratio; + float y_clamp = y + h * h_ratio; + ImVec2 pmin = {x, y}; + ImVec2 pmax = {x, y}; + bool first_screen = true; + for(int yc = 0; yc < SE_MAX_CONTROL_POINTS; ++yc) { se_control_point_t *ycp = &r->control_points_y[yc]; - if(ycp->start_pixel>=ycp->end_pixel)continue; - pmax.x=pmin.x=x; - float rh = (ycp->end_pixel-ycp->start_pixel)*uniform_scale_factor; - if(ycp->screen_control){ - if(ycp->resize_control!=SE_RESIZE_FIXED)rh*=lcd_non_fixed_scale[1]; - }else if(ycp->resize_control!=SE_RESIZE_FIXED)rh*=non_fixed_pixels_scale[1]; + if(ycp->start_pixel >= ycp->end_pixel) continue; + pmax.x = pmin.x = x; + float rh = (ycp->end_pixel - ycp->start_pixel) * uniform_scale_factor; + if(ycp->screen_control) { + if(ycp->resize_control != SE_RESIZE_FIXED) rh *= lcd_non_fixed_scale[1]; + } else if(ycp->resize_control != SE_RESIZE_FIXED) + rh *= non_fixed_pixels_scale[1]; pmax.y += rh; - for(int xc=0;xccontrol_points_x[xc]; - if(xcp->start_pixel>=xcp->end_pixel)continue; - ImVec2 uv0 = {(xcp->start_pixel+1)/tex_w, (ycp->start_pixel+1)/tex_h}; - ImVec2 uv1 = {(xcp->end_pixel-1)/tex_w, (ycp->end_pixel-1)/tex_h}; - float rw= (xcp->end_pixel-xcp->start_pixel)*uniform_scale_factor; - if(xcp->screen_control){ - if(xcp->resize_control!=SE_RESIZE_FIXED)rw*=lcd_non_fixed_scale[0]; - }else if(xcp->resize_control!=SE_RESIZE_FIXED)rw*=non_fixed_pixels_scale[0]; + if(xcp->start_pixel >= xcp->end_pixel) continue; + ImVec2 uv0 = {(xcp->start_pixel + 1) / tex_w, (ycp->start_pixel + 1) / tex_h}; + ImVec2 uv1 = {(xcp->end_pixel - 1) / tex_w, (ycp->end_pixel - 1) / tex_h}; + float rw = (xcp->end_pixel - xcp->start_pixel) * uniform_scale_factor; + if(xcp->screen_control) { + if(xcp->resize_control != SE_RESIZE_FIXED) rw *= lcd_non_fixed_scale[0]; + } else if(xcp->resize_control != SE_RESIZE_FIXED) + rw *= non_fixed_pixels_scale[0]; pmax.x += rw; - if(pmin.x>x_clamp||pmin.y>y_clamp)continue; - if(pmax.x>x_clamp){ - uv1.x = uv0.x+(uv1.x-uv0.x)*(x_clamp-pmin.x)/(pmax.x-pmin.x); + if(pmin.x > x_clamp || pmin.y > y_clamp) continue; + if(pmax.x > x_clamp) { + uv1.x = uv0.x + (uv1.x - uv0.x) * (x_clamp - pmin.x) / (pmax.x - pmin.x); pmax.x = x_clamp; } - if(pmax.y>y_clamp){ - uv1.y = uv0.y+(uv1.y-uv0.y)*(y_clamp-pmin.y)/(pmax.y-pmin.y); + if(pmax.y > y_clamp) { + uv1.y = uv0.y + (uv1.y - uv0.y) * (y_clamp - pmin.y) / (pmax.y - pmin.y); pmax.y = y_clamp; } - if(xcp->screen_control&&ycp->screen_control&&first_screen){ - first_screen = false; + if(xcp->screen_control && ycp->screen_control && first_screen) { + first_screen = false; float dpi_scale = se_dpi_scale(); - float lcd_pos[2] = {ceil((pmin.x+lcd_dims[0]*0.5)*dpi_scale)/dpi_scale,ceil((pmin.y+lcd_dims[1]*0.5)*dpi_scale)/dpi_scale}; - se_draw_lcd_in_rect(lcd_pos[0],lcd_pos[1],lcd_dims[0],lcd_dims[1],hybrid_nds); + float lcd_pos[2] = {ceil((pmin.x + lcd_dims[0] * 0.5) * dpi_scale) / dpi_scale, ceil((pmin.y + lcd_dims[1] * 0.5) * dpi_scale) / dpi_scale}; + se_draw_lcd_in_rect(lcd_pos[0], lcd_pos[1], lcd_dims[0], lcd_dims[1], hybrid_nds); } - int t = 0xff000000; - ImDrawList_AddImage(igGetWindowDrawList(),(ImTextureID)(uintptr_t)gui_state.theme.image.id,pmin,pmax,uv0,uv1,tint); - //ImDrawList_AddRect(igGetWindowDrawList(),pmin,pmax,t,0,ImDrawCornerFlags_None, 2); - pmin.x=pmax.x; + int t = 0xff000000; + ImDrawList_AddImage(igGetWindowDrawList(), (ImTextureID)(uintptr_t)gui_state.theme.image.id, pmin, pmax, uv0, uv1, tint); + // ImDrawList_AddRect(igGetWindowDrawList(),pmin,pmax,t,0,ImDrawCornerFlags_None, 2); + pmin.x = pmax.x; } pmin.y = pmax.y; } return true; } -static bool se_draw_theme_region_tint(int region, float x, float y, float w, float h,uint32_t tint){ +static bool se_draw_theme_region_tint(int region, float x, float y, float w, float h, uint32_t tint) { return se_draw_theme_region_tint_partial(region, x, y, w, h, 1.0, 1.0, tint); } -static bool se_draw_theme_region(int region, float x, float y, float w, float h){ - return se_draw_theme_region_tint(region,x,y,w,h,0xffffffff); +static bool se_draw_theme_region(int region, float x, float y, float w, float h) { + return se_draw_theme_region_tint(region, x, y, w, h, 0xffffffff); } -static void se_compute_lcd_render_dims(float * available_dims, float * render_dims){ - +static void se_compute_lcd_render_dims(float *available_dims, float *render_dims) { } -static bool se_load_theme_from_image(uint8_t* im, uint32_t im_w, uint32_t im_h){ - if(!im){return false; } +static bool se_load_theme_from_image(uint8_t *im, uint32_t im_w, uint32_t im_h) { + if(!im) { return false; } - uint32_t version_code = (uint32_t)im[(75+32*im_w)*4+3]; - version_code |= (uint32_t)im[(75+32*im_w)*4+2]<<(8*1); - version_code |= (uint32_t)im[(75+32*im_w)*4+1]<<(8*2); - version_code |= (uint32_t)im[(75+32*im_w)*4+0]<<(8*3); - if(version_code!= 0x6f8a91ff){ - printf("Error Loading Theme: Unknown Version Code %08x\n",version_code); + uint32_t version_code = (uint32_t)im[(75 + 32 * im_w) * 4 + 3]; + version_code |= (uint32_t)im[(75 + 32 * im_w) * 4 + 2] << (8 * 1); + version_code |= (uint32_t)im[(75 + 32 * im_w) * 4 + 1] << (8 * 2); + version_code |= (uint32_t)im[(75 + 32 * im_w) * 4 + 0] << (8 * 3); + if(version_code != 0x6f8a91ff) { + printf("Error Loading Theme: Unknown Version Code %08x\n", version_code); return false; } - se_custom_theme_t* theme = &gui_state.theme; - theme->im_h= im_h; - theme->im_w= im_w; + se_custom_theme_t *theme = &gui_state.theme; + theme->im_h = im_h; + theme->im_w = im_w; // Name and author - for(int i=0;i<2;++i){ - se_theme_region_t * region = &theme->regions[SE_REGION_NAME+i]; + for(int i = 0; i < 2; ++i) { + se_theme_region_t *region = &theme->regions[SE_REGION_NAME + i]; region->x = 51; - region->y = 94+i*(154-94); + region->y = 94 + i * (154 - 94); region->w = 900; - region->h = 146-94; + region->h = 146 - 94; } // Palettes - for(int i=0;i<5;++i){ - int im_x = i*70 + 1420; - int im_y = 177; - theme->palettes[i*4+0]= im[(im_x+im_y*im_w)*4+0]; - theme->palettes[i*4+1]= im[(im_x+im_y*im_w)*4+1]; - theme->palettes[i*4+2]= im[(im_x+im_y*im_w)*4+2]; - theme->palettes[i*4+3]= im[(im_x+im_y*im_w)*4+3]; + for(int i = 0; i < 5; ++i) { + int im_x = i * 70 + 1420; + int im_y = 177; + theme->palettes[i * 4 + 0] = im[(im_x + im_y * im_w) * 4 + 0]; + theme->palettes[i * 4 + 1] = im[(im_x + im_y * im_w) * 4 + 1]; + theme->palettes[i * 4 + 2] = im[(im_x + im_y * im_w) * 4 + 2]; + theme->palettes[i * 4 + 3] = im[(im_x + im_y * im_w) * 4 + 3]; } - //Menu Buttons - for(int x=0;x<8;++x){ - for(int y=0;y<3;++y){ - se_theme_region_t * region = &theme->regions[SE_REGION_MENU+y+x*3]; - region->x=2220+x*(2450-2220); - region->y=82+y*(262-82); - region->w=2440-2220; - region->h=252-82; + // Menu Buttons + for(int x = 0; x < 8; ++x) { + for(int y = 0; y < 3; ++y) { + se_theme_region_t *region = &theme->regions[SE_REGION_MENU + y + x * 3]; + region->x = 2220 + x * (2450 - 2220); + region->y = 82 + y * (262 - 82); + region->w = 2440 - 2220; + region->h = 252 - 82; } } - //Volume Bar - for(int x=0;x<2;++x){ - for(int y=0;y<2;++y){ - se_theme_region_t * region = &theme->regions[SE_REGION_VOL_EMPTY+y+x*2]; - region->x=4057+x*(4567-4057); - region->y=82+y*(262-82); - region->w=4557-4057; - region->h=252-82; + // Volume Bar + for(int x = 0; x < 2; ++x) { + for(int y = 0; y < 2; ++y) { + se_theme_region_t *region = &theme->regions[SE_REGION_VOL_EMPTY + y + x * 2]; + region->x = 4057 + x * (4567 - 4057); + region->y = 82 + y * (262 - 82); + region->w = 4557 - 4057; + region->h = 252 - 82; } } - //Volume Knob - for(int y=0;y<2;++y){ - se_theme_region_t * region = &theme->regions[SE_REGION_VOL_KNOB+y]; - region->x=5077; - region->y=82+y*(262-82); - region->w=5237-5077; - region->h=252-82; + // Volume Knob + for(int y = 0; y < 2; ++y) { + se_theme_region_t *region = &theme->regions[SE_REGION_VOL_KNOB + y]; + region->x = 5077; + region->y = 82 + y * (262 - 82); + region->w = 5237 - 5077; + region->h = 252 - 82; } - //Menu background + // Menu background { - se_theme_region_t * region = &theme->regions[SE_REGION_MENUBAR]; - region->x=4057; - region->y=442; - region->w=5237-region->x; - region->h=612-region->y; + se_theme_region_t *region = &theme->regions[SE_REGION_MENUBAR]; + region->x = 4057; + region->y = 442; + region->w = 5237 - region->x; + region->h = 612 - region->y; } - //Bezel Portrait + // Bezel Portrait { - se_theme_region_t * region = &theme->regions[SE_REGION_BEZEL_PORTRAIT]; - region->x=15; - region->y=250; - region->w=2160; - region->h=3840; + se_theme_region_t *region = &theme->regions[SE_REGION_BEZEL_PORTRAIT]; + region->x = 15; + region->y = 250; + region->w = 2160; + region->h = 3840; } - //Bezel Landscape + // Bezel Landscape { - se_theme_region_t * region = &theme->regions[SE_REGION_BEZEL_LANDSCAPE]; - region->x=15; - region->y=4158; - region->w=3840; - region->h=2160; + se_theme_region_t *region = &theme->regions[SE_REGION_BEZEL_LANDSCAPE]; + region->x = 15; + region->y = 4158; + region->w = 3840; + region->h = 2160; } - for(int key = 0; key<7;++key){ - se_theme_region_t * key_up = &theme->regions[key*2+SE_REGION_KEY_A]; - se_theme_region_t * key_down = &theme->regions[key*2+SE_REGION_KEY_A_PRESSED]; + for(int key = 0; key < 7; ++key) { + se_theme_region_t *key_up = &theme->regions[key * 2 + SE_REGION_KEY_A]; + se_theme_region_t *key_down = &theme->regions[key * 2 + SE_REGION_KEY_A_PRESSED]; key_up->x = 4194; - key_up->y = 3764+(4284-3764)*key; + key_up->y = 3764 + (4284 - 3764) * key; key_up->w = 500; key_up->h = 500; key_down->x = 4704; @@ -7043,218 +7182,217 @@ static bool se_load_theme_from_image(uint8_t* im, uint32_t im_w, uint32_t im_h){ key_down->w = key_up->w; key_down->h = key_up->h; } - for(int dpad = 0; dpad<9;++dpad){ - se_theme_region_t * dpad_region = &theme->regions[dpad+SE_REGION_DPAD_UL]; - int x = dpad%3; - int y = dpad/3; - - dpad_region->x = 2209 + (3219-2209)*x; - dpad_region->y = 704+ (1714-704)*y; + for(int dpad = 0; dpad < 9; ++dpad) { + se_theme_region_t *dpad_region = &theme->regions[dpad + SE_REGION_DPAD_UL]; + int x = dpad % 3; + int y = dpad / 3; + + dpad_region->x = 2209 + (3219 - 2209) * x; + dpad_region->y = 704 + (1714 - 704) * y; dpad_region->w = 1000; dpad_region->h = 1000; } - //Select/start - for(int x=0;x<2;++x){ - for(int y=0;y<2;++y){ - se_theme_region_t * region = &theme->regions[SE_REGION_KEY_START+y+x*2]; - region->x=2055+x*(3062-2055); - region->y=6378+y*(6888-6378); - region->w=3048-2055; - region->h=6878-6378; - } - } - - //L/R - for(int x=0;x<2;++x){ - for(int y=0;y<2;++y){ - se_theme_region_t * region = &theme->regions[SE_REGION_KEY_L+y+x*2]; - region->x=15+x*(3062-2055); - region->y=6378+y*(6888-6378); - region->w=3048-2055; - region->h=6878-6378; - } - } - - for(int i=0; iregions[i]; - region->active = false; - //Determine if region is active - for(int y=1;yh-1;++y){ - for(int x=1;xw-1;++x){ - int pixel = (x+region->x)+(y+region->y)*im_w; - if(im[pixel*4+3]>0x01){ - region->active=true; + // Select/start + for(int x = 0; x < 2; ++x) { + for(int y = 0; y < 2; ++y) { + se_theme_region_t *region = &theme->regions[SE_REGION_KEY_START + y + x * 2]; + region->x = 2055 + x * (3062 - 2055); + region->y = 6378 + y * (6888 - 6378); + region->w = 3048 - 2055; + region->h = 6878 - 6378; + } + } + + // L/R + for(int x = 0; x < 2; ++x) { + for(int y = 0; y < 2; ++y) { + se_theme_region_t *region = &theme->regions[SE_REGION_KEY_L + y + x * 2]; + region->x = 15 + x * (3062 - 2055); + region->y = 6378 + y * (6888 - 6378); + region->w = 3048 - 2055; + region->h = 6878 - 6378; + } + } + + for(int i = 0; i < SE_TOTAL_REGIONS; ++i) { + se_theme_region_t *region = &theme->regions[i]; + region->active = false; + // Determine if region is active + for(int y = 1; y < region->h - 1; ++y) { + for(int x = 1; x < region->w - 1; ++x) { + int pixel = (x + region->x) + (y + region->y) * im_w; + if(im[pixel * 4 + 3] > 0x01) { + region->active = true; break; } } - if(region->active)break; - } - for(int i=0;icontrol_points_x[i].start_pixel= - region->control_points_x[i].end_pixel= - region->control_points_y[i].start_pixel= - region->control_points_y[i].end_pixel=0; - region->control_points_x[i].resize_control= - region->control_points_x[i].screen_control= - region->control_points_x[i].gamepad_control=0; - region->control_points_y[i].resize_control= - region->control_points_y[i].screen_control= - region->control_points_y[i].gamepad_control=0; - } - //Load Control Points - if(region->active){ - for(int dir = 0; dir<2;++dir){ - int current_point = 0; - se_control_point_t * cp = region->control_points_x; - int start_x = region->x; - int start_y = region->y-3; - int end_x = region->x+region->w; - int end_y = region->y+region->h; - int inc_x = 1; - int inc_y = 0; - if(dir){ + if(region->active) break; + } + for(int i = 0; i < SE_MAX_CONTROL_POINTS; ++i) { + region->control_points_x[i].start_pixel = + region->control_points_x[i].end_pixel = + region->control_points_y[i].start_pixel = + region->control_points_y[i].end_pixel = 0; + region->control_points_x[i].resize_control = + region->control_points_x[i].screen_control = + region->control_points_x[i].gamepad_control = 0; + region->control_points_y[i].resize_control = + region->control_points_y[i].screen_control = + region->control_points_y[i].gamepad_control = 0; + } + // Load Control Points + if(region->active) { + for(int dir = 0; dir < 2; ++dir) { + int current_point = 0; + se_control_point_t *cp = region->control_points_x; + int start_x = region->x; + int start_y = region->y - 3; + int end_x = region->x + region->w; + int end_y = region->y + region->h; + int inc_x = 1; + int inc_y = 0; + if(dir) { cp = region->control_points_y; - start_x = region->x-3; + start_x = region->x - 3; start_y = region->y; inc_x = 0; - inc_y = 1; + inc_y = 1; } int curr_x = start_x; - int curr_y = start_y; - cp->start_pixel=dir? curr_y : curr_x; - while(curr_xresize_control||screen!=cp->screen_control||gamepad!=cp->gamepad_control){ + int curr_y = start_y; + cp->start_pixel = dir ? curr_y : curr_x; + while(curr_x < end_x && curr_y < end_y) { + int p = (curr_x + curr_y * im_w) * 4; + int resize = im[p + 0]; + int screen = im[p + 1]; + int gamepad = im[p + 2]; + if(resize != cp->resize_control || screen != cp->screen_control || gamepad != cp->gamepad_control) { ++current_point; - if(current_point>=SE_MAX_CONTROL_POINTS){ - printf("Error: Theme requires more control points than the %d limit\n",SE_MAX_CONTROL_POINTS); + if(current_point >= SE_MAX_CONTROL_POINTS) { + printf("Error: Theme requires more control points than the %d limit\n", SE_MAX_CONTROL_POINTS); break; } cp++; - cp->start_pixel=dir? curr_y : curr_x; - cp->screen_control=screen; - cp->resize_control=resize; - cp->gamepad_control=gamepad; + cp->start_pixel = dir ? curr_y : curr_x; + cp->screen_control = screen; + cp->resize_control = resize; + cp->gamepad_control = gamepad; } - curr_x+=inc_x; - curr_y+=inc_y; - cp->end_pixel=dir? curr_y : curr_x; + curr_x += inc_x; + curr_y += inc_y; + cp->end_pixel = dir ? curr_y : curr_x; } } } } - sg_image_data im_data={0}; - + sg_image_data im_data = {0}; + im_data.subimage[0][0].ptr = im; - im_data.subimage[0][0].size = im_w*im_h*4; - sg_image_desc desc={ - .type= SG_IMAGETYPE_2D, - .render_target= false, - .width= im_w, - .height= im_h, - .num_slices= 1, - .num_mipmaps= 1, - .usage= SG_USAGE_IMMUTABLE, - .pixel_format= SG_PIXELFORMAT_RGBA8, - .sample_count= 1, - .min_filter= SG_FILTER_LINEAR, - .mag_filter= SG_FILTER_LINEAR, - .wrap_u= SG_WRAP_CLAMP_TO_EDGE, - .wrap_v= SG_WRAP_CLAMP_TO_EDGE, - .wrap_w= SG_WRAP_CLAMP_TO_EDGE, - .border_color= SG_BORDERCOLOR_OPAQUE_BLACK, - .max_anisotropy= 1, - .min_lod= 0.0f, - .max_lod= 1e9f, - .data= im_data, + im_data.subimage[0][0].size = im_w * im_h * 4; + sg_image_desc desc = { + .type = SG_IMAGETYPE_2D, + .render_target = false, + .width = im_w, + .height = im_h, + .num_slices = 1, + .num_mipmaps = 1, + .usage = SG_USAGE_IMMUTABLE, + .pixel_format = SG_PIXELFORMAT_RGBA8, + .sample_count = 1, + .min_filter = SG_FILTER_LINEAR, + .mag_filter = SG_FILTER_LINEAR, + .wrap_u = SG_WRAP_CLAMP_TO_EDGE, + .wrap_v = SG_WRAP_CLAMP_TO_EDGE, + .wrap_w = SG_WRAP_CLAMP_TO_EDGE, + .border_color = SG_BORDERCOLOR_OPAQUE_BLACK, + .max_anisotropy = 1, + .min_lod = 0.0f, + .max_lod = 1e9f, + .data = im_data, }; - gui_state.theme.image= sg_make_image(&desc); + gui_state.theme.image = sg_make_image(&desc); return true; } -static bool se_load_theme_from_file(const char * filename){ - int im_w, im_h, im_c; - strncpy(gui_state.loaded_theme_path,filename,SB_FILE_PATH_SIZE); +static bool se_load_theme_from_file(const char *filename) { + int im_w, im_h, im_c; + strncpy(gui_state.loaded_theme_path, filename, SB_FILE_PATH_SIZE); uint8_t *imdata = stbi_load(filename, &im_w, &im_h, &im_c, 4); - if(!imdata){ - printf("Failed to open theme image %s\n",filename); + if(!imdata) { + printf("Failed to open theme image %s\n", filename); return false; } bool ret = se_load_theme_from_image(imdata, im_w, im_h); stbi_image_free(imdata); - if(ret){ - printf("Successfully loaded theme: %s\n",filename); + if(ret) { + printf("Successfully loaded theme: %s\n", filename); } - return ret; + return ret; } -static void se_init(){ - printf("SkyEmu %s\n",GIT_COMMIT_HASH); +static void se_init() { + printf("SkyEmu %s\n", GIT_COMMIT_HASH); stm_setup(); se_load_settings(); se_reset_cheats(); bool http_server_mode = false; - if(emu_state.cmd_line_arg_count >3&&strcmp("http_server",emu_state.cmd_line_args[1])==0){ - gui_state.test_runner_mode=true; + if(emu_state.cmd_line_arg_count > 3 && strcmp("http_server", emu_state.cmd_line_args[1]) == 0) { + gui_state.test_runner_mode = true; gui_state.settings.http_control_server_port = atoi(emu_state.cmd_line_args[2]); - emu_state.cmd_line_arg_count =emu_state.cmd_line_arg_count-2; - emu_state.cmd_line_args =emu_state.cmd_line_args+2; - gui_state.settings.http_control_server_enable=true; - http_server_mode=true; + emu_state.cmd_line_arg_count = emu_state.cmd_line_arg_count - 2; + emu_state.cmd_line_args = emu_state.cmd_line_args + 2; + gui_state.settings.http_control_server_enable = true; + http_server_mode = true; // HTTP Server mode only has frame stepping which is not allowed in hardcore mode. - gui_state.settings.hardcore_mode = false; - } - if(emu_state.cmd_line_arg_count>=2){ + gui_state.settings.hardcore_mode = false; + } + if(emu_state.cmd_line_arg_count >= 2) { se_load_rom(emu_state.cmd_line_args[1]); - if(http_server_mode)emu_state.run_mode=SB_MODE_PAUSE; + if(http_server_mode) emu_state.run_mode = SB_MODE_PAUSE; } } static void init(void) { - gui_state.overlay_open= true; + gui_state.overlay_open = true; #ifdef USE_SDL SDL_SetMainReady(); - if(SDL_Init(SDL_INIT_GAMECONTROLLER)){ - printf("Failed to init SDL: %s\n",SDL_GetError()); + if(SDL_Init(SDL_INIT_GAMECONTROLLER)) { + printf("Failed to init SDL: %s\n", SDL_GetError()); } #endif - gui_state.ui_type=SE_UI_DESKTOP; - #if defined(PLATFORM_ANDROID) + gui_state.ui_type = SE_UI_DESKTOP; +#if defined(PLATFORM_ANDROID) gui_state.ui_type = SE_UI_ANDROID; - #elif defined(PLATFORM_IOS) +#elif defined(PLATFORM_IOS) gui_state.ui_type = SE_UI_IOS; - #elif defined(PLATFORM_WEB) +#elif defined(PLATFORM_WEB) gui_state.ui_type = SE_UI_WEB; - #endif +#endif se_initialize_keybind(&gui_state.key); sg_setup(&(sg_desc){ - .context = sapp_sgcontext() - }); - simgui_setup(&(simgui_desc_t){ .dpi_scale= se_dpi_scale()}); + .context = sapp_sgcontext()}); + simgui_setup(&(simgui_desc_t){.dpi_scale = se_dpi_scale()}); se_init(); se_imgui_theme(); // initial clear color - gui_state.pass_action = (sg_pass_action) { - .colors[0] = { .action = SG_ACTION_CLEAR, .value={0,0,0,1} } + gui_state.pass_action = (sg_pass_action){ + .colors[0] = {.action = SG_ACTION_CLEAR, .value = {0, 0, 0, 1}} }; - gui_state.last_touch_time=-10000; + gui_state.last_touch_time = -10000; se_init_audio(); sg_push_debug_group("LCD Shader Init"); gui_state.lcd_prog = sg_make_shader(lcdprog_shader_desc(sg_query_backend())); /* pipeline object for imgui rendering */ - sg_pipeline_desc pip_desc={0}; + sg_pipeline_desc pip_desc = {0}; pip_desc.layout.buffers[0].stride = 16; { - sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[0]; - attr->offset =0; - attr->format = SG_VERTEXFORMAT_FLOAT2; + sg_vertex_attr_desc *attr = &pip_desc.layout.attrs[0]; + attr->offset = 0; + attr->format = SG_VERTEXFORMAT_FLOAT2; } { - sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[1]; - attr->offset = 8; - attr->format = SG_VERTEXFORMAT_FLOAT2; + sg_vertex_attr_desc *attr = &pip_desc.layout.attrs[1]; + attr->offset = 8; + attr->format = SG_VERTEXFORMAT_FLOAT2; } pip_desc.shader = gui_state.lcd_prog; pip_desc.index_type = SG_INDEXTYPE_NONE; @@ -7263,27 +7401,44 @@ static void init(void) { pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; pip_desc.label = "lcd-pipeline"; gui_state.lcd_pipeline = sg_make_pipeline(&pip_desc); - printf("Built pipeline: %d\n",gui_state.lcd_pipeline.id); - static float quad_verts[6*4]={ - 0,0, 0,0, - 1,0, 1,0, - 1,1, 1,1, - - 1,1, 1,1, - 0,1, 0,1, - 0,0, 0,0, + printf("Built pipeline: %d\n", gui_state.lcd_pipeline.id); + static float quad_verts[6 * 4] = { + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, }; - sg_buffer_desc vb_desc={ - .usage = SG_USAGE_IMMUTABLE, - .data.size =sizeof(quad_verts), - .data.ptr = quad_verts - }; + sg_buffer_desc vb_desc = { + .usage = SG_USAGE_IMMUTABLE, + .data.size = sizeof(quad_verts), + .data.ptr = quad_verts}; gui_state.quad_vb = sg_make_buffer(&vb_desc); sg_pop_debug_group(); #ifdef PLATFORM_ANDROID se_android_request_permissions(); - #endif +#endif } static void cleanup(void) { simgui_shutdown(); @@ -7295,99 +7450,98 @@ static void cleanup(void) { #endif } #ifdef EMSCRIPTEN -static void emsc_load_callback(const sapp_html5_fetch_response* response) { - if (response->succeeded) { - sb_save_file_data((char*)response->user_data, (uint8_t*)response->buffer_ptr, response->fetched_size); - se_load_rom((char*)response->user_data); - }else{ - printf("Failed to load dropped file:%d\n",response->error_code); +static void emsc_load_callback(const sapp_html5_fetch_response *response) { + if(response->succeeded) { + sb_save_file_data((char *)response->user_data, (uint8_t *)response->buffer_ptr, response->fetched_size); + se_load_rom((char *)response->user_data); + } else { + printf("Failed to load dropped file:%d\n", response->error_code); } free(response->buffer_ptr); free(response->user_data); } -#endif -static void event(const sapp_event* ev) { +#endif +static void event(const sapp_event *ev) { simgui_handle_event(ev); - if (ev->type == SAPP_EVENTTYPE_FILES_DROPPED) { + if(ev->type == SAPP_EVENTTYPE_FILES_DROPPED) { // get the number of files and their paths like this: const int num_dropped_files = sapp_get_num_dropped_files(); - if(num_dropped_files){ + if(num_dropped_files) { #ifdef EMSCRIPTEN - for(int i=0;itype == SAPP_EVENTTYPE_KEY_DOWN) { + } else if(ev->type == SAPP_EVENTTYPE_KEY_DOWN) { gui_state.button_state[ev->key_code] = true; - gui_state.key.last_bind_activitiy = ev->key_code; - } - else if (ev->type == SAPP_EVENTTYPE_KEY_UP) { + gui_state.key.last_bind_activitiy = ev->key_code; + } else if(ev->type == SAPP_EVENTTYPE_KEY_UP) { gui_state.button_state[ev->key_code] = false; - }else if(ev->type==SAPP_EVENTTYPE_TOUCHES_BEGAN|| - ev->type==SAPP_EVENTTYPE_TOUCHES_MOVED|| - ev->type==SAPP_EVENTTYPE_TOUCHES_ENDED|| - ev->type==SAPP_EVENTTYPE_TOUCHES_CANCELLED){ - - for(int i=0;inum_touches>i; - if(ev->type==SAPP_EVENTTYPE_TOUCHES_ENDED||ev->type==SAPP_EVENTTYPE_TOUCHES_CANCELLED) + } else if(ev->type == SAPP_EVENTTYPE_TOUCHES_BEGAN || + ev->type == SAPP_EVENTTYPE_TOUCHES_MOVED || + ev->type == SAPP_EVENTTYPE_TOUCHES_ENDED || + ev->type == SAPP_EVENTTYPE_TOUCHES_CANCELLED) { + + for(int i = 0; i < SAPP_MAX_TOUCHPOINTS; ++i) { + gui_state.touch_points[i].active = ev->num_touches > i; + if(ev->type == SAPP_EVENTTYPE_TOUCHES_ENDED || ev->type == SAPP_EVENTTYPE_TOUCHES_CANCELLED) gui_state.touch_points[i].active &= !ev->touches[i].changed; gui_state.touch_points[i].pos[0] = ev->touches[i].pos_x; gui_state.touch_points[i].pos[1] = ev->touches[i].pos_y; - if(ev->touches[i].pos_ytouches[i].pos_y < gui_state.screen_height * 0.05 && gui_state.touch_points[i].active) gui_state.menubar_hide_timer = se_time(); } - }else if(ev->type==SAPP_EVENTTYPE_MOUSE_MOVE){ - gui_state.mouse_pos[0]=ev->mouse_x; - gui_state.mouse_pos[1]=ev->mouse_y; - if(gui_state.mouse_pos[1]type==SAPP_EVENTTYPE_MOUSE_UP||ev->type==SAPP_EVENTTYPE_MOUSE_DOWN){ + } else if(ev->type == SAPP_EVENTTYPE_MOUSE_MOVE) { + gui_state.mouse_pos[0] = ev->mouse_x; + gui_state.mouse_pos[1] = ev->mouse_y; + if(gui_state.mouse_pos[1] < gui_state.screen_height * 0.1) gui_state.menubar_hide_timer = se_time(); + } else if(ev->type == SAPP_EVENTTYPE_MOUSE_UP || ev->type == SAPP_EVENTTYPE_MOUSE_DOWN) { int b = ev->mouse_button; - if(b<3)gui_state.mouse_button[0] = ev->type==SAPP_EVENTTYPE_MOUSE_DOWN; + if(b < 3) gui_state.mouse_button[0] = ev->type == SAPP_EVENTTYPE_MOUSE_DOWN; } } -bool se_run_ar_cheat(const uint32_t* buffer, uint32_t size){ - if(emu_state.system ==SYSTEM_GBA)return gba_run_ar_cheat(&core.gba, buffer, size); - if(emu_state.system ==SYSTEM_GB)return sb_run_ar_cheat(&core.gb, buffer, size); - if(emu_state.system ==SYSTEM_NDS)return nds_run_ar_cheat(&core.nds, buffer, size); +bool se_run_ar_cheat(const uint32_t *buffer, uint32_t size) { + if(emu_state.system == SYSTEM_GBA) return gba_run_ar_cheat(&core.gba, buffer, size); + if(emu_state.system == SYSTEM_GB) return sb_run_ar_cheat(&core.gb, buffer, size); + if(emu_state.system == SYSTEM_NDS) return nds_run_ar_cheat(&core.nds, buffer, size); return false; } -void se_run_all_ar_cheats(){ - for(int i=0;i< SE_NUM_CHEATS ;++i){ - se_cheat_t * cheat = cheats+i; - if(cheat->state!=1)continue; - bool success = se_run_ar_cheat(cheat->buffer,cheat->size); - if(!success) cheat->state = 0; +void se_run_all_ar_cheats() { + for(int i = 0; i < SE_NUM_CHEATS; ++i) { + se_cheat_t *cheat = cheats + i; + if(cheat->state != 1) continue; + bool success = se_run_ar_cheat(cheat->buffer, cheat->size); + if(!success) cheat->state = 0; } } -static void headless_mode(){ - //Leave here so the entry point still exists +static void headless_mode() { + // Leave here so the entry point still exists #ifdef ENABLE_HTTP_CONTROL_SERVER se_init(); se_update_frame(); hcs_join_server_thread(); -#endif +#endif } #ifdef PLATFORM_ANDROID void Java_com_sky_SkyEmu_EnhancedNativeActivity_se_1android_1load_1rom(JNIEnv *env, jobject thiz, jstring filePath) { - const char *nativeFilePath = (*env)->GetStringUTFChars(env, filePath, 0); - gui_state.ran_from_launcher=true; - se_load_rom(nativeFilePath); - (*env)->ReleaseStringUTFChars(env, filePath, nativeFilePath); + const char *nativeFilePath = (*env)->GetStringUTFChars(env, filePath, 0); + gui_state.ran_from_launcher = true; + se_load_rom(nativeFilePath); + (*env)->ReleaseStringUTFChars(env, filePath, nativeFilePath); } void Java_com_sky_SkyEmu_EnhancedNativeActivity_se_1android_1load_1file(JNIEnv *env, jobject thiz, jstring filePath) { const char *nativeFilePath = (*env)->GetStringUTFChars(env, filePath, 0); @@ -7396,50 +7550,50 @@ void Java_com_sky_SkyEmu_EnhancedNativeActivity_se_1android_1load_1file(JNIEnv * } #endif -sapp_desc sokol_main(int argc, char* argv[]) { - emu_state.cmd_line_arg_count =argc; - emu_state.cmd_line_args =argv; +sapp_desc sokol_main(int argc, char *argv[]) { + emu_state.cmd_line_arg_count = argc; + emu_state.cmd_line_args = argv; int width = 1280; int height = 800; - if(argc>2&&strcmp("run_gb_test",argv[1])==0){ - gui_state.test_runner_mode=true; - emu_state.cmd_line_arg_count =argc-1; - emu_state.cmd_line_args =argv+1; + if(argc > 2 && strcmp("run_gb_test", argv[1]) == 0) { + gui_state.test_runner_mode = true; + emu_state.cmd_line_arg_count = argc - 1; + emu_state.cmd_line_args = argv + 1; width = SB_LCD_W; - height= SB_LCD_H; + height = SB_LCD_H; } - if(argc>2&&strcmp("run_gba_test",argv[1])==0){ - gui_state.test_runner_mode=true; - emu_state.cmd_line_arg_count =argc-1; - emu_state.cmd_line_args =argv+1; + if(argc > 2 && strcmp("run_gba_test", argv[1]) == 0) { + gui_state.test_runner_mode = true; + emu_state.cmd_line_arg_count = argc - 1; + emu_state.cmd_line_args = argv + 1; width = GBA_LCD_W; - height= GBA_LCD_H; - } - #if defined(EMSCRIPTEN) - em_init_fs(); - #endif - if(emu_state.cmd_line_arg_count >3&&strcmp("http_server",emu_state.cmd_line_args[1])==0)headless_mode(); - - #ifdef PLATFORM_IOS + height = GBA_LCD_H; + } +#if defined(EMSCRIPTEN) + em_init_fs(); +#endif + if(emu_state.cmd_line_arg_count > 3 && strcmp("http_server", emu_state.cmd_line_args[1]) == 0) headless_mode(); + +#ifdef PLATFORM_IOS se_ios_set_documents_working_directory(); - #endif - - return (sapp_desc){ - .init_cb = init, - .frame_cb = frame, - .cleanup_cb = cleanup, - .event_cb = event, - .window_title = "SkyEmu", - .width = width, - .height = height, - .enable_dragndrop = true, - .enable_clipboard =true, - .high_dpi = true, - .max_dropped_file_path_length = 8192, +#endif + + return (sapp_desc) { + .init_cb = init, + .frame_cb = frame, + .cleanup_cb = cleanup, + .event_cb = event, + .window_title = "SkyEmu", + .width = width, + .height = height, + .enable_dragndrop = true, + .enable_clipboard = true, + .high_dpi = true, + .max_dropped_file_path_length = 8192, #if defined(EMSCRIPTEN) - .max_dropped_files=32, + .max_dropped_files = 32, #endif - .swap_interval=0, - .ios_keyboard_resizes_canvas=true + .swap_interval = 0, + .ios_keyboard_resizes_canvas = true }; } diff --git a/src/nds.h b/src/nds.h index 4f68a3e80..11d9b8404 100644 --- a/src/nds.h +++ b/src/nds.h @@ -8,10 +8,10 @@ #define NDS_SCANLINE_PPU 1 -typedef enum{ +typedef enum { kARM7, kARM9, -}nds_arm_mode_t; +} nds_arm_mode_t; ////////////////////////////////////////////////////////////////////////////////////////// // MMIO Register listing from GBATEK (https://problemkaputt.de/gbatek.htm#dsiomaps) // ////////////////////////////////////////////////////////////////////////////////////////// @@ -24,99 +24,99 @@ typedef enum{ // GBA I/O Map // ////////////////// -#define GBA_DISPCNT 0x4000000 /* R/W LCD Control */ -#define GBA_GREENSWP 0x4000002 /* R/W Undocumented - Green Swap */ -#define GBA_DISPSTAT 0x4000004 /* R/W General LCD Status (STAT,LYC) */ -#define GBA_VCOUNT 0x4000006 /* R Vertical Counter (LY) */ -#define GBA_BG0CNT 0x4000008 /* R/W BG0 Control */ -#define GBA_BG1CNT 0x400000A /* R/W BG1 Control */ -#define GBA_BG2CNT 0x400000C /* R/W BG2 Control */ -#define GBA_BG3CNT 0x400000E /* R/W BG3 Control */ -#define GBA_BG0HOFS 0x4000010 /* W BG0 X-Offset */ -#define GBA_BG0VOFS 0x4000012 /* W BG0 Y-Offset */ -#define GBA_BG1HOFS 0x4000014 /* W BG1 X-Offset */ -#define GBA_BG1VOFS 0x4000016 /* W BG1 Y-Offset */ -#define GBA_BG2HOFS 0x4000018 /* W BG2 X-Offset */ -#define GBA_BG2VOFS 0x400001A /* W BG2 Y-Offset */ -#define GBA_BG3HOFS 0x400001C /* W BG3 X-Offset */ -#define GBA_BG3VOFS 0x400001E /* W BG3 Y-Offset */ -#define GBA_BG2PA 0x4000020 /* W BG2 Rotation/Scaling Parameter A (dx) */ -#define GBA_BG2PB 0x4000022 /* W BG2 Rotation/Scaling Parameter B (dmx) */ -#define GBA_BG2PC 0x4000024 /* W BG2 Rotation/Scaling Parameter C (dy) */ -#define GBA_BG2PD 0x4000026 /* W BG2 Rotation/Scaling Parameter D (dmy) */ -#define GBA_BG2X 0x4000028 /* W BG2 Reference Point X-Coordinate */ -#define GBA_BG2Y 0x400002C /* W BG2 Reference Point Y-Coordinate */ -#define GBA_BG3PA 0x4000030 /* W BG3 Rotation/Scaling Parameter A (dx) */ -#define GBA_BG3PB 0x4000032 /* W BG3 Rotation/Scaling Parameter B (dmx) */ -#define GBA_BG3PC 0x4000034 /* W BG3 Rotation/Scaling Parameter C (dy) */ -#define GBA_BG3PD 0x4000036 /* W BG3 Rotation/Scaling Parameter D (dmy) */ -#define GBA_BG3X 0x4000038 /* W BG3 Reference Point X-Coordinate */ -#define GBA_BG3Y 0x400003C /* W BG3 Reference Point Y-Coordinate */ -#define GBA_WIN0H 0x4000040 /* W Window 0 Horizontal Dimensions */ -#define GBA_WIN1H 0x4000042 /* W Window 1 Horizontal Dimensions */ -#define GBA_WIN0V 0x4000044 /* W Window 0 Vertical Dimensions */ -#define GBA_WIN1V 0x4000046 /* W Window 1 Vertical Dimensions */ -#define GBA_WININ 0x4000048 /* R/W Inside of Window 0 and 1 */ -#define GBA_WINOUT 0x400004A /* R/W Inside of OBJ Window & Outside of Windows */ -#define GBA_MOSAIC 0x400004C /* W Mosaic Size */ -#define GBA_BLDCNT 0x4000050 /* R/W Color Special Effects Selection */ -#define GBA_BLDALPHA 0x4000052 /* R/W Alpha Blending Coefficients */ -#define GBA_BLDY 0x4000054 /* W Brightness (Fade-In/Out) Coefficient */ -#define NDS_DISP3DCNT 0x04000060 /* 3D Display Control Register (R/W) */ -#define NDS_DISPCAPCNT 0x04000064 /* Display Capture Control Register (R/W) */ -#define NDS_DISP_MMEM_FIFO 0x04000068 /* Main Memory Display FIFO (R?/W) */ -#define NDS_A_MASTER_BRIGHT 0x0400006C /* Master Brightness Up/Down */ +#define GBA_DISPCNT 0x4000000 /* R/W LCD Control */ +#define GBA_GREENSWP 0x4000002 /* R/W Undocumented - Green Swap */ +#define GBA_DISPSTAT 0x4000004 /* R/W General LCD Status (STAT,LYC) */ +#define GBA_VCOUNT 0x4000006 /* R Vertical Counter (LY) */ +#define GBA_BG0CNT 0x4000008 /* R/W BG0 Control */ +#define GBA_BG1CNT 0x400000A /* R/W BG1 Control */ +#define GBA_BG2CNT 0x400000C /* R/W BG2 Control */ +#define GBA_BG3CNT 0x400000E /* R/W BG3 Control */ +#define GBA_BG0HOFS 0x4000010 /* W BG0 X-Offset */ +#define GBA_BG0VOFS 0x4000012 /* W BG0 Y-Offset */ +#define GBA_BG1HOFS 0x4000014 /* W BG1 X-Offset */ +#define GBA_BG1VOFS 0x4000016 /* W BG1 Y-Offset */ +#define GBA_BG2HOFS 0x4000018 /* W BG2 X-Offset */ +#define GBA_BG2VOFS 0x400001A /* W BG2 Y-Offset */ +#define GBA_BG3HOFS 0x400001C /* W BG3 X-Offset */ +#define GBA_BG3VOFS 0x400001E /* W BG3 Y-Offset */ +#define GBA_BG2PA 0x4000020 /* W BG2 Rotation/Scaling Parameter A (dx) */ +#define GBA_BG2PB 0x4000022 /* W BG2 Rotation/Scaling Parameter B (dmx) */ +#define GBA_BG2PC 0x4000024 /* W BG2 Rotation/Scaling Parameter C (dy) */ +#define GBA_BG2PD 0x4000026 /* W BG2 Rotation/Scaling Parameter D (dmy) */ +#define GBA_BG2X 0x4000028 /* W BG2 Reference Point X-Coordinate */ +#define GBA_BG2Y 0x400002C /* W BG2 Reference Point Y-Coordinate */ +#define GBA_BG3PA 0x4000030 /* W BG3 Rotation/Scaling Parameter A (dx) */ +#define GBA_BG3PB 0x4000032 /* W BG3 Rotation/Scaling Parameter B (dmx) */ +#define GBA_BG3PC 0x4000034 /* W BG3 Rotation/Scaling Parameter C (dy) */ +#define GBA_BG3PD 0x4000036 /* W BG3 Rotation/Scaling Parameter D (dmy) */ +#define GBA_BG3X 0x4000038 /* W BG3 Reference Point X-Coordinate */ +#define GBA_BG3Y 0x400003C /* W BG3 Reference Point Y-Coordinate */ +#define GBA_WIN0H 0x4000040 /* W Window 0 Horizontal Dimensions */ +#define GBA_WIN1H 0x4000042 /* W Window 1 Horizontal Dimensions */ +#define GBA_WIN0V 0x4000044 /* W Window 0 Vertical Dimensions */ +#define GBA_WIN1V 0x4000046 /* W Window 1 Vertical Dimensions */ +#define GBA_WININ 0x4000048 /* R/W Inside of Window 0 and 1 */ +#define GBA_WINOUT 0x400004A /* R/W Inside of OBJ Window & Outside of Windows */ +#define GBA_MOSAIC 0x400004C /* W Mosaic Size */ +#define GBA_BLDCNT 0x4000050 /* R/W Color Special Effects Selection */ +#define GBA_BLDALPHA 0x4000052 /* R/W Alpha Blending Coefficients */ +#define GBA_BLDY 0x4000054 /* W Brightness (Fade-In/Out) Coefficient */ +#define NDS_DISP3DCNT 0x04000060 /* 3D Display Control Register (R/W) */ +#define NDS_DISPCAPCNT 0x04000064 /* Display Capture Control Register (R/W) */ +#define NDS_DISP_MMEM_FIFO 0x04000068 /* Main Memory Display FIFO (R?/W) */ +#define NDS_A_MASTER_BRIGHT 0x0400006C /* Master Brightness Up/Down */ // DMA Transfer Channels -#define GBA_DMA0SAD 0x40000B0 /* W DMA 0 Source Address */ -#define GBA_DMA0DAD 0x40000B4 /* W DMA 0 Destination Address */ -#define GBA_DMA0CNT_L 0x40000B8 /* W DMA 0 Word Count */ -#define GBA_DMA0CNT_H 0x40000BA /* R/W DMA 0 Control */ -#define GBA_DMA1SAD 0x40000BC /* W DMA 1 Source Address */ -#define GBA_DMA1DAD 0x40000C0 /* W DMA 1 Destination Address */ -#define GBA_DMA1CNT_L 0x40000C4 /* W DMA 1 Word Count */ -#define GBA_DMA1CNT_H 0x40000C6 /* R/W DMA 1 Control */ -#define GBA_DMA2SAD 0x40000C8 /* W DMA 2 Source Address */ -#define GBA_DMA2DAD 0x40000CC /* W DMA 2 Destination Address */ -#define GBA_DMA2CNT_L 0x40000D0 /* W DMA 2 Word Count */ -#define GBA_DMA2CNT_H 0x40000D2 /* R/W DMA 2 Control */ -#define GBA_DMA3SAD 0x40000D4 /* W DMA 3 Source Address */ -#define GBA_DMA3DAD 0x40000D8 /* W DMA 3 Destination Address */ -#define GBA_DMA3CNT_L 0x40000DC /* W DMA 3 Word Count */ -#define GBA_DMA3CNT_H 0x40000DE /* R/W DMA 3 Control */ -#define NDS9_DMA0FILL 0x40000E0 /* NDS9 only - DMA0FILL - DMA 0 Filldata (R/W)*/ -#define NDS9_DMA1FILL 0x40000E4 /* NDS9 only - DMA1FILL - DMA 1 Filldata (R/W)*/ -#define NDS9_DMA2FILL 0x40000E8 /* NDS9 only - DMA2FILL - DMA 2 Filldata (R/W)*/ -#define NDS9_DMA3FILL 0x40000EC /* NDS9 only - DMA3FILL - DMA 3 Filldata (R/W)*/ +#define GBA_DMA0SAD 0x40000B0 /* W DMA 0 Source Address */ +#define GBA_DMA0DAD 0x40000B4 /* W DMA 0 Destination Address */ +#define GBA_DMA0CNT_L 0x40000B8 /* W DMA 0 Word Count */ +#define GBA_DMA0CNT_H 0x40000BA /* R/W DMA 0 Control */ +#define GBA_DMA1SAD 0x40000BC /* W DMA 1 Source Address */ +#define GBA_DMA1DAD 0x40000C0 /* W DMA 1 Destination Address */ +#define GBA_DMA1CNT_L 0x40000C4 /* W DMA 1 Word Count */ +#define GBA_DMA1CNT_H 0x40000C6 /* R/W DMA 1 Control */ +#define GBA_DMA2SAD 0x40000C8 /* W DMA 2 Source Address */ +#define GBA_DMA2DAD 0x40000CC /* W DMA 2 Destination Address */ +#define GBA_DMA2CNT_L 0x40000D0 /* W DMA 2 Word Count */ +#define GBA_DMA2CNT_H 0x40000D2 /* R/W DMA 2 Control */ +#define GBA_DMA3SAD 0x40000D4 /* W DMA 3 Source Address */ +#define GBA_DMA3DAD 0x40000D8 /* W DMA 3 Destination Address */ +#define GBA_DMA3CNT_L 0x40000DC /* W DMA 3 Word Count */ +#define GBA_DMA3CNT_H 0x40000DE /* R/W DMA 3 Control */ +#define NDS9_DMA0FILL 0x40000E0 /* NDS9 only - DMA0FILL - DMA 0 Filldata (R/W)*/ +#define NDS9_DMA1FILL 0x40000E4 /* NDS9 only - DMA1FILL - DMA 1 Filldata (R/W)*/ +#define NDS9_DMA2FILL 0x40000E8 /* NDS9 only - DMA2FILL - DMA 2 Filldata (R/W)*/ +#define NDS9_DMA3FILL 0x40000EC /* NDS9 only - DMA3FILL - DMA 3 Filldata (R/W)*/ // Timer Registers -#define GBA_TM0CNT_L 0x4000100 /* R/W Timer 0 Counter/Reload */ -#define GBA_TM0CNT_H 0x4000102 /* R/W Timer 0 Control */ -#define GBA_TM1CNT_L 0x4000104 /* R/W Timer 1 Counter/Reload */ -#define GBA_TM1CNT_H 0x4000106 /* R/W Timer 1 Control */ -#define GBA_TM2CNT_L 0x4000108 /* R/W Timer 2 Counter/Reload */ -#define GBA_TM2CNT_H 0x400010A /* R/W Timer 2 Control */ -#define GBA_TM3CNT_L 0x400010C /* R/W Timer 3 Counter/Reload */ -#define GBA_TM3CNT_H 0x400010E /* R/W Timer 3 Control */ +#define GBA_TM0CNT_L 0x4000100 /* R/W Timer 0 Counter/Reload */ +#define GBA_TM0CNT_H 0x4000102 /* R/W Timer 0 Control */ +#define GBA_TM1CNT_L 0x4000104 /* R/W Timer 1 Counter/Reload */ +#define GBA_TM1CNT_H 0x4000106 /* R/W Timer 1 Control */ +#define GBA_TM2CNT_L 0x4000108 /* R/W Timer 2 Counter/Reload */ +#define GBA_TM2CNT_H 0x400010A /* R/W Timer 2 Control */ +#define GBA_TM3CNT_L 0x400010C /* R/W Timer 3 Counter/Reload */ +#define GBA_TM3CNT_H 0x400010E /* R/W Timer 3 Control */ // Serial Communication (1) -#define GBA_SIODATA32 0x4000120 /*R/W SIO Data (Normal-32bit Mode; shared with below) */ -#define GBA_SIOMULTI0 0x4000120 /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ -#define GBA_SIOMULTI1 0x4000122 /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ -#define GBA_SIOMULTI2 0x4000124 /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ -#define GBA_SIOMULTI3 0x4000126 /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ -#define GBA_SIOCNT 0x4000128 /*R/W SIO Control Register */ -#define GBA_SIOMLT_SEND 0x400012A /*R/W SIO Data (Local of MultiPlayer; shared below) */ -#define GBA_SIODATA8 0x400012A /*R/W SIO Data (Normal-8bit and UART Mode) */ +#define GBA_SIODATA32 0x4000120 /*R/W SIO Data (Normal-32bit Mode; shared with below) */ +#define GBA_SIOMULTI0 0x4000120 /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ +#define GBA_SIOMULTI1 0x4000122 /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ +#define GBA_SIOMULTI2 0x4000124 /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ +#define GBA_SIOMULTI3 0x4000126 /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ +#define GBA_SIOCNT 0x4000128 /*R/W SIO Control Register */ +#define GBA_SIOMLT_SEND 0x400012A /*R/W SIO Data (Local of MultiPlayer; shared below) */ +#define GBA_SIODATA8 0x400012A /*R/W SIO Data (Normal-8bit and UART Mode) */ // Keypad Input -#define GBA_KEYINPUT 0x4000130 /* R Key Status */ -#define GBA_KEYCNT 0x4000132 /* R/W Key Interrupt Control */ +#define GBA_KEYINPUT 0x4000130 /* R Key Status */ +#define GBA_KEYCNT 0x4000132 /* R/W Key Interrupt Control */ // Serial Communication (2) -#define GBA_JOYCNT 0x4000140 /* R/W SIO JOY Bus Control */ -#define GBA_JOY_RECV 0x4000150 /* R/W SIO JOY Bus Receive Data */ -#define GBA_JOY_TRANS 0x4000154 /* R/W SIO JOY Bus Transmit Data */ -#define GBA_JOYSTAT 0x4000158 /* R/? SIO JOY Bus Receive Status */ +#define GBA_JOYCNT 0x4000140 /* R/W SIO JOY Bus Control */ +#define GBA_JOY_RECV 0x4000150 /* R/W SIO JOY Bus Receive Data */ +#define GBA_JOY_TRANS 0x4000154 /* R/W SIO JOY Bus Transmit Data */ +#define GBA_JOYSTAT 0x4000158 /* R/? SIO JOY Bus Receive Status */ ////////////////// // ARM9 I/O Map // @@ -124,15 +124,15 @@ typedef enum{ // ARM9 IPC/ROM -#define NDS9_IPCSYNC 0x04000180 /*IPC Synchronize Register (R/W)*/ -#define NDS9_IPCFIFOCNT 0x04000184 /*IPC Fifo Control Register (R/W)*/ -#define NDS9_IPCFIFOSEND 0x04000188 /*IPC Send Fifo (W)*/ -#define NDS9_AUXSPICNT 0x040001A0 /*Gamecard ROM and SPI Control*/ -#define NDS9_AUXSPIDATA 0x040001A2 /*Gamecard SPI Bus Data/Strobe*/ -#define NDS9_GC_ENC0_LO 0x040001B0 /*Gamecard Encryption Seed 0 Lower 32bit*/ -#define NDS9_GC_ENC1_LO 0x040001B4 /*Gamecard Encryption Seed 1 Lower 32bit*/ -#define NDS9_GC_ENC0_HI 0x040001B8 /*Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused)*/ -#define NDS9_GC_ENC1_HI 0x040001BA /*Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused)*/ +#define NDS9_IPCSYNC 0x04000180 /*IPC Synchronize Register (R/W)*/ +#define NDS9_IPCFIFOCNT 0x04000184 /*IPC Fifo Control Register (R/W)*/ +#define NDS9_IPCFIFOSEND 0x04000188 /*IPC Send Fifo (W)*/ +#define NDS9_AUXSPICNT 0x040001A0 /*Gamecard ROM and SPI Control*/ +#define NDS9_AUXSPIDATA 0x040001A2 /*Gamecard SPI Bus Data/Strobe*/ +#define NDS9_GC_ENC0_LO 0x040001B0 /*Gamecard Encryption Seed 0 Lower 32bit*/ +#define NDS9_GC_ENC1_LO 0x040001B4 /*Gamecard Encryption Seed 1 Lower 32bit*/ +#define NDS9_GC_ENC0_HI 0x040001B8 /*Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused)*/ +#define NDS9_GC_ENC1_HI 0x040001BA /*Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused)*/ // ARM9 Memory and IRQ Control @@ -176,45 +176,45 @@ typedef enum{ #define NDS9_FOG_TABLE 0x04000360 /* Fog Density Table, 32 entries (W) */ #define NDS9_TOON_TABLE 0x04000380 /* Toon Table, 32 colors (W) */ -#define NDS9_GXFIFO 0x04000400 /* Geometry Command FIFO (W) */ - -#define NDS9_MTX_MODE 0x04000440 /* Set Matrix Mode (W) */ -#define NDS9_MTX_PUSH 0x04000444 /* Push Current Matrix on Stack (W) */ -#define NDS9_MTX_POP 0x04000448 /* Pop Current Matrix from Stack (W) */ -#define NDS9_MTX_STORE 0x0400044C /* Store Current Matrix on Stack (W) */ -#define NDS9_MTX_RESTORE 0x04000450 /* Restore Current Matrix from Stack (W) */ -#define NDS9_MTX_IDENTITY 0x04000454 /* Load Unit Matrix to Current Matrix (W) */ -#define NDS9_MTX_LOAD_4x4 0x04000458 /* Load 4x4 Matrix to Current Matrix (W) */ -#define NDS9_MTX_LOAD_4x3 0x0400045C /* Load 4x3 Matrix to Current Matrix (W) */ -#define NDS9_MTX_MULT_4x4 0x04000460 /* Multiply Current Matrix by 4x4 Matrix (W) */ -#define NDS9_MTX_MULT_4x3 0x04000464 /* Multiply Current Matrix by 4x3 Matrix (W) */ -#define NDS9_MTX_MULT_3x3 0x04000468 /* Multiply Current Matrix by 3x3 Matrix (W) */ -#define NDS9_MTX_SCALE 0x0400046C /* Multiply Current Matrix by Scale Matrix (W) */ -#define NDS9_MTX_TRANS 0x04000470 /* Mult. Curr. Matrix by Translation Matrix (W) */ -#define NDS9_COLOR 0x04000480 /* Directly Set Vertex Color (W) */ -#define NDS9_NORMAL 0x04000484 /* Set Normal Vector (W) */ -#define NDS9_TEXCOORD 0x04000488 /* Set Texture Coordinates (W) */ -#define NDS9_VTX_16 0x0400048C /* Set Vertex XYZ Coordinates (W) */ -#define NDS9_VTX_10 0x04000490 /* Set Vertex XYZ Coordinates (W) */ -#define NDS9_VTX_XY 0x04000494 /* Set Vertex XY Coordinates (W) */ -#define NDS9_VTX_XZ 0x04000498 /* Set Vertex XZ Coordinates (W) */ -#define NDS9_VTX_YZ 0x0400049C /* Set Vertex YZ Coordinates (W) */ -#define NDS9_VTX_DIFF 0x040004A0 /* Set Relative Vertex Coordinates (W) */ -#define NDS9_POLYGON_ATTR 0x040004A4 /* Set Polygon Attributes (W) */ -#define NDS9_TEXIMAGE_PARAM 0x040004A8 /* Set Texture Parameters (W) */ -#define NDS9_PLTT_BASE 0x040004AC /* Set Texture Palette Base Address (W) */ -#define NDS9_DIF_AMB 0x040004C0 /* MaterialColor0 - Diffuse/Ambient Reflect. (W) */ -#define NDS9_SPE_EMI 0x040004C4 /* MaterialColor1 - Specular Ref. & Emission (W) */ -#define NDS9_LIGHT_VECTOR 0x040004C8 /* Set Light's Directional Vector (W) */ -#define NDS9_LIGHT_COLOR 0x040004CC /* Set Light Color (W) */ -#define NDS9_SHININESS 0x040004D0 /* Specular Reflection Shininess Table (W) */ -#define NDS9_BEGIN_VTXS 0x04000500 /* Start of Vertex List (W) */ -#define NDS9_END_VTXS 0x04000504 /* End of Vertex List (W) */ -#define NDS9_SWAP_BUFFERS 0x04000540 /* Swap Rendering Engine Buffer (W) */ -#define NDS9_VIEWPORT 0x04000580 /* Set Viewport (W) */ -#define NDS9_BOX_TEST 0x040005C0 /* Test if Cuboid Sits inside View Volume (W) */ -#define NDS9_POS_TEST 0x040005C4 /* Set Position Coordinates for Test (W) */ -#define NDS9_VEC_TEST 0x040005C8 /* Set Directional Vector for Test (W) */ +#define NDS9_GXFIFO 0x04000400 /* Geometry Command FIFO (W) */ + +#define NDS9_MTX_MODE 0x04000440 /* Set Matrix Mode (W) */ +#define NDS9_MTX_PUSH 0x04000444 /* Push Current Matrix on Stack (W) */ +#define NDS9_MTX_POP 0x04000448 /* Pop Current Matrix from Stack (W) */ +#define NDS9_MTX_STORE 0x0400044C /* Store Current Matrix on Stack (W) */ +#define NDS9_MTX_RESTORE 0x04000450 /* Restore Current Matrix from Stack (W) */ +#define NDS9_MTX_IDENTITY 0x04000454 /* Load Unit Matrix to Current Matrix (W) */ +#define NDS9_MTX_LOAD_4x4 0x04000458 /* Load 4x4 Matrix to Current Matrix (W) */ +#define NDS9_MTX_LOAD_4x3 0x0400045C /* Load 4x3 Matrix to Current Matrix (W) */ +#define NDS9_MTX_MULT_4x4 0x04000460 /* Multiply Current Matrix by 4x4 Matrix (W) */ +#define NDS9_MTX_MULT_4x3 0x04000464 /* Multiply Current Matrix by 4x3 Matrix (W) */ +#define NDS9_MTX_MULT_3x3 0x04000468 /* Multiply Current Matrix by 3x3 Matrix (W) */ +#define NDS9_MTX_SCALE 0x0400046C /* Multiply Current Matrix by Scale Matrix (W) */ +#define NDS9_MTX_TRANS 0x04000470 /* Mult. Curr. Matrix by Translation Matrix (W) */ +#define NDS9_COLOR 0x04000480 /* Directly Set Vertex Color (W) */ +#define NDS9_NORMAL 0x04000484 /* Set Normal Vector (W) */ +#define NDS9_TEXCOORD 0x04000488 /* Set Texture Coordinates (W) */ +#define NDS9_VTX_16 0x0400048C /* Set Vertex XYZ Coordinates (W) */ +#define NDS9_VTX_10 0x04000490 /* Set Vertex XYZ Coordinates (W) */ +#define NDS9_VTX_XY 0x04000494 /* Set Vertex XY Coordinates (W) */ +#define NDS9_VTX_XZ 0x04000498 /* Set Vertex XZ Coordinates (W) */ +#define NDS9_VTX_YZ 0x0400049C /* Set Vertex YZ Coordinates (W) */ +#define NDS9_VTX_DIFF 0x040004A0 /* Set Relative Vertex Coordinates (W) */ +#define NDS9_POLYGON_ATTR 0x040004A4 /* Set Polygon Attributes (W) */ +#define NDS9_TEXIMAGE_PARAM 0x040004A8 /* Set Texture Parameters (W) */ +#define NDS9_PLTT_BASE 0x040004AC /* Set Texture Palette Base Address (W) */ +#define NDS9_DIF_AMB 0x040004C0 /* MaterialColor0 - Diffuse/Ambient Reflect. (W) */ +#define NDS9_SPE_EMI 0x040004C4 /* MaterialColor1 - Specular Ref. & Emission (W) */ +#define NDS9_LIGHT_VECTOR 0x040004C8 /* Set Light's Directional Vector (W) */ +#define NDS9_LIGHT_COLOR 0x040004CC /* Set Light Color (W) */ +#define NDS9_SHININESS 0x040004D0 /* Specular Reflection Shininess Table (W) */ +#define NDS9_BEGIN_VTXS 0x04000500 /* Start of Vertex List (W) */ +#define NDS9_END_VTXS 0x04000504 /* End of Vertex List (W) */ +#define NDS9_SWAP_BUFFERS 0x04000540 /* Swap Rendering Engine Buffer (W) */ +#define NDS9_VIEWPORT 0x04000580 /* Set Viewport (W) */ +#define NDS9_BOX_TEST 0x040005C0 /* Test if Cuboid Sits inside View Volume (W) */ +#define NDS9_POS_TEST 0x040005C4 /* Set Position Coordinates for Test (W) */ +#define NDS9_VEC_TEST 0x040005C8 /* Set Directional Vector for Test (W) */ #define NDS9_GXSTAT 0x04000600 /* Geometry Engine Status Register (R and R/W) */ #define NDS9_RAM_COUNT 0x04000604 /* Polygon List & Vertex RAM Count Register (R) */ @@ -226,73 +226,73 @@ typedef enum{ // DS 3D I/O Map // ARM9 Display Engine B -#define NDS9_B_DISPCNT 0x04001000 /* R/W LCD Control */ -#define NDS9_B_BG0CNT 0x04001008 /* R/W BG0 Control */ -#define NDS9_B_BG1CNT 0x0400100A /* R/W BG1 Control */ -#define NDS9_B_BG2CNT 0x0400100C /* R/W BG2 Control */ -#define NDS9_B_BG3CNT 0x0400100E /* R/W BG3 Control */ -#define NDS9_B_BG0HOFS 0x04001010 /* W BG0 X-Offset */ -#define NDS9_B_BG0VOFS 0x04001012 /* W BG0 Y-Offset */ -#define NDS9_B_BG1HOFS 0x04001014 /* W BG1 X-Offset */ -#define NDS9_B_BG1VOFS 0x04001016 /* W BG1 Y-Offset */ -#define NDS9_B_BG2HOFS 0x04001018 /* W BG2 X-Offset */ -#define NDS9_B_BG2VOFS 0x0400101A /* W BG2 Y-Offset */ -#define NDS9_B_BG3HOFS 0x0400101C /* W BG3 X-Offset */ -#define NDS9_B_BG3VOFS 0x0400101E /* W BG3 Y-Offset */ -#define NDS9_B_BG2PA 0x04001020 /* W BG2 Rotation/Scaling Parameter A (dx) */ -#define NDS9_B_BG2PB 0x04001022 /* W BG2 Rotation/Scaling Parameter B (dmx) */ -#define NDS9_B_BG2PC 0x04001024 /* W BG2 Rotation/Scaling Parameter C (dy) */ -#define NDS9_B_BG2PD 0x04001026 /* W BG2 Rotation/Scaling Parameter D (dmy) */ -#define NDS9_B_BG2X 0x04001028 /* W BG2 Reference Point X-Coordinate */ -#define NDS9_B_BG2Y 0x0400102C /* W BG2 Reference Point Y-Coordinate */ -#define NDS9_B_BG3PA 0x04001030 /* W BG3 Rotation/Scaling Parameter A (dx) */ -#define NDS9_B_BG3PB 0x04001032 /* W BG3 Rotation/Scaling Parameter B (dmx) */ -#define NDS9_B_BG3PC 0x04001034 /* W BG3 Rotation/Scaling Parameter C (dy) */ -#define NDS9_B_BG3PD 0x04001036 /* W BG3 Rotation/Scaling Parameter D (dmy) */ -#define NDS9_B_BG3X 0x04001038 /* W BG3 Reference Point X-Coordinate */ -#define NDS9_B_BG3Y 0x0400103C /* W BG3 Reference Point Y-Coordinate */ -#define NDS9_B_WIN0H 0x04001040 /* W Window 0 Horizontal Dimensions */ -#define NDS9_B_WIN1H 0x04001042 /* W Window 1 Horizontal Dimensions */ -#define NDS9_B_WIN0V 0x04001044 /* W Window 0 Vertical Dimensions */ -#define NDS9_B_WIN1V 0x04001046 /* W Window 1 Vertical Dimensions */ -#define NDS9_B_WININ 0x04001048 /* R/W Inside of Window 0 and 1 */ -#define NDS9_B_WINOUT 0x0400104A /* R/W Inside of OBJ Window & Outside of Windows */ -#define NDS9_B_MOSAIC 0x0400104C /* W Mosaic Size */ -#define NDS9_B_BLDCNT 0x04001050 /* R/W Color Special Effects Selection */ -#define NDS9_B_BLDALPHA 0x04001052 /* R/W Alpha Blending Coefficients */ -#define NDS9_B_BLDY 0x04001054 /* W Brightness (Fade-In/Out) Coefficient */ - -#define NDS9_B_MASTER_BRIGHT 0x0400106C /* Master Brightness Up/Down */ +#define NDS9_B_DISPCNT 0x04001000 /* R/W LCD Control */ +#define NDS9_B_BG0CNT 0x04001008 /* R/W BG0 Control */ +#define NDS9_B_BG1CNT 0x0400100A /* R/W BG1 Control */ +#define NDS9_B_BG2CNT 0x0400100C /* R/W BG2 Control */ +#define NDS9_B_BG3CNT 0x0400100E /* R/W BG3 Control */ +#define NDS9_B_BG0HOFS 0x04001010 /* W BG0 X-Offset */ +#define NDS9_B_BG0VOFS 0x04001012 /* W BG0 Y-Offset */ +#define NDS9_B_BG1HOFS 0x04001014 /* W BG1 X-Offset */ +#define NDS9_B_BG1VOFS 0x04001016 /* W BG1 Y-Offset */ +#define NDS9_B_BG2HOFS 0x04001018 /* W BG2 X-Offset */ +#define NDS9_B_BG2VOFS 0x0400101A /* W BG2 Y-Offset */ +#define NDS9_B_BG3HOFS 0x0400101C /* W BG3 X-Offset */ +#define NDS9_B_BG3VOFS 0x0400101E /* W BG3 Y-Offset */ +#define NDS9_B_BG2PA 0x04001020 /* W BG2 Rotation/Scaling Parameter A (dx) */ +#define NDS9_B_BG2PB 0x04001022 /* W BG2 Rotation/Scaling Parameter B (dmx) */ +#define NDS9_B_BG2PC 0x04001024 /* W BG2 Rotation/Scaling Parameter C (dy) */ +#define NDS9_B_BG2PD 0x04001026 /* W BG2 Rotation/Scaling Parameter D (dmy) */ +#define NDS9_B_BG2X 0x04001028 /* W BG2 Reference Point X-Coordinate */ +#define NDS9_B_BG2Y 0x0400102C /* W BG2 Reference Point Y-Coordinate */ +#define NDS9_B_BG3PA 0x04001030 /* W BG3 Rotation/Scaling Parameter A (dx) */ +#define NDS9_B_BG3PB 0x04001032 /* W BG3 Rotation/Scaling Parameter B (dmx) */ +#define NDS9_B_BG3PC 0x04001034 /* W BG3 Rotation/Scaling Parameter C (dy) */ +#define NDS9_B_BG3PD 0x04001036 /* W BG3 Rotation/Scaling Parameter D (dmy) */ +#define NDS9_B_BG3X 0x04001038 /* W BG3 Reference Point X-Coordinate */ +#define NDS9_B_BG3Y 0x0400103C /* W BG3 Reference Point Y-Coordinate */ +#define NDS9_B_WIN0H 0x04001040 /* W Window 0 Horizontal Dimensions */ +#define NDS9_B_WIN1H 0x04001042 /* W Window 1 Horizontal Dimensions */ +#define NDS9_B_WIN0V 0x04001044 /* W Window 0 Vertical Dimensions */ +#define NDS9_B_WIN1V 0x04001046 /* W Window 1 Vertical Dimensions */ +#define NDS9_B_WININ 0x04001048 /* R/W Inside of Window 0 and 1 */ +#define NDS9_B_WINOUT 0x0400104A /* R/W Inside of OBJ Window & Outside of Windows */ +#define NDS9_B_MOSAIC 0x0400104C /* W Mosaic Size */ +#define NDS9_B_BLDCNT 0x04001050 /* R/W Color Special Effects Selection */ +#define NDS9_B_BLDALPHA 0x04001052 /* R/W Alpha Blending Coefficients */ +#define NDS9_B_BLDY 0x04001054 /* W Brightness (Fade-In/Out) Coefficient */ + +#define NDS9_B_MASTER_BRIGHT 0x0400106C /* Master Brightness Up/Down */ // ARM9 IPC/ROM -#define NDS_IPCFIFORECV (0x04100000|NDS_IO_MAP_041_OFFSET) /* IPC Receive Fifo (R)*/ -#define NDS_GC_BUS (0x04100010|NDS_IO_MAP_041_OFFSET) /* Gamecard bus 4-byte data in, for manual or dma read (R) (or W) */ -#define NDS_IPCSYNC 0x04000180 /* IPC Synchronize Register (R/W) */ -#define NDS_IPCFIFOCNT 0x04000184 /* IPC Fifo Control Register (R/W) */ -#define NDS_IPCFIFOSEND 0x04000188 /* IPC Send Fifo (W) */ +#define NDS_IPCFIFORECV (0x04100000 | NDS_IO_MAP_041_OFFSET) /* IPC Receive Fifo (R)*/ +#define NDS_GC_BUS (0x04100010 | NDS_IO_MAP_041_OFFSET) /* Gamecard bus 4-byte data in, for manual or dma read (R) (or W) */ +#define NDS_IPCSYNC 0x04000180 /* IPC Synchronize Register (R/W) */ +#define NDS_IPCFIFOCNT 0x04000184 /* IPC Fifo Control Register (R/W) */ +#define NDS_IPCFIFOSEND 0x04000188 /* IPC Send Fifo (W) */ -//Main Memory Control +// Main Memory Control -#define NDS9_MEM_CTRL 0x027FFFFE /* Main Memory Control*/ +#define NDS9_MEM_CTRL 0x027FFFFE /* Main Memory Control*/ ////////////////// // ARM7 I/O Map // ////////////////// -#define NDS7_DEBUG_RCNT 0x04000134 /* Debug RCNT */ -#define NDS7_EXTKEYIN 0x04000136 /* EXTKEYIN */ -#define NDS7_RTC_BUS 0x04000138 /* RTC Realtime Clock Bus */ -#define NDS7_AUXSPICNT 0x040001A0 /* Gamecard ROM and SPI Control */ -#define NDS7_AUXSPIDATA 0x040001A2 /* Gamecard SPI Bus Data/Strobe */ +#define NDS7_DEBUG_RCNT 0x04000134 /* Debug RCNT */ +#define NDS7_EXTKEYIN 0x04000136 /* EXTKEYIN */ +#define NDS7_RTC_BUS 0x04000138 /* RTC Realtime Clock Bus */ +#define NDS7_AUXSPICNT 0x040001A0 /* Gamecard ROM and SPI Control */ +#define NDS7_AUXSPIDATA 0x040001A2 /* Gamecard SPI Bus Data/Strobe */ #define NDS_GCBUS_CTL 0x040001A4 /* Gamecard bus timing/control */ #define NDS_GCBUS_CMD 0x040001A8 /* Gamecard bus 8-byte command out */ #define NDS_GCBUS_SEED0_LO 0x040001B0 /* Gamecard Encryption Seed 0 Lower 32bit */ #define NDS_GCBUS_SEED1_LO 0x040001B4 /* Gamecard Encryption Seed 1 Lower 32bit */ #define NDS_GCBUS_SEED0_HI 0x040001B8 /* Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused) */ #define NDS_GCBUS_SEED1_HI 0x040001BA /* Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused) */ -#define NDS7_SPI_BUS_CTL 0x040001C0 /* SPI bus Control (Firmware, Touchscreen, Powerman) */ -#define NDS7_SPI_BUS_DATA 0x040001C2 /* SPI bus Data */ +#define NDS7_SPI_BUS_CTL 0x040001C0 /* SPI bus Control (Firmware, Touchscreen, Powerman) */ +#define NDS7_SPI_BUS_DATA 0x040001C2 /* SPI bus Data */ // ARM7 Memory and IRQ Control #define NDS7_EXMEMSTAT 0x04000204 /* EXMEMSTAT - External Memory Status */ @@ -307,7 +307,7 @@ typedef enum{ #define NDS7_POWCNT2 0x04000304 /* POWCNT2 Sound/Wifi Power Control Register (R/W) */ #define NDS7_BIOSPROT 0x04000308 /* BIOSPROT - Bios-data-read-protection address */ -// ARM7 Sound Registers (Sound Channel 0..15 (10h bytes each)) +// ARM7 Sound Registers (Sound Channel 0..15 (10h bytes each)) #define NDS7_SOUND0_CNT 0x04000400 /* Sound Channel 0 Control Register (R/W) */ #define NDS7_SOUND0_SAD 0x04000404 /* Sound Channel 0 Data Source Register (W) */ #define NDS7_SOUND0_TMR 0x04000408 /* Sound Channel 0 Timer Register (W) */ @@ -398,1442 +398,1453 @@ typedef enum{ #define NDS7_SNDCAP1DAD 0x04000518 /* Sound Capture 1 Destination Address (R/W) */ #define NDS7_SNDCAP1LEN 0x0400051C /* Sound Capture 1 Length (W) */ -#define NDS_SPI_POWER 0 +#define NDS_SPI_POWER 0 #define NDS_SPI_FIRMWARE 1 -#define NDS_SPI_TOUCH 2 - -#define NDS_FIRMWARE_SIZE (256*1024) - -#define NDS_IO_MAP_SPLIT_OFFSET 0x2000 -#define NDS_IO_MAP_041_OFFSET 0x4000 - - - -mmio_reg_t nds9_io_reg_desc[]={ - { GBA_DISPCNT , "DISPCNT ", { - { 0, 3, "BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)"}, - { 3 ,1, "BG0 2D/3D Selection"}, - { 4 ,1, "Tile OBJ Mapping (0=2D; max 32KB, 1=1D; max 32KB..256KB)"}, - { 5 ,1, "Bitmap OBJ 2D-Dimension (0=128x512 dots, 1=256x256 dots)"}, - { 6 ,1, "OBJ Character VRAM Mapping (0=2D, 1=1D"}, - { 7 ,1, "Forced Blank (1=Allow FAST VRAM,Palette,OAM)"}, - { 8 ,1, "Screen Display BG0 (0=Off, 1=On)"}, - { 9 ,1, "Screen Display BG1 (0=Off, 1=On)"}, - { 10,1, "Screen Display BG2 (0=Off, 1=On)"}, - { 11,1, "Screen Display BG3 (0=Off, 1=On)"}, - { 12,1, "Screen Display OBJ (0=Off, 1=On)"}, - { 13,1, "Window 0 Display Flag (0=Off, 1=On)"}, - { 14,1, "Window 1 Display Flag (0=Off, 1=On)"}, - { 15,1, "OBJ Window Display Flag (0=Off, 1=On)"}, - { 16,2, "Display Mode (0..3)"}, - { 18,2, "VRAM block (0..3=VRAM A..D) (For Capture & above Display Mode=2)"}, - { 20,2, "Tile OBJ 1D-Boundary (see Bit4)"}, - { 22,1, "Bitmap OBJ 1D-Boundary (see Bit5-6)"}, - { 23,1, "OBJ Processing during H-Blank (was located in Bit5 on GBA)"}, - { 24,3, "Character Base (in 64K steps) (merged with 16K step in BGxCNT)"}, - { 27,3, "Screen Base (in 64K steps) (merged with 2K step in BGxCNT)"}, - { 30,1, "BG Extended Palettes (0=Disable, 1=Enable)"}, - { 31,1, "OBJ Extended Palettes (0=Disable, 1=Enable)"} - } }, - { GBA_GREENSWP, "GREENSWP", { {0, 1, "Green Swap (0=Normal, 1=Swap)" }} }, /* R/W Undocumented - Green Swap */ - { GBA_DISPSTAT, "DISPSTAT", { - { 0,1, "V-Blank flag (1=VBlank) (set in line 160..226; not 227",}, - { 1,1, "H-Blank flag (1=HBlank) (toggled in all lines, 0..227",}, - { 2,1, "V-Counter flag (1=Match) (set in selected line)",}, - { 3,1, "V-Blank IRQ Enable (1=Enable)",}, - { 4,1, "H-Blank IRQ Enable (1=Enable)",}, - { 5,1, "V-Counter IRQ Enable (1=Enable)",}, - { 6,1, "DSi: LCD Initialization Ready (0=Busy, 1=Ready",}, - { 7,1, "NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262",}, - { 8,8, "V-Count Setting (LYC) (0..227)",}, - - } }, /* R/W General LCD Status (STAT,LYC) */ - { GBA_VCOUNT , "VCOUNT ", { - {0,8,"LCD-Y"} - } }, /* R Vertical Counter (LY) */ - { GBA_BG0CNT , "BG0CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG0 Control */ - { GBA_BG1CNT , "BG1CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG1 Control */ - { GBA_BG2CNT , "BG2CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG2 Control */ - { GBA_BG3CNT , "BG3CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG3 Control */ - { GBA_BG0HOFS , "BG0HOFS", { 0 } }, /* W BG0 X-Offset */ - { GBA_BG0VOFS , "BG0VOFS", { 0 } }, /* W BG0 Y-Offset */ - { GBA_BG1HOFS , "BG1HOFS", { 0 } }, /* W BG1 X-Offset */ - { GBA_BG1VOFS , "BG1VOFS", { 0 } }, /* W BG1 Y-Offset */ - { GBA_BG2HOFS , "BG2HOFS", { 0 } }, /* W BG2 X-Offset */ - { GBA_BG2VOFS , "BG2VOFS", { 0 } }, /* W BG2 Y-Offset */ - { GBA_BG3HOFS , "BG3HOFS", { 0 } }, /* W BG3 X-Offset */ - { GBA_BG3VOFS , "BG3VOFS", { 0 } }, /* W BG3 Y-Offset */ - { GBA_BG2PA , "BG2PA", { 0 } }, /* W BG2 Rotation/Scaling Parameter A (dx) */ - { GBA_BG2PB , "BG2PB", { 0 } }, /* W BG2 Rotation/Scaling Parameter B (dmx) */ - { GBA_BG2PC , "BG2PC", { 0 } }, /* W BG2 Rotation/Scaling Parameter C (dy) */ - { GBA_BG2PD , "BG2PD", { 0 } }, /* W BG2 Rotation/Scaling Parameter D (dmy) */ - { GBA_BG2X , "BG2X", { 0 } }, /* W BG2 Reference Point X-Coordinate */ - { GBA_BG2Y , "BG2Y", { 0 } }, /* W BG2 Reference Point Y-Coordinate */ - { GBA_BG3PA , "BG3PA", { 0 } }, /* W BG3 Rotation/Scaling Parameter A (dx) */ - { GBA_BG3PB , "BG3PB", { 0 } }, /* W BG3 Rotation/Scaling Parameter B (dmx) */ - { GBA_BG3PC , "BG3PC", { 0 } }, /* W BG3 Rotation/Scaling Parameter C (dy) */ - { GBA_BG3PD , "BG3PD", { 0 } }, /* W BG3 Rotation/Scaling Parameter D (dmy) */ - { GBA_BG3X , "BG3X", { 0 } }, /* W BG3 Reference Point X-Coordinate */ - { GBA_BG3Y , "BG3Y", { 0 } }, /* W BG3 Reference Point Y-Coordinate */ - { GBA_WIN0H , "WIN0H", { - { 0, 8, "X2, Rightmost coordinate of window, plus 1 " }, - { 8, 8, "X1, Leftmost coordinate of window"}, - } }, /* W Window 0 Horizontal Dimensions */ - { GBA_WIN1H , "WIN1H", { - { 0, 8, "X2, Rightmost coordinate of window, plus 1 " }, - { 8, 8, "X1, Leftmost coordinate of window"}, - } }, /* W Window 1 Horizontal Dimensions */ - { GBA_WIN0V , "WIN0V", { - {0, 8, "Y2, Bottom-most coordinate of window, plus 1" }, - {8, 8, "Y1, Top-most coordinate of window" }, - } }, /* W Window 0 Vertical Dimensions */ - { GBA_WIN1V , "WIN1V", { - {0, 8, "Y2, Bottom-most coordinate of window, plus 1" }, - {8, 8, "Y1, Top-most coordinate of window" }, - } }, /* W Window 1 Vertical Dimensions */ - { GBA_WININ , "WININ", { - { 0 , 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 1 , 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 2 , 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 3 , 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 4 , 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 5 , 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, - { 8 , 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 9 , 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, - } }, /* R/W Inside of Window 0 and 1 */ - { GBA_WINOUT , "WINOUT", { - { 0 , 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 1 , 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 2 , 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 3 , 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 4 , 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 5 , 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, - { 8 , 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 9 , 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, - } }, /* R/W Inside of OBJ Window & Outside of Windows */ - { GBA_MOSAIC , "MOSAIC", { - { 0, 4, "BG Mosaic H-Size (minus 1)" }, - { 4, 4, "BG Mosaic V-Size (minus 1)" }, - { 8, 4, "OBJ Mosaic H-Size (minus 1)" }, - { 12,4, "OBJ Mosaic V-Size (minus 1)" }, - } }, /* W Mosaic Size */ - { GBA_BLDCNT , "BLDCNT", { - { 0 , 1, "BG0 1st Target Pixel (Background 0)" }, - { 1 , 1, "BG1 1st Target Pixel (Background 1)" }, - { 2 , 1, "BG2 1st Target Pixel (Background 2)" }, - { 3 , 1, "BG3 1st Target Pixel (Background 3)" }, - { 4 , 1, "OBJ 1st Target Pixel (Top-most OBJ pixel)" }, - { 5 , 1, "BD 1st Target Pixel (Backdrop)" }, - { 6 , 2, "Color Effect (0: None 1: Alpha 2: Lighten 3: Darken)" }, - { 8 , 1, "BG0 2nd Target Pixel (Background 0)" }, - { 9 , 1, "BG1 2nd Target Pixel (Background 1)" }, - { 10, 1, "BG2 2nd Target Pixel (Background 2)" }, - { 11, 1, "BG3 2nd Target Pixel (Background 3)" }, - { 12, 1, "OBJ 2nd Target Pixel (Top-most OBJ pixel)" }, - { 13, 1, "BD 2nd Target Pixel (Backdrop)" }, - } }, /* R/W Color Special Effects Selection */ - { GBA_BLDALPHA, "BLDALPHA", { - {0, 4, "EVA Coef. (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, - {8, 4, "EVB Coef. (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, - } }, /* R/W Alpha Blending Coefficients */ - { GBA_BLDY , "BLDY", { - {0, 5, "EVY Coefficient (Brightness) (0..16 = 0/16..16/16, 17..31=16/16)"}, - } }, /* W Brightness (Fade-In/Out) Coefficient */ - { NDS_DISP3DCNT, "DISP3DCNT", { - {0 ,1, "Texture Mapping (0=Disable, 1=Enable)"}, - {1 ,1, "PolygonAttr Shading (0=Toon Shading, 1=Highlight Shading)"}, - {2 ,1, "Alpha-Test (0=Disable, 1=Enable) (see ALPHA_TEST_REF)"}, - {3 ,1, "Alpha-Blending (0=Disable, 1=Enable) (see various Alpha values)"}, - {4 ,1, "Anti-Aliasing (0=Disable, 1=Enable)"}, - {5 ,1, "Edge-Marking (0=Disable, 1=Enable) (see EDGE_COLOR)"}, - {6 ,1, "Fog Color/Alpha Mode (0=Alpha and Color, 1=Only Alpha) (see FOG_COLOR)"}, - {7 ,1, "Fog Master Enable (0=Disable, 1=Enable)"}, - {8 ,4, "Fog Depth Shift (FOG_STEP=400h shr FOG_SHIFT) (see FOG_OFFSET)"}, - {12 ,1, "Color Buffer RDLINES Underflow (0=None, 1=Underflow/Acknowledge)"}, - {13 ,1, "Polygon/Vertex RAM Overflow (0=None, 1=Overflow/Acknowledge)"}, - {14 ,1, "Rear-Plane Mode (0=Blank, 1=Bitmap)"}, - } }, /* 3D Display Control Register (R/W) */ - { NDS_DISPCAPCNT, "DISPCAPCNT", { - { 0 ,5, "EVA (0..16 = Blending Factor for Source A)"}, - { 8 ,5, "EVB (0..16 = Blending Factor for Source B)"}, - { 16 ,2, "VRAM Write Block (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)"}, - { 18 ,2, "VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)"}, - { 20 ,2, "Capture Size (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)"}, - { 24 ,1, "Source A (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)"}, - { 25 ,1, "Source B (0=VRAM, 1=Main Memory Display FIFO)"}, - { 26 ,2, "VRAM Read Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)"}, - { 29 ,2, "Capture Source (0=Source A, 1=Source B, 2/3=Sources A+B blended)"}, - { 31 ,1, "Capture Enable (0=Disable/Ready, 1=Enable/Busy)"}, - } }, /* Display Capture Control Register (R/W) */ - { NDS_DISP_MMEM_FIFO, "DISP_MMEM_FIFO", { 0 } }, /* Main Memory Display FIFO (R?/W) */ - { NDS_A_MASTER_BRIGHT, "A_MASTER_BRIGHT", { - {0,5,"Factor used for 6bit R,G,B Intensities (0-16, values >16 same as 16)"}, - {14,2, "Mode (0=Disable, 1=Up, 2=Down, 3=Reserved)"}, - } }, /* Master Brightness Up/Down */ +#define NDS_SPI_TOUCH 2 + +#define NDS_FIRMWARE_SIZE (256 * 1024) + +#define NDS_IO_MAP_SPLIT_OFFSET 0x2000 +#define NDS_IO_MAP_041_OFFSET 0x4000 + +mmio_reg_t nds9_io_reg_desc[] = { + { GBA_DISPCNT, "DISPCNT ", {{0, 3, "BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)"}, {3, 1, "BG0 2D/3D Selection"}, {4, 1, "Tile OBJ Mapping (0=2D; max 32KB, 1=1D; max 32KB..256KB)"}, {5, 1, "Bitmap OBJ 2D-Dimension (0=128x512 dots, 1=256x256 dots)"}, {6, 1, "OBJ Character VRAM Mapping (0=2D, 1=1D"}, {7, 1, "Forced Blank (1=Allow FAST VRAM,Palette,OAM)"}, {8, 1, "Screen Display BG0 (0=Off, 1=On)"}, {9, 1, "Screen Display BG1 (0=Off, 1=On)"}, {10, 1, "Screen Display BG2 (0=Off, 1=On)"}, {11, 1, "Screen Display BG3 (0=Off, 1=On)"}, {12, 1, "Screen Display OBJ (0=Off, 1=On)"}, {13, 1, "Window 0 Display Flag (0=Off, 1=On)"}, {14, 1, "Window 1 Display Flag (0=Off, 1=On)"}, {15, 1, "OBJ Window Display Flag (0=Off, 1=On)"}, {16, 2, "Display Mode (0..3)"}, {18, 2, "VRAM block (0..3=VRAM A..D) (For Capture & above Display Mode=2)"}, {20, 2, "Tile OBJ 1D-Boundary (see Bit4)"}, {22, 1, "Bitmap OBJ 1D-Boundary (see Bit5-6)"}, {23, 1, "OBJ Processing during H-Blank (was located in Bit5 on GBA)"}, {24, 3, "Character Base (in 64K steps) (merged with 16K step in BGxCNT)"}, {27, 3, "Screen Base (in 64K steps) (merged with 2K step in BGxCNT)"}, {30, 1, "BG Extended Palettes (0=Disable, 1=Enable)"}, {31, 1, "OBJ Extended Palettes (0=Disable, 1=Enable)"}}}, + { GBA_GREENSWP, "GREENSWP", {{0, 1, "Green Swap (0=Normal, 1=Swap)"}}}, /* R/W Undocumented - Green Swap */ + { GBA_DISPSTAT, "DISPSTAT", { + { + 0, + 1, + "V-Blank flag (1=VBlank) (set in line 160..226; not 227", + }, + { + 1, + 1, + "H-Blank flag (1=HBlank) (toggled in all lines, 0..227", + }, + { + 2, + 1, + "V-Counter flag (1=Match) (set in selected line)", + }, + { + 3, + 1, + "V-Blank IRQ Enable (1=Enable)", + }, + { + 4, + 1, + "H-Blank IRQ Enable (1=Enable)", + }, + { + 5, + 1, + "V-Counter IRQ Enable (1=Enable)", + }, + { + 6, + 1, + "DSi: LCD Initialization Ready (0=Busy, 1=Ready", + }, + { + 7, + 1, + "NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262", + }, + { + 8, + 8, + "V-Count Setting (LYC) (0..227)", + }, + + } }, /* R/W General LCD Status (STAT,LYC) */ + { GBA_VCOUNT, "VCOUNT ", {{0, 8, "LCD-Y"}}}, /* R Vertical Counter (LY) */ + { GBA_BG0CNT, "BG0CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG0 Control */ + { GBA_BG1CNT, "BG1CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG1 Control */ + { GBA_BG2CNT, "BG2CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG2 Control */ + { GBA_BG3CNT, "BG3CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG3 Control */ + { GBA_BG0HOFS, "BG0HOFS", {0}}, /* W BG0 X-Offset */ + { GBA_BG0VOFS, "BG0VOFS", {0}}, /* W BG0 Y-Offset */ + { GBA_BG1HOFS, "BG1HOFS", {0}}, /* W BG1 X-Offset */ + { GBA_BG1VOFS, "BG1VOFS", {0}}, /* W BG1 Y-Offset */ + { GBA_BG2HOFS, "BG2HOFS", {0}}, /* W BG2 X-Offset */ + { GBA_BG2VOFS, "BG2VOFS", {0}}, /* W BG2 Y-Offset */ + { GBA_BG3HOFS, "BG3HOFS", {0}}, /* W BG3 X-Offset */ + { GBA_BG3VOFS, "BG3VOFS", {0}}, /* W BG3 Y-Offset */ + { GBA_BG2PA, "BG2PA", {0}}, /* W BG2 Rotation/Scaling Parameter A (dx) */ + { GBA_BG2PB, "BG2PB", {0}}, /* W BG2 Rotation/Scaling Parameter B (dmx) */ + { GBA_BG2PC, "BG2PC", {0}}, /* W BG2 Rotation/Scaling Parameter C (dy) */ + { GBA_BG2PD, "BG2PD", {0}}, /* W BG2 Rotation/Scaling Parameter D (dmy) */ + { GBA_BG2X, "BG2X", {0}}, /* W BG2 Reference Point X-Coordinate */ + { GBA_BG2Y, "BG2Y", {0}}, /* W BG2 Reference Point Y-Coordinate */ + { GBA_BG3PA, "BG3PA", {0}}, /* W BG3 Rotation/Scaling Parameter A (dx) */ + { GBA_BG3PB, "BG3PB", {0}}, /* W BG3 Rotation/Scaling Parameter B (dmx) */ + { GBA_BG3PC, "BG3PC", {0}}, /* W BG3 Rotation/Scaling Parameter C (dy) */ + { GBA_BG3PD, "BG3PD", {0}}, /* W BG3 Rotation/Scaling Parameter D (dmy) */ + { GBA_BG3X, "BG3X", {0}}, /* W BG3 Reference Point X-Coordinate */ + { GBA_BG3Y, "BG3Y", {0}}, /* W BG3 Reference Point Y-Coordinate */ + { GBA_WIN0H, "WIN0H", { + {0, 8, "X2, Rightmost coordinate of window, plus 1 "}, + {8, 8, "X1, Leftmost coordinate of window"}, + } }, /* W Window 0 Horizontal Dimensions */ + { GBA_WIN1H, "WIN1H", { + {0, 8, "X2, Rightmost coordinate of window, plus 1 "}, + {8, 8, "X1, Leftmost coordinate of window"}, + } }, /* W Window 1 Horizontal Dimensions */ + { GBA_WIN0V, "WIN0V", { + {0, 8, "Y2, Bottom-most coordinate of window, plus 1"}, + {8, 8, "Y1, Top-most coordinate of window"}, + } }, /* W Window 0 Vertical Dimensions */ + { GBA_WIN1V, "WIN1V", { + {0, 8, "Y2, Bottom-most coordinate of window, plus 1"}, + {8, 8, "Y1, Top-most coordinate of window"}, + } }, /* W Window 1 Vertical Dimensions */ + { GBA_WININ, "WININ", { + {0, 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, + {1, 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, + {2, 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, + {3, 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, + {4, 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, + {5, 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, + {8, 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, + {9, 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, + {10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, + {11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, + {12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, + {13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, + } }, /* R/W Inside of Window 0 and 1 */ + { GBA_WINOUT, "WINOUT", { + {0, 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, + {1, 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, + {2, 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, + {3, 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, + {4, 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, + {5, 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, + {8, 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, + {9, 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, + {10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, + {11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, + {12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, + {13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, + } }, /* R/W Inside of OBJ Window & Outside of Windows */ + { GBA_MOSAIC, "MOSAIC", { + {0, 4, "BG Mosaic H-Size (minus 1)"}, + {4, 4, "BG Mosaic V-Size (minus 1)"}, + {8, 4, "OBJ Mosaic H-Size (minus 1)"}, + {12, 4, "OBJ Mosaic V-Size (minus 1)"}, + } }, /* W Mosaic Size */ + { GBA_BLDCNT, "BLDCNT", { + {0, 1, "BG0 1st Target Pixel (Background 0)"}, + {1, 1, "BG1 1st Target Pixel (Background 1)"}, + {2, 1, "BG2 1st Target Pixel (Background 2)"}, + {3, 1, "BG3 1st Target Pixel (Background 3)"}, + {4, 1, "OBJ 1st Target Pixel (Top-most OBJ pixel)"}, + {5, 1, "BD 1st Target Pixel (Backdrop)"}, + {6, 2, "Color Effect (0: None 1: Alpha 2: Lighten 3: Darken)"}, + {8, 1, "BG0 2nd Target Pixel (Background 0)"}, + {9, 1, "BG1 2nd Target Pixel (Background 1)"}, + {10, 1, "BG2 2nd Target Pixel (Background 2)"}, + {11, 1, "BG3 2nd Target Pixel (Background 3)"}, + {12, 1, "OBJ 2nd Target Pixel (Top-most OBJ pixel)"}, + {13, 1, "BD 2nd Target Pixel (Backdrop)"}, + } }, /* R/W Color Special Effects Selection */ + { GBA_BLDALPHA, "BLDALPHA", { + {0, 4, "EVA Coef. (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, + {8, 4, "EVB Coef. (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, + } }, /* R/W Alpha Blending Coefficients */ + { GBA_BLDY, "BLDY", { + {0, 5, "EVY Coefficient (Brightness) (0..16 = 0/16..16/16, 17..31=16/16)"}, + } }, /* W Brightness (Fade-In/Out) Coefficient */ + { NDS_DISP3DCNT, "DISP3DCNT", { + {0, 1, "Texture Mapping (0=Disable, 1=Enable)"}, + {1, 1, "PolygonAttr Shading (0=Toon Shading, 1=Highlight Shading)"}, + {2, 1, "Alpha-Test (0=Disable, 1=Enable) (see ALPHA_TEST_REF)"}, + {3, 1, "Alpha-Blending (0=Disable, 1=Enable) (see various Alpha values)"}, + {4, 1, "Anti-Aliasing (0=Disable, 1=Enable)"}, + {5, 1, "Edge-Marking (0=Disable, 1=Enable) (see EDGE_COLOR)"}, + {6, 1, "Fog Color/Alpha Mode (0=Alpha and Color, 1=Only Alpha) (see FOG_COLOR)"}, + {7, 1, "Fog Master Enable (0=Disable, 1=Enable)"}, + {8, 4, "Fog Depth Shift (FOG_STEP=400h shr FOG_SHIFT) (see FOG_OFFSET)"}, + {12, 1, "Color Buffer RDLINES Underflow (0=None, 1=Underflow/Acknowledge)"}, + {13, 1, "Polygon/Vertex RAM Overflow (0=None, 1=Overflow/Acknowledge)"}, + {14, 1, "Rear-Plane Mode (0=Blank, 1=Bitmap)"}, + } }, /* 3D Display Control Register (R/W) */ + { NDS_DISPCAPCNT, "DISPCAPCNT", { + {0, 5, "EVA (0..16 = Blending Factor for Source A)"}, + {8, 5, "EVB (0..16 = Blending Factor for Source B)"}, + {16, 2, "VRAM Write Block (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)"}, + {18, 2, "VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)"}, + {20, 2, "Capture Size (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)"}, + {24, 1, "Source A (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)"}, + {25, 1, "Source B (0=VRAM, 1=Main Memory Display FIFO)"}, + {26, 2, "VRAM Read Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)"}, + {29, 2, "Capture Source (0=Source A, 1=Source B, 2/3=Sources A+B blended)"}, + {31, 1, "Capture Enable (0=Disable/Ready, 1=Enable/Busy)"}, + } }, /* Display Capture Control Register (R/W) */ + { NDS_DISP_MMEM_FIFO, "DISP_MMEM_FIFO", {0}}, /* Main Memory Display FIFO (R?/W) */ + { NDS_A_MASTER_BRIGHT, "A_MASTER_BRIGHT", { + {0, 5, "Factor used for 6bit R,G,B Intensities (0-16, values >16 same as 16)"}, + {14, 2, "Mode (0=Disable, 1=Up, 2=Down, 3=Reserved)"}, + } }, /* Master Brightness Up/Down */ // DMA Transfer Channels - { GBA_DMA0SAD , "DMA0SAD", { 0 } }, /* W DMA 0 Source Address */ - { GBA_DMA0DAD , "DMA0DAD", { 0 } }, /* W DMA 0 Destination Address */ - { GBA_DMA0CNT_L, "DMA0CNT_L", { 0 } }, /* W DMA 0 Word Count */ - { GBA_DMA0CNT_H, "DMA0CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 0 Control */ - { GBA_DMA1SAD , "DMA1SAD", { 0 } }, /* W DMA 1 Source Address */ - { GBA_DMA1DAD , "DMA1DAD", { 0 } }, /* W DMA 1 Destination Address */ - { GBA_DMA1CNT_L, "DMA1CNT_L", { 0 } }, /* W DMA 1 Word Count */ - { GBA_DMA1CNT_H, "DMA1CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 1 Control */ - { GBA_DMA2SAD , "DMA2SAD", { 0 } }, /* W DMA 2 Source Address */ - { GBA_DMA2DAD , "DMA2DAD", { 0 } }, /* W DMA 2 Destination Address */ - { GBA_DMA2CNT_L, "DMA2CNT_L", { 0 } }, /* W DMA 2 Word Count */ - { GBA_DMA2CNT_H, "DMA2CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 2 Control */ - { GBA_DMA3SAD , "DMA3SAD", { 0 } }, /* W DMA 3 Source Address */ - { GBA_DMA3DAD , "DMA3DAD", { 0 } }, /* W DMA 3 Destination Address */ - { GBA_DMA3CNT_L, "DMA3CNT_L", { 0 } }, /* W DMA 3 Word Count */ - { GBA_DMA3CNT_H, "DMA3CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 3 Control */ - { NDS9_DMA0FILL, "NDS9_DMA0FILL",{0}}, - { NDS9_DMA1FILL, "NDS9_DMA1FILL",{0}}, - { NDS9_DMA2FILL, "NDS9_DMA2FILL",{0}}, - { NDS9_DMA3FILL, "NDS9_DMA3FILL",{0}}, - - // Timer Registers - { GBA_TM0CNT_L, "TM0CNT_L", {0} }, /* R/W Timer 0 Counter/Reload */ - { GBA_TM0CNT_H, "TM0CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 0 Control */ - { GBA_TM1CNT_L, "TM1CNT_L", {0} }, /* R/W Timer 1 Counter/Reload */ - { GBA_TM1CNT_H, "TM1CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 1 Control */ - { GBA_TM2CNT_L, "TM2CNT_L", {0} }, /* R/W Timer 2 Counter/Reload */ - { GBA_TM2CNT_H, "TM2CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 2 Control */ - { GBA_TM3CNT_L, "TM3CNT_L", {0} }, /* R/W Timer 3 Counter/Reload */ - { GBA_TM3CNT_H, "TM3CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 3 Control */ + { GBA_DMA0SAD, "DMA0SAD", {0}}, /* W DMA 0 Source Address */ + { GBA_DMA0DAD, "DMA0DAD", {0}}, /* W DMA 0 Destination Address */ + { GBA_DMA0CNT_L, "DMA0CNT_L", {0}}, /* W DMA 0 Word Count */ + { GBA_DMA0CNT_H, "DMA0CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 0 Control */ + { GBA_DMA1SAD, "DMA1SAD", {0}}, /* W DMA 1 Source Address */ + { GBA_DMA1DAD, "DMA1DAD", {0}}, /* W DMA 1 Destination Address */ + { GBA_DMA1CNT_L, "DMA1CNT_L", {0}}, /* W DMA 1 Word Count */ + { GBA_DMA1CNT_H, "DMA1CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 1 Control */ + { GBA_DMA2SAD, "DMA2SAD", {0}}, /* W DMA 2 Source Address */ + { GBA_DMA2DAD, "DMA2DAD", {0}}, /* W DMA 2 Destination Address */ + { GBA_DMA2CNT_L, "DMA2CNT_L", {0}}, /* W DMA 2 Word Count */ + { GBA_DMA2CNT_H, "DMA2CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 2 Control */ + { GBA_DMA3SAD, "DMA3SAD", {0}}, /* W DMA 3 Source Address */ + { GBA_DMA3DAD, "DMA3DAD", {0}}, /* W DMA 3 Destination Address */ + { GBA_DMA3CNT_L, "DMA3CNT_L", {0}}, /* W DMA 3 Word Count */ + { GBA_DMA3CNT_H, "DMA3CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 3, "DMA Start Timing (0=Immediately, 1=VBlank, 2=HBlank, 3=Video, 4=Main memory display, 5=DS Cartridge Slot, 6=GBA Cartridge Slot, 7=Geometry Command FIFO)"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 3 Control */ + { NDS9_DMA0FILL, "NDS9_DMA0FILL", {0}}, + { NDS9_DMA1FILL, "NDS9_DMA1FILL", {0}}, + { NDS9_DMA2FILL, "NDS9_DMA2FILL", {0}}, + { NDS9_DMA3FILL, "NDS9_DMA3FILL", {0}}, + + // Timer Registers + { GBA_TM0CNT_L, "TM0CNT_L", {0}}, /* R/W Timer 0 Counter/Reload */ + { GBA_TM0CNT_H, "TM0CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 0 Control */ + { GBA_TM1CNT_L, "TM1CNT_L", {0}}, /* R/W Timer 1 Counter/Reload */ + { GBA_TM1CNT_H, "TM1CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 1 Control */ + { GBA_TM2CNT_L, "TM2CNT_L", {0}}, /* R/W Timer 2 Counter/Reload */ + { GBA_TM2CNT_H, "TM2CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 2 Control */ + { GBA_TM3CNT_L, "TM3CNT_L", {0}}, /* R/W Timer 3 Counter/Reload */ + { GBA_TM3CNT_H, "TM3CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 3 Control */ // Serial Communication (1) - { GBA_SIODATA32 , "SIODATA32", {0} }, /*R/W SIO Data (Normal-32bit Mode; shared with below) */ - { GBA_SIOMULTI0 , "SIOMULTI0", {0} }, /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ - { GBA_SIOMULTI1 , "SIOMULTI1", {0} }, /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ - { GBA_SIOMULTI2 , "SIOMULTI2", {0} }, /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ - { GBA_SIOMULTI3 , "SIOMULTI3", {0} }, /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ - { GBA_SIOCNT , "SIOCNT", {0} }, /*R/W SIO Control Register */ - { GBA_SIOMLT_SEND, "SIOMLT_SEND", {0} }, /*R/W SIO Data (Local of MultiPlayer; shared below) */ - { GBA_SIODATA8 , "SIODATA8", {0} }, /*R/W SIO Data (Normal-8bit and UART Mode) */ + { GBA_SIODATA32, "SIODATA32", {0}}, /*R/W SIO Data (Normal-32bit Mode; shared with below) */ + { GBA_SIOMULTI0, "SIOMULTI0", {0}}, /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ + { GBA_SIOMULTI1, "SIOMULTI1", {0}}, /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ + { GBA_SIOMULTI2, "SIOMULTI2", {0}}, /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ + { GBA_SIOMULTI3, "SIOMULTI3", {0}}, /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ + { GBA_SIOCNT, "SIOCNT", {0}}, /*R/W SIO Control Register */ + { GBA_SIOMLT_SEND, "SIOMLT_SEND", {0}}, /*R/W SIO Data (Local of MultiPlayer; shared below) */ + { GBA_SIODATA8, "SIODATA8", {0}}, /*R/W SIO Data (Normal-8bit and UART Mode) */ // Keypad Input - { GBA_KEYINPUT, "GBA_KEYINPUT", { - { 0, 1, "Button A" }, - { 1, 1, "Button B" }, - { 2, 1, "Select" }, - { 3, 1, "Start" }, - { 4, 1, "Right" }, - { 5, 1, "Left" }, - { 6, 1, "Up" }, - { 7, 1, "Down" }, - { 8, 1, "Button R" }, - { 9, 1, "Button L" }, - } }, /* R Key Status */ - { GBA_KEYCNT , "GBA_KEYCNT", { - { 0, 1, "Button A" }, - { 1, 1, "Button B" }, - { 2, 1, "Select" }, - { 3, 1, "Start" }, - { 4, 1, "Right" }, - { 5, 1, "Left" }, - { 6, 1, "Up" }, - { 7, 1, "Down" }, - { 8, 1, "Button R" }, - { 9, 1, "Button L" }, - { 14,1, "Button IRQ Enable (0=Disable, 1=Enable)" }, - { 15,1, "Button IRQ Condition (0=OR, 1=AND)"}, - } }, /* R/W Key Interrupt Control */ + { GBA_KEYINPUT, "GBA_KEYINPUT", { + {0, 1, "Button A"}, + {1, 1, "Button B"}, + {2, 1, "Select"}, + {3, 1, "Start"}, + {4, 1, "Right"}, + {5, 1, "Left"}, + {6, 1, "Up"}, + {7, 1, "Down"}, + {8, 1, "Button R"}, + {9, 1, "Button L"}, + } }, /* R Key Status */ + { GBA_KEYCNT, "GBA_KEYCNT", { + {0, 1, "Button A"}, + {1, 1, "Button B"}, + {2, 1, "Select"}, + {3, 1, "Start"}, + {4, 1, "Right"}, + {5, 1, "Left"}, + {6, 1, "Up"}, + {7, 1, "Down"}, + {8, 1, "Button R"}, + {9, 1, "Button L"}, + {14, 1, "Button IRQ Enable (0=Disable, 1=Enable)"}, + {15, 1, "Button IRQ Condition (0=OR, 1=AND)"}, + } }, /* R/W Key Interrupt Control */ // Serial Communication (2) - { GBA_JOYCNT , "JOYCNT", {0} }, /* R/W SIO JOY Bus Control */ - { GBA_JOY_RECV , "JOY_RECV", {0} }, /* R/W SIO JOY Bus Receive Data */ - { GBA_JOY_TRANS, "JOY_TRANS", {0} }, /* R/W SIO JOY Bus Transmit Data */ - { GBA_JOYSTAT , "JOYSTAT", {0} }, /* R/? SIO JOY Bus Receive Status */ - - { NDS_IPCSYNC , "IPCSYNC", { - { 0 ,4,"Data input from IPCSYNC Bit8-11 of remote CPU (00h..0Fh)"}, - { 8 ,4,"Data output to IPCSYNC Bit0-3 of remote CPU (00h..0Fh)"}, - { 13 ,1,"Send IRQ to remote CPU (0=None, 1=Send IRQ)"}, - { 14 ,1,"Enable IRQ from remote CPU (0=Disable, 1=Enable)"}, - } }, /*IPC Synchronize Register (R/W)*/ - { NDS_IPCFIFOCNT , "IPCFIFOCNT", { - { 0 ,1, "Send Fifo Empty Status (0=Not Empty, 1=Empty)"}, - { 1 ,1, "Send Fifo Full Status (0=Not Full, 1=Full)"}, - { 2 ,1, "Send Fifo Empty IRQ (0=Disable, 1=Enable)"}, - { 3 ,1, "Send Fifo Clear (0=Nothing, 1=Flush Send Fifo)"}, - { 8 ,1, "Receive Fifo Empty (0=Not Empty, 1=Empty)"}, - { 9 ,1, "Receive Fifo Full (0=Not Full, 1=Full)"}, - { 10 ,1, "Receive Fifo Not Empty IRQ (0=Disable, 1=Enable)"}, - { 14 ,1, "Error, Read Empty/Send Full (0=No Error, 1=Error/Acknowledge)"}, - { 15 ,1, "Enable Send/Receive Fifo (0=Disable, 1=Enable)"}, - } }, /*IPC Fifo Control Register (R/W)*/ - { NDS_IPCFIFOSEND , "IPCFIFOSEND", { 0 } }, /*IPC Send Fifo (W)*/ - { NDS_IPCFIFORECV, "IPCFIFORECV", { 0 }}, /* Sound Capture 1 Length (W) */ - { NDS9_AUXSPICNT , "AUXSPICNT", { - { 0 ,2,"SPI Baudrate (0=4MHz/Default, 1=2MHz, 2=1MHz, 3=512KHz)" }, - { 6 ,1,"SPI Hold Chipselect (0=Deselect after transfer, 1=Keep selected)" }, - { 7 ,1,"SPI Busy (0=Ready, 1=Busy) (presumably Read-only)" }, - { 13 ,1,"NDS Slot Mode (0=Parallel/ROM, 1=Serial/SPI-Backup)" }, - { 14 ,1,"Transfer Ready IRQ (0=Disable, 1=Enable) (for ROM, not for AUXSPI)" }, - { 15 ,1,"NDS Slot Enable (0=Disable, 1=Enable) (for both ROM and AUXSPI)" }, - } }, /*Gamecard ROM and SPI Control*/ - { NDS9_AUXSPIDATA , "AUXSPIDATA", { 0 } }, /*Gamecard SPI Bus Data/Strobe*/ - { NDS_GCBUS_CTL , "GC_BUS_CTL", { - { 0 ,13,"KEY1 gap1 length (0-1FFFh) (forced min 08F8h by BIOS) (leading gap)" }, - { 13 ,1, "KEY2 encrypt data (0=Disable, 1=Enable KEY2 Encryption for Data)" }, - { 14 ,1, "Unknown (SE)" }, - { 15 ,1, "KEY2 Apply Seed (0=No change, 1=Apply Encryption Seed) (Write only)" }, - { 16 ,6, "KEY1 gap2 length (0-3Fh) (forced min 18h by BIOS) (200h-byte gap)" }, - { 22 ,1, "KEY2 encrypt cmd (0=Disable, 1=Enable KEY2 Encryption for Commands)" }, - { 23 ,1, "Data-Word Status (0=Busy, 1=Ready/DRQ) (Read-only)" }, - { 24 ,3, "Data Block size (0=None, 1..6=100h SHL (1..6) bytes, 7=4 bytes)" }, - { 27 ,1, "Transfer CLK rate (0=6.7MHz=33.51MHz/5, 1=4.2MHz=33.51MHz/8)" }, - { 28 ,1, "KEY1 Gap CLKs (0=Hold CLK High during gaps, 1=Output Dummy CLK Pulses)" }, - { 29 ,1, "RESB Release Reset (0=Reset, 1=Release) (cannot be cleared once set)" }, - { 30 ,1, "Data Direction 'WR' (0=Normal/read, 1=Write, for FLASH/NAND carts)" }, - { 31 ,1, "Block Start/Status (0=Ready, 1=Start/Busy) (IRQ See 40001A0h/Bit14)" }, - } }, /*Gamecard bus timing/control*/ - { NDS_GCBUS_CMD , "GC_BUS_CMD", { 0 } }, /*Gamecard bus 8-byte command out*/ - { NDS9_GC_ENC0_LO , "GC_ENC0_LO", { 0 } }, /*Gamecard Encryption Seed 0 Lower 32bit*/ - { NDS9_GC_ENC1_LO , "GC_ENC1_LO", { 0 } }, /*Gamecard Encryption Seed 1 Lower 32bit*/ - { NDS9_GC_ENC0_HI , "GC_ENC0_HI", { 0 } }, /*Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused)*/ - { NDS9_GC_ENC1_HI , "GC_ENC1_HI", { 0 } }, /*Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused)*/ - + { GBA_JOYCNT, "JOYCNT", {0}}, /* R/W SIO JOY Bus Control */ + { GBA_JOY_RECV, "JOY_RECV", {0}}, /* R/W SIO JOY Bus Receive Data */ + { GBA_JOY_TRANS, "JOY_TRANS", {0}}, /* R/W SIO JOY Bus Transmit Data */ + { GBA_JOYSTAT, "JOYSTAT", {0}}, /* R/? SIO JOY Bus Receive Status */ + + { NDS_IPCSYNC, "IPCSYNC", { + {0, 4, "Data input from IPCSYNC Bit8-11 of remote CPU (00h..0Fh)"}, + {8, 4, "Data output to IPCSYNC Bit0-3 of remote CPU (00h..0Fh)"}, + {13, 1, "Send IRQ to remote CPU (0=None, 1=Send IRQ)"}, + {14, 1, "Enable IRQ from remote CPU (0=Disable, 1=Enable)"}, + } }, /*IPC Synchronize Register (R/W)*/ + { NDS_IPCFIFOCNT, "IPCFIFOCNT", { + {0, 1, "Send Fifo Empty Status (0=Not Empty, 1=Empty)"}, + {1, 1, "Send Fifo Full Status (0=Not Full, 1=Full)"}, + {2, 1, "Send Fifo Empty IRQ (0=Disable, 1=Enable)"}, + {3, 1, "Send Fifo Clear (0=Nothing, 1=Flush Send Fifo)"}, + {8, 1, "Receive Fifo Empty (0=Not Empty, 1=Empty)"}, + {9, 1, "Receive Fifo Full (0=Not Full, 1=Full)"}, + {10, 1, "Receive Fifo Not Empty IRQ (0=Disable, 1=Enable)"}, + {14, 1, "Error, Read Empty/Send Full (0=No Error, 1=Error/Acknowledge)"}, + {15, 1, "Enable Send/Receive Fifo (0=Disable, 1=Enable)"}, + } }, /*IPC Fifo Control Register (R/W)*/ + { NDS_IPCFIFOSEND, "IPCFIFOSEND", {0}}, /*IPC Send Fifo (W)*/ + { NDS_IPCFIFORECV, "IPCFIFORECV", {0}}, /* Sound Capture 1 Length (W) */ + { NDS9_AUXSPICNT, "AUXSPICNT", { + {0, 2, "SPI Baudrate (0=4MHz/Default, 1=2MHz, 2=1MHz, 3=512KHz)"}, + {6, 1, "SPI Hold Chipselect (0=Deselect after transfer, 1=Keep selected)"}, + {7, 1, "SPI Busy (0=Ready, 1=Busy) (presumably Read-only)"}, + {13, 1, "NDS Slot Mode (0=Parallel/ROM, 1=Serial/SPI-Backup)"}, + {14, 1, "Transfer Ready IRQ (0=Disable, 1=Enable) (for ROM, not for AUXSPI)"}, + {15, 1, "NDS Slot Enable (0=Disable, 1=Enable) (for both ROM and AUXSPI)"}, + } }, /*Gamecard ROM and SPI Control*/ + { NDS9_AUXSPIDATA, "AUXSPIDATA", {0}}, /*Gamecard SPI Bus Data/Strobe*/ + { NDS_GCBUS_CTL, "GC_BUS_CTL", { + {0, 13, "KEY1 gap1 length (0-1FFFh) (forced min 08F8h by BIOS) (leading gap)"}, + {13, 1, "KEY2 encrypt data (0=Disable, 1=Enable KEY2 Encryption for Data)"}, + {14, 1, "Unknown (SE)"}, + {15, 1, "KEY2 Apply Seed (0=No change, 1=Apply Encryption Seed) (Write only)"}, + {16, 6, "KEY1 gap2 length (0-3Fh) (forced min 18h by BIOS) (200h-byte gap)"}, + {22, 1, "KEY2 encrypt cmd (0=Disable, 1=Enable KEY2 Encryption for Commands)"}, + {23, 1, "Data-Word Status (0=Busy, 1=Ready/DRQ) (Read-only)"}, + {24, 3, "Data Block size (0=None, 1..6=100h SHL (1..6) bytes, 7=4 bytes)"}, + {27, 1, "Transfer CLK rate (0=6.7MHz=33.51MHz/5, 1=4.2MHz=33.51MHz/8)"}, + {28, 1, "KEY1 Gap CLKs (0=Hold CLK High during gaps, 1=Output Dummy CLK Pulses)"}, + {29, 1, "RESB Release Reset (0=Reset, 1=Release) (cannot be cleared once set)"}, + {30, 1, "Data Direction 'WR' (0=Normal/read, 1=Write, for FLASH/NAND carts)"}, + {31, 1, "Block Start/Status (0=Ready, 1=Start/Busy) (IRQ See 40001A0h/Bit14)"}, + } }, /*Gamecard bus timing/control*/ + { NDS_GCBUS_CMD, "GC_BUS_CMD", {0}}, /*Gamecard bus 8-byte command out*/ + { NDS9_GC_ENC0_LO, "GC_ENC0_LO", {0}}, /*Gamecard Encryption Seed 0 Lower 32bit*/ + { NDS9_GC_ENC1_LO, "GC_ENC1_LO", {0}}, /*Gamecard Encryption Seed 1 Lower 32bit*/ + { NDS9_GC_ENC0_HI, "GC_ENC0_HI", {0}}, /*Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused)*/ + { NDS9_GC_ENC1_HI, "GC_ENC1_HI", {0}}, /*Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused)*/ + // ARM9 Memory and IRQ Control - { NDS9_EXMEMCNT , "EXMEMCNT", { - {0,2,"32-pin GBA Slot SRAM Access Time (0-3 = 10, 8, 6, 18 cycles)"}, - {2,2,"32-pin GBA Slot ROM 1st Access Time (0-3 = 10, 8, 6, 18 cycles)"}, - {4,1,"32-pin GBA Slot ROM 2nd Access Time (0-1 = 6, 4 cycles)"}, - {6 ,2, "32-pin GBA Slot PHI-pin out (0-3 = Low, 4.19MHz, 8.38MHz, 16.76MHz)"}, - {7 ,1, "32-pin GBA Slot Access Rights (0=ARM9, 1=ARM7)"}, - {11 ,1, "17-pin NDS Slot Access Rights (0=ARM9, 1=ARM7)"}, - {13 ,1, "NDS:Always set? ;set/tested by DSi bootcode: Main RAM enable, CE2 pin?"}, - {14 ,1, "Main Memory Interface Mode Switch (0=Async/GBA/Reserved, 1=Synchronous)"}, - {15 ,1, "Main Memory Access Priority (0=ARM9 Priority, 1=ARM7 Priority)"}, - } }, /* External Memory Control (R/W) */ - { NDS9_IME , "IME", { 0 } }, /* Interrupt Master Enable (R/W) */ - { NDS9_IE , "IE", { - { 0 , 1, "LCD V-Blank" }, - { 1 , 1, "LCD H-Blank" }, - { 2 , 1, "LCD V-Counter Match" }, - { 3 , 1, "Timer 0 Overflow" }, - { 4 , 1, "Timer 1 Overflow" }, - { 5 , 1, "Timer 2 Overflow" }, - { 6 , 1, "Timer 3 Overflow" }, - { 8 , 1, "DMA 0" }, - { 9 , 1, "DMA 1" }, - { 10, 1, "DMA 2" }, - { 11, 1, "DMA 3" }, - { 12, 1, "Keypad" }, - { 13, 1, "GBA-Slot (external IRQ source) / DSi: None such" }, - { 16, 1, "IPC Sync" }, - { 17, 1, "IPC Send FIFO Empty" }, - { 18, 1, "IPC Recv FIFO Not Empty" }, - { 19, 1, "NDS-Slot Game Card Data Transfer Completion" }, - { 20, 1, "NDS-Slot Game Card IREQ_MC" }, - { 21, 1, "NDS9 only: Geometry Command FIFO" }, - { 22, 1, "NDS7 only: Screens unfolding" }, - { 23, 1, "NDS7 only: SPI bus" }, - { 24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP" }, - { 25, 1, "DSi9: Camera" }, - { 26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh" }, - { 27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?" }, - { 28, 1, "DSi: NewDMA0" }, - { 29, 1, "DSi: NewDMA1" }, - { 30, 1, "DSi: NewDMA2" }, - { 31, 1, "DSi: NewDMA3" }, - } }, /* Interrupt Enable (R/W) */ - { NDS9_IF , "IF", { - { 0 , 1, "LCD V-Blank" }, - { 1 , 1, "LCD H-Blank" }, - { 2 , 1, "LCD V-Counter Match" }, - { 3 , 1, "Timer 0 Overflow" }, - { 4 , 1, "Timer 1 Overflow" }, - { 5 , 1, "Timer 2 Overflow" }, - { 6 , 1, "Timer 3 Overflow" }, - { 8 , 1, "DMA 0" }, - { 9 , 1, "DMA 1" }, - { 10, 1, "DMA 2" }, - { 11, 1, "DMA 3" }, - { 12, 1, "Keypad" }, - { 13, 1, "GBA-Slot (external IRQ source) / DSi: None such" }, - { 16, 1, "IPC Sync" }, - { 17, 1, "IPC Send FIFO Empty" }, - { 18, 1, "IPC Recv FIFO Not Empty" }, - { 19, 1, "NDS-Slot Game Card Data Transfer Completion" }, - { 20, 1, "NDS-Slot Game Card IREQ_MC" }, - { 21, 1, "NDS9 only: Geometry Command FIFO" }, - { 22, 1, "NDS7 only: Screens unfolding" }, - { 23, 1, "NDS7 only: SPI bus" }, - { 24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP" }, - { 25, 1, "DSi9: Camera" }, - { 26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh" }, - { 27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?" }, - { 28, 1, "DSi: NewDMA0" }, - { 29, 1, "DSi: NewDMA1" }, - { 30, 1, "DSi: NewDMA2" }, - { 31, 1, "DSi: NewDMA3" }, - } }, /* Interrupt Request Flags (R/W) */ - { NDS9_VRAMCNT_A, "VRAMCNT_A", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-A (128K) Bank Control (W) */ - { NDS9_VRAMCNT_B, "VRAMCNT_B", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-B (128K) Bank Control (W) */ - { NDS9_VRAMCNT_C, "VRAMCNT_C", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-C (128K) Bank Control (W) */ - { NDS9_VRAMCNT_D, "VRAMCNT_D", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-D (128K) Bank Control (W) */ - { NDS9_VRAMCNT_E, "VRAMCNT_E", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-E (64K) Bank Control (W) */ - { NDS9_VRAMCNT_F, "VRAMCNT_F", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-F (16K) Bank Control (W) */ - { NDS9_VRAMCNT_G, "VRAMCNT_G", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-G (16K) Bank Control (W) */ - { NDS9_VRAMCNT_H, "VRAMCNT_H", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-H (32K) Bank Control (W) */ - { NDS9_VRAMCNT_I, "VRAMCNT_I", { - { 0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I" }, - { 3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I" }, - { 5, 2, "Not used" }, - { 7, 1, "VRAM Enable (0=Disable, 1=Enable)" }, - } }, /* VRAM-I (16K) Bank Control (W) */ - { NDS9_WRAMCNT , "WRAMCNT", { - {0,2, "WRAM Mode ARM9/ARM7 (0-3 = 32K/0K, 2nd 16K/1st 16K, 1st 16K/2nd 16K, 0K/32K)"} - } }, /* WRAM Bank Control (W) */ + { NDS9_EXMEMCNT, "EXMEMCNT", { + {0, 2, "32-pin GBA Slot SRAM Access Time (0-3 = 10, 8, 6, 18 cycles)"}, + {2, 2, "32-pin GBA Slot ROM 1st Access Time (0-3 = 10, 8, 6, 18 cycles)"}, + {4, 1, "32-pin GBA Slot ROM 2nd Access Time (0-1 = 6, 4 cycles)"}, + {6, 2, "32-pin GBA Slot PHI-pin out (0-3 = Low, 4.19MHz, 8.38MHz, 16.76MHz)"}, + {7, 1, "32-pin GBA Slot Access Rights (0=ARM9, 1=ARM7)"}, + {11, 1, "17-pin NDS Slot Access Rights (0=ARM9, 1=ARM7)"}, + {13, 1, "NDS:Always set? ;set/tested by DSi bootcode: Main RAM enable, CE2 pin?"}, + {14, 1, "Main Memory Interface Mode Switch (0=Async/GBA/Reserved, 1=Synchronous)"}, + {15, 1, "Main Memory Access Priority (0=ARM9 Priority, 1=ARM7 Priority)"}, + } }, /* External Memory Control (R/W) */ + { NDS9_IME, "IME", {0}}, /* Interrupt Master Enable (R/W) */ + { NDS9_IE, "IE", { + {0, 1, "LCD V-Blank"}, + {1, 1, "LCD H-Blank"}, + {2, 1, "LCD V-Counter Match"}, + {3, 1, "Timer 0 Overflow"}, + {4, 1, "Timer 1 Overflow"}, + {5, 1, "Timer 2 Overflow"}, + {6, 1, "Timer 3 Overflow"}, + {8, 1, "DMA 0"}, + {9, 1, "DMA 1"}, + {10, 1, "DMA 2"}, + {11, 1, "DMA 3"}, + {12, 1, "Keypad"}, + {13, 1, "GBA-Slot (external IRQ source) / DSi: None such"}, + {16, 1, "IPC Sync"}, + {17, 1, "IPC Send FIFO Empty"}, + {18, 1, "IPC Recv FIFO Not Empty"}, + {19, 1, "NDS-Slot Game Card Data Transfer Completion"}, + {20, 1, "NDS-Slot Game Card IREQ_MC"}, + {21, 1, "NDS9 only: Geometry Command FIFO"}, + {22, 1, "NDS7 only: Screens unfolding"}, + {23, 1, "NDS7 only: SPI bus"}, + {24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP"}, + {25, 1, "DSi9: Camera"}, + {26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh"}, + {27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?"}, + {28, 1, "DSi: NewDMA0"}, + {29, 1, "DSi: NewDMA1"}, + {30, 1, "DSi: NewDMA2"}, + {31, 1, "DSi: NewDMA3"}, + } }, /* Interrupt Enable (R/W) */ + { NDS9_IF, "IF", { + {0, 1, "LCD V-Blank"}, + {1, 1, "LCD H-Blank"}, + {2, 1, "LCD V-Counter Match"}, + {3, 1, "Timer 0 Overflow"}, + {4, 1, "Timer 1 Overflow"}, + {5, 1, "Timer 2 Overflow"}, + {6, 1, "Timer 3 Overflow"}, + {8, 1, "DMA 0"}, + {9, 1, "DMA 1"}, + {10, 1, "DMA 2"}, + {11, 1, "DMA 3"}, + {12, 1, "Keypad"}, + {13, 1, "GBA-Slot (external IRQ source) / DSi: None such"}, + {16, 1, "IPC Sync"}, + {17, 1, "IPC Send FIFO Empty"}, + {18, 1, "IPC Recv FIFO Not Empty"}, + {19, 1, "NDS-Slot Game Card Data Transfer Completion"}, + {20, 1, "NDS-Slot Game Card IREQ_MC"}, + {21, 1, "NDS9 only: Geometry Command FIFO"}, + {22, 1, "NDS7 only: Screens unfolding"}, + {23, 1, "NDS7 only: SPI bus"}, + {24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP"}, + {25, 1, "DSi9: Camera"}, + {26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh"}, + {27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?"}, + {28, 1, "DSi: NewDMA0"}, + {29, 1, "DSi: NewDMA1"}, + {30, 1, "DSi: NewDMA2"}, + {31, 1, "DSi: NewDMA3"}, + } }, /* Interrupt Request Flags (R/W) */ + { NDS9_VRAMCNT_A, "VRAMCNT_A", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-A (128K) Bank Control (W) */ + { NDS9_VRAMCNT_B, "VRAMCNT_B", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-B (128K) Bank Control (W) */ + { NDS9_VRAMCNT_C, "VRAMCNT_C", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-C (128K) Bank Control (W) */ + { NDS9_VRAMCNT_D, "VRAMCNT_D", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-D (128K) Bank Control (W) */ + { NDS9_VRAMCNT_E, "VRAMCNT_E", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-E (64K) Bank Control (W) */ + { NDS9_VRAMCNT_F, "VRAMCNT_F", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-F (16K) Bank Control (W) */ + { NDS9_VRAMCNT_G, "VRAMCNT_G", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-G (16K) Bank Control (W) */ + { NDS9_VRAMCNT_H, "VRAMCNT_H", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-H (32K) Bank Control (W) */ + { NDS9_VRAMCNT_I, "VRAMCNT_I", { + {0, 3, "VRAM MST ;Bit2 not used by VRAM-A,B,H,I"}, + {3, 2, "VRAM Offset (0-3) ;Offset not used by VRAM-E,H,I"}, + {5, 2, "Not used"}, + {7, 1, "VRAM Enable (0=Disable, 1=Enable)"}, + } }, /* VRAM-I (16K) Bank Control (W) */ + { NDS9_WRAMCNT, "WRAMCNT", {{0, 2, "WRAM Mode ARM9/ARM7 (0-3 = 32K/0K, 2nd 16K/1st 16K, 1st 16K/2nd 16K, 0K/32K)"}}}, /* WRAM Bank Control (W) */ // ARM9 Maths - { NDS9_DIVCNT, "DIVCNT", { - {0,2, "Division Mode (0-2=See below) (3=Reserved; same as Mode 1)"}, - {14,1, "Division by zero (0=Okay, 1=Division by zero error; 64bit Denom=0)"}, - {15,1, "Busy (0=Ready, 1=Busy) (Execution time see below)"}, - } }, /* Division Control (R/W) */ - { NDS9_DIV_NUMER, "DIV_NUMER", { 0 } }, /* Division Numerator (R/W) */ - { NDS9_DIV_DENOM, "DIV_DENOM", { 0 } }, /* Division Denominator (R/W) */ - { NDS9_DIV_RESULT, "DIV_RESULT", { 0 } }, /* Division Quotient (=Numer/Denom) (R) */ - { NDS9_DIVREM_RESULT, "DIVREM_RESULT", { 0 } }, /* Division Remainder (=Numer MOD Denom) (R) */ - { NDS9_SQRTCNT, "SQRTCNT", { - {0 ,1, "Mode (0=32bit input, 1=64bit input)"}, - {15,1, "Busy (0=Ready, 1=Busy) (Execution time is 13 clks, in either Mode)"}, - } }, /* Square Root Control (R/W) */ - { NDS9_SQRT_RESULT, "SQRT_RESULT", { 0 } }, /* Square Root Result (R) */ - { NDS9_SQRT_PARAM, "SQRT_PARAM", { 0 } }, /* Square Root Parameter Input (R/W) */ - { NDS9_POSTFLG, "POSTFLG", { - { 0, 1, "First Boot Flag (0=First, 1=Further)" }, - } }, /* Undoc */ - { NDS9_POWCNT1, "POWCNT1", { - { 0 , 1, "Enable Flag for both LCDs (0=Disable) (Prohibited, see notes)"}, - { 1 , 1, "2D Graphics Engine A (0=Disable) (Ports 008h-05Fh, Pal 5000000h)"}, - { 2 , 1, "3D Rendering Engine (0=Disable) (Ports 320h-3FFh)"}, - { 3 , 1, "3D Geometry Engine (0=Disable) (Ports 400h-6FFh)"}, - { 9 , 1, "2D Graphics Engine B (0=Disable) (Ports 1008h-105Fh, Pal 5000400h)"}, - { 15, 1, "Display Swap (0=Send Display A to Lower Screen, 1=To Upper Screen)"}, - } }, /* Graphics Power Control Register (R/W) */ + { NDS9_DIVCNT, "DIVCNT", { + {0, 2, "Division Mode (0-2=See below) (3=Reserved; same as Mode 1)"}, + {14, 1, "Division by zero (0=Okay, 1=Division by zero error; 64bit Denom=0)"}, + {15, 1, "Busy (0=Ready, 1=Busy) (Execution time see below)"}, + } }, /* Division Control (R/W) */ + { NDS9_DIV_NUMER, "DIV_NUMER", {0}}, /* Division Numerator (R/W) */ + { NDS9_DIV_DENOM, "DIV_DENOM", {0}}, /* Division Denominator (R/W) */ + { NDS9_DIV_RESULT, "DIV_RESULT", {0}}, /* Division Quotient (=Numer/Denom) (R) */ + { NDS9_DIVREM_RESULT, "DIVREM_RESULT", {0}}, /* Division Remainder (=Numer MOD Denom) (R) */ + { NDS9_SQRTCNT, "SQRTCNT", { + {0, 1, "Mode (0=32bit input, 1=64bit input)"}, + {15, 1, "Busy (0=Ready, 1=Busy) (Execution time is 13 clks, in either Mode)"}, + } }, /* Square Root Control (R/W) */ + { NDS9_SQRT_RESULT, "SQRT_RESULT", {0}}, /* Square Root Result (R) */ + { NDS9_SQRT_PARAM, "SQRT_PARAM", {0}}, /* Square Root Parameter Input (R/W) */ + { NDS9_POSTFLG, "POSTFLG", { + {0, 1, "First Boot Flag (0=First, 1=Further)"}, + } }, /* Undoc */ + { NDS9_POWCNT1, "POWCNT1", { + {0, 1, "Enable Flag for both LCDs (0=Disable) (Prohibited, see notes)"}, + {1, 1, "2D Graphics Engine A (0=Disable) (Ports 008h-05Fh, Pal 5000000h)"}, + {2, 1, "3D Rendering Engine (0=Disable) (Ports 320h-3FFh)"}, + {3, 1, "3D Geometry Engine (0=Disable) (Ports 400h-6FFh)"}, + {9, 1, "2D Graphics Engine B (0=Disable) (Ports 1008h-105Fh, Pal 5000400h)"}, + {15, 1, "Display Swap (0=Send Display A to Lower Screen, 1=To Upper Screen)"}, + } }, /* Graphics Power Control Register (R/W) */ // ARM9 3D Display Engine - { NDS9_RDLINES_COUNT, "RDLINES_COUNT", { 0 } }, /* Rendered Line Count Register (R) */ - { NDS9_EDGE_COLOR, "EDGE_COLOR", { 0 } }, /* Edge Colors 0..7 (W) */ - { NDS9_ALPHA_TEST_REF, "ALPHA_TEST_REF", { 0 } }, /* Alpha-Test Comparision Value (W) */ - { NDS9_CLEAR_COLOR, "CLEAR_COLOR", { 0 } }, /* Clear Color Attribute Register (W) */ - { NDS9_CLEAR_DEPTH, "CLEAR_DEPTH", { 0 } }, /* Clear Depth Register (W) */ - { NDS9_CLRIMAGE_OFFSET, "CLRIMAGE_OFFSET", { 0 } }, /* Rear-plane Bitmap Scroll Offsets (W) */ - { NDS9_FOG_COLOR, "FOG_COLOR", { 0 } }, /* Fog Color (W) */ - { NDS9_FOG_OFFSET, "FOG_OFFSET", { 0 } }, /* Fog Depth Offset (W) */ - { NDS9_FOG_TABLE, "FOG_TABLE", { 0 } }, /* Fog Density Table, 32 entries (W) */ - { NDS9_TOON_TABLE, "TOON_TABLE", { 0 } }, /* Toon Table, 32 colors (W) */ - { NDS9_GXFIFO, "GXFIFO", { 0 } }, /* Geometry Command FIFO (W) */ - { NDS9_MTX_MODE, "MTX_MODE", { 0 } }, /* Set Matrix Mode (W) */ - { NDS9_MTX_PUSH, "MTX_PUSH", { 0 } }, /* Push Current Matrix on Stack (W) */ - { NDS9_MTX_POP, "MTX_POP", { 0 } }, /* Pop Current Matrix from Stack (W) */ - { NDS9_MTX_STORE, "MTX_STORE", { 0 } }, /* Store Current Matrix on Stack (W) */ - { NDS9_MTX_RESTORE, "MTX_RESTORE", { 0 } }, /* Restore Current Matrix from Stack (W) */ - { NDS9_MTX_IDENTITY, "MTX_IDENTITY", { 0 } }, /* Load Unit Matrix to Current Matrix (W) */ - { NDS9_MTX_LOAD_4x4, "MTX_LOAD_4x4", { 0 } }, /* Load 4x4 Matrix to Current Matrix (W) */ - { NDS9_MTX_LOAD_4x3, "MTX_LOAD_4x3", { 0 } }, /* Load 4x3 Matrix to Current Matrix (W) */ - { NDS9_MTX_MULT_4x4, "MTX_MULT_4x4", { 0 } }, /* Multiply Current Matrix by 4x4 Matrix (W) */ - { NDS9_MTX_MULT_4x3, "MTX_MULT_4x3", { 0 } }, /* Multiply Current Matrix by 4x3 Matrix (W) */ - { NDS9_MTX_MULT_3x3, "MTX_MULT_3x3", { 0 } }, /* Multiply Current Matrix by 3x3 Matrix (W) */ - { NDS9_MTX_SCALE, "MTX_SCALE", { 0 } }, /* Multiply Current Matrix by Scale Matrix (W) */ - { NDS9_MTX_TRANS, "MTX_TRANS", { 0 } }, /* Mult. Curr. Matrix by Translation Matrix (W) */ - { NDS9_COLOR, "COLOR", { 0 } }, /* Directly Set Vertex Color (W) */ - { NDS9_NORMAL, "NORMAL", { 0 } }, /* Set Normal Vector (W) */ - { NDS9_TEXCOORD, "TEXCOORD", { 0 } }, /* Set Texture Coordinates (W) */ - { NDS9_VTX_16, "VTX_16(param 0)", { - {0, 16, "(Param 1)X Coord 1.3.12 fixed point"}, - {16, 16, "(Param 1)Y Coord 1.3.12 fixed point"}, - {0, 16, "(Param 2)Z Coord 1.3.12 fixed point"} - } }, /* Set Vertex XYZ Coordinates (W) */ - { NDS9_VTX_10, "VTX_10", { 0 } }, /* Set Vertex XYZ Coordinates (W) */ - { NDS9_VTX_XY, "VTX_XY", { 0 } }, /* Set Vertex XY Coordinates (W) */ - { NDS9_VTX_XZ, "VTX_XZ", { 0 } }, /* Set Vertex XZ Coordinates (W) */ - { NDS9_VTX_YZ, "VTX_YZ", { 0 } }, /* Set Vertex YZ Coordinates (W) */ - { NDS9_VTX_DIFF, "VTX_DIFF", { 0 } }, /* Set Relative Vertex Coordinates (W) */ - { NDS9_POLYGON_ATTR, "POLYGON_ATTR", { 0 } }, /* Set Polygon Attributes (W) */ - { NDS9_TEXIMAGE_PARAM, "TEXIMAGE_PARAM", { 0 } }, /* Set Texture Parameters (W) */ - { NDS9_PLTT_BASE, "PLTT_BASE", { 0 } }, /* Set Texture Palette Base Address (W) */ - { NDS9_DIF_AMB, "DIF_AMB", { 0 } }, /* MaterialColor0 - Diffuse/Ambient Reflect. (W) */ - { NDS9_SPE_EMI, "SPE_EMI", { 0 } }, /* MaterialColor1 - Specular Ref. & Emission (W) */ - { NDS9_LIGHT_VECTOR, "LIGHT_VECTOR", { 0 } }, /* Set Light's Directional Vector (W) */ - { NDS9_LIGHT_COLOR, "LIGHT_COLOR", { 0 } }, /* Set Light Color (W) */ - { NDS9_SHININESS, "SHININESS", { 0 } }, /* Specular Reflection Shininess Table (W) */ - { NDS9_BEGIN_VTXS, "BEGIN_VTXS", { - {0,2,"Primitive Type(0=Triangles, 1=Quads, 2=Tri Strips, 3=Quad Strips"}, - } }, /* Start of Vertex List (W) */ - { NDS9_END_VTXS, "END_VTXS", { 0 } }, /* End of Vertex List (W) */ - { NDS9_SWAP_BUFFERS, "SWAP_BUFFERS", { 0 } }, /* Swap Rendering Engine Buffer (W) */ - { NDS9_VIEWPORT, "VIEWPORT", { 0 } }, /* Set Viewport (W) */ - { NDS9_BOX_TEST, "BOX_TEST", { 0 } }, /* Test if Cuboid Sits inside View Volume (W) */ - { NDS9_POS_TEST, "POS_TEST", { 0 } }, /* Set Position Coordinates for Test (W) */ - { NDS9_VEC_TEST, "VEC_TEST", { 0 } }, /* Set Directional Vector for Test (W) */ - { NDS9_GXSTAT, "GXSTAT", { - { 0 , 1, "BoxTest,PositionTest,VectorTest Busy (0=Ready, 1=Busy)" }, - { 1 , 1, "BoxTest Result (0=All Outside View, 1=Parts or Fully Inside View)" }, - { 8 , 5, "Position & Vector Matrix Stack Level (0..31) (lower 5bit of 6bit value)" }, - { 13 , 1, "Projection Matrix Stack Level (0..1)" }, - { 14 , 1, "Matrix Stack Busy (0=No, 1=Yes; Currently executing a Push/Pop command)" }, - { 15 , 1, "Matrix Stack Overflow/Underflow Error (0=No, 1=Error/Acknowledge/Reset)" }, - { 16 , 9, "Number of 40bit-entries in Command FIFO (0..256)" }, - { 25 , 1, "Command FIFO Less Than Half Full (0=No, 1=Yes; Less than Half-full)" }, - { 26 , 1, "Command FIFO Empty (0=No, 1=Yes; Empty)" }, - { 27 , 1, "Geometry Engine Busy (0=No, 1=Yes; Busy; Commands are executing)" }, - { 30 , 2, "Command FIFO IRQ (0=Never, 1=Less than half full, 2=Empty, 3=Reserved)" }, - } }, /* Geometry Engine Status Register (R and R/W) */ - { NDS9_RAM_COUNT, "RAM_COUNT", { 0 } }, /* Polygon List & Vertex RAM Count Register (R) */ - { NDS9_DISP_1DOT_DEPTH, "DISP_1DOT_DEPTH", { 0 } }, /* 1-Dot Polygon Display Boundary Depth (W) */ - { NDS9_POS_RESULT, "POS_RESULT", { 0 } }, /* Position Test Results (R) */ - { NDS9_VEC_RESULT, "VEC_RESULT", { 0 } }, /* Vector Test Results (R) */ - { NDS9_CLIPMTX_RESULT, "CLIPMTX_RESULT", { 0 } }, /* Read Current Clip Coordinates Matrix (R) */ - { NDS9_VECMTX_RESULT, "VECMTX_RESULT", { 0 } }, /* Read Current Directional Vector Matrix (R) */ - { NDS9_B_DISPCNT , "(2D-B)DISPCNT ", { - { 0, 3, "BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)"}, - { 3 ,1, "Reserved / CGB Mode (0=GBA, 1=CGB)"}, - { 4 ,1, "Display Frame Select (0-1=Frame 0-1)"}, - { 5 ,1, "Bitmap OBJ 2D-Dimension (0=128x512 dots, 1=256x256 dots)"}, - { 6 ,1, "OBJ Character VRAM Mapping (0=2D, 1=1D"}, - { 7 ,1, "Forced Blank (1=Allow FAST VRAM,Palette,OAM)"}, - { 8 ,1, "Screen Display BG0 (0=Off, 1=On)"}, - { 9 ,1, "Screen Display BG1 (0=Off, 1=On)"}, - { 10,1, "Screen Display BG2 (0=Off, 1=On)"}, - { 11,1, "Screen Display BG3 (0=Off, 1=On)"}, - { 12,1, "Screen Display OBJ (0=Off, 1=On)"}, - { 13,1, "Window 0 Display Flag (0=Off, 1=On)"}, - { 14,1, "Window 1 Display Flag (0=Off, 1=On)"}, - { 15,1, "OBJ Window Display Flag (0=Off, 1=On)"}, - { 16,2, "Display Mode (0..1)"}, - { 18,2, "VRAM block (0..3=VRAM A..D) (For Capture & above Display Mode=2)"}, - { 20,2, "Tile OBJ 1D-Boundary (see Bit4)"}, - { 23,1, "OBJ Processing during H-Blank (was located in Bit5 on GBA)"}, - { 24,3, "Character Base (in 64K steps) (merged with 16K step in BGxCNT)"}, - { 30,1, "BG Extended Palettes (0=Disable, 1=Enable)"}, - { 31,1, "OBJ Extended Palettes (0=Disable, 1=Enable)"} - } }, - // ARM9 Display Engine B - { NDS9_B_BG0CNT , "(2D-B) BG0CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG0 Control */ - { NDS9_B_BG1CNT , "(2D-B) BG1CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG1 Control */ - { NDS9_B_BG2CNT , "(2D-B) BG2CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG2 Control */ - { NDS9_B_BG3CNT , "(2D-B) BG3CNT ", { - { 0,2 , "BG Priority (0-3, 0=Highest)"}, - { 2,4 , "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, - { 6,1 , "Mosaic (0=Disable, 1=Enable)"}, - { 7,1 , "Colors/Palettes (0=16/16, 1=256/1)"}, - { 8,5 , "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, - { 13,1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, - { 14,2, "Screen Size (0-3)"}, - } }, /* R/W BG3 Control */ - { NDS9_B_BG0HOFS , "(2D-B) BG0HOFS", { 0 } }, /* W BG0 X-Offset */ - { NDS9_B_BG0VOFS , "(2D-B) BG0VOFS", { 0 } }, /* W BG0 Y-Offset */ - { NDS9_B_BG1HOFS , "(2D-B) BG1HOFS", { 0 } }, /* W BG1 X-Offset */ - { NDS9_B_BG1VOFS , "(2D-B) BG1VOFS", { 0 } }, /* W BG1 Y-Offset */ - { NDS9_B_BG2HOFS , "(2D-B) BG2HOFS", { 0 } }, /* W BG2 X-Offset */ - { NDS9_B_BG2VOFS , "(2D-B) BG2VOFS", { 0 } }, /* W BG2 Y-Offset */ - { NDS9_B_BG3HOFS , "(2D-B) BG3HOFS", { 0 } }, /* W BG3 X-Offset */ - { NDS9_B_BG3VOFS , "(2D-B) BG3VOFS", { 0 } }, /* W BG3 Y-Offset */ - { NDS9_B_BG2PA , "(2D-B) BG2PA", { 0 } }, /* W BG2 Rotation/Scaling Parameter A (dx) */ - { NDS9_B_BG2PB , "(2D-B) BG2PB", { 0 } }, /* W BG2 Rotation/Scaling Parameter B (dmx) */ - { NDS9_B_BG2PC , "(2D-B) BG2PC", { 0 } }, /* W BG2 Rotation/Scaling Parameter C (dy) */ - { NDS9_B_BG2PD , "(2D-B) BG2PD", { 0 } }, /* W BG2 Rotation/Scaling Parameter D (dmy) */ - { NDS9_B_BG2X , "(2D-B) BG2X", { 0 } }, /* W BG2 Reference Point X-Coordinate */ - { NDS9_B_BG2Y , "(2D-B) BG2Y", { 0 } }, /* W BG2 Reference Point Y-Coordinate */ - { NDS9_B_BG3PA , "(2D-B) BG3PA", { 0 } }, /* W BG3 Rotation/Scaling Parameter A (dx) */ - { NDS9_B_BG3PB , "(2D-B) BG3PB", { 0 } }, /* W BG3 Rotation/Scaling Parameter B (dmx) */ - { NDS9_B_BG3PC , "(2D-B) BG3PC", { 0 } }, /* W BG3 Rotation/Scaling Parameter C (dy) */ - { NDS9_B_BG3PD , "(2D-B) BG3PD", { 0 } }, /* W BG3 Rotation/Scaling Parameter D (dmy) */ - { NDS9_B_BG3X , "(2D-B) BG3X", { 0 } }, /* W BG3 Reference Point X-Coordinate */ - { NDS9_B_BG3Y , "(2D-B) BG3Y", { 0 } }, /* W BG3 Reference Point Y-Coordinate */ - { NDS9_B_WIN0H , "(2D-B) WIN0H", { - { 0, 8, "X2, Rightmost coordinate of window, plus 1 " }, - { 8, 8, "X1, Leftmost coordinate of window"}, - } }, /* W Window 0 Horizontal Dimensions */ - { NDS9_B_WIN1H , "(2D-B) WIN1H", { - { 0, 8, "X2, Rightmost coordinate of window, plus 1 " }, - { 8, 8, "X1, Leftmost coordinate of window"}, - } }, /* W Window 1 Horizontal Dimensions */ - { NDS9_B_WIN0V , "(2D-B) WIN0V", { - {0, 8, "Y2, Bottom-most coordinate of window, plus 1" }, - {8, 8, "Y1, Top-most coordinate of window" }, - } }, /* W Window 0 Vertical Dimensions */ - { NDS9_B_WIN1V , "(2D-B) WIN1V", { - {0, 8, "Y2, Bottom-most coordinate of window, plus 1" }, - {8, 8, "Y1, Top-most coordinate of window" }, - } }, /* W Window 1 Vertical Dimensions */ - { NDS9_B_WININ , "(2D-B) WININ", { - { 0 , 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 1 , 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 2 , 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 3 , 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 4 , 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 5 , 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, - { 8 , 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 9 , 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, - } }, /* R/W Inside of Window 0 and 1 */ - { NDS9_B_WINOUT , "(2D-B) WINOUT", { - { 0 , 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 1 , 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 2 , 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 3 , 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 4 , 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 5 , 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, - { 8 , 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, - { 9 , 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, - { 10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, - { 11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, - { 12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, - { 13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, - } }, /* R/W Inside of OBJ Window & Outside of Windows */ - { NDS9_B_MOSAIC , "(2D-B) MOSAIC", { - { 0, 4, "BG Mosaic H-Size (minus 1)" }, - { 4, 4, "BG Mosaic V-Size (minus 1)" }, - { 8, 4, "OBJ Mosaic H-Size (minus 1)" }, - { 12,4, "OBJ Mosaic V-Size (minus 1)" }, - } }, /* W Mosaic Size */ - { NDS9_B_BLDCNT , "(2D-B) BLDCNT", { - { 0 , 1, "BG0 1st Target Pixel (Background 0)" }, - { 1 , 1, "BG1 1st Target Pixel (Background 1)" }, - { 2 , 1, "BG2 1st Target Pixel (Background 2)" }, - { 3 , 1, "BG3 1st Target Pixel (Background 3)" }, - { 4 , 1, "OBJ 1st Target Pixel (Top-most OBJ pixel)" }, - { 5 , 1, "BD 1st Target Pixel (Backdrop)" }, - { 6 , 2, "Color Effect (0: None 1: Alpha 2: Lighten 3: Darken)" }, - { 8 , 1, "BG0 2nd Target Pixel (Background 0)" }, - { 9 , 1, "BG1 2nd Target Pixel (Background 1)" }, - { 10, 1, "BG2 2nd Target Pixel (Background 2)" }, - { 11, 1, "BG3 2nd Target Pixel (Background 3)" }, - { 12, 1, "OBJ 2nd Target Pixel (Top-most OBJ pixel)" }, - { 13, 1, "BD 2nd Target Pixel (Backdrop)" }, - } }, /* R/W Color Special Effects Selection */ - { NDS9_B_BLDALPHA, "(2D-B) BLDALPHA", { - {0, 4, "EVA Coef. (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, - {8, 4, "EVB Coef. (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, - } }, /* R/W Alpha Blending Coefficients */ - { NDS9_B_BLDY , "(2D-B) BLDY", { - {0, 5, "EVY Coefficient (Brightness) (0..16 = 0/16..16/16, 17..31=16/16)"}, - } }, /* W Brightness (Fade-In/Out) Coefficient */ - - { NDS9_B_MASTER_BRIGHT ,"(2D-B) MASTER_BRIGHT", { - {0,5, "Factor used for 6bit R,G,B Intensities (0-16, values >16 same as 16)"}, - {14,2, "Mode (0=Disable, 1=Up, 2=Down, 3=Reserved)"}, - } }, /* Master Brightness Up/Down */ + { NDS9_RDLINES_COUNT, "RDLINES_COUNT", {0}}, /* Rendered Line Count Register (R) */ + { NDS9_EDGE_COLOR, "EDGE_COLOR", {0}}, /* Edge Colors 0..7 (W) */ + { NDS9_ALPHA_TEST_REF, "ALPHA_TEST_REF", {0}}, /* Alpha-Test Comparision Value (W) */ + { NDS9_CLEAR_COLOR, "CLEAR_COLOR", {0}}, /* Clear Color Attribute Register (W) */ + { NDS9_CLEAR_DEPTH, "CLEAR_DEPTH", {0}}, /* Clear Depth Register (W) */ + {NDS9_CLRIMAGE_OFFSET, "CLRIMAGE_OFFSET", {0}}, /* Rear-plane Bitmap Scroll Offsets (W) */ + { NDS9_FOG_COLOR, "FOG_COLOR", {0}}, /* Fog Color (W) */ + { NDS9_FOG_OFFSET, "FOG_OFFSET", {0}}, /* Fog Depth Offset (W) */ + { NDS9_FOG_TABLE, "FOG_TABLE", {0}}, /* Fog Density Table, 32 entries (W) */ + { NDS9_TOON_TABLE, "TOON_TABLE", {0}}, /* Toon Table, 32 colors (W) */ + { NDS9_GXFIFO, "GXFIFO", {0}}, /* Geometry Command FIFO (W) */ + { NDS9_MTX_MODE, "MTX_MODE", {0}}, /* Set Matrix Mode (W) */ + { NDS9_MTX_PUSH, "MTX_PUSH", {0}}, /* Push Current Matrix on Stack (W) */ + { NDS9_MTX_POP, "MTX_POP", {0}}, /* Pop Current Matrix from Stack (W) */ + { NDS9_MTX_STORE, "MTX_STORE", {0}}, /* Store Current Matrix on Stack (W) */ + { NDS9_MTX_RESTORE, "MTX_RESTORE", {0}}, /* Restore Current Matrix from Stack (W) */ + { NDS9_MTX_IDENTITY, "MTX_IDENTITY", {0}}, /* Load Unit Matrix to Current Matrix (W) */ + { NDS9_MTX_LOAD_4x4, "MTX_LOAD_4x4", {0}}, /* Load 4x4 Matrix to Current Matrix (W) */ + { NDS9_MTX_LOAD_4x3, "MTX_LOAD_4x3", {0}}, /* Load 4x3 Matrix to Current Matrix (W) */ + { NDS9_MTX_MULT_4x4, "MTX_MULT_4x4", {0}}, /* Multiply Current Matrix by 4x4 Matrix (W) */ + { NDS9_MTX_MULT_4x3, "MTX_MULT_4x3", {0}}, /* Multiply Current Matrix by 4x3 Matrix (W) */ + { NDS9_MTX_MULT_3x3, "MTX_MULT_3x3", {0}}, /* Multiply Current Matrix by 3x3 Matrix (W) */ + { NDS9_MTX_SCALE, "MTX_SCALE", {0}}, /* Multiply Current Matrix by Scale Matrix (W) */ + { NDS9_MTX_TRANS, "MTX_TRANS", {0}}, /* Mult. Curr. Matrix by Translation Matrix (W) */ + { NDS9_COLOR, "COLOR", {0}}, /* Directly Set Vertex Color (W) */ + { NDS9_NORMAL, "NORMAL", {0}}, /* Set Normal Vector (W) */ + { NDS9_TEXCOORD, "TEXCOORD", {0}}, /* Set Texture Coordinates (W) */ + { NDS9_VTX_16, "VTX_16(param 0)", {{0, 16, "(Param 1)X Coord 1.3.12 fixed point"}, {16, 16, "(Param 1)Y Coord 1.3.12 fixed point"}, {0, 16, "(Param 2)Z Coord 1.3.12 fixed point"}}}, /* Set Vertex XYZ Coordinates (W) */ + { NDS9_VTX_10, "VTX_10", {0}}, /* Set Vertex XYZ Coordinates (W) */ + { NDS9_VTX_XY, "VTX_XY", {0}}, /* Set Vertex XY Coordinates (W) */ + { NDS9_VTX_XZ, "VTX_XZ", {0}}, /* Set Vertex XZ Coordinates (W) */ + { NDS9_VTX_YZ, "VTX_YZ", {0}}, /* Set Vertex YZ Coordinates (W) */ + { NDS9_VTX_DIFF, "VTX_DIFF", {0}}, /* Set Relative Vertex Coordinates (W) */ + { NDS9_POLYGON_ATTR, "POLYGON_ATTR", {0}}, /* Set Polygon Attributes (W) */ + { NDS9_TEXIMAGE_PARAM, "TEXIMAGE_PARAM", {0}}, /* Set Texture Parameters (W) */ + { NDS9_PLTT_BASE, "PLTT_BASE", {0}}, /* Set Texture Palette Base Address (W) */ + { NDS9_DIF_AMB, "DIF_AMB", {0}}, /* MaterialColor0 - Diffuse/Ambient Reflect. (W) */ + { NDS9_SPE_EMI, "SPE_EMI", {0}}, /* MaterialColor1 - Specular Ref. & Emission (W) */ + { NDS9_LIGHT_VECTOR, "LIGHT_VECTOR", {0}}, /* Set Light's Directional Vector (W) */ + { NDS9_LIGHT_COLOR, "LIGHT_COLOR", {0}}, /* Set Light Color (W) */ + { NDS9_SHININESS, "SHININESS", {0}}, /* Specular Reflection Shininess Table (W) */ + { NDS9_BEGIN_VTXS, "BEGIN_VTXS", { + {0, 2, "Primitive Type(0=Triangles, 1=Quads, 2=Tri Strips, 3=Quad Strips"}, + } }, /* Start of Vertex List (W) */ + { NDS9_END_VTXS, "END_VTXS", {0}}, /* End of Vertex List (W) */ + { NDS9_SWAP_BUFFERS, "SWAP_BUFFERS", {0}}, /* Swap Rendering Engine Buffer (W) */ + { NDS9_VIEWPORT, "VIEWPORT", {0}}, /* Set Viewport (W) */ + { NDS9_BOX_TEST, "BOX_TEST", {0}}, /* Test if Cuboid Sits inside View Volume (W) */ + { NDS9_POS_TEST, "POS_TEST", {0}}, /* Set Position Coordinates for Test (W) */ + { NDS9_VEC_TEST, "VEC_TEST", {0}}, /* Set Directional Vector for Test (W) */ + { NDS9_GXSTAT, "GXSTAT", { + {0, 1, "BoxTest,PositionTest,VectorTest Busy (0=Ready, 1=Busy)"}, + {1, 1, "BoxTest Result (0=All Outside View, 1=Parts or Fully Inside View)"}, + {8, 5, "Position & Vector Matrix Stack Level (0..31) (lower 5bit of 6bit value)"}, + {13, 1, "Projection Matrix Stack Level (0..1)"}, + {14, 1, "Matrix Stack Busy (0=No, 1=Yes; Currently executing a Push/Pop command)"}, + {15, 1, "Matrix Stack Overflow/Underflow Error (0=No, 1=Error/Acknowledge/Reset)"}, + {16, 9, "Number of 40bit-entries in Command FIFO (0..256)"}, + {25, 1, "Command FIFO Less Than Half Full (0=No, 1=Yes; Less than Half-full)"}, + {26, 1, "Command FIFO Empty (0=No, 1=Yes; Empty)"}, + {27, 1, "Geometry Engine Busy (0=No, 1=Yes; Busy; Commands are executing)"}, + {30, 2, "Command FIFO IRQ (0=Never, 1=Less than half full, 2=Empty, 3=Reserved)"}, + } }, /* Geometry Engine Status Register (R and R/W) */ + { NDS9_RAM_COUNT, "RAM_COUNT", {0}}, /* Polygon List & Vertex RAM Count Register (R) */ + {NDS9_DISP_1DOT_DEPTH, "DISP_1DOT_DEPTH", {0}}, /* 1-Dot Polygon Display Boundary Depth (W) */ + { NDS9_POS_RESULT, "POS_RESULT", {0}}, /* Position Test Results (R) */ + { NDS9_VEC_RESULT, "VEC_RESULT", {0}}, /* Vector Test Results (R) */ + { NDS9_CLIPMTX_RESULT, "CLIPMTX_RESULT", {0}}, /* Read Current Clip Coordinates Matrix (R) */ + { NDS9_VECMTX_RESULT, "VECMTX_RESULT", {0}}, /* Read Current Directional Vector Matrix (R) */ + { NDS9_B_DISPCNT, "(2D-B)DISPCNT ", {{0, 3, "BG Mode (0-5=Video Mode 0-5, 6-7=Prohibited)"}, {3, 1, "Reserved / CGB Mode (0=GBA, 1=CGB)"}, {4, 1, "Display Frame Select (0-1=Frame 0-1)"}, {5, 1, "Bitmap OBJ 2D-Dimension (0=128x512 dots, 1=256x256 dots)"}, {6, 1, "OBJ Character VRAM Mapping (0=2D, 1=1D"}, {7, 1, "Forced Blank (1=Allow FAST VRAM,Palette,OAM)"}, {8, 1, "Screen Display BG0 (0=Off, 1=On)"}, {9, 1, "Screen Display BG1 (0=Off, 1=On)"}, {10, 1, "Screen Display BG2 (0=Off, 1=On)"}, {11, 1, "Screen Display BG3 (0=Off, 1=On)"}, {12, 1, "Screen Display OBJ (0=Off, 1=On)"}, {13, 1, "Window 0 Display Flag (0=Off, 1=On)"}, {14, 1, "Window 1 Display Flag (0=Off, 1=On)"}, {15, 1, "OBJ Window Display Flag (0=Off, 1=On)"}, {16, 2, "Display Mode (0..1)"}, {18, 2, "VRAM block (0..3=VRAM A..D) (For Capture & above Display Mode=2)"}, {20, 2, "Tile OBJ 1D-Boundary (see Bit4)"}, {23, 1, "OBJ Processing during H-Blank (was located in Bit5 on GBA)"}, {24, 3, "Character Base (in 64K steps) (merged with 16K step in BGxCNT)"}, {30, 1, "BG Extended Palettes (0=Disable, 1=Enable)"}, {31, 1, "OBJ Extended Palettes (0=Disable, 1=Enable)"}}}, + // ARM9 Display Engine B + { NDS9_B_BG0CNT, "(2D-B) BG0CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG0 Control */ + { NDS9_B_BG1CNT, "(2D-B) BG1CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG1 Control */ + { NDS9_B_BG2CNT, "(2D-B) BG2CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG2 Control */ + { NDS9_B_BG3CNT, "(2D-B) BG3CNT ", { + {0, 2, "BG Priority (0-3, 0=Highest)"}, + {2, 4, "Character Base Block (0-3, in units of 16 KBytes) (=BG Tile Data)"}, + {6, 1, "Mosaic (0=Disable, 1=Enable)"}, + {7, 1, "Colors/Palettes (0=16/16, 1=256/1)"}, + {8, 5, "Screen Base Block (0-31, in units of 2 KBytes) (=BG Map Data)"}, + {13, 1, "BG0/BG1: (NDS: Ext Palette ) BG2/BG3: Overflow (0=Transp, 1=Wrap)"}, + {14, 2, "Screen Size (0-3)"}, + } }, /* R/W BG3 Control */ + { NDS9_B_BG0HOFS, "(2D-B) BG0HOFS", {0}}, /* W BG0 X-Offset */ + { NDS9_B_BG0VOFS, "(2D-B) BG0VOFS", {0}}, /* W BG0 Y-Offset */ + { NDS9_B_BG1HOFS, "(2D-B) BG1HOFS", {0}}, /* W BG1 X-Offset */ + { NDS9_B_BG1VOFS, "(2D-B) BG1VOFS", {0}}, /* W BG1 Y-Offset */ + { NDS9_B_BG2HOFS, "(2D-B) BG2HOFS", {0}}, /* W BG2 X-Offset */ + { NDS9_B_BG2VOFS, "(2D-B) BG2VOFS", {0}}, /* W BG2 Y-Offset */ + { NDS9_B_BG3HOFS, "(2D-B) BG3HOFS", {0}}, /* W BG3 X-Offset */ + { NDS9_B_BG3VOFS, "(2D-B) BG3VOFS", {0}}, /* W BG3 Y-Offset */ + { NDS9_B_BG2PA, "(2D-B) BG2PA", {0}}, /* W BG2 Rotation/Scaling Parameter A (dx) */ + { NDS9_B_BG2PB, "(2D-B) BG2PB", {0}}, /* W BG2 Rotation/Scaling Parameter B (dmx) */ + { NDS9_B_BG2PC, "(2D-B) BG2PC", {0}}, /* W BG2 Rotation/Scaling Parameter C (dy) */ + { NDS9_B_BG2PD, "(2D-B) BG2PD", {0}}, /* W BG2 Rotation/Scaling Parameter D (dmy) */ + { NDS9_B_BG2X, "(2D-B) BG2X", {0}}, /* W BG2 Reference Point X-Coordinate */ + { NDS9_B_BG2Y, "(2D-B) BG2Y", {0}}, /* W BG2 Reference Point Y-Coordinate */ + { NDS9_B_BG3PA, "(2D-B) BG3PA", {0}}, /* W BG3 Rotation/Scaling Parameter A (dx) */ + { NDS9_B_BG3PB, "(2D-B) BG3PB", {0}}, /* W BG3 Rotation/Scaling Parameter B (dmx) */ + { NDS9_B_BG3PC, "(2D-B) BG3PC", {0}}, /* W BG3 Rotation/Scaling Parameter C (dy) */ + { NDS9_B_BG3PD, "(2D-B) BG3PD", {0}}, /* W BG3 Rotation/Scaling Parameter D (dmy) */ + { NDS9_B_BG3X, "(2D-B) BG3X", {0}}, /* W BG3 Reference Point X-Coordinate */ + { NDS9_B_BG3Y, "(2D-B) BG3Y", {0}}, /* W BG3 Reference Point Y-Coordinate */ + { NDS9_B_WIN0H, "(2D-B) WIN0H", { + {0, 8, "X2, Rightmost coordinate of window, plus 1 "}, + {8, 8, "X1, Leftmost coordinate of window"}, + } }, /* W Window 0 Horizontal Dimensions */ + { NDS9_B_WIN1H, "(2D-B) WIN1H", { + {0, 8, "X2, Rightmost coordinate of window, plus 1 "}, + {8, 8, "X1, Leftmost coordinate of window"}, + } }, /* W Window 1 Horizontal Dimensions */ + { NDS9_B_WIN0V, "(2D-B) WIN0V", { + {0, 8, "Y2, Bottom-most coordinate of window, plus 1"}, + {8, 8, "Y1, Top-most coordinate of window"}, + } }, /* W Window 0 Vertical Dimensions */ + { NDS9_B_WIN1V, "(2D-B) WIN1V", { + {0, 8, "Y2, Bottom-most coordinate of window, plus 1"}, + {8, 8, "Y1, Top-most coordinate of window"}, + } }, /* W Window 1 Vertical Dimensions */ + { NDS9_B_WININ, "(2D-B) WININ", { + {0, 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, + {1, 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, + {2, 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, + {3, 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, + {4, 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, + {5, 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, + {8, 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, + {9, 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, + {10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, + {11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, + {12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, + {13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, + } }, /* R/W Inside of Window 0 and 1 */ + { NDS9_B_WINOUT, "(2D-B) WINOUT", { + {0, 1, "Window 0 BG0 Enable Bits (0=No Display, 1=Display)"}, + {1, 1, "Window 0 BG1 Enable Bits (0=No Display, 1=Display)"}, + {2, 1, "Window 0 BG2 Enable Bits (0=No Display, 1=Display)"}, + {3, 1, "Window 0 BG3 Enable Bits (0=No Display, 1=Display)"}, + {4, 1, "Window 0 OBJ Enable Bit (0=No Display, 1=Display)"}, + {5, 1, "Window 0 Color Special Effect (0=Disable, 1=Enable)"}, + {8, 1, "Window 1 BG0 Enable Bits (0=No Display, 1=Display)"}, + {9, 1, "Window 1 BG1 Enable Bits (0=No Display, 1=Display)"}, + {10, 1, "Window 1 BG2 Enable Bits (0=No Display, 1=Display)"}, + {11, 1, "Window 1 BG3 Enable Bits (0=No Display, 1=Display)"}, + {12, 1, "Window 1 OBJ Enable Bit (0=No Display, 1=Display)"}, + {13, 1, "Window 1 Color Special Effect (0=Disable, 1=Enable)"}, + } }, /* R/W Inside of OBJ Window & Outside of Windows */ + { NDS9_B_MOSAIC, "(2D-B) MOSAIC", { + {0, 4, "BG Mosaic H-Size (minus 1)"}, + {4, 4, "BG Mosaic V-Size (minus 1)"}, + {8, 4, "OBJ Mosaic H-Size (minus 1)"}, + {12, 4, "OBJ Mosaic V-Size (minus 1)"}, + } }, /* W Mosaic Size */ + { NDS9_B_BLDCNT, "(2D-B) BLDCNT", { + {0, 1, "BG0 1st Target Pixel (Background 0)"}, + {1, 1, "BG1 1st Target Pixel (Background 1)"}, + {2, 1, "BG2 1st Target Pixel (Background 2)"}, + {3, 1, "BG3 1st Target Pixel (Background 3)"}, + {4, 1, "OBJ 1st Target Pixel (Top-most OBJ pixel)"}, + {5, 1, "BD 1st Target Pixel (Backdrop)"}, + {6, 2, "Color Effect (0: None 1: Alpha 2: Lighten 3: Darken)"}, + {8, 1, "BG0 2nd Target Pixel (Background 0)"}, + {9, 1, "BG1 2nd Target Pixel (Background 1)"}, + {10, 1, "BG2 2nd Target Pixel (Background 2)"}, + {11, 1, "BG3 2nd Target Pixel (Background 3)"}, + {12, 1, "OBJ 2nd Target Pixel (Top-most OBJ pixel)"}, + {13, 1, "BD 2nd Target Pixel (Backdrop)"}, + } }, /* R/W Color Special Effects Selection */ + { NDS9_B_BLDALPHA, "(2D-B) BLDALPHA", { + {0, 4, "EVA Coef. (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, + {8, 4, "EVB Coef. (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)"}, + } }, /* R/W Alpha Blending Coefficients */ + { NDS9_B_BLDY, "(2D-B) BLDY", { + {0, 5, "EVY Coefficient (Brightness) (0..16 = 0/16..16/16, 17..31=16/16)"}, + } }, /* W Brightness (Fade-In/Out) Coefficient */ + + {NDS9_B_MASTER_BRIGHT, "(2D-B) MASTER_BRIGHT", { + {0, 5, "Factor used for 6bit R,G,B Intensities (0-16, values >16 same as 16)"}, + {14, 2, "Mode (0=Disable, 1=Up, 2=Down, 3=Reserved)"}, + } }, /* Master Brightness Up/Down */ }; -mmio_reg_t nds7_io_reg_desc[]={ - { GBA_DISPSTAT, "DISPSTAT", { - { 0,1, "V-Blank flag (1=VBlank) (set in line 160..226; not 227",}, - { 1,1, "H-Blank flag (1=HBlank) (toggled in all lines, 0..227",}, - { 2,1, "V-Counter flag (1=Match) (set in selected line)",}, - { 3,1, "V-Blank IRQ Enable (1=Enable)",}, - { 4,1, "H-Blank IRQ Enable (1=Enable)",}, - { 5,1, "V-Counter IRQ Enable (1=Enable)",}, - { 6,1, "DSi: LCD Initialization Ready (0=Busy, 1=Ready",}, - { 7,1, "NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262",}, - { 8,8, "V-Count Setting (LYC) (0..227)",}, - - } }, /* R/W General LCD Status (STAT,LYC) */ - { GBA_VCOUNT , "VCOUNT ", { - {0,8,"LCD-Y"} - } }, /* R Vertical Counter (LY) */ +mmio_reg_t nds7_io_reg_desc[] = { + { GBA_DISPSTAT, "DISPSTAT", { + { + 0, + 1, + "V-Blank flag (1=VBlank) (set in line 160..226; not 227", + }, + { + 1, + 1, + "H-Blank flag (1=HBlank) (toggled in all lines, 0..227", + }, + { + 2, + 1, + "V-Counter flag (1=Match) (set in selected line)", + }, + { + 3, + 1, + "V-Blank IRQ Enable (1=Enable)", + }, + { + 4, + 1, + "H-Blank IRQ Enable (1=Enable)", + }, + { + 5, + 1, + "V-Counter IRQ Enable (1=Enable)", + }, + { + 6, + 1, + "DSi: LCD Initialization Ready (0=Busy, 1=Ready", + }, + { + 7, + 1, + "NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262", + }, + { + 8, + 8, + "V-Count Setting (LYC) (0..227)", + }, + + } }, /* R/W General LCD Status (STAT,LYC) */ + { GBA_VCOUNT, "VCOUNT ", {{0, 8, "LCD-Y"}}}, /* R Vertical Counter (LY) */ // DMA Transfer Channels - { GBA_DMA0SAD , "DMA0SAD", { 0 } }, /* W DMA 0 Source Address */ - { GBA_DMA0DAD , "DMA0DAD", { 0 } }, /* W DMA 0 Destination Address */ - { GBA_DMA0CNT_L, "DMA0CNT_L", { 0 } }, /* W DMA 0 Word Count */ - { GBA_DMA0CNT_H, "DMA0CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=Wireless interrupt" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 0 Control */ - { GBA_DMA1SAD , "DMA1SAD", { 0 } }, /* W DMA 1 Source Address */ - { GBA_DMA1DAD , "DMA1DAD", { 0 } }, /* W DMA 1 Destination Address */ - { GBA_DMA1CNT_L, "DMA1CNT_L", { 0 } }, /* W DMA 1 Word Count */ - { GBA_DMA1CNT_H, "DMA1CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=GBA Cartridge Slot" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 1 Control */ - { GBA_DMA2SAD , "DMA2SAD", { 0 } }, /* W DMA 2 Source Address */ - { GBA_DMA2DAD , "DMA2DAD", { 0 } }, /* W DMA 2 Destination Address */ - { GBA_DMA2CNT_L, "DMA2CNT_L", { 0 } }, /* W DMA 2 Word Count */ - { GBA_DMA2CNT_H, "DMA2CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=Wireless interrupt" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 2 Control */ - { GBA_DMA3SAD , "DMA3SAD", { 0 } }, /* W DMA 3 Source Address */ - { GBA_DMA3DAD , "DMA3DAD", { 0 } }, /* W DMA 3 Destination Address */ - { GBA_DMA3CNT_L, "DMA3CNT_L", { 0 } }, /* W DMA 3 Word Count */ - { GBA_DMA3CNT_H, "DMA3CNT_H", { - { 5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)" }, - { 7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)" }, - { 9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)" }, - { 10, 1, "DMA Transfer Type (0=16bit, 1=32bit)" }, - { 11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=GBA Cartridge Slot" }, - { 14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)" }, - { 15, 1, "DMA Enable (0=Off, 1=On)" }, - } }, /* R/W DMA 3 Control */ + { GBA_DMA0SAD, "DMA0SAD", {0}}, /* W DMA 0 Source Address */ + { GBA_DMA0DAD, "DMA0DAD", {0}}, /* W DMA 0 Destination Address */ + { GBA_DMA0CNT_L, "DMA0CNT_L", {0}}, /* W DMA 0 Word Count */ + { GBA_DMA0CNT_H, "DMA0CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=Wireless interrupt"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 0 Control */ + { GBA_DMA1SAD, "DMA1SAD", {0}}, /* W DMA 1 Source Address */ + { GBA_DMA1DAD, "DMA1DAD", {0}}, /* W DMA 1 Destination Address */ + { GBA_DMA1CNT_L, "DMA1CNT_L", {0}}, /* W DMA 1 Word Count */ + { GBA_DMA1CNT_H, "DMA1CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=GBA Cartridge Slot"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 1 Control */ + { GBA_DMA2SAD, "DMA2SAD", {0}}, /* W DMA 2 Source Address */ + { GBA_DMA2DAD, "DMA2DAD", {0}}, /* W DMA 2 Destination Address */ + { GBA_DMA2CNT_L, "DMA2CNT_L", {0}}, /* W DMA 2 Word Count */ + { GBA_DMA2CNT_H, "DMA2CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=Wireless interrupt"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 2 Control */ + { GBA_DMA3SAD, "DMA3SAD", {0}}, /* W DMA 3 Source Address */ + { GBA_DMA3DAD, "DMA3DAD", {0}}, /* W DMA 3 Destination Address */ + { GBA_DMA3CNT_L, "DMA3CNT_L", {0}}, /* W DMA 3 Word Count */ + { GBA_DMA3CNT_H, "DMA3CNT_H", { + {5, 2, "Dest Addr Control (0=Incr,1=Decr,2=Fixed,3=Incr/Reload)"}, + {7, 2, "Source Adr Control (0=Incr,1=Decr,2=Fixed,3=Prohibited)"}, + {9, 1, "DMA Repeat (0=Off, 1=On) (Must be zero if Bit 11 set)"}, + {10, 1, "DMA Transfer Type (0=16bit, 1=32bit)"}, + {11, 2, "DMA Start Timing (0=Immediately, 1=VBlank, 2=DS Cartridge Slot, 3=GBA Cartridge Slot"}, + {14, 1, "IRQ upon end of Word Count (0=Disable, 1=Enable)"}, + {15, 1, "DMA Enable (0=Off, 1=On)"}, + } }, /* R/W DMA 3 Control */ // Timer Registers - { GBA_TM0CNT_L, "TM0CNT_L", {0} }, /* R/W Timer 0 Counter/Reload */ - { GBA_TM0CNT_H, "TM0CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 0 Control */ - { GBA_TM1CNT_L, "TM1CNT_L", {0} }, /* R/W Timer 1 Counter/Reload */ - { GBA_TM1CNT_H, "TM1CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 1 Control */ - { GBA_TM2CNT_L, "TM2CNT_L", {0} }, /* R/W Timer 2 Counter/Reload */ - { GBA_TM2CNT_H, "TM2CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 2 Control */ - { GBA_TM3CNT_L, "TM3CNT_L", {0} }, /* R/W Timer 3 Counter/Reload */ - { GBA_TM3CNT_H, "TM3CNT_H", { - { 0 ,2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)" }, - { 2 ,1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)" }, - { 6 ,1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)" }, - { 7 ,1, "Timer Start/Stop (0=Stop, 1=Operate)" }, - } }, /* R/W Timer 3 Control */ + { GBA_TM0CNT_L, "TM0CNT_L", {0}}, /* R/W Timer 0 Counter/Reload */ + { GBA_TM0CNT_H, "TM0CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 0 Control */ + { GBA_TM1CNT_L, "TM1CNT_L", {0}}, /* R/W Timer 1 Counter/Reload */ + { GBA_TM1CNT_H, "TM1CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 1 Control */ + { GBA_TM2CNT_L, "TM2CNT_L", {0}}, /* R/W Timer 2 Counter/Reload */ + { GBA_TM2CNT_H, "TM2CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 2 Control */ + { GBA_TM3CNT_L, "TM3CNT_L", {0}}, /* R/W Timer 3 Counter/Reload */ + { GBA_TM3CNT_H, "TM3CNT_H", { + {0, 2, "Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)"}, + {2, 1, "Count-up (0=Normal, 1=Incr. on prev. Timer overflow)"}, + {6, 1, "Timer IRQ Enable (0=Disable, 1=IRQ on Timer overflow)"}, + {7, 1, "Timer Start/Stop (0=Stop, 1=Operate)"}, + } }, /* R/W Timer 3 Control */ // Serial Communication (1) - { GBA_SIODATA32 , "SIODATA32", {0} }, /*R/W SIO Data (Normal-32bit Mode; shared with below) */ - { GBA_SIOMULTI0 , "SIOMULTI0", {0} }, /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ - { GBA_SIOMULTI1 , "SIOMULTI1", {0} }, /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ - { GBA_SIOMULTI2 , "SIOMULTI2", {0} }, /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ - { GBA_SIOMULTI3 , "SIOMULTI3", {0} }, /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ - { GBA_SIOCNT , "SIOCNT", {0} }, /*R/W SIO Control Register */ - { GBA_SIOMLT_SEND, "SIOMLT_SEND", {0} }, /*R/W SIO Data (Local of MultiPlayer; shared below) */ - { GBA_SIODATA8 , "SIODATA8", {0} }, /*R/W SIO Data (Normal-8bit and UART Mode) */ + { GBA_SIODATA32, "SIODATA32", {0}}, /*R/W SIO Data (Normal-32bit Mode; shared with below) */ + { GBA_SIOMULTI0, "SIOMULTI0", {0}}, /*R/W SIO Data 0 (Parent) (Multi-Player Mode) */ + { GBA_SIOMULTI1, "SIOMULTI1", {0}}, /*R/W SIO Data 1 (1st Child) (Multi-Player Mode) */ + { GBA_SIOMULTI2, "SIOMULTI2", {0}}, /*R/W SIO Data 2 (2nd Child) (Multi-Player Mode) */ + { GBA_SIOMULTI3, "SIOMULTI3", {0}}, /*R/W SIO Data 3 (3rd Child) (Multi-Player Mode) */ + { GBA_SIOCNT, "SIOCNT", {0}}, /*R/W SIO Control Register */ + { GBA_SIOMLT_SEND, "SIOMLT_SEND", {0}}, /*R/W SIO Data (Local of MultiPlayer; shared below) */ + { GBA_SIODATA8, "SIODATA8", {0}}, /*R/W SIO Data (Normal-8bit and UART Mode) */ // Keypad Input - { GBA_KEYINPUT, "GBA_KEYINPUT", { - { 0, 1, "Button A" }, - { 1, 1, "Button B" }, - { 2, 1, "Select" }, - { 3, 1, "Start" }, - { 4, 1, "Right" }, - { 5, 1, "Left" }, - { 6, 1, "Up" }, - { 7, 1, "Down" }, - { 8, 1, "Button R" }, - { 9, 1, "Button L" }, - } }, /* R Key Status */ - { GBA_KEYCNT , "GBA_KEYCNT", { - { 0, 1, "Button A" }, - { 1, 1, "Button B" }, - { 2, 1, "Select" }, - { 3, 1, "Start" }, - { 4, 1, "Right" }, - { 5, 1, "Left" }, - { 6, 1, "Up" }, - { 7, 1, "Down" }, - { 8, 1, "Button R" }, - { 9, 1, "Button L" }, - { 14,1, "Button IRQ Enable (0=Disable, 1=Enable)" }, - { 15,1, "Button IRQ Condition (0=OR, 1=AND)"}, - } }, /* R/W Key Interrupt Control */ + { GBA_KEYINPUT, "GBA_KEYINPUT", { + {0, 1, "Button A"}, + {1, 1, "Button B"}, + {2, 1, "Select"}, + {3, 1, "Start"}, + {4, 1, "Right"}, + {5, 1, "Left"}, + {6, 1, "Up"}, + {7, 1, "Down"}, + {8, 1, "Button R"}, + {9, 1, "Button L"}, + } }, /* R Key Status */ + { GBA_KEYCNT, "GBA_KEYCNT", { + {0, 1, "Button A"}, + {1, 1, "Button B"}, + {2, 1, "Select"}, + {3, 1, "Start"}, + {4, 1, "Right"}, + {5, 1, "Left"}, + {6, 1, "Up"}, + {7, 1, "Down"}, + {8, 1, "Button R"}, + {9, 1, "Button L"}, + {14, 1, "Button IRQ Enable (0=Disable, 1=Enable)"}, + {15, 1, "Button IRQ Condition (0=OR, 1=AND)"}, + } }, /* R/W Key Interrupt Control */ // Serial Communication (2) - { GBA_JOYCNT , "JOYCNT", {0} }, /* R/W SIO JOY Bus Control */ - { GBA_JOY_RECV , "JOY_RECV", {0} }, /* R/W SIO JOY Bus Receive Data */ - { GBA_JOY_TRANS, "JOY_TRANS", {0} }, /* R/W SIO JOY Bus Transmit Data */ - { GBA_JOYSTAT , "JOYSTAT", {0} }, /* R/? SIO JOY Bus Receive Status */ - - { NDS7_DEBUG_RCNT, "DEBUG_RCNT", { 0 } }, /* Debug RCNT */ - { NDS7_EXTKEYIN, "EXTKEYIN", { - { 0,1, "Button X (0=Pressed, 1=Released)"}, - { 1,1, "Button Y (0=Pressed, 1=Released)"}, - { 3,1, "DEBUG button (0=Pressed, 1=Released/None such)"}, - { 6,1, "Pen down (0=Pressed, 1=Released/Disabled) (always 0 in DSi mode)"}, - { 7,1, "Hinge/folded (0=Open, 1=Closed)"}, - } }, /* EXTKEYIN */ - { NDS7_RTC_BUS, "RTC_BUS", { 0 } }, /* RTC Realtime Clock Bus */ - { NDS_IPCSYNC, "IPCSYNC", { - { 0 ,4,"Data input from IPCSYNC Bit8-11 of remote CPU (00h..0Fh)"}, - { 8 ,4,"Data output to IPCSYNC Bit0-3 of remote CPU (00h..0Fh)"}, - { 13 ,1,"Send IRQ to remote CPU (0=None, 1=Send IRQ)"}, - { 14 ,1,"Enable IRQ from remote CPU (0=Disable, 1=Enable)"}, - } }, /* IPC Synchronize Register (R/W) */ - { NDS_IPCFIFOCNT, "IPCFIFOCNT", { - { 0 ,1, "Send Fifo Empty Status (0=Not Empty, 1=Empty)"}, - { 1 ,1, "Send Fifo Full Status (0=Not Full, 1=Full)"}, - { 2 ,1, "Send Fifo Empty IRQ (0=Disable, 1=Enable)"}, - { 3 ,1, "Send Fifo Clear (0=Nothing, 1=Flush Send Fifo)"}, - { 8 ,1, "Receive Fifo Empty (0=Not Empty, 1=Empty)"}, - { 9 ,1, "Receive Fifo Full (0=Not Full, 1=Full)"}, - { 10 ,1, "Receive Fifo Not Empty IRQ (0=Disable, 1=Enable)"}, - { 14 ,1, "Error, Read Empty/Send Full (0=No Error, 1=Error/Acknowledge)"}, - { 15 ,1, "Enable Send/Receive Fifo (0=Disable, 1=Enable)"}, - } }, /* IPC Fifo Control Register (R/W) */ - { NDS_IPCFIFOSEND, "IPCFIFOSEND", { 0 } }, /* IPC Send Fifo (W) */ - { NDS_IPCFIFORECV, "IPCFIFORECV", { 0 }}, /* Sound Capture 1 Length (W) */ - { NDS7_AUXSPICNT, "AUXSPICNT", { - { 0 ,2,"SPI Baudrate (0=4MHz/Default, 1=2MHz, 2=1MHz, 3=512KHz)" }, - { 6 ,1,"SPI Hold Chipselect (0=Deselect after transfer, 1=Keep selected)" }, - { 7 ,1,"SPI Busy (0=Ready, 1=Busy) (presumably Read-only)" }, - { 13 ,1,"NDS Slot Mode (0=Parallel/ROM, 1=Serial/SPI-Backup)" }, - { 14 ,1,"Transfer Ready IRQ (0=Disable, 1=Enable) (for ROM, not for AUXSPI)" }, - { 15 ,1,"NDS Slot Enable (0=Disable, 1=Enable) (for both ROM and AUXSPI)" }, - } }, /* Gamecard ROM and SPI Control */ - { NDS7_AUXSPIDATA, "AUXSPIDATA", { 0 } }, /* Gamecard SPI Bus Data/Strobe */ - { NDS_GCBUS_CTL, "GCBUS_CTL", { - { 0 ,13,"KEY1 gap1 length (0-1FFFh) (forced min 08F8h by BIOS) (leading gap)" }, - { 13 ,1, "KEY2 encrypt data (0=Disable, 1=Enable KEY2 Encryption for Data)" }, - { 14 ,1, "Unknown (SE)" }, - { 15 ,1, "KEY2 Apply Seed (0=No change, 1=Apply Encryption Seed) (Write only)" }, - { 16 ,6, "KEY1 gap2 length (0-3Fh) (forced min 18h by BIOS) (200h-byte gap)" }, - { 22 ,1, "KEY2 encrypt cmd (0=Disable, 1=Enable KEY2 Encryption for Commands)" }, - { 23 ,1, "Data-Word Status (0=Busy, 1=Ready/DRQ) (Read-only)" }, - { 24 ,3, "Data Block size (0=None, 1..6=100h SHL (1..6) bytes, 7=4 bytes)" }, - { 27 ,1, "Transfer CLK rate (0=6.7MHz=33.51MHz/5, 1=4.2MHz=33.51MHz/8)" }, - { 28 ,1, "KEY1 Gap CLKs (0=Hold CLK High during gaps, 1=Output Dummy CLK Pulses)" }, - { 29 ,1, "RESB Release Reset (0=Reset, 1=Release) (cannot be cleared once set)" }, - { 30 ,1, "Data Direction 'WR' (0=Normal/read, 1=Write, for FLASH/NAND carts)" }, - { 31 ,1, "Block Start/Status (0=Ready, 1=Start/Busy) (IRQ See 40001A0h/Bit14)" }, - } }, /* Gamecard bus timing/control */ - { NDS_GCBUS_CMD, "GCBUS_CMD", { 0 } }, /* Gamecard bus 8-byte command out */ - { NDS_GCBUS_SEED0_LO, "GCBUS_SEED0_LO", { 0 } }, /* Gamecard Encryption Seed 0 Lower 32bit */ - { NDS_GCBUS_SEED1_LO, "GCBUS_SEED1_LO", { 0 } }, /* Gamecard Encryption Seed 1 Lower 32bit */ - { NDS_GCBUS_SEED0_HI, "GCBUS_SEED0_HI", { 0 } }, /* Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused) */ - { NDS_GCBUS_SEED1_HI, "GCBUS_SEED1_HI", { 0 } }, /* Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused) */ - { NDS7_SPI_BUS_CTL, "SPI_BUS_CTL", { - { 0 , 2,"Baudrate (0=4MHz/Firmware, 1=2MHz/Touchscr, 2=1MHz/Powerman., 3=512KHz)"}, - { 2 , 1,"DSi: Baudrate MSB (4=8MHz, 5..7=None/0Hz) (when SCFG_EXT7.bit9=1)"}, - { 7 , 1,"Busy Flag (0=Ready, 1=Busy) (presumably Read-only)"}, - { 8 , 2,"Device Select (0=Powerman., 1=Firmware, 2=Touchscr, 3=Reserved)"}, - { 10 , 1,"Transfer Size (0=8bit/Normal, 1=16bit/Bugged)"}, - { 11 , 1,"Chipselect Hold (0=Deselect after transfer, 1=Keep selected)"}, - { 14 , 1,"Interrupt Request (0=Disable, 1=Enable)"}, - { 15 , 1,"SPI Bus Enable (0=Disable, 1=Enable)"}, - } }, /* SPI bus Control (Firmware, Touchscreen, Powerman) */ - { NDS7_SPI_BUS_DATA, "SPI_BUS_DATA", { 0 } }, /* SPI bus Data */ + { GBA_JOYCNT, "JOYCNT", {0}}, /* R/W SIO JOY Bus Control */ + { GBA_JOY_RECV, "JOY_RECV", {0}}, /* R/W SIO JOY Bus Receive Data */ + { GBA_JOY_TRANS, "JOY_TRANS", {0}}, /* R/W SIO JOY Bus Transmit Data */ + { GBA_JOYSTAT, "JOYSTAT", {0}}, /* R/? SIO JOY Bus Receive Status */ + + { NDS7_DEBUG_RCNT, "DEBUG_RCNT", {0}}, /* Debug RCNT */ + { NDS7_EXTKEYIN, "EXTKEYIN", { + {0, 1, "Button X (0=Pressed, 1=Released)"}, + {1, 1, "Button Y (0=Pressed, 1=Released)"}, + {3, 1, "DEBUG button (0=Pressed, 1=Released/None such)"}, + {6, 1, "Pen down (0=Pressed, 1=Released/Disabled) (always 0 in DSi mode)"}, + {7, 1, "Hinge/folded (0=Open, 1=Closed)"}, + } }, /* EXTKEYIN */ + { NDS7_RTC_BUS, "RTC_BUS", {0}}, /* RTC Realtime Clock Bus */ + { NDS_IPCSYNC, "IPCSYNC", { + {0, 4, "Data input from IPCSYNC Bit8-11 of remote CPU (00h..0Fh)"}, + {8, 4, "Data output to IPCSYNC Bit0-3 of remote CPU (00h..0Fh)"}, + {13, 1, "Send IRQ to remote CPU (0=None, 1=Send IRQ)"}, + {14, 1, "Enable IRQ from remote CPU (0=Disable, 1=Enable)"}, + } }, /* IPC Synchronize Register (R/W) */ + { NDS_IPCFIFOCNT, "IPCFIFOCNT", { + {0, 1, "Send Fifo Empty Status (0=Not Empty, 1=Empty)"}, + {1, 1, "Send Fifo Full Status (0=Not Full, 1=Full)"}, + {2, 1, "Send Fifo Empty IRQ (0=Disable, 1=Enable)"}, + {3, 1, "Send Fifo Clear (0=Nothing, 1=Flush Send Fifo)"}, + {8, 1, "Receive Fifo Empty (0=Not Empty, 1=Empty)"}, + {9, 1, "Receive Fifo Full (0=Not Full, 1=Full)"}, + {10, 1, "Receive Fifo Not Empty IRQ (0=Disable, 1=Enable)"}, + {14, 1, "Error, Read Empty/Send Full (0=No Error, 1=Error/Acknowledge)"}, + {15, 1, "Enable Send/Receive Fifo (0=Disable, 1=Enable)"}, + } }, /* IPC Fifo Control Register (R/W) */ + { NDS_IPCFIFOSEND, "IPCFIFOSEND", {0}}, /* IPC Send Fifo (W) */ + { NDS_IPCFIFORECV, "IPCFIFORECV", {0}}, /* Sound Capture 1 Length (W) */ + { NDS7_AUXSPICNT, "AUXSPICNT", { + {0, 2, "SPI Baudrate (0=4MHz/Default, 1=2MHz, 2=1MHz, 3=512KHz)"}, + {6, 1, "SPI Hold Chipselect (0=Deselect after transfer, 1=Keep selected)"}, + {7, 1, "SPI Busy (0=Ready, 1=Busy) (presumably Read-only)"}, + {13, 1, "NDS Slot Mode (0=Parallel/ROM, 1=Serial/SPI-Backup)"}, + {14, 1, "Transfer Ready IRQ (0=Disable, 1=Enable) (for ROM, not for AUXSPI)"}, + {15, 1, "NDS Slot Enable (0=Disable, 1=Enable) (for both ROM and AUXSPI)"}, + } }, /* Gamecard ROM and SPI Control */ + { NDS7_AUXSPIDATA, "AUXSPIDATA", {0}}, /* Gamecard SPI Bus Data/Strobe */ + { NDS_GCBUS_CTL, "GCBUS_CTL", { + {0, 13, "KEY1 gap1 length (0-1FFFh) (forced min 08F8h by BIOS) (leading gap)"}, + {13, 1, "KEY2 encrypt data (0=Disable, 1=Enable KEY2 Encryption for Data)"}, + {14, 1, "Unknown (SE)"}, + {15, 1, "KEY2 Apply Seed (0=No change, 1=Apply Encryption Seed) (Write only)"}, + {16, 6, "KEY1 gap2 length (0-3Fh) (forced min 18h by BIOS) (200h-byte gap)"}, + {22, 1, "KEY2 encrypt cmd (0=Disable, 1=Enable KEY2 Encryption for Commands)"}, + {23, 1, "Data-Word Status (0=Busy, 1=Ready/DRQ) (Read-only)"}, + {24, 3, "Data Block size (0=None, 1..6=100h SHL (1..6) bytes, 7=4 bytes)"}, + {27, 1, "Transfer CLK rate (0=6.7MHz=33.51MHz/5, 1=4.2MHz=33.51MHz/8)"}, + {28, 1, "KEY1 Gap CLKs (0=Hold CLK High during gaps, 1=Output Dummy CLK Pulses)"}, + {29, 1, "RESB Release Reset (0=Reset, 1=Release) (cannot be cleared once set)"}, + {30, 1, "Data Direction 'WR' (0=Normal/read, 1=Write, for FLASH/NAND carts)"}, + {31, 1, "Block Start/Status (0=Ready, 1=Start/Busy) (IRQ See 40001A0h/Bit14)"}, + } }, /* Gamecard bus timing/control */ + { NDS_GCBUS_CMD, "GCBUS_CMD", {0}}, /* Gamecard bus 8-byte command out */ + {NDS_GCBUS_SEED0_LO, "GCBUS_SEED0_LO", {0}}, /* Gamecard Encryption Seed 0 Lower 32bit */ + {NDS_GCBUS_SEED1_LO, "GCBUS_SEED1_LO", {0}}, /* Gamecard Encryption Seed 1 Lower 32bit */ + {NDS_GCBUS_SEED0_HI, "GCBUS_SEED0_HI", {0}}, /* Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused) */ + {NDS_GCBUS_SEED1_HI, "GCBUS_SEED1_HI", {0}}, /* Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused) */ + { NDS7_SPI_BUS_CTL, "SPI_BUS_CTL", { + {0, 2, "Baudrate (0=4MHz/Firmware, 1=2MHz/Touchscr, 2=1MHz/Powerman., 3=512KHz)"}, + {2, 1, "DSi: Baudrate MSB (4=8MHz, 5..7=None/0Hz) (when SCFG_EXT7.bit9=1)"}, + {7, 1, "Busy Flag (0=Ready, 1=Busy) (presumably Read-only)"}, + {8, 2, "Device Select (0=Powerman., 1=Firmware, 2=Touchscr, 3=Reserved)"}, + {10, 1, "Transfer Size (0=8bit/Normal, 1=16bit/Bugged)"}, + {11, 1, "Chipselect Hold (0=Deselect after transfer, 1=Keep selected)"}, + {14, 1, "Interrupt Request (0=Disable, 1=Enable)"}, + {15, 1, "SPI Bus Enable (0=Disable, 1=Enable)"}, + } }, /* SPI bus Control (Firmware, Touchscreen, Powerman) */ + { NDS7_SPI_BUS_DATA, "SPI_BUS_DATA", {0}}, /* SPI bus Data */ // ARM7 Memory and IRQ Control - { NDS7_EXMEMSTAT, "EXMEMSTAT", { - {0,2,"32-pin GBA Slot SRAM Access Time (0-3 = 10, 8, 6, 18 cycles)"}, - {2,2,"32-pin GBA Slot ROM 1st Access Time (0-3 = 10, 8, 6, 18 cycles)"}, - {4,1,"32-pin GBA Slot ROM 2nd Access Time (0-1 = 6, 4 cycles)"}, - {6 ,2, "32-pin GBA Slot PHI-pin out (0-3 = Low, 4.19MHz, 8.38MHz, 16.76MHz)"}, - {7 ,1, "32-pin GBA Slot Access Rights (0=ARM9, 1=ARM7)"}, - {11 ,1, "17-pin NDS Slot Access Rights (0=ARM9, 1=ARM7)"}, - {13 ,1, "NDS:Always set? ;set/tested by DSi bootcode: Main RAM enable, CE2 pin?"}, - {14 ,1, "Main Memory Interface Mode Switch (0=Async/GBA/Reserved, 1=Synchronous)"}, - {15 ,1, "Main Memory Access Priority (0=ARM9 Priority, 1=ARM7 Priority)"}, - }}, /* EXMEMSTAT - External Memory Status */ - { NDS7_WIFIWAITCNT, "WIFIWAITCNT", { 0 }}, /* WIFIWAITCNT */ - { NDS7_IME, "IME", { 0 }}, /* IME - Interrupt Master Enable (R/W) */ - { NDS7_IE, "IE", { - { 0 , 1, "LCD V-Blank" }, - { 1 , 1, "LCD H-Blank" }, - { 2 , 1, "LCD V-Counter Match" }, - { 3 , 1, "Timer 0 Overflow" }, - { 4 , 1, "Timer 1 Overflow" }, - { 5 , 1, "Timer 2 Overflow" }, - { 6 , 1, "Timer 3 Overflow" }, - { 7 , 1, "SIO/RCNT/RTC (Real Time Clock)" }, - { 8 , 1, "DMA 0" }, - { 9 , 1, "DMA 1" }, - { 10, 1, "DMA 2" }, - { 11, 1, "DMA 3" }, - { 12, 1, "Keypad" }, - { 13, 1, "GBA-Slot (external IRQ source) / DSi: None such" }, - { 16, 1, "IPC Sync" }, - { 17, 1, "IPC Send FIFO Empty" }, - { 18, 1, "IPC Recv FIFO Not Empty" }, - { 19, 1, "NDS-Slot Game Card Data Transfer Completion" }, - { 20, 1, "NDS-Slot Game Card IREQ_MC" }, - { 21, 1, "NDS9 only: Geometry Command FIFO" }, - { 22, 1, "NDS7 only: Screens unfolding" }, - { 23, 1, "NDS7 only: SPI bus" }, - { 24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP" }, - { 25, 1, "DSi9: Camera" }, - { 26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh" }, - { 27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?" }, - { 28, 1, "DSi: NewDMA0" }, - { 29, 1, "DSi: NewDMA1" }, - { 30, 1, "DSi: NewDMA2" }, - { 31, 1, "DSi: NewDMA3" }, - }}, /* IE - Interrupt Enable (R/W) */ - { NDS7_IF, "IF", { - { 0 , 1, "LCD V-Blank" }, - { 1 , 1, "LCD H-Blank" }, - { 2 , 1, "LCD V-Counter Match" }, - { 3 , 1, "Timer 0 Overflow" }, - { 4 , 1, "Timer 1 Overflow" }, - { 5 , 1, "Timer 2 Overflow" }, - { 6 , 1, "Timer 3 Overflow" }, - { 7 , 1, "SIO/RCNT/RTC (Real Time Clock)" }, - { 8 , 1, "DMA 0" }, - { 9 , 1, "DMA 1" }, - { 10, 1, "DMA 2" }, - { 11, 1, "DMA 3" }, - { 12, 1, "Keypad" }, - { 13, 1, "GBA-Slot (external IRQ source) / DSi: None such" }, - { 16, 1, "IPC Sync" }, - { 17, 1, "IPC Send FIFO Empty" }, - { 18, 1, "IPC Recv FIFO Not Empty" }, - { 19, 1, "NDS-Slot Game Card Data Transfer Completion" }, - { 20, 1, "NDS-Slot Game Card IREQ_MC" }, - { 21, 1, "NDS9 only: Geometry Command FIFO" }, - { 22, 1, "NDS7 only: Screens unfolding" }, - { 23, 1, "NDS7 only: SPI bus" }, - { 24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP" }, - { 25, 1, "DSi9: Camera" }, - { 26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh" }, - { 27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?" }, - { 28, 1, "DSi: NewDMA0" }, - { 29, 1, "DSi: NewDMA1" }, - { 30, 1, "DSi: NewDMA2" }, - { 31, 1, "DSi: NewDMA3" }, - - }}, /* IF - Interrupt Request Flags (R/W) */ - { NDS7_VRAMSTAT, "VRAMSTAT", { - { 0, 1, "VRAM C enabled and allocated to NDS7 (0=No, 1=Yes)"}, - { 1, 1, "VRAM D enabled and allocated to NDS7 (0=No, 1=Yes)"}, - }}, /* VRAMSTAT - VRAM-C,D Bank Status (R) */ - { NDS7_WRAMSTAT, "WRAMSTAT", { - {0,2, "WRAM Mode ARM9/ARM7 (0-3 = 32K/0K, 2nd 16K/1st 16K, 1st 16K/2nd 16K, 0K/32K)"} - }}, /* WRAMSTAT - WRAM Bank Status (R) */ - { NDS7_POSTFLG, "POSTFLG", { - { 0, 1, "First Boot Flag (0=First, 1=Further)" }, - }}, /* POSTFLG */ - { NDS7_HALTCNT, "HALTCNT", { - { 0, 2, " Power Down Mode (0=No function, 1=Enter GBA Mode, 2=Halt, 3=Sleep)" }, - }}, /* HALTCNT (different bits than on GBA) (plus NOP delay) */ - { NDS7_POWCNT2, "POWCNT2", { - { 0, 1, "Sound Speakers (0=Disable, 1=Enable) (Initial setting = 1)" }, - { 1, 1, "Wifi (0=Disable, 1=Enable) (Initial setting = 0)" }, - }}, /* POWCNT2 Sound/Wifi Power Control Register (R/W) */ - { NDS7_BIOSPROT, "BIOSPROT", { 0 }}, /* BIOSPROT - Bios-data-read-protection address */ - - // ARM7 Sound Registers (Sound Channel 0..15 (10h bytes each)) - { NDS7_SOUND0_CNT, "SOUND0_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 0 Control Register (R/W) */ - { NDS7_SOUND0_SAD, "SOUND0_SAD", { 0 }}, /* Sound Channel 0 Data Source Register (W) */ - { NDS7_SOUND0_TMR, "SOUND0_TMR", { 0 }}, /* Sound Channel 0 Timer Register (W) */ - { NDS7_SOUND0_PNT, "SOUND0_PNT", { 0 }}, /* Sound Channel 0 Loopstart Register (W) */ - { NDS7_SOUND0_LEN, "SOUND0_LEN", { 0 }}, /* Sound Channel 0 Length Register (W) */ - { NDS7_SOUND1_CNT, "SOUND1_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 1 Control Register (R/W) */ - { NDS7_SOUND1_SAD, "SOUND1_SAD", { 0 }}, /* Sound Channel 1 Data Source Register (W) */ - { NDS7_SOUND1_TMR, "SOUND1_TMR", { 0 }}, /* Sound Channel 1 Timer Register (W) */ - { NDS7_SOUND1_PNT, "SOUND1_PNT", { 0 }}, /* Sound Channel 1 Loopstart Register (W) */ - { NDS7_SOUND1_LEN, "SOUND1_LEN", { 0 }}, /* Sound Channel 1 Length Register (W) */ - { NDS7_SOUND2_CNT, "SOUND2_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 2 Control Register (R/W) */ - { NDS7_SOUND2_SAD, "SOUND2_SAD", { 0 }}, /* Sound Channel 2 Data Source Register (W) */ - { NDS7_SOUND2_TMR, "SOUND2_TMR", { 0 }}, /* Sound Channel 2 Timer Register (W) */ - { NDS7_SOUND2_PNT, "SOUND2_PNT", { 0 }}, /* Sound Channel 2 Loopstart Register (W) */ - { NDS7_SOUND2_LEN, "SOUND2_LEN", { 0 }}, /* Sound Channel 2 Length Register (W) */ - { NDS7_SOUND3_CNT, "SOUND3_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 3 Control Register (R/W) */ - { NDS7_SOUND3_SAD, "SOUND3_SAD", { 0 }}, /* Sound Channel 3 Data Source Register (W) */ - { NDS7_SOUND3_TMR, "SOUND3_TMR", { 0 }}, /* Sound Channel 3 Timer Register (W) */ - { NDS7_SOUND3_PNT, "SOUND3_PNT", { 0 }}, /* Sound Channel 3 Loopstart Register (W) */ - { NDS7_SOUND3_LEN, "SOUND3_LEN", { 0 }}, /* Sound Channel 3 Length Register (W) */ - { NDS7_SOUND4_CNT, "SOUND4_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 4 Control Register (R/W) */ - { NDS7_SOUND4_SAD, "SOUND4_SAD", { 0 }}, /* Sound Channel 4 Data Source Register (W) */ - { NDS7_SOUND4_TMR, "SOUND4_TMR", { 0 }}, /* Sound Channel 4 Timer Register (W) */ - { NDS7_SOUND4_PNT, "SOUND4_PNT", { 0 }}, /* Sound Channel 4 Loopstart Register (W) */ - { NDS7_SOUND4_LEN, "SOUND4_LEN", { 0 }}, /* Sound Channel 4 Length Register (W) */ - { NDS7_SOUND5_CNT, "SOUND5_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 5 Control Register (R/W) */ - { NDS7_SOUND5_SAD, "SOUND5_SAD", { 0 }}, /* Sound Channel 5 Data Source Register (W) */ - { NDS7_SOUND5_TMR, "SOUND5_TMR", { 0 }}, /* Sound Channel 5 Timer Register (W) */ - { NDS7_SOUND5_PNT, "SOUND5_PNT", { 0 }}, /* Sound Channel 5 Loopstart Register (W) */ - { NDS7_SOUND5_LEN, "SOUND5_LEN", { 0 }}, /* Sound Channel 5 Length Register (W) */ - { NDS7_SOUND6_CNT, "SOUND6_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 6 Control Register (R/W) */ - { NDS7_SOUND6_SAD, "SOUND6_SAD", { 0 }}, /* Sound Channel 6 Data Source Register (W) */ - { NDS7_SOUND6_TMR, "SOUND6_TMR", { 0 }}, /* Sound Channel 6 Timer Register (W) */ - { NDS7_SOUND6_PNT, "SOUND6_PNT", { 0 }}, /* Sound Channel 6 Loopstart Register (W) */ - { NDS7_SOUND6_LEN, "SOUND6_LEN", { 0 }}, /* Sound Channel 6 Length Register (W) */ - { NDS7_SOUND7_CNT, "SOUND7_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 7 Control Register (R/W) */ - { NDS7_SOUND7_SAD, "SOUND7_SAD", { 0 }}, /* Sound Channel 7 Data Source Register (W) */ - { NDS7_SOUND7_TMR, "SOUND7_TMR", { 0 }}, /* Sound Channel 7 Timer Register (W) */ - { NDS7_SOUND7_PNT, "SOUND7_PNT", { 0 }}, /* Sound Channel 7 Loopstart Register (W) */ - { NDS7_SOUND7_LEN, "SOUND7_LEN", { 0 }}, /* Sound Channel 7 Length Register (W) */ - { NDS7_SOUND8_CNT, "SOUND8_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 8 Control Register (R/W) */ - { NDS7_SOUND8_SAD, "SOUND8_SAD", { 0 }}, /* Sound Channel 8 Data Source Register (W) */ - { NDS7_SOUND8_TMR, "SOUND8_TMR", { 0 }}, /* Sound Channel 8 Timer Register (W) */ - { NDS7_SOUND8_PNT, "SOUND8_PNT", { 0 }}, /* Sound Channel 8 Loopstart Register (W) */ - { NDS7_SOUND8_LEN, "SOUND8_LEN", { 0 }}, /* Sound Channel 8 Length Register (W) */ - { NDS7_SOUND9_CNT, "SOUND9_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 9 Control Register (R/W) */ - { NDS7_SOUND9_SAD, "SOUND9_SAD", { 0 }}, /* Sound Channel 9 Data Source Register (W) */ - { NDS7_SOUND9_TMR, "SOUND9_TMR", { 0 }}, /* Sound Channel 9 Timer Register (W) */ - { NDS7_SOUND9_PNT, "SOUND9_PNT", { 0 }}, /* Sound Channel 9 Loopstart Register (W) */ - { NDS7_SOUND9_LEN, "SOUND9_LEN", { 0 }}, /* Sound Channel 9 Length Register (W) */ - { NDS7_SOUNDA_CNT, "SOUNDA_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 10 Control Register (R/W) */ - { NDS7_SOUNDA_SAD, "SOUNDA_SAD", { 0 }}, /* Sound Channel 10 Data Source Register (W) */ - { NDS7_SOUNDA_TMR, "SOUNDA_TMR", { 0 }}, /* Sound Channel 10 Timer Register (W) */ - { NDS7_SOUNDA_PNT, "SOUNDA_PNT", { 0 }}, /* Sound Channel 10 Loopstart Register (W) */ - { NDS7_SOUNDA_LEN, "SOUNDA_LEN", { 0 }}, /* Sound Channel 10 Length Register (W) */ - { NDS7_SOUNDB_CNT, "SOUNDB_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 11 Control Register (R/W) */ - { NDS7_SOUNDB_SAD, "SOUNDB_SAD", { 0 }}, /* Sound Channel 11 Data Source Register (W) */ - { NDS7_SOUNDB_TMR, "SOUNDB_TMR", { 0 }}, /* Sound Channel 11 Timer Register (W) */ - { NDS7_SOUNDB_PNT, "SOUNDB_PNT", { 0 }}, /* Sound Channel 11 Loopstart Register (W) */ - { NDS7_SOUNDB_LEN, "SOUNDB_LEN", { 0 }}, /* Sound Channel 11 Length Register (W) */ - { NDS7_SOUNDC_CNT, "SOUNDC_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 12 Control Register (R/W) */ - { NDS7_SOUNDC_SAD, "SOUNDC_SAD", { 0 }}, /* Sound Channel 12 Data Source Register (W) */ - { NDS7_SOUNDC_TMR, "SOUNDC_TMR", { 0 }}, /* Sound Channel 12 Timer Register (W) */ - { NDS7_SOUNDC_PNT, "SOUNDC_PNT", { 0 }}, /* Sound Channel 12 Loopstart Register (W) */ - { NDS7_SOUNDC_LEN, "SOUNDC_LEN", { 0 }}, /* Sound Channel 12 Length Register (W) */ - { NDS7_SOUNDD_CNT, "SOUNDD_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 13 Control Register (R/W) */ - { NDS7_SOUNDD_SAD, "SOUNDD_SAD", { 0 }}, /* Sound Channel 13 Data Source Register (W) */ - { NDS7_SOUNDD_TMR, "SOUNDD_TMR", { 0 }}, /* Sound Channel 13 Timer Register (W) */ - { NDS7_SOUNDD_PNT, "SOUNDD_PNT", { 0 }}, /* Sound Channel 13 Loopstart Register (W) */ - { NDS7_SOUNDD_LEN, "SOUNDD_LEN", { 0 }}, /* Sound Channel 13 Length Register (W) */ - { NDS7_SOUNDE_CNT, "SOUNDE_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 14 Control Register (R/W) */ - { NDS7_SOUNDE_SAD, "SOUNDE_SAD", { 0 }}, /* Sound Channel 14 Data Source Register (W) */ - { NDS7_SOUNDE_TMR, "SOUNDE_TMR", { 0 }}, /* Sound Channel 14 Timer Register (W) */ - { NDS7_SOUNDE_PNT, "SOUNDE_PNT", { 0 }}, /* Sound Channel 14 Loopstart Register (W) */ - { NDS7_SOUNDE_LEN, "SOUNDE_LEN", { 0 }}, /* Sound Channel 14 Length Register (W) */ - { NDS7_SOUNDF_CNT, "SOUNDF_CNT", { - { 0, 7, "Volume Mul (0..127=silent..loud)" }, - { 7, 1, "Not used (always zero)" }, - { 8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)" }, - { 10,5, "Not used (always zero)" }, - { 15,1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)" }, - { 16,7, "Panning (0..127=left..right) (64=half volume on both speakers)" }, - { 23,1, "Not used (always zero)" }, - { 24,3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)" }, - { 27,2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)" }, - { 29,2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)" }, - { 31,1, "Start/Status (0=Stop, 1=Start/Busy)" }, - }}, /* Sound Channel 15 Control Register (R/W) */ - { NDS7_SOUNDF_SAD, "SOUNDF_SAD", { 0 }}, /* Sound Channel 15 Data Source Register (W) */ - { NDS7_SOUNDF_TMR, "SOUNDF_TMR", { 0 }}, /* Sound Channel 15 Timer Register (W) */ - { NDS7_SOUNDF_PNT, "SOUNDF_PNT", { 0 }}, /* Sound Channel 15 Loopstart Register (W) */ - { NDS7_SOUNDF_LEN, "SOUNDF_LEN", { 0 }}, /* Sound Channel 15 Length Register (W) */ - - { NDS7_SOUNDCNT, "SOUNDCNT", { 0 }}, /* Sound Control Register (R/W) */ - { NDS7_SOUNDBIAS, "SOUNDBIAS", { 0 }}, /* Sound Bias Register (R/W) */ - { NDS7_SNDCAP0CNT, "SNDCAP0CNT", { - {0,1, "Output Sound Channel 1 (0=As is, 1=Add to Channel 0)"}, - {1,1, "Capture 0 Source (0=Left Mixer, 1=Channel 0/Bugged)"}, - {2,1, "Capture Repeat (0=Loop, 1=One-shot)"}, - {3,1, "Capture Format (0=PCM16, 1=PCM8)"}, - {7,1, "Capture Start/Status (0=Stop, 1=Start/Busy)"}, - }}, /* Sound Capture 0 Control Register (R/W) */ - { NDS7_SNDCAP1CNT, "SNDCAP1CNT", { - {0,1, "Output Sound Channel 3 (0=As is, 1=Add to Channel 2)"}, - {1,1, "Capture 1 Source (0=Left Mixer, 1=Channel 0/Bugged)"}, - {2,1, "Capture Repeat (0=Loop, 1=One-shot)"}, - {3,1, "Capture Format (0=PCM16, 1=PCM8)"}, - {7,1, "Capture Start/Status (0=Stop, 1=Start/Busy)"}, - }}, /* Sound Capture 1 Control Register (R/W) */ - { NDS7_SNDCAP0DAD, "SNDCAP0DAD", { 0 }}, /* Sound Capture 0 Destination Address (R/W) */ - { NDS7_SNDCAP0LEN, "SNDCAP0LEN", { 0 }}, /* Sound Capture 0 Length (W) */ - { NDS7_SNDCAP1DAD, "SNDCAP1DAD", { 0 }}, /* Sound Capture 1 Destination Address (R/W) */ - { NDS7_SNDCAP1LEN, "SNDCAP1LEN", { 0 }}, /* Sound Capture 1 Length (W) */ - + { NDS7_EXMEMSTAT, "EXMEMSTAT", { + {0, 2, "32-pin GBA Slot SRAM Access Time (0-3 = 10, 8, 6, 18 cycles)"}, + {2, 2, "32-pin GBA Slot ROM 1st Access Time (0-3 = 10, 8, 6, 18 cycles)"}, + {4, 1, "32-pin GBA Slot ROM 2nd Access Time (0-1 = 6, 4 cycles)"}, + {6, 2, "32-pin GBA Slot PHI-pin out (0-3 = Low, 4.19MHz, 8.38MHz, 16.76MHz)"}, + {7, 1, "32-pin GBA Slot Access Rights (0=ARM9, 1=ARM7)"}, + {11, 1, "17-pin NDS Slot Access Rights (0=ARM9, 1=ARM7)"}, + {13, 1, "NDS:Always set? ;set/tested by DSi bootcode: Main RAM enable, CE2 pin?"}, + {14, 1, "Main Memory Interface Mode Switch (0=Async/GBA/Reserved, 1=Synchronous)"}, + {15, 1, "Main Memory Access Priority (0=ARM9 Priority, 1=ARM7 Priority)"}, + } }, /* EXMEMSTAT - External Memory Status */ + { NDS7_WIFIWAITCNT, "WIFIWAITCNT", {0}}, /* WIFIWAITCNT */ + { NDS7_IME, "IME", {0}}, /* IME - Interrupt Master Enable (R/W) */ + { NDS7_IE, "IE", { + {0, 1, "LCD V-Blank"}, + {1, 1, "LCD H-Blank"}, + {2, 1, "LCD V-Counter Match"}, + {3, 1, "Timer 0 Overflow"}, + {4, 1, "Timer 1 Overflow"}, + {5, 1, "Timer 2 Overflow"}, + {6, 1, "Timer 3 Overflow"}, + {7, 1, "SIO/RCNT/RTC (Real Time Clock)"}, + {8, 1, "DMA 0"}, + {9, 1, "DMA 1"}, + {10, 1, "DMA 2"}, + {11, 1, "DMA 3"}, + {12, 1, "Keypad"}, + {13, 1, "GBA-Slot (external IRQ source) / DSi: None such"}, + {16, 1, "IPC Sync"}, + {17, 1, "IPC Send FIFO Empty"}, + {18, 1, "IPC Recv FIFO Not Empty"}, + {19, 1, "NDS-Slot Game Card Data Transfer Completion"}, + {20, 1, "NDS-Slot Game Card IREQ_MC"}, + {21, 1, "NDS9 only: Geometry Command FIFO"}, + {22, 1, "NDS7 only: Screens unfolding"}, + {23, 1, "NDS7 only: SPI bus"}, + {24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP"}, + {25, 1, "DSi9: Camera"}, + {26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh"}, + {27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?"}, + {28, 1, "DSi: NewDMA0"}, + {29, 1, "DSi: NewDMA1"}, + {30, 1, "DSi: NewDMA2"}, + {31, 1, "DSi: NewDMA3"}, + } }, /* IE - Interrupt Enable (R/W) */ + { NDS7_IF, "IF", { + {0, 1, "LCD V-Blank"}, + {1, 1, "LCD H-Blank"}, + {2, 1, "LCD V-Counter Match"}, + {3, 1, "Timer 0 Overflow"}, + {4, 1, "Timer 1 Overflow"}, + {5, 1, "Timer 2 Overflow"}, + {6, 1, "Timer 3 Overflow"}, + {7, 1, "SIO/RCNT/RTC (Real Time Clock)"}, + {8, 1, "DMA 0"}, + {9, 1, "DMA 1"}, + {10, 1, "DMA 2"}, + {11, 1, "DMA 3"}, + {12, 1, "Keypad"}, + {13, 1, "GBA-Slot (external IRQ source) / DSi: None such"}, + {16, 1, "IPC Sync"}, + {17, 1, "IPC Send FIFO Empty"}, + {18, 1, "IPC Recv FIFO Not Empty"}, + {19, 1, "NDS-Slot Game Card Data Transfer Completion"}, + {20, 1, "NDS-Slot Game Card IREQ_MC"}, + {21, 1, "NDS9 only: Geometry Command FIFO"}, + {22, 1, "NDS7 only: Screens unfolding"}, + {23, 1, "NDS7 only: SPI bus"}, + {24, 1, "NDS7 only: Wifi DSi9: XpertTeak DSP"}, + {25, 1, "DSi9: Camera"}, + {26, 1, "DSi9: Undoc, IF.26 set on FFh-filling 40021Axh"}, + {27, 1, "DSi: Maybe IREQ_MC for 2nd gamecard?"}, + {28, 1, "DSi: NewDMA0"}, + {29, 1, "DSi: NewDMA1"}, + {30, 1, "DSi: NewDMA2"}, + {31, 1, "DSi: NewDMA3"}, + + } }, /* IF - Interrupt Request Flags (R/W) */ + { NDS7_VRAMSTAT, "VRAMSTAT", { + {0, 1, "VRAM C enabled and allocated to NDS7 (0=No, 1=Yes)"}, + {1, 1, "VRAM D enabled and allocated to NDS7 (0=No, 1=Yes)"}, + } }, /* VRAMSTAT - VRAM-C,D Bank Status (R) */ + { NDS7_WRAMSTAT, "WRAMSTAT", {{0, 2, "WRAM Mode ARM9/ARM7 (0-3 = 32K/0K, 2nd 16K/1st 16K, 1st 16K/2nd 16K, 0K/32K)"}}}, /* WRAMSTAT - WRAM Bank Status (R) */ + { NDS7_POSTFLG, "POSTFLG", { + {0, 1, "First Boot Flag (0=First, 1=Further)"}, + } }, /* POSTFLG */ + { NDS7_HALTCNT, "HALTCNT", { + {0, 2, " Power Down Mode (0=No function, 1=Enter GBA Mode, 2=Halt, 3=Sleep)"}, + } }, /* HALTCNT (different bits than on GBA) (plus NOP delay) */ + { NDS7_POWCNT2, "POWCNT2", { + {0, 1, "Sound Speakers (0=Disable, 1=Enable) (Initial setting = 1)"}, + {1, 1, "Wifi (0=Disable, 1=Enable) (Initial setting = 0)"}, + } }, /* POWCNT2 Sound/Wifi Power Control Register (R/W) */ + { NDS7_BIOSPROT, "BIOSPROT", {0}}, /* BIOSPROT - Bios-data-read-protection address */ + + // ARM7 Sound Registers (Sound Channel 0..15 (10h bytes each)) + { NDS7_SOUND0_CNT, "SOUND0_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 0 Control Register (R/W) */ + { NDS7_SOUND0_SAD, "SOUND0_SAD", {0}}, /* Sound Channel 0 Data Source Register (W) */ + { NDS7_SOUND0_TMR, "SOUND0_TMR", {0}}, /* Sound Channel 0 Timer Register (W) */ + { NDS7_SOUND0_PNT, "SOUND0_PNT", {0}}, /* Sound Channel 0 Loopstart Register (W) */ + { NDS7_SOUND0_LEN, "SOUND0_LEN", {0}}, /* Sound Channel 0 Length Register (W) */ + { NDS7_SOUND1_CNT, "SOUND1_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 1 Control Register (R/W) */ + { NDS7_SOUND1_SAD, "SOUND1_SAD", {0}}, /* Sound Channel 1 Data Source Register (W) */ + { NDS7_SOUND1_TMR, "SOUND1_TMR", {0}}, /* Sound Channel 1 Timer Register (W) */ + { NDS7_SOUND1_PNT, "SOUND1_PNT", {0}}, /* Sound Channel 1 Loopstart Register (W) */ + { NDS7_SOUND1_LEN, "SOUND1_LEN", {0}}, /* Sound Channel 1 Length Register (W) */ + { NDS7_SOUND2_CNT, "SOUND2_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 2 Control Register (R/W) */ + { NDS7_SOUND2_SAD, "SOUND2_SAD", {0}}, /* Sound Channel 2 Data Source Register (W) */ + { NDS7_SOUND2_TMR, "SOUND2_TMR", {0}}, /* Sound Channel 2 Timer Register (W) */ + { NDS7_SOUND2_PNT, "SOUND2_PNT", {0}}, /* Sound Channel 2 Loopstart Register (W) */ + { NDS7_SOUND2_LEN, "SOUND2_LEN", {0}}, /* Sound Channel 2 Length Register (W) */ + { NDS7_SOUND3_CNT, "SOUND3_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 3 Control Register (R/W) */ + { NDS7_SOUND3_SAD, "SOUND3_SAD", {0}}, /* Sound Channel 3 Data Source Register (W) */ + { NDS7_SOUND3_TMR, "SOUND3_TMR", {0}}, /* Sound Channel 3 Timer Register (W) */ + { NDS7_SOUND3_PNT, "SOUND3_PNT", {0}}, /* Sound Channel 3 Loopstart Register (W) */ + { NDS7_SOUND3_LEN, "SOUND3_LEN", {0}}, /* Sound Channel 3 Length Register (W) */ + { NDS7_SOUND4_CNT, "SOUND4_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 4 Control Register (R/W) */ + { NDS7_SOUND4_SAD, "SOUND4_SAD", {0}}, /* Sound Channel 4 Data Source Register (W) */ + { NDS7_SOUND4_TMR, "SOUND4_TMR", {0}}, /* Sound Channel 4 Timer Register (W) */ + { NDS7_SOUND4_PNT, "SOUND4_PNT", {0}}, /* Sound Channel 4 Loopstart Register (W) */ + { NDS7_SOUND4_LEN, "SOUND4_LEN", {0}}, /* Sound Channel 4 Length Register (W) */ + { NDS7_SOUND5_CNT, "SOUND5_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 5 Control Register (R/W) */ + { NDS7_SOUND5_SAD, "SOUND5_SAD", {0}}, /* Sound Channel 5 Data Source Register (W) */ + { NDS7_SOUND5_TMR, "SOUND5_TMR", {0}}, /* Sound Channel 5 Timer Register (W) */ + { NDS7_SOUND5_PNT, "SOUND5_PNT", {0}}, /* Sound Channel 5 Loopstart Register (W) */ + { NDS7_SOUND5_LEN, "SOUND5_LEN", {0}}, /* Sound Channel 5 Length Register (W) */ + { NDS7_SOUND6_CNT, "SOUND6_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 6 Control Register (R/W) */ + { NDS7_SOUND6_SAD, "SOUND6_SAD", {0}}, /* Sound Channel 6 Data Source Register (W) */ + { NDS7_SOUND6_TMR, "SOUND6_TMR", {0}}, /* Sound Channel 6 Timer Register (W) */ + { NDS7_SOUND6_PNT, "SOUND6_PNT", {0}}, /* Sound Channel 6 Loopstart Register (W) */ + { NDS7_SOUND6_LEN, "SOUND6_LEN", {0}}, /* Sound Channel 6 Length Register (W) */ + { NDS7_SOUND7_CNT, "SOUND7_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 7 Control Register (R/W) */ + { NDS7_SOUND7_SAD, "SOUND7_SAD", {0}}, /* Sound Channel 7 Data Source Register (W) */ + { NDS7_SOUND7_TMR, "SOUND7_TMR", {0}}, /* Sound Channel 7 Timer Register (W) */ + { NDS7_SOUND7_PNT, "SOUND7_PNT", {0}}, /* Sound Channel 7 Loopstart Register (W) */ + { NDS7_SOUND7_LEN, "SOUND7_LEN", {0}}, /* Sound Channel 7 Length Register (W) */ + { NDS7_SOUND8_CNT, "SOUND8_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 8 Control Register (R/W) */ + { NDS7_SOUND8_SAD, "SOUND8_SAD", {0}}, /* Sound Channel 8 Data Source Register (W) */ + { NDS7_SOUND8_TMR, "SOUND8_TMR", {0}}, /* Sound Channel 8 Timer Register (W) */ + { NDS7_SOUND8_PNT, "SOUND8_PNT", {0}}, /* Sound Channel 8 Loopstart Register (W) */ + { NDS7_SOUND8_LEN, "SOUND8_LEN", {0}}, /* Sound Channel 8 Length Register (W) */ + { NDS7_SOUND9_CNT, "SOUND9_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 9 Control Register (R/W) */ + { NDS7_SOUND9_SAD, "SOUND9_SAD", {0}}, /* Sound Channel 9 Data Source Register (W) */ + { NDS7_SOUND9_TMR, "SOUND9_TMR", {0}}, /* Sound Channel 9 Timer Register (W) */ + { NDS7_SOUND9_PNT, "SOUND9_PNT", {0}}, /* Sound Channel 9 Loopstart Register (W) */ + { NDS7_SOUND9_LEN, "SOUND9_LEN", {0}}, /* Sound Channel 9 Length Register (W) */ + { NDS7_SOUNDA_CNT, "SOUNDA_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 10 Control Register (R/W) */ + { NDS7_SOUNDA_SAD, "SOUNDA_SAD", {0}}, /* Sound Channel 10 Data Source Register (W) */ + { NDS7_SOUNDA_TMR, "SOUNDA_TMR", {0}}, /* Sound Channel 10 Timer Register (W) */ + { NDS7_SOUNDA_PNT, "SOUNDA_PNT", {0}}, /* Sound Channel 10 Loopstart Register (W) */ + { NDS7_SOUNDA_LEN, "SOUNDA_LEN", {0}}, /* Sound Channel 10 Length Register (W) */ + { NDS7_SOUNDB_CNT, "SOUNDB_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 11 Control Register (R/W) */ + { NDS7_SOUNDB_SAD, "SOUNDB_SAD", {0}}, /* Sound Channel 11 Data Source Register (W) */ + { NDS7_SOUNDB_TMR, "SOUNDB_TMR", {0}}, /* Sound Channel 11 Timer Register (W) */ + { NDS7_SOUNDB_PNT, "SOUNDB_PNT", {0}}, /* Sound Channel 11 Loopstart Register (W) */ + { NDS7_SOUNDB_LEN, "SOUNDB_LEN", {0}}, /* Sound Channel 11 Length Register (W) */ + { NDS7_SOUNDC_CNT, "SOUNDC_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 12 Control Register (R/W) */ + { NDS7_SOUNDC_SAD, "SOUNDC_SAD", {0}}, /* Sound Channel 12 Data Source Register (W) */ + { NDS7_SOUNDC_TMR, "SOUNDC_TMR", {0}}, /* Sound Channel 12 Timer Register (W) */ + { NDS7_SOUNDC_PNT, "SOUNDC_PNT", {0}}, /* Sound Channel 12 Loopstart Register (W) */ + { NDS7_SOUNDC_LEN, "SOUNDC_LEN", {0}}, /* Sound Channel 12 Length Register (W) */ + { NDS7_SOUNDD_CNT, "SOUNDD_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 13 Control Register (R/W) */ + { NDS7_SOUNDD_SAD, "SOUNDD_SAD", {0}}, /* Sound Channel 13 Data Source Register (W) */ + { NDS7_SOUNDD_TMR, "SOUNDD_TMR", {0}}, /* Sound Channel 13 Timer Register (W) */ + { NDS7_SOUNDD_PNT, "SOUNDD_PNT", {0}}, /* Sound Channel 13 Loopstart Register (W) */ + { NDS7_SOUNDD_LEN, "SOUNDD_LEN", {0}}, /* Sound Channel 13 Length Register (W) */ + { NDS7_SOUNDE_CNT, "SOUNDE_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 14 Control Register (R/W) */ + { NDS7_SOUNDE_SAD, "SOUNDE_SAD", {0}}, /* Sound Channel 14 Data Source Register (W) */ + { NDS7_SOUNDE_TMR, "SOUNDE_TMR", {0}}, /* Sound Channel 14 Timer Register (W) */ + { NDS7_SOUNDE_PNT, "SOUNDE_PNT", {0}}, /* Sound Channel 14 Loopstart Register (W) */ + { NDS7_SOUNDE_LEN, "SOUNDE_LEN", {0}}, /* Sound Channel 14 Length Register (W) */ + { NDS7_SOUNDF_CNT, "SOUNDF_CNT", { + {0, 7, "Volume Mul (0..127=silent..loud)"}, + {7, 1, "Not used (always zero)"}, + {8, 2, "Volume Div (0=Normal, 1=Div2, 2=Div4, 3=Div16)"}, + {10, 5, "Not used (always zero)"}, + {15, 1, "Hold (0=Normal, 1=Hold last sample after one-shot sound)"}, + {16, 7, "Panning (0..127=left..right) (64=half volume on both speakers)"}, + {23, 1, "Not used (always zero)"}, + {24, 3, "Wave Duty (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)"}, + {27, 2, "Repeat Mode (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)"}, + {29, 2, "Format (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)"}, + {31, 1, "Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Channel 15 Control Register (R/W) */ + { NDS7_SOUNDF_SAD, "SOUNDF_SAD", {0}}, /* Sound Channel 15 Data Source Register (W) */ + { NDS7_SOUNDF_TMR, "SOUNDF_TMR", {0}}, /* Sound Channel 15 Timer Register (W) */ + { NDS7_SOUNDF_PNT, "SOUNDF_PNT", {0}}, /* Sound Channel 15 Loopstart Register (W) */ + { NDS7_SOUNDF_LEN, "SOUNDF_LEN", {0}}, /* Sound Channel 15 Length Register (W) */ + + { NDS7_SOUNDCNT, "SOUNDCNT", {0}}, /* Sound Control Register (R/W) */ + { NDS7_SOUNDBIAS, "SOUNDBIAS", {0}}, /* Sound Bias Register (R/W) */ + { NDS7_SNDCAP0CNT, "SNDCAP0CNT", { + {0, 1, "Output Sound Channel 1 (0=As is, 1=Add to Channel 0)"}, + {1, 1, "Capture 0 Source (0=Left Mixer, 1=Channel 0/Bugged)"}, + {2, 1, "Capture Repeat (0=Loop, 1=One-shot)"}, + {3, 1, "Capture Format (0=PCM16, 1=PCM8)"}, + {7, 1, "Capture Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Capture 0 Control Register (R/W) */ + { NDS7_SNDCAP1CNT, "SNDCAP1CNT", { + {0, 1, "Output Sound Channel 3 (0=As is, 1=Add to Channel 2)"}, + {1, 1, "Capture 1 Source (0=Left Mixer, 1=Channel 0/Bugged)"}, + {2, 1, "Capture Repeat (0=Loop, 1=One-shot)"}, + {3, 1, "Capture Format (0=PCM16, 1=PCM8)"}, + {7, 1, "Capture Start/Status (0=Stop, 1=Start/Busy)"}, + } }, /* Sound Capture 1 Control Register (R/W) */ + { NDS7_SNDCAP0DAD, "SNDCAP0DAD", {0}}, /* Sound Capture 0 Destination Address (R/W) */ + { NDS7_SNDCAP0LEN, "SNDCAP0LEN", {0}}, /* Sound Capture 0 Length (W) */ + { NDS7_SNDCAP1DAD, "SNDCAP1DAD", {0}}, /* Sound Capture 1 Destination Address (R/W) */ + { NDS7_SNDCAP1LEN, "SNDCAP1LEN", {0}}, /* Sound Capture 1 Length (W) */ }; // Interrupt sources -#define GBA_INT_LCD_VBLANK 0 -#define GBA_INT_LCD_HBLANK 1 -#define GBA_INT_LCD_VCOUNT 2 -#define GBA_INT_TIMER0 3 -#define GBA_INT_TIMER1 4 -#define GBA_INT_TIMER2 5 -#define GBA_INT_TIMER3 6 -#define GBA_INT_SERIAL 7 -#define GBA_INT_DMA0 8 -#define GBA_INT_DMA1 9 -#define GBA_INT_DMA2 10 -#define GBA_INT_DMA3 11 -#define GBA_INT_KEYPAD 12 -#define GBA_INT_GAMEPAK 13 - -#define NDS_INT_IPC_SYNC 16 /* IPC Sync */ -#define NDS_INT_IPC_FIFO_SEND 17 /* IPC Send FIFO Empty */ -#define NDS_INT_IPC_FIFO_RECV 18 /* IPC Recv FIFO Not Empty */ -#define NDS_INT_GC_TRANSFER_DONE 19 /* NDS-Slot Game Card Data Transfer Completion */ -#define NDS_INT_GC_IREQ_MC 20 /* NDS-Slot Game Card IREQ_MC */ -#define NDS9_INT_GX_FIFO 21 /* NDS9 only: Geometry Command FIFO */ -#define NDS7_INT_SCREEN_FOLD 22 /* NDS7 only: Screens unfolding */ -#define NDS7_INT_SPI 23 /* NDS7 only: SPI bus */ -#define NDS7_WIFI 24 /* NDS7 only: Wifi / DSi9: XpertTeak DSP */ -#define NDSi9_DSP 24 /* NDS7 only: Wifi / DSi9: XpertTeak DSP */ - -#define NDSi9_CAMERA 25 /* Not used / DSi9: Camera */ -#define NDSi9_UNDOC 26 /* Not used / DSi9: Undoc, IF.26 set on FFh-filling 40021Axh */ -#define NDSi_IREQ_MC 27 /* Not used / DSi: Maybe IREQ_MC for 2nd gamecard? */ -#define NDSi_DMA0 28 /* Not used / DSi: NewDMA0 */ -#define NDSi_DMA1 29 /* Not used / DSi: NewDMA1 */ -#define NDSi_DMA2 30 /* Not used / DSi: NewDMA2 */ -#define NDSi_DMA3 31 /* Not used / DSi: NewDMA3 */ - -#define GBA_BG_PALETTE 0x00000000 -#define GBA_OBJ_PALETTE 0x00000200 -#define GBA_OBJ_TILES0_2 0x00010000 -#define GBA_OBJ_TILES3_5 0x00014000 -#define GBA_OAM 0x07000000 +#define GBA_INT_LCD_VBLANK 0 +#define GBA_INT_LCD_HBLANK 1 +#define GBA_INT_LCD_VCOUNT 2 +#define GBA_INT_TIMER0 3 +#define GBA_INT_TIMER1 4 +#define GBA_INT_TIMER2 5 +#define GBA_INT_TIMER3 6 +#define GBA_INT_SERIAL 7 +#define GBA_INT_DMA0 8 +#define GBA_INT_DMA1 9 +#define GBA_INT_DMA2 10 +#define GBA_INT_DMA3 11 +#define GBA_INT_KEYPAD 12 +#define GBA_INT_GAMEPAK 13 + +#define NDS_INT_IPC_SYNC 16 /* IPC Sync */ +#define NDS_INT_IPC_FIFO_SEND 17 /* IPC Send FIFO Empty */ +#define NDS_INT_IPC_FIFO_RECV 18 /* IPC Recv FIFO Not Empty */ +#define NDS_INT_GC_TRANSFER_DONE 19 /* NDS-Slot Game Card Data Transfer Completion */ +#define NDS_INT_GC_IREQ_MC 20 /* NDS-Slot Game Card IREQ_MC */ +#define NDS9_INT_GX_FIFO 21 /* NDS9 only: Geometry Command FIFO */ +#define NDS7_INT_SCREEN_FOLD 22 /* NDS7 only: Screens unfolding */ +#define NDS7_INT_SPI 23 /* NDS7 only: SPI bus */ +#define NDS7_WIFI 24 /* NDS7 only: Wifi / DSi9: XpertTeak DSP */ +#define NDSi9_DSP 24 /* NDS7 only: Wifi / DSi9: XpertTeak DSP */ + +#define NDSi9_CAMERA 25 /* Not used / DSi9: Camera */ +#define NDSi9_UNDOC 26 /* Not used / DSi9: Undoc, IF.26 set on FFh-filling 40021Axh */ +#define NDSi_IREQ_MC 27 /* Not used / DSi: Maybe IREQ_MC for 2nd gamecard? */ +#define NDSi_DMA0 28 /* Not used / DSi: NewDMA0 */ +#define NDSi_DMA1 29 /* Not used / DSi: NewDMA1 */ +#define NDSi_DMA2 30 /* Not used / DSi: NewDMA2 */ +#define NDSi_DMA3 31 /* Not used / DSi: NewDMA3 */ + +#define GBA_BG_PALETTE 0x00000000 +#define GBA_OBJ_PALETTE 0x00000200 +#define GBA_OBJ_TILES0_2 0x00010000 +#define GBA_OBJ_TILES3_5 0x00014000 +#define GBA_OAM 0x07000000 #define GBA_BACKUP_NONE 0 #define GBA_BACKUP_EEPROM 1 #define GBA_BACKUP_EEPROM_512B 2 #define GBA_BACKUP_EEPROM_8KB 3 #define GBA_BACKUP_SRAM 4 -#define GBA_BACKUP_FLASH_64K 5 -#define GBA_BACKUP_FLASH_128K 6 +#define GBA_BACKUP_FLASH_64K 5 +#define GBA_BACKUP_FLASH_128K 6 #define GBA_REQ_1B 0x01 #define GBA_REQ_2B 0x02 @@ -1844,56 +1855,56 @@ mmio_reg_t nds7_io_reg_desc[]={ #define NDS_LCD_W 256 #define NDS_LCD_H 192 -#define NDS_VRAM_BGA_SLOT0 0x06A00000 -#define NDS_VRAM_BGB_SLOT0 0x06B00000 -#define NDS_VRAM_OBJA_SLOT0 0x06C00000 -#define NDS_VRAM_OBJB_SLOT0 0x06D00000 -#define NDS_VRAM_TEX_SLOT0 0x06E00000 -#define NDS_VRAM_TEX_SLOT1 (0x06E00000 + 128*1024) -#define NDS_VRAM_TEX_PAL_SLOT0 0x06F00000 - -#define NDS_VRAM_SLOT_OFF 0x20000 -#define NDS_ARM9 1 -#define NDS_ARM7 0 - -#define NDS_GXFIFO_SIZE 256 -#define NDS_GXFIFO_STORAGE 512 -#define NDS_GXFIFO_MASK 0x1ff -#define NDS_GPU_MAX_PARAM 64 +#define NDS_VRAM_BGA_SLOT0 0x06A00000 +#define NDS_VRAM_BGB_SLOT0 0x06B00000 +#define NDS_VRAM_OBJA_SLOT0 0x06C00000 +#define NDS_VRAM_OBJB_SLOT0 0x06D00000 +#define NDS_VRAM_TEX_SLOT0 0x06E00000 +#define NDS_VRAM_TEX_SLOT1 (0x06E00000 + 128 * 1024) +#define NDS_VRAM_TEX_PAL_SLOT0 0x06F00000 + +#define NDS_VRAM_SLOT_OFF 0x20000 +#define NDS_ARM9 1 +#define NDS_ARM7 0 + +#define NDS_GXFIFO_SIZE 256 +#define NDS_GXFIFO_STORAGE 512 +#define NDS_GXFIFO_MASK 0x1ff +#define NDS_GPU_MAX_PARAM 64 #define NDS_GX_DMA_THRESHOLD 128 -typedef struct { - uint8_t ram[4*1024*1024]; /*4096KB Main RAM (8192KB in debug version)*/ - uint8_t wram[96*1024]; /*96KB WRAM (64K mapped to NDS7, plus 32K mappable to NDS7 or NDS9)*/ +typedef struct { + uint8_t ram[4 * 1024 * 1024]; /*4096KB Main RAM (8192KB in debug version)*/ + uint8_t wram[96 * 1024]; /*96KB WRAM (64K mapped to NDS7, plus 32K mappable to NDS7 or NDS9)*/ /* TCM/Cache (TCM: 16K Data, 32K Code) (Cache: 4K Data, 8K Code) */ - uint8_t code_tcm[32*1024]; - uint8_t data_tcm[16*1024]; - uint8_t code_cache[8*1024]; - uint8_t data_cache[4*1024]; - uint8_t vram[1024*1024]; /* VRAM (allocateable as BG/OBJ/2D/3D/Palette/Texture/WRAM memory) */ - uint64_t vram_translation_cache[1024*16]; - uint8_t palette[2*1024]; + uint8_t code_tcm[32 * 1024]; + uint8_t data_tcm[16 * 1024]; + uint8_t code_cache[8 * 1024]; + uint8_t data_cache[4 * 1024]; + uint8_t vram[1024 * 1024]; /* VRAM (allocateable as BG/OBJ/2D/3D/Palette/Texture/WRAM memory) */ + uint64_t vram_translation_cache[1024 * 16]; + uint8_t palette[2 * 1024]; uint8_t *save_data; - uint8_t oam[4*1024]; /* OAM/PAL (2K OBJ Attribute Memory, 2K Standard Palette RAM) */ + uint8_t oam[4 * 1024]; /* OAM/PAL (2K OBJ Attribute Memory, 2K Standard Palette RAM) */ /* BIOS ROM (4K NDS9, 16K NDS7, 16K GBA) */ uint8_t *nds7_bios; uint8_t *nds9_bios; /* Firmware FLASH (512KB in iQue variant, with chinese charset) */ uint8_t *firmware; - uint8_t io[64*1024]; - uint8_t wifi_io[64*1024]; - uint8_t baseband_io[0x70]; - uint8_t rf_io[0x10]; - uint8_t mmio_debug_access_buffer[16*1024]; + uint8_t io[64 * 1024]; + uint8_t wifi_io[64 * 1024]; + uint8_t baseband_io[0x70]; + uint8_t rf_io[0x10]; + uint8_t mmio_debug_access_buffer[16 * 1024]; uint8_t *card_data; - size_t card_size; - uint8_t card_transfer_data[0x1000]; + size_t card_size; + uint8_t card_transfer_data[0x1000]; uint32_t card_chip_id; - int card_read_offset; - int card_transfer_bytes; - uint64_t curr_vram_translation_key; + int card_read_offset; + int card_transfer_bytes; + uint64_t curr_vram_translation_key; uint32_t requests; uint32_t openbus_word; uint32_t arm7_bios_word; @@ -1901,270 +1912,270 @@ typedef struct { uint32_t dtcm_end_address; uint32_t itcm_start_address; uint32_t itcm_end_address; - bool dtcm_load_mode; - bool itcm_load_mode; - bool dtcm_enable; - bool itcm_enable; - uint32_t slow_bus_cycles; + bool dtcm_load_mode; + bool itcm_load_mode; + bool dtcm_enable; + bool itcm_enable; + uint32_t slow_bus_cycles; } nds_mem_t; typedef struct { - //Bytes 0..31 - uint8_t title[12]; /* Game Title (Uppercase ASCII, padded with 00h) */ - uint8_t gamecode[4]; /* Gamecode (Uppercase ASCII, NTR-) (0=homebrew) */ - uint8_t makercode[2]; /* Makercode (Uppercase ASCII, eg. "01"=Nintendo) (0=homebrew) */ - uint8_t unitcode; /* Unitcode (00h=NDS, 02h=NDS+DSi, 03h=DSi) (bit1=DSi) */ + // Bytes 0..31 + uint8_t title[12]; /* Game Title (Uppercase ASCII, padded with 00h) */ + uint8_t gamecode[4]; /* Gamecode (Uppercase ASCII, NTR-) (0=homebrew) */ + uint8_t makercode[2]; /* Makercode (Uppercase ASCII, eg. "01"=Nintendo) (0=homebrew) */ + uint8_t unitcode; /* Unitcode (00h=NDS, 02h=NDS+DSi, 03h=DSi) (bit1=DSi) */ uint8_t seed_sel; /* Encryption Seed Select (00..07h, usually 00h) */ uint8_t device_capacity; /* Devicecapacity (Chipsize = 128KB SHL nn) (eg. 7 = 16MB) */ uint8_t reserved[8]; - uint8_t region; /* NDS Region (00h=Normal, 80h=China, 40h=Korea) (other on DSi) */ - uint8_t rom_version; /* ROM Version (usually 00h) */ - uint8_t autostart; /* Autostart (Bit2: Skip "Press Button" after Health and Safety) */ - //Byte 32..63 - uint32_t arm9_rom_offset; /* ARM9 rom_offset (4000h and up, align 1000h) */ - uint32_t arm9_entrypoint; /* ARM9 entry_address (2000000h..23BFE00h) */ - uint32_t arm9_ram_address;/* ARM9 ram_address (2000000h..23BFE00h) */ - uint32_t arm9_size; /* ARM9 size (max 3BFE00h) (3839.5KB) */ + uint8_t region; /* NDS Region (00h=Normal, 80h=China, 40h=Korea) (other on DSi) */ + uint8_t rom_version; /* ROM Version (usually 00h) */ + uint8_t autostart; /* Autostart (Bit2: Skip "Press Button" after Health and Safety) */ + // Byte 32..63 + uint32_t arm9_rom_offset; /* ARM9 rom_offset (4000h and up, align 1000h) */ + uint32_t arm9_entrypoint; /* ARM9 entry_address (2000000h..23BFE00h) */ + uint32_t arm9_ram_address; /* ARM9 ram_address (2000000h..23BFE00h) */ + uint32_t arm9_size; /* ARM9 size (max 3BFE00h) (3839.5KB) */ uint32_t arm7_rom_offset; /* ARM7 rom_offset (8000h and up) */ uint32_t arm7_entrypoint; /* ARM7 entry_address (2000000h..23BFE00h, or 37F8000h..3807E00h) */ uint32_t arm7_ram_address; /* ARM7 ram_address (2000000h..23BFE00h, or 37F8000h..3807E00h) */ uint32_t arm7_size; /* ARM7 size (max 3BFE00h, or FE00h) (3839.5KB, 63.5KB) */ - - //Byte 64..95 - uint32_t fnt_offset; /* File Name Table (FNT) offset */ - uint32_t fnt_size; /* File Name Table (FNT) size */ - uint32_t fat_offset; /* File Allocation Table (FAT) offset */ - uint32_t fat_size; /* File Allocation Table (FAT) size */ + + // Byte 64..95 + uint32_t fnt_offset; /* File Name Table (FNT) offset */ + uint32_t fnt_size; /* File Name Table (FNT) size */ + uint32_t fat_offset; /* File Allocation Table (FAT) offset */ + uint32_t fat_size; /* File Allocation Table (FAT) size */ uint32_t arm9_overlay_offset; /* File ARM9 overlay_offset */ uint32_t arm9_overlay_size; /* File ARM9 overlay_size */ uint32_t arm7_overlay_offset; /* File ARM7 overlay_offset */ uint32_t arm7_overlay_size; /* File ARM7 overlay_size */ - //Byte 96..127 - uint32_t port0; /* Port 40001A4h setting for normal commands (usually 00586000h) */ - uint32_t port1; /* Port 40001A4h setting for KEY1 commands (usually 001808F8h) */ + // Byte 96..127 + uint32_t port0; /* Port 40001A4h setting for normal commands (usually 00586000h) */ + uint32_t port1; /* Port 40001A4h setting for KEY1 commands (usually 001808F8h) */ uint32_t icon_title_offset; /* Icon/Title offset (0=None) (8000h and up) */ - uint16_t sec_checksum; /* Secure Area Checksum, CRC-16 of [[020h]..00007FFFh] */ - uint16_t sec_delay; /* Secure Area Delay (in 131kHz units) (051Eh=10ms or 0D7Eh=26ms) */ - uint32_t arm9_autoload; /* ARM9 Auto Load List Hook RAM Address (?) ;\endaddr of auto-load */ - uint32_t arm7_autoload; /* ARM7 Auto Load List Hook RAM Address (?) ;/functions */ - uint8_t sec_disable[8]; /* Secure Area Disable (by encrypted "NmMdOnly") (usually zero) */ - //Byte 128..159 - uint32_t rom_size_used; /* Total Used ROM size (remaining/unused bytes usually FFh-padded) */ - uint32_t rom_header_size; /* ROM Header Size (4000h) */ - uint8_t reserved2[24]; + uint16_t sec_checksum; /* Secure Area Checksum, CRC-16 of [[020h]..00007FFFh] */ + uint16_t sec_delay; /* Secure Area Delay (in 131kHz units) (051Eh=10ms or 0D7Eh=26ms) */ + uint32_t arm9_autoload; /* ARM9 Auto Load List Hook RAM Address (?) ;\endaddr of auto-load */ + uint32_t arm7_autoload; /* ARM7 Auto Load List Hook RAM Address (?) ;/functions */ + uint8_t sec_disable[8]; /* Secure Area Disable (by encrypted "NmMdOnly") (usually zero) */ + // Byte 128..159 + uint32_t rom_size_used; /* Total Used ROM size (remaining/unused bytes usually FFh-padded) */ + uint32_t rom_header_size; /* ROM Header Size (4000h) */ + uint8_t reserved2[24]; } nds_card_t; -typedef struct{ - bool up,down,left,right; - bool a, b, start, select; - bool l,r; - bool x,y; +typedef struct { + bool up, down, left, right; + bool a, b, start, select; + bool l, r; + bool x, y; float touch_x; float touch_y; } nds_input_t; -typedef struct{ +typedef struct { uint32_t source_addr; uint32_t dest_addr; uint32_t length; uint32_t current_transaction; - bool last_enable; - bool last_vblank; - bool last_hblank; + bool last_enable; + bool last_vblank; + bool last_hblank; uint32_t latched_transfer; - int startup_delay; - uint32_t gx_dma_subtransfer; - uint16_t trigger_mode; -} nds_dma_t; -typedef struct{ - int scan_clock; + int startup_delay; + uint32_t gx_dma_subtransfer; + uint16_t trigger_mode; +} nds_dma_t; +typedef struct { + int scan_clock; bool last_vblank; bool last_hblank; bool last_vcmp; bool last_vcmp7; - int last_lcd_y; + int last_lcd_y; struct { int32_t internal_bgx; int32_t internal_bgy; - }aff[2]; + } aff[2]; uint16_t dispcnt_pipeline[3]; uint32_t first_target_buffer[NDS_LCD_W]; uint32_t second_target_buffer[NDS_LCD_W]; - uint8_t window[NDS_LCD_W]; + uint8_t window[NDS_LCD_W]; uint32_t bg_vram_base; - uint32_t obj_vram_base; - bool new_frame; -}nds_ppu_t; -typedef struct{ - bool last_enable; - uint16_t reload_value; - uint16_t pending_reload_value; + uint32_t obj_vram_base; + bool new_frame; +} nds_ppu_t; +typedef struct { + bool last_enable; + uint16_t reload_value; + uint16_t pending_reload_value; uint16_t prescaler_timer; - int startup_delay; -}nds_timer_t; -typedef struct{ + int startup_delay; +} nds_timer_t; +typedef struct { uint32_t serial_state; uint32_t serial_bits_clocked; uint64_t input_register; uint64_t output_register; uint32_t state; - uint8_t status_register; + uint8_t status_register; uint16_t year; - uint8_t month; - uint8_t day; - uint8_t day_of_week; - uint8_t hour; - uint8_t minute; - uint8_t second; -}nds_rtc_t; -typedef struct{ + uint8_t month; + uint8_t day; + uint8_t day_of_week; + uint8_t hour; + uint8_t minute; + uint8_t second; +} nds_rtc_t; +typedef struct { uint32_t fifo[16]; uint32_t read_ptr; uint32_t write_ptr; uint32_t sync_data; - bool error; -}nds_ipc_t; -typedef struct{ + bool error; +} nds_ipc_t; +typedef struct { //[Cn][Cm][Cp] - uint32_t reg[16*16*8]; -}nds_system_control_processor; -typedef struct{ + uint32_t reg[16 * 16 * 8]; +} nds_system_control_processor; +typedef struct { uint64_t div_last_update_clock; uint64_t sqrt_last_update_clock; -}nds_math_t; -typedef struct{ +} nds_math_t; +typedef struct { uint8_t last_device; -}nds_spi_t; -typedef struct{ - uint8_t state; - uint8_t cmd; +} nds_spi_t; +typedef struct { + uint8_t state; + uint8_t cmd; uint32_t addr; - bool write_enable; -}nds_flash_t; -typedef struct{ + bool write_enable; +} nds_flash_t; +typedef struct { nds_flash_t flash; - uint8_t command[8]; - uint32_t backup_type; - int command_offset; - bool write_enable; - uint8_t status_reg; - bool is_dirty; -}nds_card_backup_t; -typedef struct{ - uint16_t x_reg, y_reg; - uint16_t tx_reg; -}nds_touch_t; -typedef struct{ - double current_sim_time; - double current_sample_generated_time; + uint8_t command[8]; + uint32_t backup_type; + int command_offset; + bool write_enable; + uint8_t status_reg; + bool is_dirty; +} nds_card_backup_t; +typedef struct { + uint16_t x_reg, y_reg; + uint16_t tx_reg; +} nds_touch_t; +typedef struct { + double current_sim_time; + double current_sample_generated_time; uint32_t cycles_since_tick; - struct{ + struct { uint32_t timer; uint32_t sample; - int32_t adpcm_sample; - int32_t adpcm_index; - int32_t adpcm_sample_latch; - int32_t adpcm_index_latch; + int32_t adpcm_sample; + int32_t adpcm_index; + int32_t adpcm_sample_latch; + int32_t adpcm_index_latch; uint32_t lfsr; - }channel[16]; + } channel[16]; -}nds_audio_t; +} nds_audio_t; #define NDS_MATRIX_PROJ 0 -#define NDS_MATRIX_MV 1 -#define NDS_MATRIX_DIR 2 //<- TODO: Future Sky problem -#define NDS_MATRIX_TEX 3 +#define NDS_MATRIX_MV 1 +#define NDS_MATRIX_DIR 2 //<- TODO: Future Sky problem +#define NDS_MATRIX_TEX 3 #define NDS_MAX_VERTS 8192 -typedef struct{ - float pos[4]; - float clip_pos[3]; +typedef struct { + float pos[4]; + float clip_pos[3]; uint8_t color[3]; - float tex[2]; -}nds_vert_t; -typedef struct{ - uint32_t fifo_data[NDS_GXFIFO_STORAGE]; - uint8_t fifo_cmd[NDS_GXFIFO_STORAGE]; - uint32_t fifo_read_ptr, fifo_write_ptr; + float tex[2]; +} nds_vert_t; +typedef struct { + uint32_t fifo_data[NDS_GXFIFO_STORAGE]; + uint8_t fifo_cmd[NDS_GXFIFO_STORAGE]; + uint32_t fifo_read_ptr, fifo_write_ptr; nds_vert_t *vert_buffer; - uint32_t curr_vert; - uint32_t curr_draw_vert; - uint32_t prim_type; + uint32_t curr_vert; + uint32_t curr_draw_vert; + uint32_t prim_type; float proj_matrix[16]; float tex_matrix[16]; float mv_matrix[16]; float direction_matrix[16]; - float proj_matrix_stack[16*2]; - float tex_matrix_stack[16*2]; - float mv_matrix_stack[16*32]; - float direction_matrix_stack[16*32]; + float proj_matrix_stack[16 * 2]; + float tex_matrix_stack[16 * 2]; + float mv_matrix_stack[16 * 32]; + float direction_matrix_stack[16 * 32]; uint8_t curr_color[4]; uint8_t curr_ambient_color[3]; uint8_t curr_diffuse_color[3]; uint8_t curr_specular_color[3]; uint8_t curr_emission_color[3]; uint8_t shininess_table[128]; - bool use_shininess_table; - - float light_vector[4*4]; - uint8_t light_color[4*3]; - - int16_t curr_tex_coord[2]; - int16_t last_vertex_pos[3]; - float transformed_normal[4]; - int matrix_mode; - int mv_matrix_stack_ptr; - int proj_matrix_stack_ptr; - int tex_matrix_stack_ptr; + bool use_shininess_table; + + float light_vector[4 * 4]; + uint8_t light_color[4 * 3]; + + int16_t curr_tex_coord[2]; + int16_t last_vertex_pos[3]; + float transformed_normal[4]; + int matrix_mode; + int mv_matrix_stack_ptr; + int proj_matrix_stack_ptr; + int tex_matrix_stack_ptr; uint32_t cmd_busy_cycles; - uint32_t packed_cmd; - uint8_t packed_cmd_param; - bool matrix_stack_error; + uint32_t packed_cmd; + uint8_t packed_cmd_param; + bool matrix_stack_error; uint32_t tex_image_param; uint32_t tex_plt_base; uint32_t poly_attr; uint32_t poly_ram_offset; - bool pending_swap; - bool box_test_result; - int test_busy; - uint32_t rendered_primitive_tracker; -}nds_gpu_t; - -typedef struct{ - uint32_t bess_version; //Versioning field must be 1 - /* - r0-r15 + bool pending_swap; + bool box_test_result; + int test_busy; + uint32_t rendered_primitive_tracker; +} nds_gpu_t; + +typedef struct { + uint32_t bess_version; // Versioning field must be 1 + /* + r0-r15 CPSR 16 - SPSR 17 - R13_fiq 22 - R13_irq 24 - R13_svc 26 - R13_abt 28 - R13_und 30 - R14_fiq 23 - R14_irq 25 - R14_svc 27 - R14_abt 29 - R14_und 31 - SPSR_fiq 32 - SPSR_irq 33 - SPSR_svc 34 - SPSR_abt 35 - SPSR_und 36 + SPSR 17 + R13_fiq 22 + R13_irq 24 + R13_svc 26 + R13_abt 28 + R13_und 30 + R14_fiq 23 + R14_irq 25 + R14_svc 27 + R14_abt 29 + R14_und 31 + SPSR_fiq 32 + SPSR_irq 33 + SPSR_svc 34 + SPSR_abt 35 + SPSR_und 36 */ uint32_t cpu9_reg_seg; uint32_t cpu7_reg_seg; uint32_t ram_seg; - uint32_t wram_seg; + uint32_t wram_seg; uint32_t code_tcm_seg; uint32_t data_tcm_seg; uint32_t code_cache_seg; uint32_t data_cache_seg; - uint32_t vram_seg; - uint32_t palette_seg; + uint32_t vram_seg; + uint32_t palette_seg; uint32_t oam_seg; uint32_t io_seg; uint32_t card_transfer_data_seg; @@ -2176,274 +2187,275 @@ typedef struct{ uint32_t dtcm_end_address; uint32_t itcm_start_address; uint32_t itcm_end_address; - uint8_t dtcm_load_mode; - uint8_t itcm_load_mode; - uint8_t dtcm_enable; - uint8_t itcm_enable; + uint8_t dtcm_load_mode; + uint8_t itcm_load_mode; + uint8_t dtcm_enable; + uint8_t itcm_enable; uint32_t card_read_offset; uint32_t card_transfer_bytes; uint32_t padding[39]; -}nds_bess_info_t; - -typedef struct{ - nds_mem_t mem; - arm7_t arm7; - arm7_t arm9; - nds_card_t card; - nds_input_t joy; - nds_ppu_t ppu[2]; - nds_gpu_t gpu; - nds_rtc_t rtc; - nds_dma_t dma[2][4]; - nds_ipc_t ipc[2]; +} nds_bess_info_t; + +typedef struct { + nds_mem_t mem; + arm7_t arm7; + arm7_t arm9; + nds_card_t card; + nds_input_t joy; + nds_ppu_t ppu[2]; + nds_gpu_t gpu; + nds_rtc_t rtc; + nds_dma_t dma[2][4]; + nds_ipc_t ipc[2]; nds_system_control_processor cp15; - nds_math_t math; - nds_spi_t spi; - nds_flash_t firmware; - nds_touch_t touch; - nds_audio_t audio; - nds_card_backup_t backup; - nds_bess_info_t bess; - //There is a 2 cycle penalty when the CPU takes over from the DMA - bool last_transaction_dma; - bool activate_dmas; - bool dma_wait_gx; - bool dma_wait_ppu; - bool dma_processed[2]; - bool display_flip; + nds_math_t math; + nds_spi_t spi; + nds_flash_t firmware; + nds_touch_t touch; + nds_audio_t audio; + nds_card_backup_t backup; + nds_bess_info_t bess; + // There is a 2 cycle penalty when the CPU takes over from the DMA + bool last_transaction_dma; + bool activate_dmas; + bool dma_wait_gx; + bool dma_wait_ppu; + bool dma_processed[2]; + bool display_flip; nds_timer_t timers[2][4]; - uint32_t next_timer_clock; - uint64_t last_timer_clock; - bool prev_key_interrupt; - // Some HW has up to a 4 cycle delay before its IF propagates. - // This array acts as a FIFO to keep track of that. + uint32_t next_timer_clock; + uint64_t last_timer_clock; + bool prev_key_interrupt; + // Some HW has up to a 4 cycle delay before its IF propagates. + // This array acts as a FIFO to keep track of that. uint32_t nds9_pipelined_if[5]; uint32_t nds7_pipelined_if[5]; - int active_if_pipe_stages; - char save_file_path[SB_FILE_PATH_SIZE]; + int active_if_pipe_stages; + char save_file_path[SB_FILE_PATH_SIZE]; uint8_t *framebuffer_top; uint8_t *framebuffer_bottom; - float *framebuffer_3d_depth; + float *framebuffer_3d_depth; uint8_t *framebuffer_3d; uint8_t *framebuffer_3d_disp; uint64_t current_clock; - float ghosting_strength; - int ppu_fast_forward_ticks; - FILE * gx_log; - FILE * io9_log; - FILE * io7_log; - FILE * gc_log; - FILE * dma_log; - FILE * vert_log; -} nds_t; -typedef struct{ - uint8_t nds7_bios[16*1024]; - uint8_t nds9_bios[4*1024]; + float ghosting_strength; + int ppu_fast_forward_ticks; + FILE *gx_log; + FILE *io9_log; + FILE *io7_log; + FILE *gc_log; + FILE *dma_log; + FILE *vert_log; +} nds_t; +typedef struct { + uint8_t nds7_bios[16 * 1024]; + uint8_t nds9_bios[4 * 1024]; /* Firmware FLASH (512KB in iQue variant, with chinese charset) */ - uint8_t firmware[NDS_FIRMWARE_SIZE]; - uint8_t save_data[8*1024*1024]; - uint8_t framebuffer_top[NDS_LCD_W*NDS_LCD_H*4]; - uint8_t framebuffer_bottom[NDS_LCD_W*NDS_LCD_H*4]; - float framebuffer_3d_depth[NDS_LCD_W*NDS_LCD_H]; - uint8_t framebuffer_3d[NDS_LCD_W*NDS_LCD_H*4]; - uint8_t framebuffer_3d_disp[NDS_LCD_W*NDS_LCD_H*4]; + uint8_t firmware[NDS_FIRMWARE_SIZE]; + uint8_t save_data[8 * 1024 * 1024]; + uint8_t framebuffer_top[NDS_LCD_W * NDS_LCD_H * 4]; + uint8_t framebuffer_bottom[NDS_LCD_W * NDS_LCD_H * 4]; + float framebuffer_3d_depth[NDS_LCD_W * NDS_LCD_H]; + uint8_t framebuffer_3d[NDS_LCD_W * NDS_LCD_H * 4]; + uint8_t framebuffer_3d_disp[NDS_LCD_W * NDS_LCD_H * 4]; nds_vert_t vert_buffer[NDS_MAX_VERTS]; -}nds_scratch_t; -static void nds_tick_keypad(sb_joy_t*joy, nds_t* nds); -static void nds_tick_touch(sb_joy_t*joy, nds_t* nds); -static FORCE_INLINE void nds_tick_timers(nds_t* nds); -static FORCE_INLINE int nds_cycles_till_vblank(nds_t*nds); -static void nds_compute_timers(nds_t* nds); -static uint32_t nds_get_save_size(nds_t*nds); -static uint8_t nds_process_flash_write(nds_t *nds, uint8_t write_data, nds_flash_t* flash, uint8_t *flash_data, uint32_t flash_size); -static bool nds_run_ar_cheat(nds_t* nds, const uint32_t* buffer, uint32_t size); - - -//Returns offset into savestate where bess info can be found -static uint32_t nds_save_best_effort_state(nds_t* nds){ - nds->bess.bess_version = 1; - - nds->bess.cpu9_reg_seg= (uint8_t*)nds->arm9.registers-(uint8_t*)nds; - nds->bess.cpu7_reg_seg= (uint8_t*)nds->arm7.registers-(uint8_t*)nds; - nds->bess.ram_seg= (uint8_t*)nds->mem.ram-(uint8_t*)nds; - nds->bess.wram_seg= (uint8_t*)nds->mem.wram-(uint8_t*)nds; - nds->bess.code_tcm_seg= (uint8_t*)nds->mem.code_tcm-(uint8_t*)nds; - nds->bess.data_tcm_seg= (uint8_t*)nds->mem.data_tcm-(uint8_t*)nds; - nds->bess.code_cache_seg= (uint8_t*)nds->mem.code_cache-(uint8_t*)nds; - nds->bess.data_cache_seg= (uint8_t*)nds->mem.data_cache-(uint8_t*)nds; - nds->bess.vram_seg= (uint8_t*)nds->mem.vram-(uint8_t*)nds; - nds->bess.palette_seg= (uint8_t*)nds->mem.palette-(uint8_t*)nds; - nds->bess.oam_seg= (uint8_t*)nds->mem.oam-(uint8_t*)nds; - nds->bess.io_seg= (uint8_t*)nds->mem.io-(uint8_t*)nds; - nds->bess.card_transfer_data_seg= (uint8_t*)nds->mem.card_transfer_data-(uint8_t*)nds; - nds->bess.coproc_reg_seg= (uint8_t*)nds->cp15.reg-(uint8_t*)nds; - nds->bess.dtcm_start_address=nds->mem.dtcm_start_address; - nds->bess.dtcm_end_address=nds->mem.dtcm_end_address; - nds->bess.itcm_start_address=nds->mem.itcm_start_address; - nds->bess.itcm_end_address=nds->mem.itcm_end_address; - nds->bess.dtcm_load_mode=nds->mem.dtcm_load_mode; - nds->bess.itcm_load_mode=nds->mem.itcm_load_mode; - nds->bess.dtcm_enable=nds->mem.dtcm_enable; - nds->bess.itcm_enable=nds->mem.itcm_enable; - nds->bess.card_read_offset=nds->mem.card_read_offset; - nds->bess.card_transfer_bytes=nds->mem.card_transfer_bytes; - - for(int cpu=0;cpu<2;++cpu) - for(int i=0;i<4;++i)nds->bess.timer_reload_values[cpu][i]=nds->timers[cpu][i].reload_value; - return ((uint8_t*)&nds->bess)-(uint8_t*)(nds); +} nds_scratch_t; +static void nds_tick_keypad(sb_joy_t *joy, nds_t *nds); +static void nds_tick_touch(sb_joy_t *joy, nds_t *nds); +static FORCE_INLINE void nds_tick_timers(nds_t *nds); +static FORCE_INLINE int nds_cycles_till_vblank(nds_t *nds); +static void nds_compute_timers(nds_t *nds); +static uint32_t nds_get_save_size(nds_t *nds); +static uint8_t nds_process_flash_write(nds_t *nds, uint8_t write_data, nds_flash_t *flash, uint8_t *flash_data, uint32_t flash_size); +static bool nds_run_ar_cheat(nds_t *nds, const uint32_t *buffer, uint32_t size); + +// Returns offset into savestate where bess info can be found +static uint32_t nds_save_best_effort_state(nds_t *nds) { + nds->bess.bess_version = 1; + + nds->bess.cpu9_reg_seg = (uint8_t *)nds->arm9.registers - (uint8_t *)nds; + nds->bess.cpu7_reg_seg = (uint8_t *)nds->arm7.registers - (uint8_t *)nds; + nds->bess.ram_seg = (uint8_t *)nds->mem.ram - (uint8_t *)nds; + nds->bess.wram_seg = (uint8_t *)nds->mem.wram - (uint8_t *)nds; + nds->bess.code_tcm_seg = (uint8_t *)nds->mem.code_tcm - (uint8_t *)nds; + nds->bess.data_tcm_seg = (uint8_t *)nds->mem.data_tcm - (uint8_t *)nds; + nds->bess.code_cache_seg = (uint8_t *)nds->mem.code_cache - (uint8_t *)nds; + nds->bess.data_cache_seg = (uint8_t *)nds->mem.data_cache - (uint8_t *)nds; + nds->bess.vram_seg = (uint8_t *)nds->mem.vram - (uint8_t *)nds; + nds->bess.palette_seg = (uint8_t *)nds->mem.palette - (uint8_t *)nds; + nds->bess.oam_seg = (uint8_t *)nds->mem.oam - (uint8_t *)nds; + nds->bess.io_seg = (uint8_t *)nds->mem.io - (uint8_t *)nds; + nds->bess.card_transfer_data_seg = (uint8_t *)nds->mem.card_transfer_data - (uint8_t *)nds; + nds->bess.coproc_reg_seg = (uint8_t *)nds->cp15.reg - (uint8_t *)nds; + nds->bess.dtcm_start_address = nds->mem.dtcm_start_address; + nds->bess.dtcm_end_address = nds->mem.dtcm_end_address; + nds->bess.itcm_start_address = nds->mem.itcm_start_address; + nds->bess.itcm_end_address = nds->mem.itcm_end_address; + nds->bess.dtcm_load_mode = nds->mem.dtcm_load_mode; + nds->bess.itcm_load_mode = nds->mem.itcm_load_mode; + nds->bess.dtcm_enable = nds->mem.dtcm_enable; + nds->bess.itcm_enable = nds->mem.itcm_enable; + nds->bess.card_read_offset = nds->mem.card_read_offset; + nds->bess.card_transfer_bytes = nds->mem.card_transfer_bytes; + + for(int cpu = 0; cpu < 2; ++cpu) + for(int i = 0; i < 4; ++i) + nds->bess.timer_reload_values[cpu][i] = nds->timers[cpu][i].reload_value; + return ((uint8_t *)&nds->bess) - (uint8_t *)(nds); } -static bool nds_load_best_effort_state(nds_t* nds,uint8_t *save_state_data, uint32_t size, uint32_t bess_offset){ - if(bess_offset+sizeof(nds_bess_info_t)>size)return false; - nds_bess_info_t * bess = (nds_bess_info_t*)(save_state_data+bess_offset); - if(bess->bess_version!=1)return false; - - if(bess->cpu9_reg_seg + sizeof(nds->arm9.registers)>size)return false; - if(bess->cpu7_reg_seg + sizeof(nds->arm7.registers)>size)return false; - if(bess->ram_seg + sizeof(nds->mem.ram)>size)return false; - if(bess->wram_seg + sizeof(nds->mem.wram)>size)return false; - if(bess->code_tcm_seg + sizeof(nds->mem.code_tcm)>size)return false; - if(bess->data_tcm_seg + sizeof(nds->mem.data_tcm)>size)return false; - if(bess->code_cache_seg + sizeof(nds->mem.code_cache)>size)return false; - if(bess->data_cache_seg + sizeof(nds->mem.data_cache)>size)return false; - if(bess->vram_seg + sizeof(nds->mem.vram)>size)return false; - if(bess->palette_seg + sizeof(nds->mem.palette)>size)return false; - if(bess->oam_seg + sizeof(nds->mem.oam)>size)return false; - if(bess->io_seg + sizeof(nds->mem.io)>size)return false; - if(bess->card_transfer_data_seg + sizeof(nds->mem.card_transfer_data)>size)return false; - if(bess->coproc_reg_seg + sizeof(nds->cp15.reg)>size)return false; - - memcpy((uint8_t*)nds->arm9.registers, save_state_data+bess->cpu9_reg_seg, sizeof(nds->arm9.registers)); - memcpy((uint8_t*)nds->arm7.registers, save_state_data+bess->cpu7_reg_seg, sizeof(nds->arm7.registers)); - memcpy((uint8_t*)nds->mem.ram, save_state_data+bess->ram_seg, sizeof(nds->mem.ram)); - memcpy((uint8_t*)nds->mem.wram, save_state_data+bess->wram_seg, sizeof(nds->mem.wram)); - memcpy((uint8_t*)nds->mem.code_tcm, save_state_data+bess->code_tcm_seg, sizeof(nds->mem.code_tcm)); - memcpy((uint8_t*)nds->mem.data_tcm, save_state_data+bess->data_tcm_seg, sizeof(nds->mem.data_tcm)); - memcpy((uint8_t*)nds->mem.code_cache, save_state_data+bess->code_cache_seg, sizeof(nds->mem.code_cache)); - memcpy((uint8_t*)nds->mem.data_cache, save_state_data+bess->data_cache_seg, sizeof(nds->mem.data_cache)); - memcpy((uint8_t*)nds->mem.vram, save_state_data+bess->vram_seg, sizeof(nds->mem.vram)); - memcpy((uint8_t*)nds->mem.palette, save_state_data+bess->palette_seg, sizeof(nds->mem.palette)); - memcpy((uint8_t*)nds->mem.oam, save_state_data+bess->oam_seg, sizeof(nds->mem.oam)); - memcpy((uint8_t*)nds->mem.io, save_state_data+bess->io_seg, sizeof(nds->mem.io)); - memcpy((uint8_t*)nds->mem.card_transfer_data, save_state_data+bess->card_transfer_data_seg, sizeof(nds->mem.card_transfer_data)); - memcpy((uint8_t*)nds->cp15.reg, save_state_data+bess->coproc_reg_seg, sizeof(nds->cp15.reg)); - - printf("ARM7 PC: %08x ARM9 PC: %08x\n",nds->arm7.registers[15],nds->arm9.registers[15]); - - nds->mem.dtcm_start_address=bess->dtcm_start_address; - nds->mem.dtcm_end_address=bess->dtcm_end_address; - nds->mem.itcm_start_address=bess->itcm_start_address; - nds->mem.itcm_end_address=bess->itcm_end_address; - nds->mem.dtcm_load_mode=bess->dtcm_load_mode; - nds->mem.itcm_load_mode=bess->itcm_load_mode; - nds->mem.dtcm_enable=bess->dtcm_enable; - nds->mem.itcm_enable=bess->itcm_enable; - - nds->mem.card_read_offset=bess->card_read_offset; - nds->mem.card_transfer_bytes=bess->card_transfer_bytes; - for(int cpu=0;cpu<2;++cpu) - for(int i=0;i<4;++i)nds->timers[cpu][i].reload_value=nds->bess.timer_reload_values[cpu][i]; +static bool nds_load_best_effort_state(nds_t *nds, uint8_t *save_state_data, uint32_t size, uint32_t bess_offset) { + if(bess_offset + sizeof(nds_bess_info_t) > size) return false; + nds_bess_info_t *bess = (nds_bess_info_t *)(save_state_data + bess_offset); + if(bess->bess_version != 1) return false; + + if(bess->cpu9_reg_seg + sizeof(nds->arm9.registers) > size) return false; + if(bess->cpu7_reg_seg + sizeof(nds->arm7.registers) > size) return false; + if(bess->ram_seg + sizeof(nds->mem.ram) > size) return false; + if(bess->wram_seg + sizeof(nds->mem.wram) > size) return false; + if(bess->code_tcm_seg + sizeof(nds->mem.code_tcm) > size) return false; + if(bess->data_tcm_seg + sizeof(nds->mem.data_tcm) > size) return false; + if(bess->code_cache_seg + sizeof(nds->mem.code_cache) > size) return false; + if(bess->data_cache_seg + sizeof(nds->mem.data_cache) > size) return false; + if(bess->vram_seg + sizeof(nds->mem.vram) > size) return false; + if(bess->palette_seg + sizeof(nds->mem.palette) > size) return false; + if(bess->oam_seg + sizeof(nds->mem.oam) > size) return false; + if(bess->io_seg + sizeof(nds->mem.io) > size) return false; + if(bess->card_transfer_data_seg + sizeof(nds->mem.card_transfer_data) > size) return false; + if(bess->coproc_reg_seg + sizeof(nds->cp15.reg) > size) return false; + + memcpy((uint8_t *)nds->arm9.registers, save_state_data + bess->cpu9_reg_seg, sizeof(nds->arm9.registers)); + memcpy((uint8_t *)nds->arm7.registers, save_state_data + bess->cpu7_reg_seg, sizeof(nds->arm7.registers)); + memcpy((uint8_t *)nds->mem.ram, save_state_data + bess->ram_seg, sizeof(nds->mem.ram)); + memcpy((uint8_t *)nds->mem.wram, save_state_data + bess->wram_seg, sizeof(nds->mem.wram)); + memcpy((uint8_t *)nds->mem.code_tcm, save_state_data + bess->code_tcm_seg, sizeof(nds->mem.code_tcm)); + memcpy((uint8_t *)nds->mem.data_tcm, save_state_data + bess->data_tcm_seg, sizeof(nds->mem.data_tcm)); + memcpy((uint8_t *)nds->mem.code_cache, save_state_data + bess->code_cache_seg, sizeof(nds->mem.code_cache)); + memcpy((uint8_t *)nds->mem.data_cache, save_state_data + bess->data_cache_seg, sizeof(nds->mem.data_cache)); + memcpy((uint8_t *)nds->mem.vram, save_state_data + bess->vram_seg, sizeof(nds->mem.vram)); + memcpy((uint8_t *)nds->mem.palette, save_state_data + bess->palette_seg, sizeof(nds->mem.palette)); + memcpy((uint8_t *)nds->mem.oam, save_state_data + bess->oam_seg, sizeof(nds->mem.oam)); + memcpy((uint8_t *)nds->mem.io, save_state_data + bess->io_seg, sizeof(nds->mem.io)); + memcpy((uint8_t *)nds->mem.card_transfer_data, save_state_data + bess->card_transfer_data_seg, sizeof(nds->mem.card_transfer_data)); + memcpy((uint8_t *)nds->cp15.reg, save_state_data + bess->coproc_reg_seg, sizeof(nds->cp15.reg)); + + printf("ARM7 PC: %08x ARM9 PC: %08x\n", nds->arm7.registers[15], nds->arm9.registers[15]); + + nds->mem.dtcm_start_address = bess->dtcm_start_address; + nds->mem.dtcm_end_address = bess->dtcm_end_address; + nds->mem.itcm_start_address = bess->itcm_start_address; + nds->mem.itcm_end_address = bess->itcm_end_address; + nds->mem.dtcm_load_mode = bess->dtcm_load_mode; + nds->mem.itcm_load_mode = bess->itcm_load_mode; + nds->mem.dtcm_enable = bess->dtcm_enable; + nds->mem.itcm_enable = bess->itcm_enable; + + nds->mem.card_read_offset = bess->card_read_offset; + nds->mem.card_transfer_bytes = bess->card_transfer_bytes; + for(int cpu = 0; cpu < 2; ++cpu) + for(int i = 0; i < 4; ++i) + nds->timers[cpu][i].reload_value = nds->bess.timer_reload_values[cpu][i]; printf("Bess restore successful\n"); - return true; + return true; +} +static void FORCE_INLINE nds9_send_interrupt(nds_t *nds, int delay, int if_bit) { + nds->active_if_pipe_stages |= 1 << delay; + nds->nds9_pipelined_if[delay] |= if_bit; } -static void FORCE_INLINE nds9_send_interrupt(nds_t*nds,int delay,int if_bit){ - nds->active_if_pipe_stages|=1<nds9_pipelined_if[delay]|= if_bit; +static void FORCE_INLINE nds7_send_interrupt(nds_t *nds, int delay, int if_bit) { + nds->active_if_pipe_stages |= 1 << delay; + nds->nds7_pipelined_if[delay] |= if_bit; } -static void FORCE_INLINE nds7_send_interrupt(nds_t*nds,int delay,int if_bit){ - nds->active_if_pipe_stages|=1<nds7_pipelined_if[delay]|= if_bit; -} -static uint64_t nds_rev_bits(uint64_t data, int bits){ +static uint64_t nds_rev_bits(uint64_t data, int bits) { uint64_t out = 0; - for(int i=0;i>=1; + for(int i = 0; i < bits; ++i) { + out <<= 1; + out |= data & 1; + data >>= 1; } return out; } -static FORCE_INLINE void nds9_io_store8(nds_t*nds, unsigned baddr, uint8_t data){nds->mem.io[baddr&0xffff]=data;} -static FORCE_INLINE void nds9_io_store16(nds_t*nds, unsigned baddr, uint16_t data){*(uint16_t*)(nds->mem.io+(baddr&0xffff))=data;} -static FORCE_INLINE void nds9_io_store32(nds_t*nds, unsigned baddr, uint32_t data){*(uint32_t*)(nds->mem.io+(baddr&0xffff))=data;} - -static FORCE_INLINE uint8_t nds9_io_read8(nds_t*nds, unsigned baddr) {return nds->mem.io[baddr&0xffff];} -static FORCE_INLINE uint16_t nds9_io_read16(nds_t*nds, unsigned baddr){return *(uint16_t*)(nds->mem.io+(baddr&0xffff));} -static FORCE_INLINE uint32_t nds9_io_read32(nds_t*nds, unsigned baddr){return *(uint32_t*)(nds->mem.io+(baddr&0xffff));} -static FORCE_INLINE uint32_t nds7_read32(nds_t*nds, unsigned baddr); -static FORCE_INLINE uint32_t nds9_read32(nds_t*nds, unsigned baddr); - -static FORCE_INLINE sb_debug_mmio_access_t nds_debug_mmio_access(nds_t*nds, int cpu, unsigned baddr, int trigger_breakpoint){ - if(baddr>=0x04100000)baddr+=NDS_IO_MAP_041_OFFSET; - if(cpu==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - baddr&=0xffff; - baddr/=4; - - if(trigger_breakpoint!=-1){ - nds->mem.mmio_debug_access_buffer[baddr]&=0x7f; - if(trigger_breakpoint!=0)nds->mem.mmio_debug_access_buffer[baddr]|=0x80; +static FORCE_INLINE void nds9_io_store8(nds_t *nds, unsigned baddr, uint8_t data) { nds->mem.io[baddr & 0xffff] = data; } +static FORCE_INLINE void nds9_io_store16(nds_t *nds, unsigned baddr, uint16_t data) { *(uint16_t *)(nds->mem.io + (baddr & 0xffff)) = data; } +static FORCE_INLINE void nds9_io_store32(nds_t *nds, unsigned baddr, uint32_t data) { *(uint32_t *)(nds->mem.io + (baddr & 0xffff)) = data; } + +static FORCE_INLINE uint8_t nds9_io_read8(nds_t *nds, unsigned baddr) { return nds->mem.io[baddr & 0xffff]; } +static FORCE_INLINE uint16_t nds9_io_read16(nds_t *nds, unsigned baddr) { return *(uint16_t *)(nds->mem.io + (baddr & 0xffff)); } +static FORCE_INLINE uint32_t nds9_io_read32(nds_t *nds, unsigned baddr) { return *(uint32_t *)(nds->mem.io + (baddr & 0xffff)); } +static FORCE_INLINE uint32_t nds7_read32(nds_t *nds, unsigned baddr); +static FORCE_INLINE uint32_t nds9_read32(nds_t *nds, unsigned baddr); + +static FORCE_INLINE sb_debug_mmio_access_t nds_debug_mmio_access(nds_t *nds, int cpu, unsigned baddr, int trigger_breakpoint) { + if(baddr >= 0x04100000) baddr += NDS_IO_MAP_041_OFFSET; + if(cpu == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + baddr &= 0xffff; + baddr /= 4; + + if(trigger_breakpoint != -1) { + nds->mem.mmio_debug_access_buffer[baddr] &= 0x7f; + if(trigger_breakpoint != 0) nds->mem.mmio_debug_access_buffer[baddr] |= 0x80; } uint8_t flag = nds->mem.mmio_debug_access_buffer[baddr]; - sb_debug_mmio_access_t access; - access.read_since_reset = flag&0x1; - access.read_in_tick = flag&0x2; + sb_debug_mmio_access_t access; + access.read_since_reset = flag & 0x1; + access.read_in_tick = flag & 0x2; - access.write_since_reset = flag&0x10; - access.write_in_tick = flag&0x20; - access.trigger_breakpoint = flag&0x80; - return access; + access.write_since_reset = flag & 0x10; + access.write_in_tick = flag & 0x20; + access.trigger_breakpoint = flag & 0x80; + return access; } -static FORCE_INLINE void nds7_io_store8(nds_t*nds, unsigned baddr, uint8_t data){ - baddr+=NDS_IO_MAP_SPLIT_OFFSET; - nds->mem.io[baddr&0xffff]=data; +static FORCE_INLINE void nds7_io_store8(nds_t *nds, unsigned baddr, uint8_t data) { + baddr += NDS_IO_MAP_SPLIT_OFFSET; + nds->mem.io[baddr & 0xffff] = data; } -static FORCE_INLINE void nds7_io_store16(nds_t*nds, unsigned baddr, uint16_t data){ - baddr+=NDS_IO_MAP_SPLIT_OFFSET; - *(uint16_t*)(nds->mem.io+(baddr&0xffff))=data; +static FORCE_INLINE void nds7_io_store16(nds_t *nds, unsigned baddr, uint16_t data) { + baddr += NDS_IO_MAP_SPLIT_OFFSET; + *(uint16_t *)(nds->mem.io + (baddr & 0xffff)) = data; } -static FORCE_INLINE void nds7_io_store32(nds_t*nds, unsigned baddr, uint32_t data){ - baddr+=NDS_IO_MAP_SPLIT_OFFSET; - *(uint32_t*)(nds->mem.io+(baddr&0xffff))=data; +static FORCE_INLINE void nds7_io_store32(nds_t *nds, unsigned baddr, uint32_t data) { + baddr += NDS_IO_MAP_SPLIT_OFFSET; + *(uint32_t *)(nds->mem.io + (baddr & 0xffff)) = data; } -static FORCE_INLINE uint8_t nds7_io_read8(nds_t*nds, unsigned baddr) { - baddr+=NDS_IO_MAP_SPLIT_OFFSET; - return nds->mem.io[baddr&0xffff]; +static FORCE_INLINE uint8_t nds7_io_read8(nds_t *nds, unsigned baddr) { + baddr += NDS_IO_MAP_SPLIT_OFFSET; + return nds->mem.io[baddr & 0xffff]; } -static FORCE_INLINE uint16_t nds7_io_read16(nds_t*nds, unsigned baddr){ - baddr+=NDS_IO_MAP_SPLIT_OFFSET; - return *(uint16_t*)(nds->mem.io+(baddr&0xffff)); +static FORCE_INLINE uint16_t nds7_io_read16(nds_t *nds, unsigned baddr) { + baddr += NDS_IO_MAP_SPLIT_OFFSET; + return *(uint16_t *)(nds->mem.io + (baddr & 0xffff)); } -static FORCE_INLINE uint32_t nds7_io_read32(nds_t*nds, unsigned baddr){ - baddr+=NDS_IO_MAP_SPLIT_OFFSET; - return *(uint32_t*)(nds->mem.io+(baddr&0xffff)); +static FORCE_INLINE uint32_t nds7_io_read32(nds_t *nds, unsigned baddr) { + baddr += NDS_IO_MAP_SPLIT_OFFSET; + return *(uint32_t *)(nds->mem.io + (baddr & 0xffff)); } -static FORCE_INLINE void nds_io_store8(nds_t*nds,int cpu_id, unsigned baddr, uint8_t data){ - if(cpu_id==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - nds->mem.io[baddr&0xffff]=data; +static FORCE_INLINE void nds_io_store8(nds_t *nds, int cpu_id, unsigned baddr, uint8_t data) { + if(cpu_id == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + nds->mem.io[baddr & 0xffff] = data; } -static FORCE_INLINE void nds_io_store16(nds_t*nds,int cpu_id, unsigned baddr, uint16_t data){ - if(cpu_id==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - *(uint16_t*)(nds->mem.io+(baddr&0xffff))=data; +static FORCE_INLINE void nds_io_store16(nds_t *nds, int cpu_id, unsigned baddr, uint16_t data) { + if(cpu_id == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + *(uint16_t *)(nds->mem.io + (baddr & 0xffff)) = data; } -static FORCE_INLINE void nds_io_store32(nds_t*nds,int cpu_id, unsigned baddr, uint32_t data){ - if(cpu_id==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - *(uint32_t*)(nds->mem.io+(baddr&0xffff))=data; +static FORCE_INLINE void nds_io_store32(nds_t *nds, int cpu_id, unsigned baddr, uint32_t data) { + if(cpu_id == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + *(uint32_t *)(nds->mem.io + (baddr & 0xffff)) = data; } -static FORCE_INLINE uint8_t nds_io_read8(nds_t*nds,int cpu_id, unsigned baddr) { - if(cpu_id==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - return nds->mem.io[baddr&0xffff]; +static FORCE_INLINE uint8_t nds_io_read8(nds_t *nds, int cpu_id, unsigned baddr) { + if(cpu_id == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + return nds->mem.io[baddr & 0xffff]; } -static FORCE_INLINE uint16_t nds_io_read16(nds_t*nds,int cpu_id, unsigned baddr){ - if(cpu_id==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - return *(uint16_t*)(nds->mem.io+(baddr&0xffff)); +static FORCE_INLINE uint16_t nds_io_read16(nds_t *nds, int cpu_id, unsigned baddr) { + if(cpu_id == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + return *(uint16_t *)(nds->mem.io + (baddr & 0xffff)); } -static FORCE_INLINE uint32_t nds_io_read32(nds_t*nds,int cpu_id, unsigned baddr){ - if(cpu_id==NDS_ARM7)baddr+=NDS_IO_MAP_SPLIT_OFFSET; - return *(uint32_t*)(nds->mem.io+(baddr&0xffff)); +static FORCE_INLINE uint32_t nds_io_read32(nds_t *nds, int cpu_id, unsigned baddr) { + if(cpu_id == NDS_ARM7) baddr += NDS_IO_MAP_SPLIT_OFFSET; + return *(uint32_t *)(nds->mem.io + (baddr & 0xffff)); } #define NDS_MEM_ARM7 0x1 @@ -2459,1390 +2471,2419 @@ static FORCE_INLINE uint32_t nds_io_read32(nds_t*nds,int cpu_id, unsigned baddr) #define NDS_MEM_SEQ 0x200 #define NDS_MEM_CODE 0x400 - -static FORCE_INLINE uint32_t nds_apply_mem_op(uint8_t * memory,uint32_t address, uint32_t data, int transaction_type){ - if(transaction_type&NDS_MEM_4B){ - address&=~3; - if(transaction_type&NDS_MEM_WRITE)*(uint32_t*)(memory+address)=data; - else data = *(uint32_t*)(memory+address); - }else if(transaction_type&NDS_MEM_2B){ - address&=~1; - if(transaction_type&NDS_MEM_WRITE)*(uint16_t*)(memory+address)=data; - else data = *(uint16_t*)(memory+address); - }else{ - if(transaction_type&NDS_MEM_WRITE)memory[address]=data; - else data = memory[address]; +static FORCE_INLINE uint32_t nds_apply_mem_op(uint8_t *memory, uint32_t address, uint32_t data, int transaction_type) { + if(transaction_type & NDS_MEM_4B) { + address &= ~3; + if(transaction_type & NDS_MEM_WRITE) + *(uint32_t *)(memory + address) = data; + else + data = *(uint32_t *)(memory + address); + } else if(transaction_type & NDS_MEM_2B) { + address &= ~1; + if(transaction_type & NDS_MEM_WRITE) + *(uint16_t *)(memory + address) = data; + else + data = *(uint16_t *)(memory + address); + } else { + if(transaction_type & NDS_MEM_WRITE) + memory[address] = data; + else + data = memory[address]; } - return data; + return data; } -static FORCE_INLINE uint32_t nds_apply_vram_mem_op(nds_t *nds,uint32_t address, uint32_t data, int transaction_type){ - //1Byte writes are ignored from the ARM9 - const int ignore_write_mask = (NDS_MEM_WRITE|NDS_MEM_1B|NDS_MEM_ARM9); - if((transaction_type&ignore_write_mask)==ignore_write_mask)return 0; +static FORCE_INLINE uint32_t nds_apply_vram_mem_op(nds_t *nds, uint32_t address, uint32_t data, int transaction_type) { + // 1Byte writes are ignored from the ARM9 + const int ignore_write_mask = (NDS_MEM_WRITE | NDS_MEM_1B | NDS_MEM_ARM9); + if((transaction_type & ignore_write_mask) == ignore_write_mask) return 0; - int lookup_addr = SB_BFE(address,14,10)*16+(transaction_type&0xf); + int lookup_addr = SB_BFE(address, 14, 10) * 16 + (transaction_type & 0xf); uint64_t key = nds->mem.vram_translation_cache[lookup_addr]; - if((key&~(1023))==nds->mem.curr_vram_translation_key){ - int vram_addr = ((key&1023)*16*1024)+SB_BFE(address,0,14); - return nds_apply_mem_op(nds->mem.vram,vram_addr,data,transaction_type); + if((key & ~(1023)) == nds->mem.curr_vram_translation_key) { + int vram_addr = ((key & 1023) * 16 * 1024) + SB_BFE(address, 0, 14); + return nds_apply_mem_op(nds->mem.vram, vram_addr, data, transaction_type); } - const static int bank_size[9]={ - 128*1024, //A - 128*1024, //B - 128*1024, //C - 128*1024, //D - 64*1024, //E - 16*1024, //F - 16*1024, //G - 32*1024, //H - 16*1024, //I + const static int bank_size[9] = { + 128 * 1024, // A + 128 * 1024, // B + 128 * 1024, // C + 128 * 1024, // D + 64 * 1024, // E + 16 * 1024, // F + 16 * 1024, // G + 32 * 1024, // H + 16 * 1024, // I }; - const uint32_t offset_table[10][5]={ - {0,0,0,0}, //Offset ignored - {0x20000*0, 0x20000*1, 0x20000*2,0x20000*3}, //(0x20000*OFS) - {0x0, 0x4000, 0x10000,0x14000}, //(4000h*OFS.0)+(10000h*OFS.1) - {NDS_VRAM_SLOT_OFF*0, NDS_VRAM_SLOT_OFF*1, NDS_VRAM_SLOT_OFF*2,NDS_VRAM_SLOT_OFF*3}, // Slot 0-3 (mirrored) - {NDS_VRAM_SLOT_OFF*0, NDS_VRAM_SLOT_OFF*2, NDS_VRAM_SLOT_OFF*0,NDS_VRAM_SLOT_OFF*2}, // Slot 0-1 (OFS=0), Slot 2-3 (OFS=1) - {NDS_VRAM_SLOT_OFF*0, NDS_VRAM_SLOT_OFF*1, NDS_VRAM_SLOT_OFF*4,NDS_VRAM_SLOT_OFF*5}, // Slot (OFS.0*1)+(OFS.1*4) - {0x20000*0, 0x20000*1, 0x20000*2,0x20000*3}, //(0x20000*OFS) - {0x10000*0, 0x10000*1, 0x10000*2,0x10000*3}, // E 64K 4 - Slot 0-3 ;only lower 32K used - {0x4000*0, 0x4000*1, 0x4000*0,0x4000*1}, // 16KB slot - {16*1024*0, 16*1024*1, 16*1024*4,16*1024*5}, // Slot (OFS.0*1)+(OFS.1*4) + const uint32_t offset_table[10][5] = { + { 0, 0, 0, 0}, // Offset ignored + { 0x20000 * 0, 0x20000 * 1, 0x20000 * 2, 0x20000 * 3}, //(0x20000*OFS) + { 0x0, 0x4000, 0x10000, 0x14000}, //(4000h*OFS.0)+(10000h*OFS.1) + {NDS_VRAM_SLOT_OFF * 0, NDS_VRAM_SLOT_OFF * 1, NDS_VRAM_SLOT_OFF * 2, NDS_VRAM_SLOT_OFF * 3}, // Slot 0-3 (mirrored) + {NDS_VRAM_SLOT_OFF * 0, NDS_VRAM_SLOT_OFF * 2, NDS_VRAM_SLOT_OFF * 0, NDS_VRAM_SLOT_OFF * 2}, // Slot 0-1 (OFS=0), Slot 2-3 (OFS=1) + {NDS_VRAM_SLOT_OFF * 0, NDS_VRAM_SLOT_OFF * 1, NDS_VRAM_SLOT_OFF * 4, NDS_VRAM_SLOT_OFF * 5}, // Slot (OFS.0*1)+(OFS.1*4) + { 0x20000 * 0, 0x20000 * 1, 0x20000 * 2, 0x20000 * 3}, //(0x20000*OFS) + { 0x10000 * 0, 0x10000 * 1, 0x10000 * 2, 0x10000 * 3}, // E 64K 4 - Slot 0-3 ;only lower 32K used + { 0x4000 * 0, 0x4000 * 1, 0x4000 * 0, 0x4000 * 1}, // 16KB slot + { 16 * 1024 * 0, 16 * 1024 * 1, 16 * 1024 * 4, 16 * 1024 * 5}, // Slot (OFS.0*1)+(OFS.1*4) }; - typedef struct vram_bank_info_t{ - int transaction_mask; // Block transactions of these types - int offset_table; + typedef struct vram_bank_info_t { + int transaction_mask; // Block transactions of these types + int offset_table; uint32_t mem_address_start; uint32_t mirror; - }vram_bank_info_t; - - const static vram_bank_info_t bank_info[9][8]={ - { //Bank A - {NDS_MEM_ARM7, 0, 0x06800000,0x100000-1}, //MST 0 6800000h-681FFFFh - {NDS_MEM_ARM7, 1, 0x06000000,0x80000-1}, //MST 1 6000000h+(20000h*OFS) - {NDS_MEM_ARM7, 6, 0x06400000,0x40000-1}, //MST 2 6400000h+(20000h*OFS.0) ;OFS.1 must be zero - {NDS_MEM_ARM7|NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, //MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) - {NDS_MEM_ARM7, 0, 0x06800000,0x100000-1}, //MST 4 - {NDS_MEM_ARM7, 1, 0x06000000,0x80000-1}, //MST 5 - {NDS_MEM_ARM7, 6, 0x06400000,0x40000-1}, //MST 6 - {NDS_MEM_ARM7|NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, //MST 7 - },{ //Bank B - {NDS_MEM_ARM7, 0, 0x06820000,0x100000-1}, //MST 0 6820000h-683FFFFh - {NDS_MEM_ARM7, 1, 0x06000000,0x80000-1}, //MST 1 6000000h+(20000h*OFS) - {NDS_MEM_ARM7, 6, 0x06400000,0x40000-1}, //MST 2 6400000h+(20000h*OFS.0) ;OFS.1 must be zero - {NDS_MEM_ARM7|NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, //MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) - {NDS_MEM_ARM7, 0, 0x06820000,0x100000-1}, //MST 4 - {NDS_MEM_ARM7, 1, 0x06000000,0x80000-1}, //MST 5 - {NDS_MEM_ARM7, 6, 0x06400000,0x40000-1}, //MST 6 - {NDS_MEM_ARM7|NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, //MST 7 - },{ //Bank C - {NDS_MEM_ARM7, 0, 0x06840000,0x100000-1}, //MST 0 6840000h-685FFFFh - {NDS_MEM_ARM7, 1, 0x06000000,0x80000-1}, //MST 1 6000000h+(20000h*OFS) - {NDS_MEM_ARM9|NDS_MEM_PPU, 6, 0x06000000,0x80000-1}, //MST 2 6000000h+(20000h*OFS.0) ;OFS.1 must be zero - {NDS_MEM_ARM7|NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, //MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) - {NDS_MEM_ARM7, 0, 0x06200000,0x20000-1}, //MST 4 6200000h - {0xffffffff, 0, 0x0}, // MST 5 INVALID - {0xffffffff, 0, 0x0}, // MST 6 INVALID - {0xffffffff, 0, 0x0}, // MST 7 INVALID - },{ //Bank D - {NDS_MEM_ARM7, 0, 0x06860000,0x100000-1}, //MST 0 6860000h-687FFFFh - {NDS_MEM_ARM7, 1, 0x06000000,0x80000-1}, //MST 1 6000000h+(20000h*OFS) - {NDS_MEM_ARM9|NDS_MEM_PPU, 6, 0x06000000,0x80000-1}, //MST 2 6000000h+(20000h*OFS.0) ;OFS.1 must be zero - {NDS_MEM_ARM7|NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, //MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) - {NDS_MEM_ARM7, 0, 0x06600000,0x20000-1}, //MST 4 6600000h - {0xffffffff, 0, 0x0}, // MST 5 INVALID - {0xffffffff, 0, 0x0}, // MST 6 INVALID - {0xffffffff, 0, 0x0}, // MST 7 INVALID - },{ //Bank E - {NDS_MEM_ARM7, 0, 0x06880000,0x100000-1}, //MST 0 6880000h-688FFFFh - {NDS_MEM_ARM7, 0, 0x06000000,0x80000-1}, //MST 1 6000000h - {NDS_MEM_ARM7, 0, 0x06400000,0x40000-1}, //MST 2 6400000h - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_TEX_PAL_SLOT0}, //MST 3 Slots 0-3;OFS=don't care - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_BGA_SLOT0}, //MST 4 (64K Slot 0-3 ;only lower 32K used) - {0xffffffff, 0, 0x0}, // MST 5 INVALID - {0xffffffff, 0, 0x0}, // MST 6 INVALID - {0xffffffff, 0, 0x0}, // MST 7 INVALID - },{ //Bank F - {NDS_MEM_ARM7, 0, 0x06890000,0x100000-1}, //MST 0 6890000h-6893FFFh - {NDS_MEM_ARM7, 2, 0x06000000,0x80000-1}, //MST 1 6000000h+(4000h*OFS.0)+(10000h*OFS.1) - {NDS_MEM_ARM7, 2, 0x06400000,0x40000-1}, //MST 2 6400000h+(4000h*OFS.0)+(10000h*OFS.1) - {NDS_MEM_ARM7|NDS_MEM_ARM9, 9, NDS_VRAM_TEX_PAL_SLOT0}, //MST 3 Slot (OFS.0*1)+(OFS.1*4) ;ie. Slot 0, 1, 4, or 5 - {NDS_MEM_ARM7|NDS_MEM_ARM9, 8, NDS_VRAM_BGA_SLOT0}, //MST 4 0..1 Slot 0-1 (OFS=0), Slot 2-3 (OFS=1) - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_OBJA_SLOT0}, //MST 5 Slot 0 ;16K each (only lower 8K used) - {0xffffffff, 0, 0x0}, // MST 6 INVALID - {0xffffffff, 0, 0x0}, // MST 7 INVALID - },{ //Bank G - {NDS_MEM_ARM7, 0, 0x06894000,0x100000-1}, //MST 0 6894000h-6897FFFh - {NDS_MEM_ARM7, 2, 0x06000000,0x80000-1}, //MST 1 6000000h+(4000h*OFS.0)+(10000h*OFS.1) - {NDS_MEM_ARM7, 2, 0x06400000,0x40000-1}, //MST 2 6400000h+(4000h*OFS.0)+(10000h*OFS.1) - {NDS_MEM_ARM7|NDS_MEM_ARM9, 9, NDS_VRAM_TEX_PAL_SLOT0}, //MST3 Slot (OFS.0*1)+(OFS.1*4) ;ie. Slot 0, 1, 4, or 5 - {NDS_MEM_ARM7|NDS_MEM_ARM9, 8, NDS_VRAM_BGA_SLOT0}, //MST 4 0..1 Slot 0-1 (OFS=0), Slot 2-3 (OFS=1) - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_OBJA_SLOT0}, //MST 5 Slot 0 ;16K each (only lower 8K used) - {0xffffffff, 0, 0x0}, // MST 6 INVALID - {0xffffffff, 0, 0x0}, // MST 7 INVALID - },{ //Bank H - {NDS_MEM_ARM7, 0, 0x06898000,0x100000-1}, //MST 0 6898000h-689FFFFh - {NDS_MEM_ARM7, 0, 0x06200000,0x10000-1}, //MST 1 6200000h - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_BGB_SLOT0}, //MST 2 Slot 0-3 - {0xffffffff, 0, 0x0}, // MST 3 INVALID - {NDS_MEM_ARM7, 0, 0x06898000,0x100000-1}, //MST 4 6898000h-689FFFFh - {NDS_MEM_ARM7, 0, 0x06200000,0x10000-1}, //MST 5 6200000h - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_BGB_SLOT0}, //MST 6 Slot 0-3 - {0xffffffff, 0, 0x0}, // MST 7 INVALID - },{ //Bank I - {NDS_MEM_ARM7, 0, 0x068A0000,0x100000-1}, //MST 0 68A0000h-68A3FFFh - {NDS_MEM_ARM7, 0, 0x06208000,0x10000-1}, //MST 1 6208000h - {NDS_MEM_ARM7, 0, 0x06600000,0x4000-1}, //MST 2 6600000h - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_OBJB_SLOT0}, //MST 3 Slot 0 ;16K each (only lower 8K used) - {NDS_MEM_ARM7, 0, 0x068A0000,0x100000-1}, //MST 4 68A0000h-68A3FFFh - {NDS_MEM_ARM7, 0, 0x06208000,0x10000-1}, //MST 5 6208000h - {NDS_MEM_ARM7, 0, 0x06600000,0x4000-1}, //MST 6 6600000h - {NDS_MEM_ARM7|NDS_MEM_ARM9, 0, NDS_VRAM_OBJB_SLOT0}, //MST 7 Slot 0 ;16K each (only lower 8K used) - } + } vram_bank_info_t; + + const static vram_bank_info_t bank_info[9][8] = { + { + //Bank A +{NDS_MEM_ARM7, 0, 0x06800000, 0x100000 - 1}, // MST 0 6800000h-681FFFFh + {NDS_MEM_ARM7, 1, 0x06000000, 0x80000 - 1}, // MST 1 6000000h+(20000h*OFS) + {NDS_MEM_ARM7, 6, 0x06400000, 0x40000 - 1}, // MST 2 6400000h+(20000h*OFS.0) ;OFS.1 must be zero + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, // MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) + {NDS_MEM_ARM7, 0, 0x06800000, 0x100000 - 1}, // MST 4 + {NDS_MEM_ARM7, 1, 0x06000000, 0x80000 - 1}, // MST 5 + {NDS_MEM_ARM7, 6, 0x06400000, 0x40000 - 1}, // MST 6 + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, // MST 7 + }, + { + //Bank B +{NDS_MEM_ARM7, 0, 0x06820000, 0x100000 - 1}, // MST 0 6820000h-683FFFFh + {NDS_MEM_ARM7, 1, 0x06000000, 0x80000 - 1}, // MST 1 6000000h+(20000h*OFS) + {NDS_MEM_ARM7, 6, 0x06400000, 0x40000 - 1}, // MST 2 6400000h+(20000h*OFS.0) ;OFS.1 must be zero + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, // MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) + {NDS_MEM_ARM7, 0, 0x06820000, 0x100000 - 1}, // MST 4 + {NDS_MEM_ARM7, 1, 0x06000000, 0x80000 - 1}, // MST 5 + {NDS_MEM_ARM7, 6, 0x06400000, 0x40000 - 1}, // MST 6 + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, // MST 7 + }, + { + //Bank C +{NDS_MEM_ARM7, 0, 0x06840000, 0x100000 - 1}, // MST 0 6840000h-685FFFFh + {NDS_MEM_ARM7, 1, 0x06000000, 0x80000 - 1}, // MST 1 6000000h+(20000h*OFS) + {NDS_MEM_ARM9 | NDS_MEM_PPU, 6, 0x06000000, 0x80000 - 1}, // MST 2 6000000h+(20000h*OFS.0) ;OFS.1 must be zero + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, // MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) + {NDS_MEM_ARM7, 0, 0x06200000, 0x20000 - 1}, // MST 4 6200000h + {0xffffffff, 0, 0x0}, // MST 5 INVALID + {0xffffffff, 0, 0x0}, // MST 6 INVALID + {0xffffffff, 0, 0x0}, // MST 7 INVALID + }, + { + //Bank D +{NDS_MEM_ARM7, 0, 0x06860000, 0x100000 - 1}, // MST 0 6860000h-687FFFFh + {NDS_MEM_ARM7, 1, 0x06000000, 0x80000 - 1}, // MST 1 6000000h+(20000h*OFS) + {NDS_MEM_ARM9 | NDS_MEM_PPU, 6, 0x06000000, 0x80000 - 1}, // MST 2 6000000h+(20000h*OFS.0) ;OFS.1 must be zero + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 6, NDS_VRAM_TEX_SLOT0}, // MST 3 Slot OFS(0-3) ;(Slot2-3: Texture, or Rear-plane) + {NDS_MEM_ARM7, 0, 0x06600000, 0x20000 - 1}, // MST 4 6600000h + {0xffffffff, 0, 0x0}, // MST 5 INVALID + {0xffffffff, 0, 0x0}, // MST 6 INVALID + {0xffffffff, 0, 0x0}, // MST 7 INVALID + }, + { + //Bank E +{NDS_MEM_ARM7, 0, 0x06880000, 0x100000 - 1}, // MST 0 6880000h-688FFFFh + {NDS_MEM_ARM7, 0, 0x06000000, 0x80000 - 1}, // MST 1 6000000h + {NDS_MEM_ARM7, 0, 0x06400000, 0x40000 - 1}, // MST 2 6400000h + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_TEX_PAL_SLOT0}, // MST 3 Slots 0-3;OFS=don't care + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_BGA_SLOT0}, // MST 4 (64K Slot 0-3 ;only lower 32K used) + {0xffffffff, 0, 0x0}, // MST 5 INVALID + {0xffffffff, 0, 0x0}, // MST 6 INVALID + {0xffffffff, 0, 0x0}, // MST 7 INVALID + }, + { + //Bank F +{NDS_MEM_ARM7, 0, 0x06890000, 0x100000 - 1}, // MST 0 6890000h-6893FFFh + {NDS_MEM_ARM7, 2, 0x06000000, 0x80000 - 1}, // MST 1 6000000h+(4000h*OFS.0)+(10000h*OFS.1) + {NDS_MEM_ARM7, 2, 0x06400000, 0x40000 - 1}, // MST 2 6400000h+(4000h*OFS.0)+(10000h*OFS.1) + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 9, NDS_VRAM_TEX_PAL_SLOT0}, // MST 3 Slot (OFS.0*1)+(OFS.1*4) ;ie. Slot 0, 1, 4, or 5 + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 8, NDS_VRAM_BGA_SLOT0}, // MST 4 0..1 Slot 0-1 (OFS=0), Slot 2-3 (OFS=1) + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_OBJA_SLOT0}, // MST 5 Slot 0 ;16K each (only lower 8K used) + {0xffffffff, 0, 0x0}, // MST 6 INVALID + {0xffffffff, 0, 0x0}, // MST 7 INVALID + }, + { + //Bank G +{NDS_MEM_ARM7, 0, 0x06894000, 0x100000 - 1}, // MST 0 6894000h-6897FFFh + {NDS_MEM_ARM7, 2, 0x06000000, 0x80000 - 1}, // MST 1 6000000h+(4000h*OFS.0)+(10000h*OFS.1) + {NDS_MEM_ARM7, 2, 0x06400000, 0x40000 - 1}, // MST 2 6400000h+(4000h*OFS.0)+(10000h*OFS.1) + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 9, NDS_VRAM_TEX_PAL_SLOT0}, // MST3 Slot (OFS.0*1)+(OFS.1*4) ;ie. Slot 0, 1, 4, or 5 + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 8, NDS_VRAM_BGA_SLOT0}, // MST 4 0..1 Slot 0-1 (OFS=0), Slot 2-3 (OFS=1) + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_OBJA_SLOT0}, // MST 5 Slot 0 ;16K each (only lower 8K used) + {0xffffffff, 0, 0x0}, // MST 6 INVALID + {0xffffffff, 0, 0x0}, // MST 7 INVALID + }, + { + //Bank H +{NDS_MEM_ARM7, 0, 0x06898000, 0x100000 - 1}, // MST 0 6898000h-689FFFFh + {NDS_MEM_ARM7, 0, 0x06200000, 0x10000 - 1}, // MST 1 6200000h + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_BGB_SLOT0}, // MST 2 Slot 0-3 + {0xffffffff, 0, 0x0}, // MST 3 INVALID + {NDS_MEM_ARM7, 0, 0x06898000, 0x100000 - 1}, // MST 4 6898000h-689FFFFh + {NDS_MEM_ARM7, 0, 0x06200000, 0x10000 - 1}, // MST 5 6200000h + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_BGB_SLOT0}, // MST 6 Slot 0-3 + {0xffffffff, 0, 0x0}, // MST 7 INVALID + }, + { + //Bank I +{NDS_MEM_ARM7, 0, 0x068A0000, 0x100000 - 1}, // MST 0 68A0000h-68A3FFFh + {NDS_MEM_ARM7, 0, 0x06208000, 0x10000 - 1}, // MST 1 6208000h + {NDS_MEM_ARM7, 0, 0x06600000, 0x4000 - 1}, // MST 2 6600000h + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_OBJB_SLOT0}, // MST 3 Slot 0 ;16K each (only lower 8K used) + {NDS_MEM_ARM7, 0, 0x068A0000, 0x100000 - 1}, // MST 4 68A0000h-68A3FFFh + {NDS_MEM_ARM7, 0, 0x06208000, 0x10000 - 1}, // MST 5 6208000h + {NDS_MEM_ARM7, 0, 0x06600000, 0x4000 - 1}, // MST 6 6600000h + {NDS_MEM_ARM7 | NDS_MEM_ARM9, 0, NDS_VRAM_OBJB_SLOT0}, // MST 7 Slot 0 ;16K each (only lower 8K used) + } }; int total_banks = 9; - int vram_offset = 0; + int vram_offset = 0; - bool special_case_multiple_found = false; - uint32_t ret_data=0; + bool special_case_multiple_found = false; + uint32_t ret_data = 0; - for(int b = 0; b= bank_size[b]) continue; + int vram_addr = bank_offset + vram_off; - int bank_offset = address-base; - bank_offset&=bank.mirror? bank.mirror : -1; - if(bank_offset>=bank_size[b])continue; - int vram_addr = bank_offset+vram_off; + if(special_case_multiple_found) + nds->mem.vram_translation_cache[lookup_addr] = 0; + else + nds->mem.vram_translation_cache[lookup_addr] = nds->mem.curr_vram_translation_key | SB_BFE(vram_addr, 14, 10); - if(special_case_multiple_found)nds->mem.vram_translation_cache[lookup_addr]=0; - else nds->mem.vram_translation_cache[lookup_addr] = nds->mem.curr_vram_translation_key | SB_BFE(vram_addr,14,10); - special_case_multiple_found = true; - - ret_data|= nds_apply_mem_op(nds->mem.vram,vram_addr,data,transaction_type); + + ret_data |= nds_apply_mem_op(nds->mem.vram, vram_addr, data, transaction_type); } - return ret_data; + return ret_data; } -static bool nds_preprocess_mmio(nds_t * nds, uint32_t addr, uint32_t data, int transaction_type); -static void nds_postprocess_mmio_write(nds_t * nds, uint32_t addr, uint32_t data, int transaction_type); -static FORCE_INLINE uint32_t nds9_process_memory_transaction(nds_t * nds, uint32_t addr, uint32_t data, int transaction_type){ +static bool nds_preprocess_mmio(nds_t *nds, uint32_t addr, uint32_t data, int transaction_type); +static void nds_postprocess_mmio_write(nds_t *nds, uint32_t addr, uint32_t data, int transaction_type); +static FORCE_INLINE uint32_t nds9_process_memory_transaction(nds_t *nds, uint32_t addr, uint32_t data, int transaction_type) { uint32_t *ret = &nds->mem.openbus_word; - switch(addr>>24){ - case 0x2: //Main RAM - if(!(transaction_type&(NDS_MEM_ARM9))||(transaction_type&(NDS_MEM_WRITE)))nds->mem.slow_bus_cycles+=(transaction_type&NDS_MEM_SEQ)?1:9; - /*else{ - bool found = false; - bool code = (transaction_type&NDS_MEM_CODE); - static uint32_t dcache[4*1024/32]; - static uint32_t icache[8*1024/32]; - uint32_t * cache = code?icache:dcache; - uint32_t hash = code? 8*1024/4/32- 1: 4*1024/4/32-1; - uint32_t key = addr/32; - if((transaction_type&NDS_MEM_WRITE)){ - if((addr/16)&1)key|=0x10000000; - else key|=0x20000000; - } - uint32_t cache_addr = (key&hash); - uint32_t shift_val = key; - uint32_t evict_key = cache[cache_addr*4+3]>>28; - for(int i=0;i<4;++i){ - uint32_t t = cache[cache_addr*4+i]; - cache[cache_addr*4+i] = shift_val; - shift_val = t; - if(((key^shift_val)&0x0fffffff)==0){ - cache[cache_addr*4+0]|=shift_val&0xf0000000; - found=true; - break; - } - } - if(!(transaction_type&NDS_MEM_WRITE)){ - if(!found){ - int seq_words = 4; - if(evict_key>2)seq_words=8; - if(code)nds->mem.slow_bus_cycles+=8; - else nds->mem.slow_bus_cycles+=8+seq_words; - } - } - }*/ - addr&=4*1024*1024-1; - *ret = nds_apply_mem_op(nds->mem.ram, addr, data, transaction_type); - break; - case 0x3: //Shared WRAM - { - nds->mem.slow_bus_cycles+=(transaction_type&NDS_MEM_SEQ)?1:4; - uint32_t orig_addr = addr; - uint8_t cnt = nds9_io_read8(nds,NDS9_WRAMCNT)&0x3; - const int offset[4]={0,16*1024,0,0}; - const int mask[4]={32*1024-1,16*1024-1,16*1024-1,0}; - if(cnt==3)break; - addr=(addr&mask[cnt])+offset[cnt]; - *ret = nds_apply_mem_op(nds->mem.wram, addr, data, transaction_type); + switch(addr >> 24) { + case 0x2: // Main RAM + if(!(transaction_type & (NDS_MEM_ARM9)) || (transaction_type & (NDS_MEM_WRITE))) nds->mem.slow_bus_cycles += (transaction_type & NDS_MEM_SEQ) ? 1 : 9; + /*else{ + bool found = false; + bool code = (transaction_type&NDS_MEM_CODE); + static uint32_t dcache[4*1024/32]; + static uint32_t icache[8*1024/32]; + uint32_t * cache = code?icache:dcache; + uint32_t hash = code? 8*1024/4/32- 1: 4*1024/4/32-1; + uint32_t key = addr/32; + if((transaction_type&NDS_MEM_WRITE)){ + if((addr/16)&1)key|=0x10000000; + else key|=0x20000000; } - break; - case 0x4: - nds->mem.slow_bus_cycles+=(transaction_type&NDS_MEM_SEQ)?1:4; - if((addr&0xffff)>=0x2000||addr>=0x04200000){*ret = 0; return *ret;} - if(addr >=0x04100000&&addr <0x04200000){addr|=NDS_IO_MAP_041_OFFSET;} - bool process_write = nds_preprocess_mmio(nds,addr,data,transaction_type); - int baddr =addr&0xffff; - if(process_write)*ret = nds_apply_mem_op(nds->mem.io, baddr, data, transaction_type); - if(!(transaction_type&NDS_MEM_DEBUG)){ - nds->mem.mmio_debug_access_buffer[baddr/4]|=(transaction_type&NDS_MEM_WRITE)?0x70:0xf; - if(nds->mem.mmio_debug_access_buffer[baddr/4]&0x80)nds->arm7.trigger_breakpoint =true; + uint32_t cache_addr = (key&hash); + uint32_t shift_val = key; + uint32_t evict_key = cache[cache_addr*4+3]>>28; + for(int i=0;i<4;++i){ + uint32_t t = cache[cache_addr*4+i]; + cache[cache_addr*4+i] = shift_val; + shift_val = t; + if(((key^shift_val)&0x0fffffff)==0){ + cache[cache_addr*4+0]|=shift_val&0xf0000000; + found=true; + break; } - if((transaction_type&NDS_MEM_WRITE)){ - nds_postprocess_mmio_write(nds,addr,data,transaction_type); + } + if(!(transaction_type&NDS_MEM_WRITE)){ + if(!found){ + int seq_words = 4; + if(evict_key>2)seq_words=8; + if(code)nds->mem.slow_bus_cycles+=8; + else nds->mem.slow_bus_cycles+=8+seq_words; } - break; - case 0x5: //Palette - nds->mem.slow_bus_cycles+=(transaction_type&NDS_MEM_SEQ)?1:4; - addr&=2*1024-1; - *ret = nds_apply_mem_op(nds->mem.palette, addr, data, transaction_type); - break; - case 0x6: //VRAM(NDS9) WRAM(NDS7) - nds->mem.slow_bus_cycles+=(transaction_type&NDS_MEM_SEQ)?1:4; - *ret = nds_apply_vram_mem_op(nds, addr, data, transaction_type); - break; - case 0x7: - nds->mem.slow_bus_cycles+=(transaction_type&NDS_MEM_SEQ)?1:4; - addr&=2*1024-1; - *ret = nds_apply_mem_op(nds->mem.oam, addr, data, transaction_type); - break; - case 0xFF: - if(addr>=0xFFFF0000){ - addr&=4*1024-1; - *ret = nds_apply_mem_op(nds->mem.nds9_bios, addr, data, transaction_type&~NDS_MEM_WRITE); } - break; + }*/ + addr &= 4 * 1024 * 1024 - 1; + *ret = nds_apply_mem_op(nds->mem.ram, addr, data, transaction_type); + break; + case 0x3: // Shared WRAM + { + nds->mem.slow_bus_cycles += (transaction_type & NDS_MEM_SEQ) ? 1 : 4; + uint32_t orig_addr = addr; + uint8_t cnt = nds9_io_read8(nds, NDS9_WRAMCNT) & 0x3; + const int offset[4] = {0, 16 * 1024, 0, 0}; + const int mask[4] = {32 * 1024 - 1, 16 * 1024 - 1, 16 * 1024 - 1, 0}; + if(cnt == 3) break; + addr = (addr & mask[cnt]) + offset[cnt]; + *ret = nds_apply_mem_op(nds->mem.wram, addr, data, transaction_type); + } break; + case 0x4: + nds->mem.slow_bus_cycles += (transaction_type & NDS_MEM_SEQ) ? 1 : 4; + if((addr & 0xffff) >= 0x2000 || addr >= 0x04200000) { + *ret = 0; + return *ret; + } + if(addr >= 0x04100000 && addr < 0x04200000) { addr |= NDS_IO_MAP_041_OFFSET; } + bool process_write = nds_preprocess_mmio(nds, addr, data, transaction_type); + int baddr = addr & 0xffff; + if(process_write) *ret = nds_apply_mem_op(nds->mem.io, baddr, data, transaction_type); + if(!(transaction_type & NDS_MEM_DEBUG)) { + nds->mem.mmio_debug_access_buffer[baddr / 4] |= (transaction_type & NDS_MEM_WRITE) ? 0x70 : 0xf; + if(nds->mem.mmio_debug_access_buffer[baddr / 4] & 0x80) nds->arm7.trigger_breakpoint = true; + } + if((transaction_type & NDS_MEM_WRITE)) { + nds_postprocess_mmio_write(nds, addr, data, transaction_type); + } + break; + case 0x5: // Palette + nds->mem.slow_bus_cycles += (transaction_type & NDS_MEM_SEQ) ? 1 : 4; + addr &= 2 * 1024 - 1; + *ret = nds_apply_mem_op(nds->mem.palette, addr, data, transaction_type); + break; + case 0x6: // VRAM(NDS9) WRAM(NDS7) + nds->mem.slow_bus_cycles += (transaction_type & NDS_MEM_SEQ) ? 1 : 4; + *ret = nds_apply_vram_mem_op(nds, addr, data, transaction_type); + break; + case 0x7: + nds->mem.slow_bus_cycles += (transaction_type & NDS_MEM_SEQ) ? 1 : 4; + addr &= 2 * 1024 - 1; + *ret = nds_apply_mem_op(nds->mem.oam, addr, data, transaction_type); + break; + case 0xFF: + if(addr >= 0xFFFF0000) { + addr &= 4 * 1024 - 1; + *ret = nds_apply_mem_op(nds->mem.nds9_bios, addr, data, transaction_type & ~NDS_MEM_WRITE); + } + break; } - return *ret; + return *ret; } -static FORCE_INLINE uint32_t nds9_process_memory_transaction_cpu(nds_t * nds, uint32_t addr, uint32_t data, int transaction_type){ +static FORCE_INLINE uint32_t nds9_process_memory_transaction_cpu(nds_t *nds, uint32_t addr, uint32_t data, int transaction_type) { uint32_t *ret = &nds->mem.openbus_word; - if(addr>=nds->mem.dtcm_start_address&&addrmem.dtcm_end_address){ - if(SB_LIKELY(nds->mem.dtcm_enable&&(!nds->mem.dtcm_load_mode||(transaction_type&NDS_MEM_WRITE)))){ - nds->mem.openbus_word = nds_apply_mem_op(nds->mem.data_tcm,(addr-nds->mem.dtcm_start_address)&(16*1024-1),data,transaction_type); - return *ret; + if(addr >= nds->mem.dtcm_start_address && addr < nds->mem.dtcm_end_address) { + if(SB_LIKELY(nds->mem.dtcm_enable && (!nds->mem.dtcm_load_mode || (transaction_type & NDS_MEM_WRITE)))) { + nds->mem.openbus_word = nds_apply_mem_op(nds->mem.data_tcm, (addr - nds->mem.dtcm_start_address) & (16 * 1024 - 1), data, transaction_type); + return *ret; } } - if(addr>=nds->mem.itcm_start_address&&addrmem.itcm_end_address){ - if(SB_LIKELY(nds->mem.itcm_enable&&(!nds->mem.itcm_load_mode||(transaction_type&NDS_MEM_WRITE)))){ - nds->mem.openbus_word = nds_apply_mem_op(nds->mem.code_tcm,(addr-nds->mem.itcm_start_address)&(32*1024-1),data,transaction_type); - return *ret; + if(addr >= nds->mem.itcm_start_address && addr < nds->mem.itcm_end_address) { + if(SB_LIKELY(nds->mem.itcm_enable && (!nds->mem.itcm_load_mode || (transaction_type & NDS_MEM_WRITE)))) { + nds->mem.openbus_word = nds_apply_mem_op(nds->mem.code_tcm, (addr - nds->mem.itcm_start_address) & (32 * 1024 - 1), data, transaction_type); + return *ret; } } - return nds9_process_memory_transaction(nds,addr,data,transaction_type); + return nds9_process_memory_transaction(nds, addr, data, transaction_type); } -static FORCE_INLINE uint32_t nds7_process_memory_transaction(nds_t * nds, uint32_t addr, uint32_t data, int transaction_type){ +static FORCE_INLINE uint32_t nds7_process_memory_transaction(nds_t *nds, uint32_t addr, uint32_t data, int transaction_type) { uint32_t *ret = &nds->mem.openbus_word; - switch(addr>>24){ - case 0x0: //BIOS(NDS7), TCM(NDS9) - if(addr<0x4000){ - if(nds->arm7.registers[PC]<0x4000) - nds->mem.arm7_bios_word = nds_apply_mem_op(nds->mem.nds7_bios,addr,data,transaction_type&~NDS_MEM_WRITE); - //else nds->mem.bios_word=0; - *ret = nds->mem.arm7_bios_word; - } - break; - case 0x2: //Main RAM - addr&=4*1024*1024-1; - *ret = nds_apply_mem_op(nds->mem.ram, addr, data, transaction_type); - break; - case 0x3: //Shared WRAM - { - uint32_t orig_addr = addr; - uint8_t cnt = nds9_io_read8(nds,NDS9_WRAMCNT)&0x3; - if(addr<=0x037FFFFF){ - const int offset[4]={0,0,16*1024,0}; - const int mask[4]={0,16*1024-1,16*1024-1,32*1024-1}; - if(mask[cnt]==0)addr= 32*1024+((addr)&(64*1024-1)); - else addr=(addr&mask[cnt])+offset[cnt]; - }else addr= 32*1024+((addr-0x03800000)&(64*1024-1)); - *ret = nds_apply_mem_op(nds->mem.wram, addr, data, transaction_type); - } - break; - case 0x4: - if(addr>=0x04200000){ - //Wifi Registers - if(addr>=0x04800000&&addr<=0x0480ffff){ - nds->mem.wifi_io[0x803D]=2; - uint32_t baddr= addr&0xffff; - *ret = nds_apply_mem_op(nds->mem.wifi_io, baddr, data, transaction_type); - if((addr&~1) == 0x04808158&&(transaction_type&NDS_MEM_WRITE)&&!(transaction_type&NDS_MEM_1B)){ - uint8_t value= nds->mem.wifi_io[0x8159]; - int direction = value >> 4; - int index = nds->mem.wifi_io[0x8158]; - - if (index < sizeof(nds->mem.baseband_io)) { - if (direction == 5) nds->mem.baseband_io[index] = nds->mem.wifi_io[0x815A]; - if (direction == 6) nds->mem.wifi_io[0x815C] = nds->mem.baseband_io[index]; - } - } - } - break; - } - if((addr&0xffff)>=0x2000){*ret = 0; return *ret;} - if(addr >=0x04100000&&addr <0x04200000){addr|=NDS_IO_MAP_041_OFFSET;} - - bool process_write = nds_preprocess_mmio(nds,addr,data,transaction_type); - int baddr =addr|NDS_IO_MAP_SPLIT_OFFSET; - baddr&=0xffff; - if(process_write)*ret = nds_apply_mem_op(nds->mem.io, baddr, data, transaction_type); - if(!(transaction_type&NDS_MEM_DEBUG)){ - nds->mem.mmio_debug_access_buffer[baddr/4]|=(transaction_type&NDS_MEM_WRITE)?0x70:0xf; - if(nds->mem.mmio_debug_access_buffer[baddr/4]&0x80)nds->arm7.trigger_breakpoint =true; - } - if((transaction_type&NDS_MEM_WRITE)){ - nds_postprocess_mmio_write(nds,addr,data,transaction_type); - } - if(SB_UNLIKELY(nds->io7_log)){ - if(addr!=0x04000180){ - const char* dir = (transaction_type&NDS_MEM_WRITE)? "W":"R"; - uint32_t io_data = (transaction_type&NDS_MEM_WRITE)?data:*ret; - fprintf(nds->io7_log,"%s %08x %08x\n",dir,addr,io_data); + switch(addr >> 24) { + case 0x0: // BIOS(NDS7), TCM(NDS9) + if(addr < 0x4000) { + if(nds->arm7.registers[PC] < 0x4000) + nds->mem.arm7_bios_word = nds_apply_mem_op(nds->mem.nds7_bios, addr, data, transaction_type & ~NDS_MEM_WRITE); + // else nds->mem.bios_word=0; + *ret = nds->mem.arm7_bios_word; + } + break; + case 0x2: // Main RAM + addr &= 4 * 1024 * 1024 - 1; + *ret = nds_apply_mem_op(nds->mem.ram, addr, data, transaction_type); + break; + case 0x3: // Shared WRAM + { + uint32_t orig_addr = addr; + uint8_t cnt = nds9_io_read8(nds, NDS9_WRAMCNT) & 0x3; + if(addr <= 0x037FFFFF) { + const int offset[4] = {0, 0, 16 * 1024, 0}; + const int mask[4] = {0, 16 * 1024 - 1, 16 * 1024 - 1, 32 * 1024 - 1}; + if(mask[cnt] == 0) + addr = 32 * 1024 + ((addr) & (64 * 1024 - 1)); + else + addr = (addr & mask[cnt]) + offset[cnt]; + } else + addr = 32 * 1024 + ((addr - 0x03800000) & (64 * 1024 - 1)); + *ret = nds_apply_mem_op(nds->mem.wram, addr, data, transaction_type); + } break; + case 0x4: + if(addr >= 0x04200000) { + // Wifi Registers + if(addr >= 0x04800000 && addr <= 0x0480ffff) { + nds->mem.wifi_io[0x803D] = 2; + uint32_t baddr = addr & 0xffff; + *ret = nds_apply_mem_op(nds->mem.wifi_io, baddr, data, transaction_type); + if((addr & ~1) == 0x04808158 && (transaction_type & NDS_MEM_WRITE) && !(transaction_type & NDS_MEM_1B)) { + uint8_t value = nds->mem.wifi_io[0x8159]; + int direction = value >> 4; + int index = nds->mem.wifi_io[0x8158]; + + if(index < sizeof(nds->mem.baseband_io)) { + if(direction == 5) nds->mem.baseband_io[index] = nds->mem.wifi_io[0x815A]; + if(direction == 6) nds->mem.wifi_io[0x815C] = nds->mem.baseband_io[index]; } } + } break; - case 0x6: //VRAM(NDS9) WRAM(NDS7) - *ret = nds_apply_vram_mem_op(nds, addr, data, transaction_type); - break; + } + if((addr & 0xffff) >= 0x2000) { + *ret = 0; + return *ret; + } + if(addr >= 0x04100000 && addr < 0x04200000) { addr |= NDS_IO_MAP_041_OFFSET; } + + bool process_write = nds_preprocess_mmio(nds, addr, data, transaction_type); + int baddr = addr | NDS_IO_MAP_SPLIT_OFFSET; + baddr &= 0xffff; + if(process_write) *ret = nds_apply_mem_op(nds->mem.io, baddr, data, transaction_type); + if(!(transaction_type & NDS_MEM_DEBUG)) { + nds->mem.mmio_debug_access_buffer[baddr / 4] |= (transaction_type & NDS_MEM_WRITE) ? 0x70 : 0xf; + if(nds->mem.mmio_debug_access_buffer[baddr / 4] & 0x80) nds->arm7.trigger_breakpoint = true; + } + if((transaction_type & NDS_MEM_WRITE)) { + nds_postprocess_mmio_write(nds, addr, data, transaction_type); + } + if(SB_UNLIKELY(nds->io7_log)) { + if(addr != 0x04000180) { + const char *dir = (transaction_type & NDS_MEM_WRITE) ? "W" : "R"; + uint32_t io_data = (transaction_type & NDS_MEM_WRITE) ? data : *ret; + fprintf(nds->io7_log, "%s %08x %08x\n", dir, addr, io_data); + } + } + break; + case 0x6: // VRAM(NDS9) WRAM(NDS7) + *ret = nds_apply_vram_mem_op(nds, addr, data, transaction_type); + break; } - return *ret; + return *ret; } -static FORCE_INLINE void nds9_write32(nds_t*nds, unsigned baddr, uint32_t data){ - nds9_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_4B|NDS_MEM_ARM9); +static FORCE_INLINE void nds9_write32(nds_t *nds, unsigned baddr, uint32_t data) { + nds9_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_4B | NDS_MEM_ARM9); } -static FORCE_INLINE void nds7_write32(nds_t*nds, unsigned baddr, uint32_t data){ - nds7_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_4B|NDS_MEM_ARM7); +static FORCE_INLINE void nds7_write32(nds_t *nds, unsigned baddr, uint32_t data) { + nds7_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_4B | NDS_MEM_ARM7); } -static FORCE_INLINE void nds9_write16(nds_t*nds, unsigned baddr, uint16_t data){ - nds9_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_2B|NDS_MEM_ARM9); +static FORCE_INLINE void nds9_write16(nds_t *nds, unsigned baddr, uint16_t data) { + nds9_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_2B | NDS_MEM_ARM9); } -static FORCE_INLINE void nds7_write16(nds_t*nds, unsigned baddr, uint16_t data){ - nds7_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_2B|NDS_MEM_ARM7); +static FORCE_INLINE void nds7_write16(nds_t *nds, unsigned baddr, uint16_t data) { + nds7_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_2B | NDS_MEM_ARM7); } -static FORCE_INLINE void nds9_write8(nds_t*nds, unsigned baddr, uint8_t data){ - nds9_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_1B|NDS_MEM_ARM9); +static FORCE_INLINE void nds9_write8(nds_t *nds, unsigned baddr, uint8_t data) { + nds9_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_1B | NDS_MEM_ARM9); } -static FORCE_INLINE void nds7_write8(nds_t*nds, unsigned baddr, uint8_t data){ - nds7_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_1B|NDS_MEM_ARM7); +static FORCE_INLINE void nds7_write8(nds_t *nds, unsigned baddr, uint8_t data) { + nds7_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_1B | NDS_MEM_ARM7); } -static FORCE_INLINE void nds9_debug_write32(nds_t*nds, unsigned baddr, uint32_t data){ - nds9_process_memory_transaction_cpu(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_4B|NDS_MEM_ARM9|NDS_MEM_DEBUG); +static FORCE_INLINE void nds9_debug_write32(nds_t *nds, unsigned baddr, uint32_t data) { + nds9_process_memory_transaction_cpu(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_4B | NDS_MEM_ARM9 | NDS_MEM_DEBUG); } -static FORCE_INLINE void nds9_debug_write16(nds_t*nds, unsigned baddr, uint16_t data){ - nds9_process_memory_transaction_cpu(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_2B|NDS_MEM_ARM9|NDS_MEM_DEBUG); +static FORCE_INLINE void nds9_debug_write16(nds_t *nds, unsigned baddr, uint16_t data) { + nds9_process_memory_transaction_cpu(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_2B | NDS_MEM_ARM9 | NDS_MEM_DEBUG); } -static FORCE_INLINE void nds9_debug_write8(nds_t*nds, unsigned baddr, uint8_t data){ - nds9_process_memory_transaction_cpu(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_1B|NDS_MEM_ARM9|NDS_MEM_DEBUG); +static FORCE_INLINE void nds9_debug_write8(nds_t *nds, unsigned baddr, uint8_t data) { + nds9_process_memory_transaction_cpu(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_1B | NDS_MEM_ARM9 | NDS_MEM_DEBUG); } -static FORCE_INLINE void nds7_debug_write8(nds_t*nds, unsigned baddr, uint8_t data){ - nds7_process_memory_transaction(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_1B|NDS_MEM_ARM7|NDS_MEM_DEBUG); +static FORCE_INLINE void nds7_debug_write8(nds_t *nds, unsigned baddr, uint8_t data) { + nds7_process_memory_transaction(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_1B | NDS_MEM_ARM7 | NDS_MEM_DEBUG); } -static FORCE_INLINE uint32_t nds9_cpu_read32(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_4B|NDS_MEM_ARM9); +static FORCE_INLINE uint32_t nds9_cpu_read32(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_ARM9); } -static FORCE_INLINE uint16_t nds9_cpu_read16(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_2B|NDS_MEM_ARM9); +static FORCE_INLINE uint16_t nds9_cpu_read16(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_ARM9); } -static FORCE_INLINE uint32_t nds9_cpu_read32_seq(nds_t*nds, unsigned baddr, bool is_sequential){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_4B|NDS_MEM_ARM9|NDS_MEM_CODE|(is_sequential?NDS_MEM_SEQ:0)); +static FORCE_INLINE uint32_t nds9_cpu_read32_seq(nds_t *nds, unsigned baddr, bool is_sequential) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_ARM9 | NDS_MEM_CODE | (is_sequential ? NDS_MEM_SEQ : 0)); } -static FORCE_INLINE uint16_t nds9_cpu_read16_seq(nds_t*nds, unsigned baddr, bool is_sequential){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_2B|NDS_MEM_ARM9|NDS_MEM_CODE|(is_sequential?NDS_MEM_SEQ:0)); +static FORCE_INLINE uint16_t nds9_cpu_read16_seq(nds_t *nds, unsigned baddr, bool is_sequential) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_ARM9 | NDS_MEM_CODE | (is_sequential ? NDS_MEM_SEQ : 0)); } -static FORCE_INLINE uint8_t nds9_cpu_read8(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_1B|NDS_MEM_ARM9); +static FORCE_INLINE uint8_t nds9_cpu_read8(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_1B | NDS_MEM_ARM9); } -static FORCE_INLINE void nds9_cpu_write32(nds_t*nds, unsigned baddr, uint32_t data){ - nds9_process_memory_transaction_cpu(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_4B|NDS_MEM_ARM9); +static FORCE_INLINE void nds9_cpu_write32(nds_t *nds, unsigned baddr, uint32_t data) { + nds9_process_memory_transaction_cpu(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_4B | NDS_MEM_ARM9); } -static FORCE_INLINE void nds9_cpu_write16(nds_t*nds, unsigned baddr, uint16_t data){ - nds9_process_memory_transaction_cpu(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_2B|NDS_MEM_ARM9); +static FORCE_INLINE void nds9_cpu_write16(nds_t *nds, unsigned baddr, uint16_t data) { + nds9_process_memory_transaction_cpu(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_2B | NDS_MEM_ARM9); } -static FORCE_INLINE void nds9_cpu_write8(nds_t*nds, unsigned baddr, uint8_t data){ - nds9_process_memory_transaction_cpu(nds,baddr,data,NDS_MEM_WRITE|NDS_MEM_1B|NDS_MEM_ARM9); +static FORCE_INLINE void nds9_cpu_write8(nds_t *nds, unsigned baddr, uint8_t data) { + nds9_process_memory_transaction_cpu(nds, baddr, data, NDS_MEM_WRITE | NDS_MEM_1B | NDS_MEM_ARM9); } -static FORCE_INLINE uint32_t nds9_read32(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction(nds,baddr,0,NDS_MEM_4B|NDS_MEM_ARM9); +static FORCE_INLINE uint32_t nds9_read32(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_ARM9); } -static FORCE_INLINE uint32_t nds7_read32(nds_t*nds, unsigned baddr){ - return nds7_process_memory_transaction(nds,baddr,0,NDS_MEM_4B|NDS_MEM_ARM7); +static FORCE_INLINE uint32_t nds7_read32(nds_t *nds, unsigned baddr) { + return nds7_process_memory_transaction(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_ARM7); } -static FORCE_INLINE uint32_t nds7_read32_seq(nds_t*nds, unsigned baddr,bool is_sequential){ - return nds7_process_memory_transaction(nds,baddr,0,NDS_MEM_4B|NDS_MEM_ARM7|NDS_MEM_CODE|(is_sequential?NDS_MEM_SEQ:0)); +static FORCE_INLINE uint32_t nds7_read32_seq(nds_t *nds, unsigned baddr, bool is_sequential) { + return nds7_process_memory_transaction(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_ARM7 | NDS_MEM_CODE | (is_sequential ? NDS_MEM_SEQ : 0)); } -static FORCE_INLINE uint16_t nds9_read16(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction(nds,baddr,0,NDS_MEM_2B|NDS_MEM_ARM9); +static FORCE_INLINE uint16_t nds9_read16(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_ARM9); } -static FORCE_INLINE uint16_t nds7_read16_seq(nds_t*nds, unsigned baddr,bool is_sequential){ - return nds7_process_memory_transaction(nds,baddr,0,NDS_MEM_2B|NDS_MEM_ARM7|NDS_MEM_CODE|(is_sequential?NDS_MEM_SEQ:0)); +static FORCE_INLINE uint16_t nds7_read16_seq(nds_t *nds, unsigned baddr, bool is_sequential) { + return nds7_process_memory_transaction(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_ARM7 | NDS_MEM_CODE | (is_sequential ? NDS_MEM_SEQ : 0)); } -static FORCE_INLINE uint16_t nds7_read16(nds_t*nds, unsigned baddr){ - return nds7_process_memory_transaction(nds,baddr,0,NDS_MEM_2B|NDS_MEM_ARM7); +static FORCE_INLINE uint16_t nds7_read16(nds_t *nds, unsigned baddr) { + return nds7_process_memory_transaction(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_ARM7); } -static FORCE_INLINE uint8_t nds9_read8(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction(nds,baddr,0,NDS_MEM_1B|NDS_MEM_ARM9); +static FORCE_INLINE uint8_t nds9_read8(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction(nds, baddr, 0, NDS_MEM_1B | NDS_MEM_ARM9); } -static FORCE_INLINE uint8_t nds7_read8(nds_t*nds, unsigned baddr){ - return nds7_process_memory_transaction(nds,baddr,0,NDS_MEM_1B|NDS_MEM_ARM7); +static FORCE_INLINE uint8_t nds7_read8(nds_t *nds, unsigned baddr) { + return nds7_process_memory_transaction(nds, baddr, 0, NDS_MEM_1B | NDS_MEM_ARM7); } -static FORCE_INLINE uint32_t nds9_debug_read32(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_4B|NDS_MEM_ARM9|NDS_MEM_DEBUG); +static FORCE_INLINE uint32_t nds9_debug_read32(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_ARM9 | NDS_MEM_DEBUG); } -static FORCE_INLINE uint16_t nds9_debug_read16(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_2B|NDS_MEM_ARM9|NDS_MEM_DEBUG); +static FORCE_INLINE uint16_t nds9_debug_read16(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_ARM9 | NDS_MEM_DEBUG); } -static FORCE_INLINE uint8_t nds9_debug_read8(nds_t*nds, unsigned baddr){ - return nds9_process_memory_transaction_cpu(nds,baddr,0,NDS_MEM_1B|NDS_MEM_ARM9|NDS_MEM_DEBUG); +static FORCE_INLINE uint8_t nds9_debug_read8(nds_t *nds, unsigned baddr) { + return nds9_process_memory_transaction_cpu(nds, baddr, 0, NDS_MEM_1B | NDS_MEM_ARM9 | NDS_MEM_DEBUG); } -static FORCE_INLINE uint8_t nds7_debug_read8(nds_t*nds, unsigned baddr){ - return nds7_process_memory_transaction(nds,baddr,0,NDS_MEM_1B|NDS_MEM_ARM7|NDS_MEM_DEBUG); +static FORCE_INLINE uint8_t nds7_debug_read8(nds_t *nds, unsigned baddr) { + return nds7_process_memory_transaction(nds, baddr, 0, NDS_MEM_1B | NDS_MEM_ARM7 | NDS_MEM_DEBUG); } -static uint32_t nds_apply_vram_mem_op(nds_t *nds,uint32_t address, uint32_t data, int transaction_type); +static uint32_t nds_apply_vram_mem_op(nds_t *nds, uint32_t address, uint32_t data, int transaction_type); -static FORCE_INLINE uint8_t nds_ppu_read8(nds_t*nds, unsigned baddr){ - return nds_apply_vram_mem_op(nds,baddr,0,NDS_MEM_1B|NDS_MEM_PPU); +static FORCE_INLINE uint8_t nds_ppu_read8(nds_t *nds, unsigned baddr) { + return nds_apply_vram_mem_op(nds, baddr, 0, NDS_MEM_1B | NDS_MEM_PPU); } -static FORCE_INLINE uint16_t nds_ppu_read16(nds_t*nds, unsigned baddr){ - return nds_apply_vram_mem_op(nds,baddr,0,NDS_MEM_2B|NDS_MEM_PPU); +static FORCE_INLINE uint16_t nds_ppu_read16(nds_t *nds, unsigned baddr) { + return nds_apply_vram_mem_op(nds, baddr, 0, NDS_MEM_2B | NDS_MEM_PPU); } -static FORCE_INLINE uint32_t nds_ppu_read32(nds_t*nds, unsigned baddr){ - return nds_apply_vram_mem_op(nds,baddr,0,NDS_MEM_4B|NDS_MEM_PPU); +static FORCE_INLINE uint32_t nds_ppu_read32(nds_t *nds, unsigned baddr) { + return nds_apply_vram_mem_op(nds, baddr, 0, NDS_MEM_4B | NDS_MEM_PPU); } -uint32_t nds9_arm_read32(void* user_data, uint32_t address){return nds9_cpu_read32((nds_t*)user_data,address);} -uint32_t nds9_arm_read16(void* user_data, uint32_t address){return nds9_cpu_read16((nds_t*)user_data,address);} -uint32_t nds9_arm_read32_seq(void* user_data, uint32_t address,bool is_sequential){return nds9_cpu_read32_seq((nds_t*)user_data,address,is_sequential);} -uint32_t nds9_arm_read16_seq(void* user_data, uint32_t address,bool is_sequential){return nds9_cpu_read16_seq((nds_t*)user_data,address,is_sequential);} -uint8_t nds9_arm_read8(void* user_data, uint32_t address){return nds9_cpu_read8((nds_t*)user_data,address);} -void nds9_arm_write32(void* user_data, uint32_t address, uint32_t data){nds9_cpu_write32((nds_t*)user_data,address,data);} -void nds9_arm_write16(void* user_data, uint32_t address, uint16_t data){nds9_cpu_write16((nds_t*)user_data,address,data);} -void nds9_arm_write8(void* user_data, uint32_t address, uint8_t data){nds9_cpu_write8((nds_t*)user_data,address,data);} - -uint32_t nds7_arm_read32(void* user_data, uint32_t address){return nds7_read32((nds_t*)user_data,address);} -uint32_t nds7_arm_read16(void* user_data, uint32_t address){return nds7_read16((nds_t*)user_data,address);} -uint32_t nds7_arm_read32_seq(void* user_data, uint32_t address,bool is_sequential){return nds7_read32_seq((nds_t*)user_data,address,is_sequential);} -uint32_t nds7_arm_read16_seq(void* user_data, uint32_t address,bool is_sequential){return nds7_read16_seq((nds_t*)user_data,address,is_sequential);} -uint8_t nds7_arm_read8(void* user_data, uint32_t address){return nds7_read8((nds_t*)user_data,address);} -void nds7_arm_write32(void* user_data, uint32_t address, uint32_t data){nds7_write32((nds_t*)user_data,address,data);} -void nds7_arm_write16(void* user_data, uint32_t address, uint16_t data){nds7_write16((nds_t*)user_data,address,data);} -void nds7_arm_write8(void* user_data, uint32_t address, uint8_t data){nds7_write8((nds_t*)user_data,address,data);} - -uint32_t nds_coprocessor_read(void* user_data, int coproc,int opcode,int Cn, int Cm,int Cp); -void nds_coprocessor_write(void* user_data, int coproc,int opcode,int Cn, int Cm,int Cp,uint32_t data); - - -static FORCE_INLINE uint32_t nds_compute_access_cycles_dma(nds_t *nds, uint32_t address,int request_size/*0: 1B,1: 2B,3: 4B*/){ +uint32_t nds9_arm_read32(void *user_data, uint32_t address) { return nds9_cpu_read32((nds_t *)user_data, address); } +uint32_t nds9_arm_read16(void *user_data, uint32_t address) { return nds9_cpu_read16((nds_t *)user_data, address); } +uint32_t nds9_arm_read32_seq(void *user_data, uint32_t address, bool is_sequential) { return nds9_cpu_read32_seq((nds_t *)user_data, address, is_sequential); } +uint32_t nds9_arm_read16_seq(void *user_data, uint32_t address, bool is_sequential) { return nds9_cpu_read16_seq((nds_t *)user_data, address, is_sequential); } +uint8_t nds9_arm_read8(void *user_data, uint32_t address) { return nds9_cpu_read8((nds_t *)user_data, address); } +void nds9_arm_write32(void *user_data, uint32_t address, uint32_t data) { nds9_cpu_write32((nds_t *)user_data, address, data); } +void nds9_arm_write16(void *user_data, uint32_t address, uint16_t data) { nds9_cpu_write16((nds_t *)user_data, address, data); } +void nds9_arm_write8(void *user_data, uint32_t address, uint8_t data) { nds9_cpu_write8((nds_t *)user_data, address, data); } + +uint32_t nds7_arm_read32(void *user_data, uint32_t address) { return nds7_read32((nds_t *)user_data, address); } +uint32_t nds7_arm_read16(void *user_data, uint32_t address) { return nds7_read16((nds_t *)user_data, address); } +uint32_t nds7_arm_read32_seq(void *user_data, uint32_t address, bool is_sequential) { return nds7_read32_seq((nds_t *)user_data, address, is_sequential); } +uint32_t nds7_arm_read16_seq(void *user_data, uint32_t address, bool is_sequential) { return nds7_read16_seq((nds_t *)user_data, address, is_sequential); } +uint8_t nds7_arm_read8(void *user_data, uint32_t address) { return nds7_read8((nds_t *)user_data, address); } +void nds7_arm_write32(void *user_data, uint32_t address, uint32_t data) { nds7_write32((nds_t *)user_data, address, data); } +void nds7_arm_write16(void *user_data, uint32_t address, uint16_t data) { nds7_write16((nds_t *)user_data, address, data); } +void nds7_arm_write8(void *user_data, uint32_t address, uint8_t data) { nds7_write8((nds_t *)user_data, address, data); } + +uint32_t nds_coprocessor_read(void *user_data, int coproc, int opcode, int Cn, int Cm, int Cp); +void nds_coprocessor_write(void *user_data, int coproc, int opcode, int Cn, int Cm, int Cp, uint32_t data); + +static FORCE_INLINE uint32_t nds_compute_access_cycles_dma(nds_t *nds, uint32_t address, int request_size /*0: 1B,1: 2B,3: 4B*/) { return 1; } // Try to load a GBA rom, return false on invalid rom -bool nds_load_rom(sb_emu_state_t*emu,nds_t* nds, nds_scratch_t* scratch); -static void nds_reset_gpu(nds_t*nds); -void nds_reset(nds_t*nds); - -void nds9_copy_card_region_to_ram(nds_t* nds, const char* region_name, uint32_t rom_offset, uint32_t ram_offset, uint32_t size){ - printf("Copy %s: Card[0x%x]-> RAM[0x%x] Size: %d Card Size:%zu\n",region_name,rom_offset,ram_offset,size,nds->mem.card_size); - for(int i=0;imem.card_size) nds9_write8(nds,ram_offset+i,nds->mem.card_data[rom_offset+i]); +bool nds_load_rom(sb_emu_state_t *emu, nds_t *nds, nds_scratch_t *scratch); +static void nds_reset_gpu(nds_t *nds); +void nds_reset(nds_t *nds); + +void nds9_copy_card_region_to_ram(nds_t *nds, const char *region_name, uint32_t rom_offset, uint32_t ram_offset, uint32_t size) { + printf("Copy %s: Card[0x%x]-> RAM[0x%x] Size: %d Card Size:%zu\n", region_name, rom_offset, ram_offset, size, nds->mem.card_size); + for(int i = 0; i < size; ++i) { + if(rom_offset + i < nds->mem.card_size) nds9_write8(nds, ram_offset + i, nds->mem.card_data[rom_offset + i]); } } -void nds7_copy_card_region_to_ram(nds_t* nds, const char* region_name, uint32_t rom_offset, uint32_t ram_offset, uint32_t size){ - printf("Copy %s: Card[0x%x]-> RAM[0x%x] Size: %d Card Size:%zu\n",region_name,rom_offset,ram_offset,size,nds->mem.card_size); - for(int i=0;imem.card_size) nds7_write8(nds,ram_offset+i,nds->mem.card_data[rom_offset+i]); +void nds7_copy_card_region_to_ram(nds_t *nds, const char *region_name, uint32_t rom_offset, uint32_t ram_offset, uint32_t size) { + printf("Copy %s: Card[0x%x]-> RAM[0x%x] Size: %d Card Size:%zu\n", region_name, rom_offset, ram_offset, size, nds->mem.card_size); + for(int i = 0; i < size; ++i) { + if(rom_offset + i < nds->mem.card_size) nds7_write8(nds, ram_offset + i, nds->mem.card_data[rom_offset + i]); } } -int nds_rom_db_compare_func(const void* a, const void *b){ - return ((nds_rom_entry_t*)a)->GameCode-*(uint32_t*)b; +int nds_rom_db_compare_func(const void *a, const void *b) { + return ((nds_rom_entry_t *)a)->GameCode - *(uint32_t *)b; } -static void nds_update_vram_mapping(nds_t*nds){ - const static int vram_cnt_array[]={ - NDS9_VRAMCNT_A, - NDS9_VRAMCNT_B, - NDS9_VRAMCNT_C, - NDS9_VRAMCNT_D, - NDS9_VRAMCNT_E, - NDS9_VRAMCNT_F, - NDS9_VRAMCNT_G, - NDS9_VRAMCNT_H, //These are not contiguous - NDS9_VRAMCNT_I, //These are not contiguous +static void nds_update_vram_mapping(nds_t *nds) { + const static int vram_cnt_array[] = { + NDS9_VRAMCNT_A, + NDS9_VRAMCNT_B, + NDS9_VRAMCNT_C, + NDS9_VRAMCNT_D, + NDS9_VRAMCNT_E, + NDS9_VRAMCNT_F, + NDS9_VRAMCNT_G, + NDS9_VRAMCNT_H, // These are not contiguous + NDS9_VRAMCNT_I, // These are not contiguous }; - //Recompute VRAM translation key - nds->mem.curr_vram_translation_key=0; - for(int b =0;bmem.curr_vram_translation_key|= bank_key<<(b*6+10); + // Recompute VRAM translation key + nds->mem.curr_vram_translation_key = 0; + for(int b = 0; b < sizeof(vram_cnt_array) / sizeof(vram_cnt_array[0]); ++b) { + uint8_t bank_settings = nds9_io_read8(nds, vram_cnt_array[b]); + uint64_t bank_key = SB_BFE(bank_settings, 0, 5); + bank_key |= SB_BFE(bank_settings, 7, 1) << 5; + nds->mem.curr_vram_translation_key |= bank_key << (b * 6 + 10); } - nds->mem.curr_vram_translation_key|=(1ull)<<63; + nds->mem.curr_vram_translation_key |= (1ull) << 63; } -bool nds_load_rom(sb_emu_state_t*emu,nds_t* nds,nds_scratch_t*scratch){ - if(!sb_path_has_file_ext(emu->rom_path, ".nds"))return false; +bool nds_load_rom(sb_emu_state_t *emu, nds_t *nds, nds_scratch_t *scratch) { + if(!sb_path_has_file_ext(emu->rom_path, ".nds")) return false; - if(emu->rom_size>512*1024*1024){ - printf("ROMs with sizes >512MB (%zu bytes) are too big for the NDS\n",emu->rom_size); + if(emu->rom_size > 512 * 1024 * 1024) { + printf("ROMs with sizes >512MB (%zu bytes) are too big for the NDS\n", emu->rom_size); return false; - } - if(emu->rom_size<1024){ - printf("ROMs with sizes <1024B (%zu bytes) are too small for the NDS\n",emu->rom_size); + } + if(emu->rom_size < 1024) { + printf("ROMs with sizes <1024B (%zu bytes) are too small for the NDS\n", emu->rom_size); return false; } - memset(nds,0,sizeof(nds_t)); + memset(nds, 0, sizeof(nds_t)); - strncpy(nds->save_file_path,emu->save_file_path,SB_FILE_PATH_SIZE); - nds->save_file_path[SB_FILE_PATH_SIZE-1]=0; - memset(&nds->mem,0,sizeof(nds->mem)); + strncpy(nds->save_file_path, emu->save_file_path, SB_FILE_PATH_SIZE); + nds->save_file_path[SB_FILE_PATH_SIZE - 1] = 0; + memset(&nds->mem, 0, sizeof(nds->mem)); - nds->mem.card_data=emu->rom_data; - nds->mem.card_size=emu->rom_size; + nds->mem.card_data = emu->rom_data; + nds->mem.card_size = emu->rom_size; nds->mem.save_data = scratch->save_data; - memcpy(&nds->card,emu->rom_data,sizeof(nds_card_t)); - nds->card.title[11]=0; + memcpy(&nds->card, emu->rom_data, sizeof(nds_card_t)); + nds->card.title[11] = 0; nds->arm7 = arm7_init(nds); nds->arm9 = arm7_init(nds); - - for(int bg = 2;bg<4;++bg){ - nds9_io_store16(nds,GBA_BG2PA+(bg-2)*0x10,1<<8); - nds9_io_store16(nds,GBA_BG2PB+(bg-2)*0x10,0<<8); - nds9_io_store16(nds,GBA_BG2PC+(bg-2)*0x10,0<<8); - nds9_io_store16(nds,GBA_BG2PD+(bg-2)*0x10,1<<8); + + for(int bg = 2; bg < 4; ++bg) { + nds9_io_store16(nds, GBA_BG2PA + (bg - 2) * 0x10, 1 << 8); + nds9_io_store16(nds, GBA_BG2PB + (bg - 2) * 0x10, 0 << 8); + nds9_io_store16(nds, GBA_BG2PC + (bg - 2) * 0x10, 0 << 8); + nds9_io_store16(nds, GBA_BG2PD + (bg - 2) * 0x10, 1 << 8); } - //nds_store32(nds,GBA_DISPCNT,0xe92d0000); - nds9_write16(nds,0x04000088,512); - nds->activate_dmas=false; - nds->last_timer_clock= 0; - if(nds->mem.card_data)memcpy(&nds->card,nds->mem.card_data,sizeof(nds->card)); - bool load_nds7= se_load_bios_file("NDS7 BIOS", nds->save_file_path, "nds7.bin", scratch->nds7_bios,sizeof(scratch->nds7_bios)); - if(!load_nds7)memcpy(scratch->nds7_bios,drastic_bios_arm7_bin,sizeof(drastic_bios_arm7_bin)); - - bool load_nds9= se_load_bios_file("NDS9 BIOS", nds->save_file_path, "nds9.bin", scratch->nds9_bios,sizeof(scratch->nds9_bios)); - if(!load_nds9)memcpy(scratch->nds9_bios,drastic_bios_arm9_bin,sizeof(drastic_bios_arm9_bin)); - - bool loaded_firmware = se_load_bios_file("NDS Firmware", nds->save_file_path, "firmware.bin", scratch->firmware,sizeof(scratch->firmware)); - - bool fast_boot =true; - if(fast_boot){ - const uint32_t initial_regs[37]={ - 0x00000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x0380fd80,0x0000000,0x8000000, - 0xdf,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0380ff80,0x0,0x0380ffc0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0, + // nds_store32(nds,GBA_DISPCNT,0xe92d0000); + nds9_write16(nds, 0x04000088, 512); + nds->activate_dmas = false; + nds->last_timer_clock = 0; + if(nds->mem.card_data) memcpy(&nds->card, nds->mem.card_data, sizeof(nds->card)); + bool load_nds7 = se_load_bios_file("NDS7 BIOS", nds->save_file_path, "nds7.bin", scratch->nds7_bios, sizeof(scratch->nds7_bios)); + if(!load_nds7) memcpy(scratch->nds7_bios, drastic_bios_arm7_bin, sizeof(drastic_bios_arm7_bin)); + + bool load_nds9 = se_load_bios_file("NDS9 BIOS", nds->save_file_path, "nds9.bin", scratch->nds9_bios, sizeof(scratch->nds9_bios)); + if(!load_nds9) memcpy(scratch->nds9_bios, drastic_bios_arm9_bin, sizeof(drastic_bios_arm9_bin)); + + bool loaded_firmware = se_load_bios_file("NDS Firmware", nds->save_file_path, "firmware.bin", scratch->firmware, sizeof(scratch->firmware)); + + bool fast_boot = true; + if(fast_boot) { + const uint32_t initial_regs[37] = { + 0x00000000, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0380fd80, + 0x0000000, + 0x8000000, + 0xdf, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0380ff80, + 0x0, + 0x0380ffc0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, }; - const uint32_t initial_regs_arm9[37]={ - 0x00000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0,0x03002f7c,0x0000000,0x8000000, - 0xdf,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - 0x03003f80,0x0,0x03003fc0,0x0,0x0,0x0,0x0,0x0, - 0x0,0x0,0x0,0x0,0x0, + const uint32_t initial_regs_arm9[37] = { + 0x00000000, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x03002f7c, + 0x0000000, + 0x8000000, + 0xdf, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x03003f80, + 0x0, + 0x03003fc0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, }; - for(int i=0;i<37;++i)nds->arm7.registers[i]=initial_regs[i]; - for(int i=0;i<37;++i)nds->arm9.registers[i]=initial_regs_arm9[i]; - const uint32_t initial_mmio_writes[]={ - 0x4000000,0x80, - 0x4000004,0x7e0000, - 0x4000020,0x100, - 0x4000024,0x1000000, - 0x4000030,0x100, - 0x4000034,0x1000000, - 0x4000080,0xe0000, - 0x4000084,0xf, - 0x4000088,0x200, - 0x4000100,0xff8a, - 0x4000130,0x3ff, - 0x4000134,0x8000, - 0x4000300,0x1, + for(int i = 0; i < 37; ++i) + nds->arm7.registers[i] = initial_regs[i]; + for(int i = 0; i < 37; ++i) + nds->arm9.registers[i] = initial_regs_arm9[i]; + const uint32_t initial_mmio_writes[] = { + 0x4000000, + 0x80, + 0x4000004, + 0x7e0000, + 0x4000020, + 0x100, + 0x4000024, + 0x1000000, + 0x4000030, + 0x100, + 0x4000034, + 0x1000000, + 0x4000080, + 0xe0000, + 0x4000084, + 0xf, + 0x4000088, + 0x200, + 0x4000100, + 0xff8a, + 0x4000130, + 0x3ff, + 0x4000134, + 0x8000, + 0x4000300, + 0x1, }; - for(int i=0;icard.title); - nds9_copy_card_region_to_ram(nds,"ARM9 Executable",nds->card.arm9_rom_offset,nds->card.arm9_ram_address,nds->card.arm9_size); - nds7_copy_card_region_to_ram(nds,"ARM7 Executable",nds->card.arm7_rom_offset,nds->card.arm7_ram_address,nds->card.arm7_size); + uint32_t init_C1C00 = 0x0005707d; // Enable ITCM and DTCM + nds_coprocessor_write(nds, 15, 0, 9, 1, 0, init_dtcm); + nds_coprocessor_write(nds, 15, 0, 9, 1, 1, 0x00000020); + nds_coprocessor_write(nds, 15, 0, 1, 0, 0, init_C1C00); + nds_coprocessor_write(nds, 15, 0, 0, 0, 1, 0x0F0D2112); + + printf("Game Name: %s\n", nds->card.title); + nds9_copy_card_region_to_ram(nds, "ARM9 Executable", nds->card.arm9_rom_offset, nds->card.arm9_ram_address, nds->card.arm9_size); + nds7_copy_card_region_to_ram(nds, "ARM7 Executable", nds->card.arm7_rom_offset, nds->card.arm7_ram_address, nds->card.arm7_size); nds->arm9.registers[PC] = nds->card.arm9_entrypoint; nds->arm7.registers[PC] = nds->card.arm7_entrypoint; - - printf("ARM9 Entry:0x%x ARM7 Entry:0x%x\n",nds->card.arm9_entrypoint,nds->card.arm7_entrypoint); - //Copy NDS Header into 27FFE00h..27FFF6F - int header_size = 0x27FFF70-0x27FFE00; - for(int i=0;icard)+i)); + printf("ARM9 Entry:0x%x ARM7 Entry:0x%x\n", nds->card.arm9_entrypoint, nds->card.arm7_entrypoint); + + // Copy NDS Header into 27FFE00h..27FFF6F + int header_size = 0x27FFF70 - 0x27FFE00; + for(int i = 0; i < header_size; i += 4) { + nds9_write32(nds, 0x027FFE00 + i, *(uint32_t *)(((uint8_t *)&nds->card) + i)); } - //Default initialize these values for a direct boot to a cartridge - const uint32_t arm9_init[]={ - 0x027FF800, 0x1FC2, // Chip ID 1 - 0x027FF804, 0x1FC2, // Chip ID 2 - 0x027FF850, 0x5835, // ARM7 BIOS CRC - 0x027FF880, 0x0007, // Message from ARM9 to ARM7 - 0x027FF884, 0x0006, // ARM7 boot task - 0x027FFC00, 0x1FC2, // Copy of chip ID 1 - 0x027FFC04, 0x1FC2, // Copy of chip ID 2 - 0x027FFC10, 0x5835, // Copy of ARM7 BIOS CRC - 0x027FFC40, 0x0001, // Boot indicator + // Default initialize these values for a direct boot to a cartridge + const uint32_t arm9_init[] = { + 0x027FF800, 0x1FC2, // Chip ID 1 + 0x027FF804, 0x1FC2, // Chip ID 2 + 0x027FF850, 0x5835, // ARM7 BIOS CRC + 0x027FF880, 0x0007, // Message from ARM9 to ARM7 + 0x027FF884, 0x0006, // ARM7 boot task + 0x027FFC00, 0x1FC2, // Copy of chip ID 1 + 0x027FFC04, 0x1FC2, // Copy of chip ID 2 + 0x027FFC10, 0x5835, // Copy of ARM7 BIOS CRC + 0x027FFC40, 0x0001, // Boot indicator }; - for(int i=0;iarm9.registers[PC] = 0xFFFF0000; nds->arm7.registers[PC] = 0; } - + nds->arm9.irq_table_address = 0xFFFF0000; - nds->mem.card_chip_id= 0x1FC2; - - if(nds->arm7.log_cmp_file){fclose(nds->arm7.log_cmp_file);nds->arm7.log_cmp_file=NULL;}; - if(nds->arm9.log_cmp_file){fclose(nds->arm9.log_cmp_file);nds->arm9.log_cmp_file=NULL;}; - nds->arm7.log_cmp_file =se_load_log_file(nds->save_file_path, "log7.bin"); - nds->arm9.log_cmp_file =se_load_log_file(nds->save_file_path, "log9.bin"); - - - //Preload user settings - uint8_t* firm_data = scratch->firmware; - uint32_t user_data_off = ((firm_data[0x21]<<8)|(firm_data[0x20]))*8; - - if(!loaded_firmware){ - uint8_t stub_header_data[0x200]={ - 0x76,0x30,0xb6,0x1e,0x34,0xe9,0xbb,0xab, - 0x4d,0x41,0x43,0x50,0x30,0x00,0x00,0x61, - 0x34,0x00,0x08,0x00,0x71,0x0c,0x58,0x00, - 0x51,0x08,0x28,0x02,0x05,0xff,0xff,0xff, - 0xc0,0x7f,0x51,0x0b,0xb3,0x0d,0x5d,0x4f, - 0xff,0xff,0xf8,0x9b,0x38,0x01,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09, - 0xbf,0x10,0xc3,0x87,0xfe,0x3f,0xff,0xff, - 0x02,0x18,0x0c,0x01,0x02,0x00,0x17,0x00, - 0x26,0x00,0x18,0x18,0x48,0x00,0x40,0x48, - 0x58,0x00,0x42,0x00,0x40,0x01,0x64,0x80, - 0xe0,0xe0,0x43,0x24,0x0e,0x00,0x32,0x00, - 0xf4,0x01,0x01,0x01,0x6d,0x9b,0x40,0x05, - 0x1b,0x6c,0x48,0x80,0x38,0x00,0x35,0x07, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xb0,0x00,0x04,0x01,0xd8,0xff,0xff,0xc7, - 0xbb,0x01,0xb4,0x7f,0x5a,0x01,0x3f,0x01, - 0x3f,0x36,0x36,0x00,0x78,0x28,0x55,0x08, - 0x28,0x16,0x00,0x01,0x0e,0x20,0x02,0x98, - 0x98,0x1f,0x0a,0x08,0x04,0x01,0x00,0x00, - 0x00,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfc, - 0xfc,0xfa,0xfa,0xfa,0xfa,0xfa,0xf8,0xf8, - 0xf6,0xa5,0x12,0x14,0x12,0x41,0x23,0x03, - 0x04,0x70,0x35,0x0e,0x16,0x16,0x00,0x00, - 0x06,0x01,0xff,0xfe,0xff,0xff,0x00,0x0e, - 0x13,0x00,0x00,0x28,0x1c,0x00,0x07,0xc0, - 0x00,0x03,0x9c,0x12,0x28,0x17,0x14,0xba, - 0xe8,0x1a,0x6f,0x45,0x1d,0xfa,0xff,0x23, - 0x30,0x1d,0x24,0x01,0x00,0x28,0x00,0x00, - 0x2c,0x03,0x9c,0x06,0x22,0x00,0x08,0x6f, - 0xff,0x0d,0x28,0x17,0x14,0xba,0xe8,0x1a, - 0x37,0x17,0x14,0x46,0x17,0x19,0x45,0x17, - 0x14,0xd1,0x45,0x1b,0x54,0x17,0x14,0x5d, - 0x74,0x19,0x62,0x17,0x14,0xe9,0xa2,0x1b, - 0x71,0x17,0x14,0x74,0xd1,0x19,0x80,0x17, - 0x14,0x00,0x00,0x18,0x8e,0x17,0x14,0x8c, - 0x2e,0x1a,0x9d,0x17,0x14,0x17,0x5d,0x18, - 0xab,0x17,0x14,0xa3,0x8b,0x1a,0xba,0x17, - 0x14,0x2f,0xba,0x18,0xc8,0x17,0x14,0xba, - 0xe8,0x1a,0xd7,0x17,0x14,0x46,0x17,0x19, - 0xfa,0x17,0x14,0x2f,0xba,0x18,0xb1,0xb1, - 0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb2,0xb2, - 0xb3,0xb3,0xb4,0xb4,0x10,0x10,0x10,0x10, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x10,0x10,0x1c,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0x01,0x00,0x7a,0x2c, - 0x66,0x50,0xa6,0xad,0x94,0x80,0x5f,0x15, - 0x73,0xa0,0x60,0x12,0x4c,0xd5,0x2e,0xed, - 0x5f,0xc7,0x6b,0x0e,0x8d,0x1c,0xa6,0x0c, - 0x02,0x27,0x6f,0x5e,0x68,0xaa,0xaf,0xd9, - 0xf9,0x47,0xcf,0x9b,0x16,0x32,0xa9,0x2d, - 0x4b,0xbf,0x28,0xb0,0x01,0xb4,0xdc,0x08, - 0xa3,0x87,0x5f,0x1d,0x37,0xe4,0x08,0x87, - 0x7f,0xa0,0x97,0xb3,0x1d,0xce,0x19,0x62, - 0xed,0xcd,0xee,0x2f,0x38,0x79,0x47,0xd5, - 0x51,0x70,0x21,0x27,0xa6,0xdc,0x47,0xe7, - 0xbd,0x51,0xdf,0xe1,0x97,0x81,0x2f,0x3d, - 0xf4,0x54,0xf1,0x5d,0x41,0x20,0xa6,0x3c, - 0x84,0x62,0x34,0xb9,0xbd,0x3d,0x3f,0xa5, - 0x5c,0x24,0x6a,0x9d,0x5a,0x1b,0xe9,0x00, - 0xb4,0x2b,0x51,0x35,0x62,0xc6,0x07,0xe4, - 0x5b,0xca,0xfa,0x81,0x1a,0x41,0x83,0xe1, + nds->mem.card_chip_id = 0x1FC2; + + if(nds->arm7.log_cmp_file) { + fclose(nds->arm7.log_cmp_file); + nds->arm7.log_cmp_file = NULL; + }; + if(nds->arm9.log_cmp_file) { + fclose(nds->arm9.log_cmp_file); + nds->arm9.log_cmp_file = NULL; + }; + nds->arm7.log_cmp_file = se_load_log_file(nds->save_file_path, "log7.bin"); + nds->arm9.log_cmp_file = se_load_log_file(nds->save_file_path, "log9.bin"); + + // Preload user settings + uint8_t *firm_data = scratch->firmware; + uint32_t user_data_off = ((firm_data[0x21] << 8) | (firm_data[0x20])) * 8; + + if(!loaded_firmware) { + uint8_t stub_header_data[0x200] = { + 0x76, + 0x30, + 0xb6, + 0x1e, + 0x34, + 0xe9, + 0xbb, + 0xab, + 0x4d, + 0x41, + 0x43, + 0x50, + 0x30, + 0x00, + 0x00, + 0x61, + 0x34, + 0x00, + 0x08, + 0x00, + 0x71, + 0x0c, + 0x58, + 0x00, + 0x51, + 0x08, + 0x28, + 0x02, + 0x05, + 0xff, + 0xff, + 0xff, + 0xc0, + 0x7f, + 0x51, + 0x0b, + 0xb3, + 0x0d, + 0x5d, + 0x4f, + 0xff, + 0xff, + 0xf8, + 0x9b, + 0x38, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x09, + 0xbf, + 0x10, + 0xc3, + 0x87, + 0xfe, + 0x3f, + 0xff, + 0xff, + 0x02, + 0x18, + 0x0c, + 0x01, + 0x02, + 0x00, + 0x17, + 0x00, + 0x26, + 0x00, + 0x18, + 0x18, + 0x48, + 0x00, + 0x40, + 0x48, + 0x58, + 0x00, + 0x42, + 0x00, + 0x40, + 0x01, + 0x64, + 0x80, + 0xe0, + 0xe0, + 0x43, + 0x24, + 0x0e, + 0x00, + 0x32, + 0x00, + 0xf4, + 0x01, + 0x01, + 0x01, + 0x6d, + 0x9b, + 0x40, + 0x05, + 0x1b, + 0x6c, + 0x48, + 0x80, + 0x38, + 0x00, + 0x35, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xb0, + 0x00, + 0x04, + 0x01, + 0xd8, + 0xff, + 0xff, + 0xc7, + 0xbb, + 0x01, + 0xb4, + 0x7f, + 0x5a, + 0x01, + 0x3f, + 0x01, + 0x3f, + 0x36, + 0x36, + 0x00, + 0x78, + 0x28, + 0x55, + 0x08, + 0x28, + 0x16, + 0x00, + 0x01, + 0x0e, + 0x20, + 0x02, + 0x98, + 0x98, + 0x1f, + 0x0a, + 0x08, + 0x04, + 0x01, + 0x00, + 0x00, + 0x00, + 0xff, + 0xff, + 0xfe, + 0xfe, + 0xfe, + 0xfe, + 0xfc, + 0xfc, + 0xfa, + 0xfa, + 0xfa, + 0xfa, + 0xfa, + 0xf8, + 0xf8, + 0xf6, + 0xa5, + 0x12, + 0x14, + 0x12, + 0x41, + 0x23, + 0x03, + 0x04, + 0x70, + 0x35, + 0x0e, + 0x16, + 0x16, + 0x00, + 0x00, + 0x06, + 0x01, + 0xff, + 0xfe, + 0xff, + 0xff, + 0x00, + 0x0e, + 0x13, + 0x00, + 0x00, + 0x28, + 0x1c, + 0x00, + 0x07, + 0xc0, + 0x00, + 0x03, + 0x9c, + 0x12, + 0x28, + 0x17, + 0x14, + 0xba, + 0xe8, + 0x1a, + 0x6f, + 0x45, + 0x1d, + 0xfa, + 0xff, + 0x23, + 0x30, + 0x1d, + 0x24, + 0x01, + 0x00, + 0x28, + 0x00, + 0x00, + 0x2c, + 0x03, + 0x9c, + 0x06, + 0x22, + 0x00, + 0x08, + 0x6f, + 0xff, + 0x0d, + 0x28, + 0x17, + 0x14, + 0xba, + 0xe8, + 0x1a, + 0x37, + 0x17, + 0x14, + 0x46, + 0x17, + 0x19, + 0x45, + 0x17, + 0x14, + 0xd1, + 0x45, + 0x1b, + 0x54, + 0x17, + 0x14, + 0x5d, + 0x74, + 0x19, + 0x62, + 0x17, + 0x14, + 0xe9, + 0xa2, + 0x1b, + 0x71, + 0x17, + 0x14, + 0x74, + 0xd1, + 0x19, + 0x80, + 0x17, + 0x14, + 0x00, + 0x00, + 0x18, + 0x8e, + 0x17, + 0x14, + 0x8c, + 0x2e, + 0x1a, + 0x9d, + 0x17, + 0x14, + 0x17, + 0x5d, + 0x18, + 0xab, + 0x17, + 0x14, + 0xa3, + 0x8b, + 0x1a, + 0xba, + 0x17, + 0x14, + 0x2f, + 0xba, + 0x18, + 0xc8, + 0x17, + 0x14, + 0xba, + 0xe8, + 0x1a, + 0xd7, + 0x17, + 0x14, + 0x46, + 0x17, + 0x19, + 0xfa, + 0x17, + 0x14, + 0x2f, + 0xba, + 0x18, + 0xb1, + 0xb1, + 0xb1, + 0xb1, + 0xb1, + 0xb2, + 0xb2, + 0xb2, + 0xb2, + 0xb2, + 0xb3, + 0xb3, + 0xb4, + 0xb4, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x1c, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0x01, + 0x00, + 0x7a, + 0x2c, + 0x66, + 0x50, + 0xa6, + 0xad, + 0x94, + 0x80, + 0x5f, + 0x15, + 0x73, + 0xa0, + 0x60, + 0x12, + 0x4c, + 0xd5, + 0x2e, + 0xed, + 0x5f, + 0xc7, + 0x6b, + 0x0e, + 0x8d, + 0x1c, + 0xa6, + 0x0c, + 0x02, + 0x27, + 0x6f, + 0x5e, + 0x68, + 0xaa, + 0xaf, + 0xd9, + 0xf9, + 0x47, + 0xcf, + 0x9b, + 0x16, + 0x32, + 0xa9, + 0x2d, + 0x4b, + 0xbf, + 0x28, + 0xb0, + 0x01, + 0xb4, + 0xdc, + 0x08, + 0xa3, + 0x87, + 0x5f, + 0x1d, + 0x37, + 0xe4, + 0x08, + 0x87, + 0x7f, + 0xa0, + 0x97, + 0xb3, + 0x1d, + 0xce, + 0x19, + 0x62, + 0xed, + 0xcd, + 0xee, + 0x2f, + 0x38, + 0x79, + 0x47, + 0xd5, + 0x51, + 0x70, + 0x21, + 0x27, + 0xa6, + 0xdc, + 0x47, + 0xe7, + 0xbd, + 0x51, + 0xdf, + 0xe1, + 0x97, + 0x81, + 0x2f, + 0x3d, + 0xf4, + 0x54, + 0xf1, + 0x5d, + 0x41, + 0x20, + 0xa6, + 0x3c, + 0x84, + 0x62, + 0x34, + 0xb9, + 0xbd, + 0x3d, + 0x3f, + 0xa5, + 0x5c, + 0x24, + 0x6a, + 0x9d, + 0x5a, + 0x1b, + 0xe9, + 0x00, + 0xb4, + 0x2b, + 0x51, + 0x35, + 0x62, + 0xc6, + 0x07, + 0xe4, + 0x5b, + 0xca, + 0xfa, + 0x81, + 0x1a, + 0x41, + 0x83, + 0xe1, }; - for(int i=0;i<0x200;++i){ - firm_data[(i)&(sizeof(scratch->firmware)-1)]=stub_header_data[i]; + for(int i = 0; i < 0x200; ++i) { + firm_data[(i) & (sizeof(scratch->firmware) - 1)] = stub_header_data[i]; } - user_data_off = ((firm_data[0x21]<<8)|(firm_data[0x20]))*8; - uint8_t user_d_stub[]={ - 0x05,0x00,0x00,0x07,0x05,0x00,0x53,0x00, - 0x6b,0x00,0x79,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf0,0x01,0xe0,0x01,0x20,0x20,0xe0,0x0d, - 0xd0,0x09,0xe0,0xa0,0x01,0xfc,0x05,0x7e, - 0x28,0xa0,0x3c,0x0a,0x00,0x00,0x00,0x00, - 0x30,0x00,0xf2,0x72,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0x05,0x00,0x00,0x07,0x05,0x00,0x53,0x00, - 0x6b,0x00,0x79,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xf0,0x01,0xe0,0x01,0x20,0x20,0xe0,0x0d, - 0xd0,0x09,0xe0,0xa0,0x01,0xfc,0x05,0x7e, - 0x28,0xa0,0x3c,0x0a,0x00,0x00,0x00,0x00, - 0x31,0x00,0xf2,0x72,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + user_data_off = ((firm_data[0x21] << 8) | (firm_data[0x20])) * 8; + uint8_t user_d_stub[] = { + 0x05, + 0x00, + 0x00, + 0x07, + 0x05, + 0x00, + 0x53, + 0x00, + 0x6b, + 0x00, + 0x79, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xf0, + 0x01, + 0xe0, + 0x01, + 0x20, + 0x20, + 0xe0, + 0x0d, + 0xd0, + 0x09, + 0xe0, + 0xa0, + 0x01, + 0xfc, + 0x05, + 0x7e, + 0x28, + 0xa0, + 0x3c, + 0x0a, + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x00, + 0xf2, + 0x72, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0x05, + 0x00, + 0x00, + 0x07, + 0x05, + 0x00, + 0x53, + 0x00, + 0x6b, + 0x00, + 0x79, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xf0, + 0x01, + 0xe0, + 0x01, + 0x20, + 0x20, + 0xe0, + 0x0d, + 0xd0, + 0x09, + 0xe0, + 0xa0, + 0x01, + 0xfc, + 0x05, + 0x7e, + 0x28, + 0xa0, + 0x3c, + 0x0a, + 0x00, + 0x00, + 0x00, + 0x00, + 0x31, + 0x00, + 0xf2, + 0x72, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, }; - for(int i=0x3FE00;i<0x40000;++i){ - firm_data[i]=user_d_stub[i-0x3FE00]; + for(int i = 0x3FE00; i < 0x40000; ++i) { + firm_data[i] = user_d_stub[i - 0x3FE00]; } - }else{ - for(int i=0x3FE00;i<0x40000;++i){ - printf("0x%02x,",firm_data[i]); - if((i%8)==7)printf("\n"); + } else { + for(int i = 0x3FE00; i < 0x40000; ++i) { + printf("0x%02x,", firm_data[i]); + if((i % 8) == 7) printf("\n"); } } - for(int i=0;i<0x070;++i){ - nds9_write8(nds,i+0x27FFC80,firm_data[(user_data_off+i)&(sizeof(scratch->firmware)-1)]); + for(int i = 0; i < 0x070; ++i) { + nds9_write8(nds, i + 0x27FFC80, firm_data[(user_data_off + i) & (sizeof(scratch->firmware) - 1)]); } nds_reset_gpu(nds); - uint32_t game_code = (nds->card.gamecode[0]<<0)|(nds->card.gamecode[1]<<8)|(nds->card.gamecode[2]<<16)|(nds->card.gamecode[3]<<24); - nds_rom_entry_t* rom_entry = (nds_rom_entry_t*)bsearch(&game_code, nds_rom_database, - sizeof(nds_rom_database)/sizeof(nds_rom_database[0]),sizeof(nds_rom_database[0]), - nds_rom_db_compare_func); - if(rom_entry&&rom_entry->GameCode==game_code){ + uint32_t game_code = (nds->card.gamecode[0] << 0) | (nds->card.gamecode[1] << 8) | (nds->card.gamecode[2] << 16) | (nds->card.gamecode[3] << 24); + nds_rom_entry_t *rom_entry = (nds_rom_entry_t *)bsearch(&game_code, nds_rom_database, + sizeof(nds_rom_database) / sizeof(nds_rom_database[0]), sizeof(nds_rom_database[0]), + nds_rom_db_compare_func); + if(rom_entry && rom_entry->GameCode == game_code) { nds->backup.backup_type = rom_entry->SaveMemType; - }else{ + } else { printf("Save type could not be looked up in the database. A default will be assumed"); nds->backup.backup_type = NDS_BACKUP_EEPROM_128KB; - } - printf("NDS Save Type: %d\n",nds->backup.backup_type); - - size_t bytes=0; - uint8_t*data = sb_load_file_data(emu->save_file_path,&bytes); - if(data){ - printf("Loaded save file: %s, bytes: %zu\n",emu->save_file_path,bytes); - if(bytes>=nds_get_save_size(nds))bytes=nds_get_save_size(nds); + } + printf("NDS Save Type: %d\n", nds->backup.backup_type); + + size_t bytes = 0; + uint8_t *data = sb_load_file_data(emu->save_file_path, &bytes); + if(data) { + printf("Loaded save file: %s, bytes: %zu\n", emu->save_file_path, bytes); + if(bytes >= nds_get_save_size(nds)) bytes = nds_get_save_size(nds); memcpy(nds->mem.save_data, data, bytes); sb_free_file_data(data); - }else{ - printf("Could not find save file: %s\n",emu->save_file_path); - for(int i=0;imem.save_data);++i) nds->mem.save_data[i]=0; + } else { + printf("Could not find save file: %s\n", emu->save_file_path); + for(int i = 0; i < sizeof(nds->mem.save_data); ++i) + nds->mem.save_data[i] = 0; } nds_update_vram_mapping(nds); - //nds->gx_log = fopen("gxlog.txt","wb"); - //nds->io7_log = fopen("io7log.txt","wb"); - //nds->io9_log = fopen("io9log.txt","wb"); - //nds->vert_log = fopen("vertlog.txt","wb"); - //nds->gc_log = fopen("gclog.txt","wb"); - //nds->dma_log = fopen("dmalog.txt","wb"); - - return true; -} -static void nds_unload(nds_t* nds, nds_scratch_t* scratch){ - if(nds->arm7.log_cmp_file){fclose(nds->arm7.log_cmp_file);nds->arm7.log_cmp_file=NULL;}; - if(nds->arm9.log_cmp_file){fclose(nds->arm9.log_cmp_file);nds->arm9.log_cmp_file=NULL;}; + // nds->gx_log = fopen("gxlog.txt","wb"); + // nds->io7_log = fopen("io7log.txt","wb"); + // nds->io9_log = fopen("io9log.txt","wb"); + // nds->vert_log = fopen("vertlog.txt","wb"); + // nds->gc_log = fopen("gclog.txt","wb"); + // nds->dma_log = fopen("dmalog.txt","wb"); + + return true; +} +static void nds_unload(nds_t *nds, nds_scratch_t *scratch) { + if(nds->arm7.log_cmp_file) { + fclose(nds->arm7.log_cmp_file); + nds->arm7.log_cmp_file = NULL; + }; + if(nds->arm9.log_cmp_file) { + fclose(nds->arm9.log_cmp_file); + nds->arm9.log_cmp_file = NULL; + }; printf("Unloading DS data\n"); } -uint32_t nds_sqrt_u64(uint64_t value){ +uint32_t nds_sqrt_u64(uint64_t value) { uint32_t res = 0; - for(uint64_t b=0;b<32;++b){ - uint64_t test = res | (1ull<<(31-b)); - if(test*test<=value)res = test; + for(uint64_t b = 0; b < 32; ++b) { + uint64_t test = res | (1ull << (31 - b)); + if(test * test <= value) res = test; } - return res; + return res; } #define NDS_CARD_MAIN_DATA_READ 0xB7 -#define NDS_CARD_CHIP_ID_READ 0xB8 -static void nds_process_gc_bus_read(nds_t*nds, int cpu_id){ - if(nds->mem.card_transfer_bytes<=0)return; - nds->activate_dmas=true; - uint16_t exmemcnt = nds9_io_read16(nds,NDS9_EXMEMCNT); - bool arm7_has_slot = SB_BFE(exmemcnt,11,1); - if(cpu_id==arm7_has_slot)return; - - uint8_t data[4]; - int bank = nds->mem.card_read_offset&~0xfff; - int bank_off = nds->mem.card_read_offset&0xfff; - data[0]= nds->mem.card_transfer_data[(bank_off++)&0xfff]; - data[1]= nds->mem.card_transfer_data[(bank_off++)&0xfff]; - data[2]= nds->mem.card_transfer_data[(bank_off++)&0xfff]; - data[3]= nds->mem.card_transfer_data[(bank_off++)&0xfff]; - uint32_t data_out = *(uint32_t*)(data); - if(nds->gc_log)fprintf(nds->gc_log,"Data: %08x\n",data_out); - //printf("data[%08x]: %08x\n",nds->mem.card_read_offset,data_out); - nds_io_store32(nds,cpu_id,NDS_GC_BUS,data_out); - nds->mem.card_read_offset = bank|(bank_off&0xfff); - - nds->mem.card_transfer_bytes-=4; - nds->activate_dmas=true; - if(nds->mem.card_transfer_bytes<=0){ - uint32_t gcbus_ctl = nds_io_read32(nds,cpu_id,NDS_GCBUS_CTL); - gcbus_ctl&=~((1<<31)|(1<<23));// Clear data ready and busy bit - nds_io_store32(nds,cpu_id,NDS_GCBUS_CTL,gcbus_ctl); - }else{ - uint16_t auxspi = nds_io_read16(nds,cpu_id,NDS9_AUXSPICNT); - bool transfer_ready_irq = SB_BFE(auxspi,14,1); - if(transfer_ready_irq){ - if(cpu_id==NDS_ARM7)nds7_send_interrupt(nds,4,1<mem.card_transfer_bytes <= 0) return; + nds->activate_dmas = true; + uint16_t exmemcnt = nds9_io_read16(nds, NDS9_EXMEMCNT); + bool arm7_has_slot = SB_BFE(exmemcnt, 11, 1); + if(cpu_id == arm7_has_slot) return; + + uint8_t data[4]; + int bank = nds->mem.card_read_offset & ~0xfff; + int bank_off = nds->mem.card_read_offset & 0xfff; + data[0] = nds->mem.card_transfer_data[(bank_off++) & 0xfff]; + data[1] = nds->mem.card_transfer_data[(bank_off++) & 0xfff]; + data[2] = nds->mem.card_transfer_data[(bank_off++) & 0xfff]; + data[3] = nds->mem.card_transfer_data[(bank_off++) & 0xfff]; + uint32_t data_out = *(uint32_t *)(data); + if(nds->gc_log) fprintf(nds->gc_log, "Data: %08x\n", data_out); + // printf("data[%08x]: %08x\n",nds->mem.card_read_offset,data_out); + nds_io_store32(nds, cpu_id, NDS_GC_BUS, data_out); + nds->mem.card_read_offset = bank | (bank_off & 0xfff); + + nds->mem.card_transfer_bytes -= 4; + nds->activate_dmas = true; + if(nds->mem.card_transfer_bytes <= 0) { + uint32_t gcbus_ctl = nds_io_read32(nds, cpu_id, NDS_GCBUS_CTL); + gcbus_ctl &= ~((1 << 31) | (1 << 23)); // Clear data ready and busy bit + nds_io_store32(nds, cpu_id, NDS_GCBUS_CTL, gcbus_ctl); + } else { + uint16_t auxspi = nds_io_read16(nds, cpu_id, NDS9_AUXSPICNT); + bool transfer_ready_irq = SB_BFE(auxspi, 14, 1); + if(transfer_ready_irq) { + if(cpu_id == NDS_ARM7) + nds7_send_interrupt(nds, 4, 1 << NDS_INT_GC_TRANSFER_DONE); + else + nds9_send_interrupt(nds, 4, 1 << NDS_INT_GC_TRANSFER_DONE); } } } -static void nds_process_gc_bus_ctl(nds_t*nds, int cpu_id){ - uint16_t exmemcnt = nds9_io_read16(nds,NDS9_EXMEMCNT); - bool arm7_has_slot = SB_BFE(exmemcnt,11,1); - if(arm7_has_slot&&cpu_id!=NDS_ARM7)return; - nds->activate_dmas=true; - uint32_t gcbus_ctl = nds_io_read32(nds,cpu_id,NDS_GCBUS_CTL); - bool start_transfer = SB_BFE(gcbus_ctl,31,1); - //printf("NDS GCBUS: 0x%08x\n",gcbus_ctl); - gcbus_ctl&=~((1u<<31)|(1u<<23));// Clear data ready and start bit - gcbus_ctl|=(1u<<23); - if(start_transfer){ - //Mask out start bit; +static void nds_process_gc_bus_ctl(nds_t *nds, int cpu_id) { + uint16_t exmemcnt = nds9_io_read16(nds, NDS9_EXMEMCNT); + bool arm7_has_slot = SB_BFE(exmemcnt, 11, 1); + if(arm7_has_slot && cpu_id != NDS_ARM7) return; + nds->activate_dmas = true; + uint32_t gcbus_ctl = nds_io_read32(nds, cpu_id, NDS_GCBUS_CTL); + bool start_transfer = SB_BFE(gcbus_ctl, 31, 1); + // printf("NDS GCBUS: 0x%08x\n",gcbus_ctl); + gcbus_ctl &= ~((1u << 31) | (1u << 23)); // Clear data ready and start bit + gcbus_ctl |= (1u << 23); + if(start_transfer) { + // Mask out start bit; uint8_t commands[8]; - for(int i=0;i<7;++i)commands[i]=nds9_io_read8(nds,NDS_GCBUS_CMD+i); - if(nds->gc_log)fprintf(nds->gc_log,"GCBUS CMD: %02x %02x %02x%02x %02x%02x %02x%02x\n",commands[0],commands[1],commands[2],commands[3] - ,commands[4],commands[5],commands[6],commands[7]); - switch(commands[0]){ - case NDS_CARD_MAIN_DATA_READ:{ - //Encrypted data read; - int read_off = (((int)commands[1])<<24)|(((int)commands[2])<<16)|(((int)commands[3])<<8)|(((int)commands[4])<<0); - if(read_off<=0x7FFF)read_off=0x8000+(read_off &0x1FF); - nds->mem.card_read_offset=read_off; - int data_block_size = SB_BFE(gcbus_ctl,24,3); - const int transfer_size_map[8]={0, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 4}; - for(int i=0;i<0x1000;++i){ - nds->mem.card_transfer_data[i]=nds->mem.card_data[(i+(read_off&~0xfff))%nds->mem.card_size]; - } - nds->mem.card_transfer_bytes=transfer_size_map[data_block_size]; - if(nds->gc_log)fprintf(nds->gc_log,"Encrypted Read: 0x%08x transfer_size: %08x\n",read_off,nds->mem.card_transfer_bytes); - gcbus_ctl|=(1<<23)|(1<<31);//Set data_ready bit and busy - }break; - case NDS_CARD_CHIP_ID_READ:{ - //Encrypted data read; - nds->mem.card_read_offset=0; - nds->mem.card_transfer_data[0]=SB_BFE(nds->mem.card_chip_id,0,8); - nds->mem.card_transfer_data[1]=SB_BFE(nds->mem.card_chip_id,8,8); - nds->mem.card_transfer_data[2]=SB_BFE(nds->mem.card_chip_id,16,8); - nds->mem.card_transfer_data[3]=SB_BFE(nds->mem.card_chip_id,24,8); - nds->mem.card_transfer_bytes=4; - if(nds->gc_log)fprintf(nds->gc_log,"CHIPID Read transfer:\n"); - gcbus_ctl|=(1<<23)|(1<<31);//Set data_ready bit and busy - }break; - default: printf("Unknown cmd: %02x\n",commands[0]);break; + for(int i = 0; i < 7; ++i) + commands[i] = nds9_io_read8(nds, NDS_GCBUS_CMD + i); + if(nds->gc_log) fprintf(nds->gc_log, "GCBUS CMD: %02x %02x %02x%02x %02x%02x %02x%02x\n", commands[0], commands[1], commands[2], commands[3], commands[4], commands[5], commands[6], commands[7]); + switch(commands[0]) { + case NDS_CARD_MAIN_DATA_READ: { + // Encrypted data read; + int read_off = (((int)commands[1]) << 24) | (((int)commands[2]) << 16) | (((int)commands[3]) << 8) | (((int)commands[4]) << 0); + if(read_off <= 0x7FFF) read_off = 0x8000 + (read_off & 0x1FF); + nds->mem.card_read_offset = read_off; + int data_block_size = SB_BFE(gcbus_ctl, 24, 3); + const int transfer_size_map[8] = {0, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 4}; + for(int i = 0; i < 0x1000; ++i) { + nds->mem.card_transfer_data[i] = nds->mem.card_data[(i + (read_off & ~0xfff)) % nds->mem.card_size]; + } + nds->mem.card_transfer_bytes = transfer_size_map[data_block_size]; + if(nds->gc_log) fprintf(nds->gc_log, "Encrypted Read: 0x%08x transfer_size: %08x\n", read_off, nds->mem.card_transfer_bytes); + gcbus_ctl |= (1 << 23) | (1 << 31); // Set data_ready bit and busy + } break; + case NDS_CARD_CHIP_ID_READ: { + // Encrypted data read; + nds->mem.card_read_offset = 0; + nds->mem.card_transfer_data[0] = SB_BFE(nds->mem.card_chip_id, 0, 8); + nds->mem.card_transfer_data[1] = SB_BFE(nds->mem.card_chip_id, 8, 8); + nds->mem.card_transfer_data[2] = SB_BFE(nds->mem.card_chip_id, 16, 8); + nds->mem.card_transfer_data[3] = SB_BFE(nds->mem.card_chip_id, 24, 8); + nds->mem.card_transfer_bytes = 4; + if(nds->gc_log) fprintf(nds->gc_log, "CHIPID Read transfer:\n"); + gcbus_ctl |= (1 << 23) | (1 << 31); // Set data_ready bit and busy + } break; + default: printf("Unknown cmd: %02x\n", commands[0]); break; } - uint16_t auxspi = nds_io_read16(nds,cpu_id,NDS9_AUXSPICNT); - bool transfer_ready_irq = SB_BFE(auxspi,14,1); - if(transfer_ready_irq&&(gcbus_ctl&(1<<23))){ - if(cpu_id==NDS_ARM7)nds7_send_interrupt(nds,4,1<activate_dmas=true; - nds_io_store32(nds,cpu_id,NDS_GCBUS_CTL,gcbus_ctl); -} + nds->activate_dmas = true; + nds_io_store32(nds, cpu_id, NDS_GCBUS_CTL, gcbus_ctl); +} /* Only simulates a small subset of the RTC needed to make time events work in the pokemon games. */ -static FORCE_INLINE void nds_process_rtc_state_machine(nds_t* nds){ - uint8_t data = nds7_io_read8(nds,NDS7_RTC_BUS); - bool clk = !SB_BFE(data,1,1); - bool io_dat = SB_BFE(data,0,1); - bool cs = SB_BFE(data,2,1); - #define SERIAL_INIT 0 - #define SERIAL_CLK_LOW 1 - #define SERIAL_CLK_HIGH 2 - - #define NDS_RTC_RECV_CMD -1 - #define NDS_RTC_RESET 0 - #define NDS_RTC_STATUS 1 - #define NDS_RTC_DATE_TIME 2 - #define NDS_RTC_TIME 3 - - nds_rtc_t * rtc = &(nds->rtc); - - rtc->status_register &= ~((1<<7)); +static FORCE_INLINE void nds_process_rtc_state_machine(nds_t *nds) { + uint8_t data = nds7_io_read8(nds, NDS7_RTC_BUS); + bool clk = !SB_BFE(data, 1, 1); + bool io_dat = SB_BFE(data, 0, 1); + bool cs = SB_BFE(data, 2, 1); +#define SERIAL_INIT 0 +#define SERIAL_CLK_LOW 1 +#define SERIAL_CLK_HIGH 2 + +#define NDS_RTC_RECV_CMD -1 +#define NDS_RTC_RESET 0 +#define NDS_RTC_STATUS 1 +#define NDS_RTC_DATE_TIME 2 +#define NDS_RTC_TIME 3 + + nds_rtc_t *rtc = &(nds->rtc); + + rtc->status_register &= ~((1 << 7)); rtc->status_register |= 0x40; - if(cs==0){ - rtc->serial_state=SERIAL_INIT; - rtc->serial_bits_clocked=0; + if(cs == 0) { + rtc->serial_state = SERIAL_INIT; + rtc->serial_bits_clocked = 0; rtc->state = NDS_RTC_RECV_CMD; } - if(cs!=0){ - bool new_bit = false; - - if(nds->rtc.serial_state==SERIAL_CLK_LOW&&clk){ - nds->rtc.input_register<<=1; - nds->rtc.input_register|=((uint64_t)io_dat); + if(cs != 0) { + bool new_bit = false; + + if(nds->rtc.serial_state == SERIAL_CLK_LOW && clk) { + nds->rtc.input_register <<= 1; + nds->rtc.input_register |= ((uint64_t)io_dat); new_bit = true; - - bool out_bit = (rtc->output_register&1); - data&=~1; - data|=out_bit&1; - nds7_io_store8(nds,NDS7_RTC_BUS,data); - rtc->output_register>>=1; + + bool out_bit = (rtc->output_register & 1); + data &= ~1; + data |= out_bit & 1; + nds7_io_store8(nds, NDS7_RTC_BUS, data); + rtc->output_register >>= 1; } - - nds->rtc.serial_state= clk? SERIAL_CLK_HIGH: SERIAL_CLK_LOW; - if(new_bit){ + nds->rtc.serial_state = clk ? SERIAL_CLK_HIGH : SERIAL_CLK_LOW; + + if(new_bit) { nds->rtc.serial_bits_clocked++; - if(nds->rtc.serial_bits_clocked==8) nds->rtc.state= SB_BFE(nds->rtc.input_register,0,4); - int cmd = SB_BFE(rtc->state,1,3); - bool read = SB_BFE(rtc->state,0,1); - switch(cmd){ - case NDS_RTC_RECV_CMD:break; - case NDS_RTC_STATUS:{ - if(rtc->serial_bits_clocked==8) rtc->output_register = rtc->status_register; - if(rtc->serial_bits_clocked==16){ - if(!read)rtc->status_register=SB_BFE(rtc->input_register,0,8); - rtc->state= NDS_RTC_RECV_CMD; - rtc->serial_bits_clocked=0; - } - break; + if(nds->rtc.serial_bits_clocked == 8) nds->rtc.state = SB_BFE(nds->rtc.input_register, 0, 4); + int cmd = SB_BFE(rtc->state, 1, 3); + bool read = SB_BFE(rtc->state, 0, 1); + switch(cmd) { + case NDS_RTC_RECV_CMD: break; + case NDS_RTC_STATUS: { + if(rtc->serial_bits_clocked == 8) rtc->output_register = rtc->status_register; + if(rtc->serial_bits_clocked == 16) { + if(!read) rtc->status_register = SB_BFE(rtc->input_register, 0, 8); + rtc->state = NDS_RTC_RECV_CMD; + rtc->serial_bits_clocked = 0; } - case NDS_RTC_DATE_TIME:{ - if(rtc->serial_bits_clocked==8) rtc->output_register = - ((uint64_t)(rtc->year&0xff) <<(0*8))| - ((uint64_t)(rtc->month&0xff) <<(1*8))| - ((uint64_t)(rtc->day&0xff) <<(2*8))| - ((uint64_t)(rtc->day_of_week&0xff)<<(3*8))| - ((uint64_t)(rtc->hour&0xff) <<(4*8))| - ((uint64_t)(rtc->minute&0xff) <<(5*8))| - ((uint64_t)(rtc->second&0xff) <<(6*8)); - if(rtc->serial_bits_clocked==8*8){ - if(!read){ - rtc->year = SB_BFE(rtc->input_register,6*8,8); - rtc->month = SB_BFE(rtc->input_register,5*8,8); - rtc->day = SB_BFE(rtc->input_register,4*8,8); - rtc->day_of_week = SB_BFE(rtc->input_register,3*8,8); - rtc->hour = SB_BFE(rtc->input_register,2*8,8); - rtc->minute = SB_BFE(rtc->input_register,1*8,8); - rtc->second = SB_BFE(rtc->input_register,0*8,8); - } - rtc->state= NDS_RTC_RECV_CMD; - rtc->serial_bits_clocked=0; + break; + } + case NDS_RTC_DATE_TIME: { + if(rtc->serial_bits_clocked == 8) rtc->output_register = + ((uint64_t)(rtc->year & 0xff) << (0 * 8)) | + ((uint64_t)(rtc->month & 0xff) << (1 * 8)) | + ((uint64_t)(rtc->day & 0xff) << (2 * 8)) | + ((uint64_t)(rtc->day_of_week & 0xff) << (3 * 8)) | + ((uint64_t)(rtc->hour & 0xff) << (4 * 8)) | + ((uint64_t)(rtc->minute & 0xff) << (5 * 8)) | + ((uint64_t)(rtc->second & 0xff) << (6 * 8)); + if(rtc->serial_bits_clocked == 8 * 8) { + if(!read) { + rtc->year = SB_BFE(rtc->input_register, 6 * 8, 8); + rtc->month = SB_BFE(rtc->input_register, 5 * 8, 8); + rtc->day = SB_BFE(rtc->input_register, 4 * 8, 8); + rtc->day_of_week = SB_BFE(rtc->input_register, 3 * 8, 8); + rtc->hour = SB_BFE(rtc->input_register, 2 * 8, 8); + rtc->minute = SB_BFE(rtc->input_register, 1 * 8, 8); + rtc->second = SB_BFE(rtc->input_register, 0 * 8, 8); } - break; + rtc->state = NDS_RTC_RECV_CMD; + rtc->serial_bits_clocked = 0; } - case NDS_RTC_TIME:{ - if(rtc->serial_bits_clocked==8) rtc->output_register = - ((uint64_t)(rtc->hour&0xff)<<(0*8))| - ((uint64_t)(rtc->minute&0xff)<<(1*8))| - ((uint64_t)(rtc->second&0xff)<<(2*8)); - if(rtc->serial_bits_clocked==4*8){ - if(!read){ - rtc->hour = SB_BFE(rtc->input_register,0*8,8); - rtc->minute = SB_BFE(rtc->input_register,1*8,8); - rtc->second = SB_BFE(rtc->input_register,2*8,8); - } - rtc->state= NDS_RTC_RECV_CMD; - rtc->serial_bits_clocked=0; + break; + } + case NDS_RTC_TIME: { + if(rtc->serial_bits_clocked == 8) rtc->output_register = + ((uint64_t)(rtc->hour & 0xff) << (0 * 8)) | + ((uint64_t)(rtc->minute & 0xff) << (1 * 8)) | + ((uint64_t)(rtc->second & 0xff) << (2 * 8)); + if(rtc->serial_bits_clocked == 4 * 8) { + if(!read) { + rtc->hour = SB_BFE(rtc->input_register, 0 * 8, 8); + rtc->minute = SB_BFE(rtc->input_register, 1 * 8, 8); + rtc->second = SB_BFE(rtc->input_register, 2 * 8, 8); } - break; + rtc->state = NDS_RTC_RECV_CMD; + rtc->serial_bits_clocked = 0; } + break; + } } } } } -static uint32_t nds_get_save_size(nds_t*nds){ - uint32_t save_size = 0; - nds_card_backup_t * bak = &nds->backup; - switch (bak->backup_type){ - case NDS_BACKUP_NONE :save_size = 0; break; - case NDS_BACKUP_EEPROM_512B :save_size = 512; break; - case NDS_BACKUP_EEPROM_8KB :save_size = 8*1024; break; - case NDS_BACKUP_EEPROM_64KB :save_size = 64*1024; break; - case NDS_BACKUP_EEPROM_128KB:save_size = 128*1024; break; - case NDS_BACKUP_FLASH_256KB :save_size = 256*1024; break; - case NDS_BACKUP_FLASH_512KB :save_size = 512*1024; break; - case NDS_BACKUP_FLASH_1MB :save_size = 1024*1024; break; - case NDS_BACKUP_NAND_8MB :save_size = 8*1024*1024; break; - case NDS_BACKUP_NAND_16MB :save_size = 16*1024*1024; break; - case NDS_BACKUP_NAND_64MB :save_size = 64*1024*1024; break; +static uint32_t nds_get_save_size(nds_t *nds) { + uint32_t save_size = 0; + nds_card_backup_t *bak = &nds->backup; + switch(bak->backup_type) { + case NDS_BACKUP_NONE: save_size = 0; break; + case NDS_BACKUP_EEPROM_512B: save_size = 512; break; + case NDS_BACKUP_EEPROM_8KB: save_size = 8 * 1024; break; + case NDS_BACKUP_EEPROM_64KB: save_size = 64 * 1024; break; + case NDS_BACKUP_EEPROM_128KB: save_size = 128 * 1024; break; + case NDS_BACKUP_FLASH_256KB: save_size = 256 * 1024; break; + case NDS_BACKUP_FLASH_512KB: save_size = 512 * 1024; break; + case NDS_BACKUP_FLASH_1MB: save_size = 1024 * 1024; break; + case NDS_BACKUP_NAND_8MB: save_size = 8 * 1024 * 1024; break; + case NDS_BACKUP_NAND_16MB: save_size = 16 * 1024 * 1024; break; + case NDS_BACKUP_NAND_64MB: save_size = 64 * 1024 * 1024; break; } return save_size; } -static uint32_t nds_get_curr_backup_address(nds_t*nds){ - uint32_t save_size = nds_get_save_size(nds); - nds_card_backup_t * bak = &nds->backup; - if(bak->backup_type==NDS_BACKUP_EEPROM_512B){ - uint32_t base_addr = nds->backup.command[1]; - if(bak->command_offset<3)return 0xffffffff; - //Handle high address commands - if(bak->command[0]==0x0B||bak->command[0]==0x0A)base_addr|=0x100; - return (base_addr+bak->command_offset-3)%save_size; +static uint32_t nds_get_curr_backup_address(nds_t *nds) { + uint32_t save_size = nds_get_save_size(nds); + nds_card_backup_t *bak = &nds->backup; + if(bak->backup_type == NDS_BACKUP_EEPROM_512B) { + uint32_t base_addr = nds->backup.command[1]; + if(bak->command_offset < 3) return 0xffffffff; + // Handle high address commands + if(bak->command[0] == 0x0B || bak->command[0] == 0x0A) base_addr |= 0x100; + return (base_addr + bak->command_offset - 3) % save_size; } - if(bak->backup_type>=NDS_BACKUP_EEPROM_8KB&&bak->backup_type<=NDS_BACKUP_EEPROM_64KB){ - uint32_t base_addr = (nds->backup.command[1]<<8)|(nds->backup.command[2]); - if(bak->command_offset<4)return 0xffffffff; - return (base_addr+bak->command_offset-4)%save_size; + if(bak->backup_type >= NDS_BACKUP_EEPROM_8KB && bak->backup_type <= NDS_BACKUP_EEPROM_64KB) { + uint32_t base_addr = (nds->backup.command[1] << 8) | (nds->backup.command[2]); + if(bak->command_offset < 4) return 0xffffffff; + return (base_addr + bak->command_offset - 4) % save_size; } - if(bak->backup_type==NDS_BACKUP_EEPROM_128KB){ - uint32_t base_addr = (nds->backup.command[1]<<16)|(nds->backup.command[2]<<8)|(nds->backup.command[3]); - if(bak->command_offset<5)return 0xffffffff; - return (base_addr+bak->command_offset-5)%save_size; + if(bak->backup_type == NDS_BACKUP_EEPROM_128KB) { + uint32_t base_addr = (nds->backup.command[1] << 16) | (nds->backup.command[2] << 8) | (nds->backup.command[3]); + if(bak->command_offset < 5) return 0xffffffff; + return (base_addr + bak->command_offset - 5) % save_size; } - if(bak->backup_type==NDS_BACKUP_NONE)return 0xffffffff; - printf("Unhandled backup_type: %d\n",bak->backup_type); + if(bak->backup_type == NDS_BACKUP_NONE) return 0xffffffff; + printf("Unhandled backup_type: %d\n", bak->backup_type); return 0xffffffff; } -static void nds_process_gc_spi(nds_t* nds, int cpu_id){ - uint32_t aux_spi_cnt = nds_io_read32(nds,cpu_id,NDS9_AUXSPICNT); - uint8_t spi_data = nds_io_read8(nds,cpu_id,NDS9_AUXSPIDATA); - bool slot_mode = SB_BFE(aux_spi_cnt,13,1); - bool slot_enable = SB_BFE(aux_spi_cnt,15,1); - //Don't process if slot is disabled or not in backup mode - if(slot_enable==false||slot_mode==false)return; - nds_card_backup_t* back = &nds->backup; - uint8_t ret_data = 0; - - if(back->command_offsetcommand)){ - back->command[back->command_offset]=spi_data; +static void nds_process_gc_spi(nds_t *nds, int cpu_id) { + uint32_t aux_spi_cnt = nds_io_read32(nds, cpu_id, NDS9_AUXSPICNT); + uint8_t spi_data = nds_io_read8(nds, cpu_id, NDS9_AUXSPIDATA); + bool slot_mode = SB_BFE(aux_spi_cnt, 13, 1); + bool slot_enable = SB_BFE(aux_spi_cnt, 15, 1); + // Don't process if slot is disabled or not in backup mode + if(slot_enable == false || slot_mode == false) return; + nds_card_backup_t *back = &nds->backup; + uint8_t ret_data = 0; + + if(back->command_offset < sizeof(back->command)) { + back->command[back->command_offset] = spi_data; } back->command_offset++; - //IR Stub (needed due to Pokemon Black Anti-Piracy Check) - //Check for IR-ID command - if(back->command[0]==0x08){ + // IR Stub (needed due to Pokemon Black Anti-Piracy Check) + // Check for IR-ID command + if(back->command[0] == 0x08) { printf("IR ID Read\n"); - ret_data=back->command_offset>1?0xAA:0; - }else{ - if(nds->backup.backup_type>=NDS_BACKUP_FLASH_256KB&&nds->backup.backup_type<=NDS_BACKUP_FLASH_1MB){ - ret_data = nds_process_flash_write(nds,spi_data,&nds->backup.flash,nds->mem.save_data, nds_get_save_size(nds)); - nds->backup.is_dirty=true; - }else{ - switch(back->command[0]){ - case 0x00: /*NOP*/ break ; - case 0x06: /*WREN*/ back->write_enable=true;break; - case 0x04: /*WRDI*/ back->write_enable=false;break; - case 0x05: /*RDSR*/ - /* - Status Register - 0 WIP Write in Progress (1=Busy) (Read only) (always 0 for FRAM chips) - 1 WEL Write Enable Latch (1=Enable) (Read only, except by WREN,WRDI) - 2-3 WP Write Protect (0=None, 1=Upper quarter, 2=Upper Half, 3=All memory) - For 0.5K EEPROM: - 4-7 ONEs Not used (all four bits are always set to "1" each) - For 8K..64K EEPROM and for FRAM: - 4-6 ZERO Not used (all three bits are always set to "0" each) - 7 SRWD Status Register Write Disable (0=Normal, 1=Lock) (Only if /W=LOW) - */ - back->status_reg&= (3<<2)|(1<<7); - if(back->write_enable)back->status_reg|=0x2; - if(back->backup_type==NDS_BACKUP_EEPROM_512B)back->status_reg|=0xf0; - ret_data = back->status_reg; - break; - case 0x01: /*WRSR*/ back->status_reg=spi_data;break; - case 0x9f: /*RDID*/ ret_data = 0xff; break; - case 0x03: /*RD/RDLO*/ - case 0x0B: /*RDHI*/{ - uint32_t addr = nds_get_curr_backup_address(nds); - if(addr!=0xffffffff)ret_data = nds->mem.save_data[addr]; - break; - } - case 0x02: /*WR/WRLO*/ - case 0x0A: /*WRHI*/{ - uint32_t addr = nds_get_curr_backup_address(nds); - if(addr!=0xffffffff&&back->write_enable){ - nds->mem.save_data[addr]=spi_data; - back->is_dirty = true; - } - break; + ret_data = back->command_offset > 1 ? 0xAA : 0; + } else { + if(nds->backup.backup_type >= NDS_BACKUP_FLASH_256KB && nds->backup.backup_type <= NDS_BACKUP_FLASH_1MB) { + ret_data = nds_process_flash_write(nds, spi_data, &nds->backup.flash, nds->mem.save_data, nds_get_save_size(nds)); + nds->backup.is_dirty = true; + } else { + switch(back->command[0]) { + case 0x00: /*NOP*/ break; + case 0x06: /*WREN*/ back->write_enable = true; break; + case 0x04: /*WRDI*/ back->write_enable = false; break; + case 0x05: /*RDSR*/ + /* + Status Register + 0 WIP Write in Progress (1=Busy) (Read only) (always 0 for FRAM chips) + 1 WEL Write Enable Latch (1=Enable) (Read only, except by WREN,WRDI) + 2-3 WP Write Protect (0=None, 1=Upper quarter, 2=Upper Half, 3=All memory) + For 0.5K EEPROM: + 4-7 ONEs Not used (all four bits are always set to "1" each) + For 8K..64K EEPROM and for FRAM: + 4-6 ZERO Not used (all three bits are always set to "0" each) + 7 SRWD Status Register Write Disable (0=Normal, 1=Lock) (Only if /W=LOW) + */ + back->status_reg &= (3 << 2) | (1 << 7); + if(back->write_enable) back->status_reg |= 0x2; + if(back->backup_type == NDS_BACKUP_EEPROM_512B) back->status_reg |= 0xf0; + ret_data = back->status_reg; + break; + case 0x01: /*WRSR*/ back->status_reg = spi_data; break; + case 0x9f: /*RDID*/ ret_data = 0xff; break; + case 0x03: /*RD/RDLO*/ + case 0x0B: /*RDHI*/ { + uint32_t addr = nds_get_curr_backup_address(nds); + if(addr != 0xffffffff) ret_data = nds->mem.save_data[addr]; + break; + } + case 0x02: /*WR/WRLO*/ + case 0x0A: /*WRHI*/ { + uint32_t addr = nds_get_curr_backup_address(nds); + if(addr != 0xffffffff && back->write_enable) { + nds->mem.save_data[addr] = spi_data; + back->is_dirty = true; } - default: - if(back->command_offset==1)printf("Unknown AUX SPI command:%02x\n",back->command[0]); - break; + break; + } + default: + if(back->command_offset == 1) printf("Unknown AUX SPI command:%02x\n", back->command[0]); + break; } } } - nds_io_store8(nds,cpu_id,NDS9_AUXSPIDATA,ret_data); - bool hold_chip_sel = SB_BFE(aux_spi_cnt,6,1); - if(!hold_chip_sel){ - nds->backup.command_offset=0; - nds->backup.flash.state =0; + nds_io_store8(nds, cpu_id, NDS9_AUXSPIDATA, ret_data); + bool hold_chip_sel = SB_BFE(aux_spi_cnt, 6, 1); + if(!hold_chip_sel) { + nds->backup.command_offset = 0; + nds->backup.flash.state = 0; } } -static FORCE_INLINE uint32_t nds_align_data(uint32_t addr, uint32_t data, int transaction_type){ - if(transaction_type&NDS_MEM_2B)data= (data&0xffff)<<((addr&2)*8); - if(transaction_type&NDS_MEM_1B)data= (data&0xff)<<((addr&3)*8); - return data; +static FORCE_INLINE uint32_t nds_align_data(uint32_t addr, uint32_t data, int transaction_type) { + if(transaction_type & NDS_MEM_2B) data = (data & 0xffff) << ((addr & 2) * 8); + if(transaction_type & NDS_MEM_1B) data = (data & 0xff) << ((addr & 3) * 8); + return data; } -static FORCE_INLINE uint32_t nds_word_mask(uint32_t addr, int transaction_type){ - if(transaction_type&NDS_MEM_2B)return (0xffffu)<<((addr&2)*8); - if(transaction_type&NDS_MEM_1B)return (0xffu)<<((addr&3)*8); +static FORCE_INLINE uint32_t nds_word_mask(uint32_t addr, int transaction_type) { + if(transaction_type & NDS_MEM_2B) return (0xffffu) << ((addr & 2) * 8); + if(transaction_type & NDS_MEM_1B) return (0xffu) << ((addr & 3) * 8); return 0xffffffff; } -#define NDS_FLASH_RECV_CMD 0 -#define NDS_FLASH_RXTX 1 +#define NDS_FLASH_RECV_CMD 0 +#define NDS_FLASH_RXTX 1 #define NDS_FLASH_SET_ADDR0 2 #define NDS_FLASH_SET_ADDR1 3 #define NDS_FLASH_SET_ADDR2 4 #define NDS_FLASH_SET_ADDR3 5 #define NDS_FLASH_DUMMY 6 -static uint8_t nds_process_flash_write(nds_t *nds, uint8_t write_data, nds_flash_t* flash, uint8_t *flash_data, uint32_t flash_size){ +static uint8_t nds_process_flash_write(nds_t *nds, uint8_t write_data, nds_flash_t *flash, uint8_t *flash_data, uint32_t flash_size) { uint8_t return_data = 0xff; - if(flash->state==NDS_FLASH_RECV_CMD){ + if(flash->state == NDS_FLASH_RECV_CMD) { flash->cmd = write_data; - switch(write_data){ - case 0x06: flash->write_enable = true; break; //WriteEnable(WREM) - case 0x04: flash->write_enable = false; break; //WriteDisable(WRDI) + switch(write_data) { + case 0x06: flash->write_enable = true; break; // WriteEnable(WREM) + case 0x04: flash->write_enable = false; break; // WriteDisable(WRDI) + + case 0x96: // ReadJEDEC(RDID) + case 0x05: // ReadStatus(RDSR) + flash->state = NDS_FLASH_RXTX; + flash->addr = 0; + break; - case 0x96: //ReadJEDEC(RDID) - case 0x05: //ReadStatus(RDSR) - flash->state = NDS_FLASH_RXTX; flash->addr=0; - break; - - case 0x03: //ReadData(READ) - case 0x0B: //ReadDataFast(FAST) - flash->state = NDS_FLASH_SET_ADDR0; - break; - - case 0x0A: //PageWrite(PW) - case 0x02: //PageProgram(PP) - case 0xDB: //PageErase(PE) - case 0xD8: //SectorErase(SE) - if(flash->write_enable)flash->state = NDS_FLASH_SET_ADDR0; - break; - case 0xB9: break; //DeepPowerDown(DP) - case 0xAB: break; //ReleaseDeepPowerDown(RDP) - } - }else if(flash->state == NDS_FLASH_RXTX){ + case 0x03: // ReadData(READ) + case 0x0B: // ReadDataFast(FAST) + flash->state = NDS_FLASH_SET_ADDR0; + break; + + case 0x0A: // PageWrite(PW) + case 0x02: // PageProgram(PP) + case 0xDB: // PageErase(PE) + case 0xD8: // SectorErase(SE) + if(flash->write_enable) flash->state = NDS_FLASH_SET_ADDR0; + break; + case 0xB9: break; // DeepPowerDown(DP) + case 0xAB: break; // ReleaseDeepPowerDown(RDP) + } + } else if(flash->state == NDS_FLASH_RXTX) { uint32_t page_mask = 0xff; uint32_t sector_mask = 0xffff; - switch(flash->cmd){ - case 0x06: flash->state=0; break; //WriteEnable(WREM) - case 0x04: flash->state=0; break; //WriteDisable(WRDI) - - case 0x96:{ //ReadID(RDID) - uint8_t jedec_id[3] = { 0x20, 0x40, 0x12 }; - return_data = jedec_id[flash->addr++]; - if(flash->addr>2)flash->state = 0; - break; - } - case 0x05: //ReadStatus(RDSR) - return_data = flash->write_enable?0x2:0; - break; - - case 0x03: //ReadData(READ) - case 0x0B:{ //ReadDataFast(FAST) - uint32_t addr = flash->addr++; - return_data = flash_data[addr&(flash_size-1)]; - break; - } - case 0x0A: //PageWrite(PW) - { - uint32_t addr = flash->addr; - flash->addr = ((flash->addr+1)&page_mask)|(flash->addr&~page_mask); - if(flash->write_enable) return_data = flash_data[addr&(flash_size-1)]=write_data; - break; - } - case 0x02: //PageProgram(PP) - { - uint32_t addr = flash->addr; - flash->addr = ((flash->addr+1)&page_mask)|(flash->addr&~page_mask); - if(flash->write_enable) return_data = flash_data[addr&(flash_size-1)]&=write_data; - break; - } - case 0xDB: //PageErase(PE) - { - flash->addr =flash->addr&~page_mask; - if(flash->write_enable) for(int i=0;i<=page_mask;++i)return_data = flash_data[(flash->addr|i)&(flash_size-1)]=0xff; - break; - } - case 0xD8: //SectorErase(SE) - { - flash->addr =flash->addr&~sector_mask; - if(flash->write_enable) for(int i=0;i<=sector_mask;++i)return_data = flash_data[(flash->addr|i)&(flash_size-1)]=0xff; - break; - } + switch(flash->cmd) { + case 0x06: flash->state = 0; break; // WriteEnable(WREM) + case 0x04: flash->state = 0; break; // WriteDisable(WRDI) + + case 0x96: { // ReadID(RDID) + uint8_t jedec_id[3] = {0x20, 0x40, 0x12}; + return_data = jedec_id[flash->addr++]; + if(flash->addr > 2) flash->state = 0; + break; + } + case 0x05: // ReadStatus(RDSR) + return_data = flash->write_enable ? 0x2 : 0; + break; - case 0xB9: flash->state = 0; break; //DeepPowerDown(DP) - case 0xAB: flash->state = 0; break; //ReleaseDeepPowerDown(RDP) + case 0x03: // ReadData(READ) + case 0x0B: { // ReadDataFast(FAST) + uint32_t addr = flash->addr++; + return_data = flash_data[addr & (flash_size - 1)]; + break; + } + case 0x0A: // PageWrite(PW) + { + uint32_t addr = flash->addr; + flash->addr = ((flash->addr + 1) & page_mask) | (flash->addr & ~page_mask); + if(flash->write_enable) return_data = flash_data[addr & (flash_size - 1)] = write_data; + break; + } + case 0x02: // PageProgram(PP) + { + uint32_t addr = flash->addr; + flash->addr = ((flash->addr + 1) & page_mask) | (flash->addr & ~page_mask); + if(flash->write_enable) return_data = flash_data[addr & (flash_size - 1)] &= write_data; + break; + } + case 0xDB: // PageErase(PE) + { + flash->addr = flash->addr & ~page_mask; + if(flash->write_enable) + for(int i = 0; i <= page_mask; ++i) + return_data = flash_data[(flash->addr | i) & (flash_size - 1)] = 0xff; + break; + } + case 0xD8: // SectorErase(SE) + { + flash->addr = flash->addr & ~sector_mask; + if(flash->write_enable) + for(int i = 0; i <= sector_mask; ++i) + return_data = flash_data[(flash->addr | i) & (flash_size - 1)] = 0xff; + break; } - //printf("NDS Firmware RXTX: cmd:%02x addr:%08x\n",flash->cmd, flash->addr); - }else{ - switch(flash->state){ - case NDS_FLASH_SET_ADDR0: - flash->addr = write_data<<16; - flash->state = NDS_FLASH_SET_ADDR1; - break; - case NDS_FLASH_SET_ADDR1: - flash->addr |= write_data<<8; - flash->state = NDS_FLASH_SET_ADDR2; - break; - case NDS_FLASH_SET_ADDR2: - flash->addr |= write_data<<0; - //Dummy byte for fast read - flash->state = flash->cmd == 0x0B?NDS_FLASH_DUMMY:NDS_FLASH_RXTX; - flash->addr&=(flash_size-1); - break; - case NDS_FLASH_DUMMY: - flash->state = NDS_FLASH_RXTX; - break; + case 0xB9: flash->state = 0; break; // DeepPowerDown(DP) + case 0xAB: flash->state = 0; break; // ReleaseDeepPowerDown(RDP) + } + // printf("NDS Firmware RXTX: cmd:%02x addr:%08x\n",flash->cmd, flash->addr); + + } else { + switch(flash->state) { + case NDS_FLASH_SET_ADDR0: + flash->addr = write_data << 16; + flash->state = NDS_FLASH_SET_ADDR1; + break; + case NDS_FLASH_SET_ADDR1: + flash->addr |= write_data << 8; + flash->state = NDS_FLASH_SET_ADDR2; + break; + case NDS_FLASH_SET_ADDR2: + flash->addr |= write_data << 0; + // Dummy byte for fast read + flash->state = flash->cmd == 0x0B ? NDS_FLASH_DUMMY : NDS_FLASH_RXTX; + flash->addr &= (flash_size - 1); + break; + case NDS_FLASH_DUMMY: + flash->state = NDS_FLASH_RXTX; + break; } } return return_data; } -static uint8_t nds_process_touch_ctrl_write(nds_t *nds, uint8_t data){ +static uint8_t nds_process_touch_ctrl_write(nds_t *nds, uint8_t data) { nds_touch_t *touch = &nds->touch; - uint8_t return_data = touch->tx_reg>>8; - touch->tx_reg<<=8; - if(data&0x80){ - //Recv'd ctrl byte - int channel = SB_BFE(data,4,3); - switch(channel){ - case 0: touch->tx_reg =0x7FF8; break; // Temperature 0 (requires calibration, step 2.1mV per 1'C accuracy) - case 1: touch->tx_reg =touch->y_reg; break; // Touchscreen Y-Position (somewhat 0B0h..F20h, or FFFh=released) - case 2: touch->tx_reg =0xf0; break; // Battery Voltage (not used, connected to GND in NDS, always 000h) - case 3: touch->tx_reg =0x7FF8; break; // Touchscreen Z1-Position (diagonal position for pressure measurement) - case 4: touch->tx_reg =0x7FF8; break; // Touchscreen Z2-Position (diagonal position for pressure measurement) - case 5: touch->tx_reg =touch->x_reg; break; // Touchscreen X-Position (somewhat 100h..ED0h, or 000h=released) - case 6: touch->tx_reg =0x7FF8; break; // AUX Input (connected to Microphone in the NDS) - case 7: touch->tx_reg =0x7FF8; break; // Temperature 1 (difference to Temp 0, without calibration, 2'C accuracy) + uint8_t return_data = touch->tx_reg >> 8; + touch->tx_reg <<= 8; + if(data & 0x80) { + // Recv'd ctrl byte + int channel = SB_BFE(data, 4, 3); + switch(channel) { + case 0: touch->tx_reg = 0x7FF8; break; // Temperature 0 (requires calibration, step 2.1mV per 1'C accuracy) + case 1: touch->tx_reg = touch->y_reg; break; // Touchscreen Y-Position (somewhat 0B0h..F20h, or FFFh=released) + case 2: touch->tx_reg = 0xf0; break; // Battery Voltage (not used, connected to GND in NDS, always 000h) + case 3: touch->tx_reg = 0x7FF8; break; // Touchscreen Z1-Position (diagonal position for pressure measurement) + case 4: touch->tx_reg = 0x7FF8; break; // Touchscreen Z2-Position (diagonal position for pressure measurement) + case 5: touch->tx_reg = touch->x_reg; break; // Touchscreen X-Position (somewhat 100h..ED0h, or 000h=released) + case 6: touch->tx_reg = 0x7FF8; break; // AUX Input (connected to Microphone in the NDS) + case 7: touch->tx_reg = 0x7FF8; break; // Temperature 1 (difference to Temp 0, without calibration, 2'C accuracy) } - //printf("Touch: %d %04x\n",channel, nds->touch.tx_reg); + // printf("Touch: %d %04x\n",channel, nds->touch.tx_reg); } return return_data; } -static void nds_deselect_spi(nds_t *nds){ - nds->firmware.state = NDS_FLASH_RECV_CMD; +static void nds_deselect_spi(nds_t *nds) { + nds->firmware.state = NDS_FLASH_RECV_CMD; nds->spi.last_device = -1; } -static float * nds_gpu_get_active_matrix(nds_t*nds){ - switch(nds->gpu.matrix_mode){ - case NDS_MATRIX_PROJ: return nds->gpu.proj_matrix; - case NDS_MATRIX_DIR:case NDS_MATRIX_MV: return nds->gpu.mv_matrix; - case NDS_MATRIX_TEX: return nds->gpu.tex_matrix; - default: - printf("GPU: Unknown matrix type:%d\n",nds->gpu.matrix_mode); - break; +static float *nds_gpu_get_active_matrix(nds_t *nds) { + switch(nds->gpu.matrix_mode) { + case NDS_MATRIX_PROJ: return nds->gpu.proj_matrix; + case NDS_MATRIX_DIR: + case NDS_MATRIX_MV: return nds->gpu.mv_matrix; + case NDS_MATRIX_TEX: return nds->gpu.tex_matrix; + default: + printf("GPU: Unknown matrix type:%d\n", nds->gpu.matrix_mode); + break; } return nds->gpu.mv_matrix; } -static void nds_identity_matrix(float* m){ - for(int i=0;i<16;++i)m[i]=(i%5)==0?1.0:0.0;; +static void nds_identity_matrix(float *m) { + for(int i = 0; i < 16; ++i) + m[i] = (i % 5) == 0 ? 1.0 : 0.0; + ; } -static void nds_reset_gpu(nds_t*nds){ +static void nds_reset_gpu(nds_t *nds) { printf("Reset GPU\n"); - nds->gpu.mv_matrix_stack_ptr=0; - nds->gpu.proj_matrix_stack_ptr=0; - nds->gpu.tex_matrix_stack_ptr=0; - nds->gpu.matrix_mode=NDS_MATRIX_PROJ; - nds->gpu.fifo_read_ptr=nds->gpu.fifo_write_ptr=0; - for(int i=0;igpu.fifo_cmd[i]=0; - nds->gpu.fifo_data[i]=0; + nds->gpu.mv_matrix_stack_ptr = 0; + nds->gpu.proj_matrix_stack_ptr = 0; + nds->gpu.tex_matrix_stack_ptr = 0; + nds->gpu.matrix_mode = NDS_MATRIX_PROJ; + nds->gpu.fifo_read_ptr = nds->gpu.fifo_write_ptr = 0; + for(int i = 0; i < NDS_GXFIFO_STORAGE; ++i) { + nds->gpu.fifo_cmd[i] = 0; + nds->gpu.fifo_data[i] = 0; } nds_identity_matrix(nds->gpu.proj_matrix); nds_identity_matrix(nds->gpu.tex_matrix); @@ -3852,57 +4893,56 @@ static void nds_reset_gpu(nds_t*nds){ nds_identity_matrix(nds->gpu.tex_matrix_stack); nds_identity_matrix(nds->gpu.mv_matrix_stack); } -static void nds_gpu_swap_buffers(nds_t*nds){ - uint32_t clear_color = nds9_io_read32(nds,NDS9_CLEAR_COLOR); - for(int i=0;iframebuffer_3d_disp[i*4+0]=nds->framebuffer_3d[i*4+0]; - nds->framebuffer_3d_disp[i*4+1]=nds->framebuffer_3d[i*4+1]; - nds->framebuffer_3d_disp[i*4+2]=nds->framebuffer_3d[i*4+2]; - nds->framebuffer_3d_disp[i*4+3]=nds->framebuffer_3d[i*4+3]; - nds->framebuffer_3d[i*4+0]=SB_BFE(clear_color,0,5)*8; - nds->framebuffer_3d[i*4+1]=SB_BFE(clear_color,5,5)*8; - nds->framebuffer_3d[i*4+2]=SB_BFE(clear_color,10,5)*8; - nds->framebuffer_3d[i*4+3]=SB_BFE(clear_color,16,5)*8; - - nds->framebuffer_3d_depth[i]=10e24; +static void nds_gpu_swap_buffers(nds_t *nds) { + uint32_t clear_color = nds9_io_read32(nds, NDS9_CLEAR_COLOR); + for(int i = 0; i < NDS_LCD_W * NDS_LCD_H; ++i) { + nds->framebuffer_3d_disp[i * 4 + 0] = nds->framebuffer_3d[i * 4 + 0]; + nds->framebuffer_3d_disp[i * 4 + 1] = nds->framebuffer_3d[i * 4 + 1]; + nds->framebuffer_3d_disp[i * 4 + 2] = nds->framebuffer_3d[i * 4 + 2]; + nds->framebuffer_3d_disp[i * 4 + 3] = nds->framebuffer_3d[i * 4 + 3]; + nds->framebuffer_3d[i * 4 + 0] = SB_BFE(clear_color, 0, 5) * 8; + nds->framebuffer_3d[i * 4 + 1] = SB_BFE(clear_color, 5, 5) * 8; + nds->framebuffer_3d[i * 4 + 2] = SB_BFE(clear_color, 10, 5) * 8; + nds->framebuffer_3d[i * 4 + 3] = SB_BFE(clear_color, 16, 5) * 8; + + nds->framebuffer_3d_depth[i] = 10e24; } - printf("Rendered %d verts and %d polys\n",nds->gpu.curr_vert,nds->gpu.poly_ram_offset); - nds->gpu.curr_vert = 0; - nds->gpu.poly_ram_offset=0; + printf("Rendered %d verts and %d polys\n", nds->gpu.curr_vert, nds->gpu.poly_ram_offset); + nds->gpu.curr_vert = 0; + nds->gpu.poly_ram_offset = 0; } -//res=res*m2 -void nds_mult_matrix4(float * res, float *m2){ - //printf("Mult Matrix:\n"); - //for(int y=0;y<4;++y)printf("%f %f %f %f\n",m2[0+y*4],m2[1+y*4],m2[2+y*4],m2[3+y*4]); +// res=res*m2 +void nds_mult_matrix4(float *res, float *m2) { + // printf("Mult Matrix:\n"); + // for(int y=0;y<4;++y)printf("%f %f %f %f\n",m2[0+y*4],m2[1+y*4],m2[2+y*4],m2[3+y*4]); float t[16]; - for(int i=0;i<16;++i)t[i]=res[i]; - - for(int y=0;y<4;++y) - for(int x=0;x<4;++x){ - res[x+y*4] = m2[0+y*4]*t[x+0*4] - +m2[1+y*4]*t[x+1*4] - +m2[2+y*4]*t[x+2*4] - +m2[3+y*4]*t[x+3*4]; - } + for(int i = 0; i < 16; ++i) + t[i] = res[i]; + + for(int y = 0; y < 4; ++y) + for(int x = 0; x < 4; ++x) { + res[x + y * 4] = m2[0 + y * 4] * t[x + 0 * 4] + m2[1 + y * 4] * t[x + 1 * 4] + m2[2 + y * 4] * t[x + 2 * 4] + m2[3 + y * 4] * t[x + 3 * 4]; + } } -void nds_translate_matrix(float * m, float x, float y, float z){ - m[12]+=m[0]*x+m[4]*y+m[8]*z; - m[13]+=m[1]*x+m[5]*y+m[9]*z; - m[14]+=m[2]*x+m[6]*y+m[10]*z; - m[15]+=m[3]*x+m[7]*y+m[11]*z; +void nds_translate_matrix(float *m, float x, float y, float z) { + m[12] += m[0] * x + m[4] * y + m[8] * z; + m[13] += m[1] * x + m[5] * y + m[9] * z; + m[14] += m[2] * x + m[6] * y + m[10] * z; + m[15] += m[3] * x + m[7] * y + m[11] * z; } -void nds_scale_matrix(float * m, float x, float y, float z){ - SE_RPT4 m[0*4+r] *=x; - SE_RPT4 m[1*4+r] *=y; - SE_RPT4 m[2*4+r] *=z; +void nds_scale_matrix(float *m, float x, float y, float z) { + SE_RPT4 m[0 * 4 + r] *= x; + SE_RPT4 m[1 * 4 + r] *= y; + SE_RPT4 m[2 * 4 + r] *= z; } -void nds_mult_matrix_vector(float * result, float * m, float *v,int dims){ - for(int x=0;x 512K RAM in Slot 0,1,2,3) (VRAM must be allocated as Texture data, see Memory Control chapter) @@ -3916,444 +4956,446 @@ static bool nds_sample_texture(nds_t* nds, float* tex_color, float*uv){ 29 Color 0 of 4/16/256-Color Palettes (0=Displayed, 1=Made Transparent) 30-31 Texture Coordinates Transformation Mode (0..3, see below)*/ uint32_t tex_param = nds->gpu.tex_image_param; - uint32_t vram_offset = SB_BFE(tex_param,0,16)*8; - bool repeat[2]={SB_BFE(tex_param,16,1),SB_BFE(tex_param,17,1)}; - bool flip[2]={SB_BFE(tex_param,18,1),SB_BFE(tex_param,19,1)}; - int sz[2]={SB_BFE(tex_param,20,3),SB_BFE(tex_param,23,3)}; - int format = SB_BFE(tex_param,26,3); - bool color0_transparent = SB_BFE(tex_param,29,1); - - tex_color[0]=0; - tex_color[1]=0; - tex_color[2]=0; - tex_color[3]=1; - - for(int i=0;i<2;++i){ - signed sz_lin = 8<=sz_lin)tex_coord=sz_lin-1; - if(tex_coord<0)tex_coord=0; - }else{ - signed int_part = tex_coord>>(3+sz[i]); - tex_coord&=sz_lin-1; - if((int_part&1)&&(flip[i]))tex_coord=sz_lin-tex_coord-1; + if(!repeat[i]) { + if(tex_coord >= sz_lin) tex_coord = sz_lin - 1; + if(tex_coord < 0) tex_coord = 0; + } else { + signed int_part = tex_coord >> (3 + sz[i]); + tex_coord &= sz_lin - 1; + if((int_part & 1) && (flip[i])) tex_coord = sz_lin - tex_coord - 1; } - uv[i]=tex_coord; - sz[i]=sz_lin; + uv[i] = tex_coord; + sz[i] = sz_lin; } - int x = uv[0], y=uv[1]; - switch(format){ - case -1: - tex_color[0]=fabs(uv[0]/sz[0]); - tex_color[1]=fabs(uv[1]/sz[1]); - tex_color[2]=0; - tex_color[3]=1; + int x = uv[0], y = uv[1]; + switch(format) { + case -1: + tex_color[0] = fabs(uv[0] / sz[0]); + tex_color[1] = fabs(uv[1] / sz[1]); + tex_color[2] = 0; + tex_color[3] = 1; break; - case 0x0: /*No Texture*/{ - for(int i=0;i<4;++i) tex_color[i]=1; - }break; - case 0x1: /*Format 1: A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)*/ - { - uint32_t palette = nds_ppu_read8(nds,NDS_VRAM_TEX_SLOT0+vram_offset+x+y*sz[0]); - uint32_t alpha = SB_BFE(palette,5,3); - palette = SB_BFE(palette,0,5); - uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base,0,13)*16; - uint16_t color= nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_base+palette*2); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = alpha/7.; - }break; - case 0x2: /*4-Color Palette Texture*/ - { - uint32_t palette = nds_ppu_read8(nds,NDS_VRAM_TEX_SLOT0+vram_offset+x/4+y*sz[0]/4); - palette = SB_BFE(palette,2*(x&3),2); - uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base,0,13)*8; - uint16_t color= nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_base+palette*2); - if(palette==0&&color0_transparent)tex_color[3]=0; - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - }break; - case 0x3: /*Format 3: 16-Color Palette Texture*/ - { - uint32_t palette = nds_ppu_read8(nds,NDS_VRAM_TEX_SLOT0+vram_offset+x/2+y*sz[0]/2); - palette = SB_BFE(palette,(x&1)*4,4); - uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base,0,13)*16; - uint16_t color= nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_base+palette*2); - if(palette==0&&color0_transparent)tex_color[3]=0; - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - }break; - case 0x4: /*Format 4: 256-Color Palette Texture*/ - { - uint32_t palette = nds_ppu_read8(nds,NDS_VRAM_TEX_SLOT0+vram_offset+x+y*sz[0]); - uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base,0,13)*16; - uint16_t color= nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_base+palette*2); - if(palette==0&&color0_transparent)tex_color[3]=0; - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - }break; - case 0x5:{ - int bx = x/4, by =y/4; - uint32_t slot0_addr= vram_offset+(bx+by*sz[0]/4)*4; - uint32_t block = nds_ppu_read32(nds,NDS_VRAM_TEX_SLOT0+slot0_addr); - - int block_offset = (x%4)*2 + (y%4)*8; - int texel = SB_BFE(block,block_offset,2); - - uint32_t slot1_addr = slot0_addr>=128*1024? slot0_addr/2-64*1024 : slot0_addr/2; - - uint16_t pal_index_data = nds_ppu_read16(nds,NDS_VRAM_TEX_SLOT1+slot1_addr); - int palette_off = SB_BFE(pal_index_data,0,14); - int mode = SB_BFE(pal_index_data,14,2); - int slot = slot0_addr/(128*1024); - uint32_t palette_addr = palette_off*4+SB_BFE(nds->gpu.tex_plt_base,0,13)*16; - - switch(texel){ - case 0:{ - uint16_t color = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = 1.0; - }break; - case 1:{ - uint16_t color = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+2); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = 1.0; - }break; - case 2:{ - if(mode==0||mode==2){ - uint16_t color = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+4); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = 1.0; - }else{ - uint16_t color0 = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+0); - uint16_t color1 = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+2); - if(mode==1){ - tex_color[0] = (SB_BFE(color0,0,5)+SB_BFE(color1,0,5))/31.*0.5; - tex_color[1] = (SB_BFE(color0,5,5)+SB_BFE(color1,5,5))/31.*0.5; - tex_color[2] = (SB_BFE(color0,10,5)+SB_BFE(color1,10,5))/31.*0.5; - }else{ - tex_color[0] = (SB_BFE(color0,0,5)*5+SB_BFE(color1,0,5)*3)/8./31.; - tex_color[1] = (SB_BFE(color0,5,5)*5+SB_BFE(color1,5,5)*3)/8./31.; - tex_color[2] = (SB_BFE(color0,10,5)*5+SB_BFE(color1,10,5)*3)/8./31.; - } - tex_color[3] = 1.0; - } - }break; - case 3:{ - if(mode==0||mode==1){ - tex_color[3]=0; - return true; - }else if(mode==2){ - uint16_t color = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+6); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = 1.0; - }else{ - uint16_t color0 = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+0); - uint16_t color1 = nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_addr+2); - tex_color[0] = (SB_BFE(color0,0,5)*3+SB_BFE(color1,0,5)*5)/8./31.; - tex_color[1] = (SB_BFE(color0,5,5)*3+SB_BFE(color1,5,5)*5)/8./31.; - tex_color[2] = (SB_BFE(color0,10,5)*3+SB_BFE(color1,10,5)*5)/8./31.; - tex_color[3] = 1.0; - } - }break; + case 0x0: /*No Texture*/ { + for(int i = 0; i < 4; ++i) + tex_color[i] = 1; + } break; + case 0x1: /*Format 1: A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)*/ + { + uint32_t palette = nds_ppu_read8(nds, NDS_VRAM_TEX_SLOT0 + vram_offset + x + y * sz[0]); + uint32_t alpha = SB_BFE(palette, 5, 3); + palette = SB_BFE(palette, 0, 5); + uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base, 0, 13) * 16; + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_base + palette * 2); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = alpha / 7.; + } break; + case 0x2: /*4-Color Palette Texture*/ + { + uint32_t palette = nds_ppu_read8(nds, NDS_VRAM_TEX_SLOT0 + vram_offset + x / 4 + y * sz[0] / 4); + palette = SB_BFE(palette, 2 * (x & 3), 2); + uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base, 0, 13) * 8; + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_base + palette * 2); + if(palette == 0 && color0_transparent) tex_color[3] = 0; + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + } break; + case 0x3: /*Format 3: 16-Color Palette Texture*/ + { + uint32_t palette = nds_ppu_read8(nds, NDS_VRAM_TEX_SLOT0 + vram_offset + x / 2 + y * sz[0] / 2); + palette = SB_BFE(palette, (x & 1) * 4, 4); + uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base, 0, 13) * 16; + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_base + palette * 2); + if(palette == 0 && color0_transparent) tex_color[3] = 0; + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + } break; + case 0x4: /*Format 4: 256-Color Palette Texture*/ + { + uint32_t palette = nds_ppu_read8(nds, NDS_VRAM_TEX_SLOT0 + vram_offset + x + y * sz[0]); + uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base, 0, 13) * 16; + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_base + palette * 2); + if(palette == 0 && color0_transparent) tex_color[3] = 0; + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + } break; + case 0x5: { + int bx = x / 4, by = y / 4; + uint32_t slot0_addr = vram_offset + (bx + by * sz[0] / 4) * 4; + uint32_t block = nds_ppu_read32(nds, NDS_VRAM_TEX_SLOT0 + slot0_addr); + + int block_offset = (x % 4) * 2 + (y % 4) * 8; + int texel = SB_BFE(block, block_offset, 2); + + uint32_t slot1_addr = slot0_addr >= 128 * 1024 ? slot0_addr / 2 - 64 * 1024 : slot0_addr / 2; + + uint16_t pal_index_data = nds_ppu_read16(nds, NDS_VRAM_TEX_SLOT1 + slot1_addr); + int palette_off = SB_BFE(pal_index_data, 0, 14); + int mode = SB_BFE(pal_index_data, 14, 2); + int slot = slot0_addr / (128 * 1024); + uint32_t palette_addr = palette_off * 4 + SB_BFE(nds->gpu.tex_plt_base, 0, 13) * 16; + + switch(texel) { + case 0: { + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = 1.0; + } break; + case 1: { + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 2); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = 1.0; + } break; + case 2: { + if(mode == 0 || mode == 2) { + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 4); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = 1.0; + } else { + uint16_t color0 = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 0); + uint16_t color1 = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 2); + if(mode == 1) { + tex_color[0] = (SB_BFE(color0, 0, 5) + SB_BFE(color1, 0, 5)) / 31. * 0.5; + tex_color[1] = (SB_BFE(color0, 5, 5) + SB_BFE(color1, 5, 5)) / 31. * 0.5; + tex_color[2] = (SB_BFE(color0, 10, 5) + SB_BFE(color1, 10, 5)) / 31. * 0.5; + } else { + tex_color[0] = (SB_BFE(color0, 0, 5) * 5 + SB_BFE(color1, 0, 5) * 3) / 8. / 31.; + tex_color[1] = (SB_BFE(color0, 5, 5) * 5 + SB_BFE(color1, 5, 5) * 3) / 8. / 31.; + tex_color[2] = (SB_BFE(color0, 10, 5) * 5 + SB_BFE(color1, 10, 5) * 3) / 8. / 31.; + } + tex_color[3] = 1.0; } - }break; - case 0x6: /*Format 6: A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)*/ - { - uint32_t palette = nds_ppu_read8(nds,NDS_VRAM_TEX_SLOT0+vram_offset+x+y*sz[0]); - uint32_t alpha = SB_BFE(palette,3,5); - palette = SB_BFE(palette,0,3); - uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base,0,13)*16; - uint16_t color= nds_ppu_read16(nds,NDS_VRAM_TEX_PAL_SLOT0+palette_base+palette*2); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = alpha/31.; - }break; - case 0x7: /* Format 7: Direct Color Texture*/ - { - uint32_t color = nds_ppu_read16(nds,NDS_VRAM_TEX_SLOT0+vram_offset+x*2+y*sz[0]*2); - tex_color[0] = SB_BFE(color,0,5)/31.; - tex_color[1] = SB_BFE(color,5,5)/31.; - tex_color[2] = SB_BFE(color,10,5)/31.; - tex_color[3] = SB_BFE(color,15,1); - }break; - default: - printf("Unknown texture format:%d\n",format); - for(int i=0;i<2;++i)tex_color[i]= uv[i]/((float)(sz[i])); - break; + } break; + case 3: { + if(mode == 0 || mode == 1) { + tex_color[3] = 0; + return true; + } else if(mode == 2) { + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 6); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = 1.0; + } else { + uint16_t color0 = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 0); + uint16_t color1 = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_addr + 2); + tex_color[0] = (SB_BFE(color0, 0, 5) * 3 + SB_BFE(color1, 0, 5) * 5) / 8. / 31.; + tex_color[1] = (SB_BFE(color0, 5, 5) * 3 + SB_BFE(color1, 5, 5) * 5) / 8. / 31.; + tex_color[2] = (SB_BFE(color0, 10, 5) * 3 + SB_BFE(color1, 10, 5) * 5) / 8. / 31.; + tex_color[3] = 1.0; + } + } break; + } + } break; + case 0x6: /*Format 6: A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)*/ + { + uint32_t palette = nds_ppu_read8(nds, NDS_VRAM_TEX_SLOT0 + vram_offset + x + y * sz[0]); + uint32_t alpha = SB_BFE(palette, 3, 5); + palette = SB_BFE(palette, 0, 3); + uint32_t palette_base = SB_BFE(nds->gpu.tex_plt_base, 0, 13) * 16; + uint16_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_PAL_SLOT0 + palette_base + palette * 2); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = alpha / 31.; + } break; + case 0x7: /* Format 7: Direct Color Texture*/ + { + uint32_t color = nds_ppu_read16(nds, NDS_VRAM_TEX_SLOT0 + vram_offset + x * 2 + y * sz[0] * 2); + tex_color[0] = SB_BFE(color, 0, 5) / 31.; + tex_color[1] = SB_BFE(color, 5, 5) / 31.; + tex_color[2] = SB_BFE(color, 10, 5) / 31.; + tex_color[3] = SB_BFE(color, 15, 1); + } break; + default: + printf("Unknown texture format:%d\n", format); + for(int i = 0; i < 2; ++i) + tex_color[i] = uv[i] / ((float)(sz[i])); + break; } - //tex_color[0]= (format&0x1)?0xff:0; - //tex_color[1]= (format&0x2)?0xff:0; - //tex_color[2]= (format&0x4)?0xff:0; - return tex_color[3]==0; + // tex_color[0]= (format&0x1)?0xff:0; + // tex_color[1]= (format&0x2)?0xff:0; + // tex_color[2]= (format&0x4)?0xff:0; + return tex_color[3] == 0; } -static bool nds_gpu_draw_tri(nds_t* nds, int vi0, int vi1, int vi2){ - if(nds->gpu.poly_ram_offset>=2048)return true;// Ignore extra polygons for now - uint32_t disp3dcnt = nds9_io_read32(nds,NDS_DISP3DCNT); - - bool tex_map = SB_BFE(disp3dcnt,0,1);/*Texture Mapping (0=Disable, 1=Enable)*/ - bool shade_mode = SB_BFE(disp3dcnt,1,1);/*PolygonAttr Shading (0=Toon Shading, 1=Highlight Shading)*/ - bool alpha_test = SB_BFE(disp3dcnt,2,1);/*Alpha-Test (0=Disable, 1=Enable) (see ALPHA_TEST_REF)*/ - bool alpha_blend = SB_BFE(disp3dcnt,3,1);/*Alpha-Blending (0=Disable, 1=Enable) (see various Alpha values)*/ - bool anti_alias = SB_BFE(disp3dcnt,4,1);/*Anti-Aliasing (0=Disable, 1=Enable)*/ - bool edge_mark = SB_BFE(disp3dcnt,5,1);/*Edge-Marking (0=Disable, 1=Enable) (see EDGE_COLOR)*/ - bool fogalpha_mode = SB_BFE(disp3dcnt,6,1);/*Fog Color/Alpha Mode (0=Alpha and Color, 1=Only Alpha) (see FOG_COLOR)*/ - bool fog_enable = SB_BFE(disp3dcnt,7,1);/*Fog Master Enable (0=Disable, 1=Enable)*/ - int fog_depth_shift = SB_BFE(disp3dcnt,8,4); /*Fog Depth Shift (FOG_STEP=400h shr FOG_SHIFT) (see FOG_OFFSET)*/ - bool rear_plane_mode = SB_BFE(disp3dcnt,14,1);/*Rear-Plane Mode (0=Blank, 1=Bitmap)*/ - - nds_vert_t *v[3] = {nds->gpu.vert_buffer+vi0,nds->gpu.vert_buffer+vi1,nds->gpu.vert_buffer+vi2}; - for(int i=0;i<3;++i){ - SE_RPT3 v[i]->clip_pos[r]=v[i]->pos[r]/fabs(v[i]->pos[3]); +static bool nds_gpu_draw_tri(nds_t *nds, int vi0, int vi1, int vi2) { + if(nds->gpu.poly_ram_offset >= 2048) return true; // Ignore extra polygons for now + uint32_t disp3dcnt = nds9_io_read32(nds, NDS_DISP3DCNT); + + bool tex_map = SB_BFE(disp3dcnt, 0, 1); /*Texture Mapping (0=Disable, 1=Enable)*/ + bool shade_mode = SB_BFE(disp3dcnt, 1, 1); /*PolygonAttr Shading (0=Toon Shading, 1=Highlight Shading)*/ + bool alpha_test = SB_BFE(disp3dcnt, 2, 1); /*Alpha-Test (0=Disable, 1=Enable) (see ALPHA_TEST_REF)*/ + bool alpha_blend = SB_BFE(disp3dcnt, 3, 1); /*Alpha-Blending (0=Disable, 1=Enable) (see various Alpha values)*/ + bool anti_alias = SB_BFE(disp3dcnt, 4, 1); /*Anti-Aliasing (0=Disable, 1=Enable)*/ + bool edge_mark = SB_BFE(disp3dcnt, 5, 1); /*Edge-Marking (0=Disable, 1=Enable) (see EDGE_COLOR)*/ + bool fogalpha_mode = SB_BFE(disp3dcnt, 6, 1); /*Fog Color/Alpha Mode (0=Alpha and Color, 1=Only Alpha) (see FOG_COLOR)*/ + bool fog_enable = SB_BFE(disp3dcnt, 7, 1); /*Fog Master Enable (0=Disable, 1=Enable)*/ + int fog_depth_shift = SB_BFE(disp3dcnt, 8, 4); /*Fog Depth Shift (FOG_STEP=400h shr FOG_SHIFT) (see FOG_OFFSET)*/ + bool rear_plane_mode = SB_BFE(disp3dcnt, 14, 1); /*Rear-Plane Mode (0=Blank, 1=Bitmap)*/ + + nds_vert_t *v[3] = {nds->gpu.vert_buffer + vi0, nds->gpu.vert_buffer + vi1, nds->gpu.vert_buffer + vi2}; + for(int i = 0; i < 3; ++i) { + SE_RPT3 v[i]->clip_pos[r] = v[i]->pos[r] / fabs(v[i]->pos[3]); } - float min_p[3] = {1,1,1}; - float max_p[3] = {-1,-1,-1}; - - for(int i=0;i<3;++i){ - SE_RPT3 if(min_p[r]>v[i]->clip_pos[r])min_p[r]=v[i]->clip_pos[r]; - SE_RPT3 if(max_p[r]clip_pos[r])max_p[r]=v[i]->clip_pos[r]; + float min_p[3] = {1, 1, 1}; + float max_p[3] = {-1, -1, -1}; + + for(int i = 0; i < 3; ++i) { + SE_RPT3 if(min_p[r] > v[i]->clip_pos[r]) min_p[r] = v[i]->clip_pos[r]; + SE_RPT3 if(max_p[r] < v[i]->clip_pos[r]) max_p[r] = v[i]->clip_pos[r]; } - SE_RPT3 if(min_p[r]<-1)min_p[r]=-1; - SE_RPT3 if(max_p[r]>1)max_p[r]=1; + SE_RPT3 if(min_p[r] < -1) min_p[r] = -1; + SE_RPT3 if(max_p[r] > 1) max_p[r] = 1; - float x_inc = 2./NDS_LCD_W; - float y_inc = 2./NDS_LCD_H; + float x_inc = 2. / NDS_LCD_W; + float y_inc = 2. / NDS_LCD_H; - min_p[0] = (floor(min_p[0]*NDS_LCD_W/2)-0.5)/NDS_LCD_W*2; - min_p[1] = (floor(min_p[1]*NDS_LCD_H/2)-0.5)/NDS_LCD_H*2; + min_p[0] = (floor(min_p[0] * NDS_LCD_W / 2) - 0.5) / NDS_LCD_W * 2; + min_p[1] = (floor(min_p[1] * NDS_LCD_H / 2) - 0.5) / NDS_LCD_H * 2; - max_p[0] = (floor(max_p[0]*NDS_LCD_W/2+0.5)+0.5)/NDS_LCD_W*2; - max_p[1] = (floor(max_p[1]*NDS_LCD_H/2+0.5)+0.5)/NDS_LCD_H*2; + max_p[0] = (floor(max_p[0] * NDS_LCD_W / 2 + 0.5) + 0.5) / NDS_LCD_W * 2; + max_p[1] = (floor(max_p[1] * NDS_LCD_H / 2 + 0.5) + 0.5) / NDS_LCD_H * 2; uint32_t poly_attr = nds->gpu.poly_attr; - int alpha = SB_BFE(poly_attr,16,5); - int polygon_mode = SB_BFE(poly_attr,4,2);//(0=Modulation,1=Decal,2=Toon/Highlight Shading,3=Shadow) - bool render_front = SB_BFE(poly_attr,6,1); - bool render_back = SB_BFE(poly_attr,7,1); - bool translucent_has_depth = SB_BFE(poly_attr,11,1); - - //Skip shadow triangles for now TODO: Fix this - if(polygon_mode==3)return true; - bool front_face=true; + int alpha = SB_BFE(poly_attr, 16, 5); + int polygon_mode = SB_BFE(poly_attr, 4, 2); //(0=Modulation,1=Decal,2=Toon/Highlight Shading,3=Shadow) + bool render_front = SB_BFE(poly_attr, 6, 1); + bool render_back = SB_BFE(poly_attr, 7, 1); + bool translucent_has_depth = SB_BFE(poly_attr, 11, 1); + + // Skip shadow triangles for now TODO: Fix this + if(polygon_mode == 3) return true; + bool front_face = true; { - float e0[2],e1[2]; - SE_RPT2 e0[r]=v[1]->clip_pos[r]-v[0]->clip_pos[r]; - SE_RPT2 e1[r]=v[2]->clip_pos[r]-v[0]->clip_pos[r]; - - front_face = (e0[1]*e1[0]-e0[0]*e1[1])<=0; - - if(!((front_face&&render_front)||(!front_face&&render_back)))return true; - - if(!front_face){ - nds_vert_t*vt = v[2]; - v[2]=v[1]; - v[1]=vt; + float e0[2], e1[2]; + SE_RPT2 e0[r] = v[1]->clip_pos[r] - v[0]->clip_pos[r]; + SE_RPT2 e1[r] = v[2]->clip_pos[r] - v[0]->clip_pos[r]; + + front_face = (e0[1] * e1[0] - e0[0] * e1[1]) <= 0; + + if(!((front_face && render_front) || (!front_face && render_back))) return true; + + if(!front_face) { + nds_vert_t *vt = v[2]; + v[2] = v[1]; + v[1] = vt; } } - bool tri_not_rendered = true; + bool tri_not_rendered = true; - float edge0[2],edge1[2],edge2[2]; + float edge0[2], edge1[2], edge2[2]; SE_RPT2 edge0[r] = v[0]->clip_pos[r]; SE_RPT2 edge1[r] = v[1]->clip_pos[r]; SE_RPT2 edge2[r] = v[2]->clip_pos[r]; - float sub_tri_area_ref[3]; - sub_tri_area_ref[0]=edge0[1]*edge1[0]-edge0[0]*edge1[1]; - sub_tri_area_ref[1]=edge1[1]*edge2[0]-edge1[0]*edge2[1]; - sub_tri_area_ref[2]=edge2[1]*edge0[0]-edge2[0]*edge0[1]; - - float tri_area = sub_tri_area_ref[0]+sub_tri_area_ref[1]+sub_tri_area_ref[2]; - float sub_tri_area_dx[3]={ - (edge1[1]-edge0[1]), - (edge2[1]-edge1[1]), - (edge0[1]-edge2[1]), + float sub_tri_area_ref[3]; + sub_tri_area_ref[0] = edge0[1] * edge1[0] - edge0[0] * edge1[1]; + sub_tri_area_ref[1] = edge1[1] * edge2[0] - edge1[0] * edge2[1]; + sub_tri_area_ref[2] = edge2[1] * edge0[0] - edge2[0] * edge0[1]; + + float tri_area = sub_tri_area_ref[0] + sub_tri_area_ref[1] + sub_tri_area_ref[2]; + float sub_tri_area_dx[3] = { + (edge1[1] - edge0[1]), + (edge2[1] - edge1[1]), + (edge0[1] - edge2[1]), }; - float sub_tri_area_dy[3]={ - (edge0[0]-edge1[0]), - (edge1[0]-edge2[0]), - (edge2[0]-edge0[0]), + float sub_tri_area_dy[3] = { + (edge0[0] - edge1[0]), + (edge1[0] - edge2[0]), + (edge2[0] - edge0[0]), }; - SE_RPT3 sub_tri_area_ref[r]+=sub_tri_area_dx[r]*min_p[0]; - SE_RPT3 sub_tri_area_dx[r]*=x_inc; - - float tex_i[2], tex_j[2],color_i[3],color_j[3]; - SE_RPT3 color_i[r]=v[1]->color[r]-v[0]->color[r]; - SE_RPT3 color_j[r]=v[2]->color[r]-v[0]->color[r]; - SE_RPT2 tex_i[r]=v[1]->tex[r]-v[0]->tex[r]; - SE_RPT2 tex_j[r]=v[2]->tex[r]-v[0]->tex[r]; - - for(float y=min_p[1];y0||sub_tri_area[1]>0||sub_tri_area[2]>0){ - if(line_rendered)break; - SE_RPT3 sub_tri_area[r]+=sub_tri_area_dx[r]; + SE_RPT3 sub_tri_area_ref[r] += sub_tri_area_dx[r] * min_p[0]; + SE_RPT3 sub_tri_area_dx[r] *= x_inc; + + float tex_i[2], tex_j[2], color_i[3], color_j[3]; + SE_RPT3 color_i[r] = v[1]->color[r] - v[0]->color[r]; + SE_RPT3 color_j[r] = v[2]->color[r] - v[0]->color[r]; + SE_RPT2 tex_i[r] = v[1]->tex[r] - v[0]->tex[r]; + SE_RPT2 tex_j[r] = v[2]->tex[r] - v[0]->tex[r]; + + for(float y = min_p[1]; y < max_p[1]; y += y_inc) { + bool line_rendered = false; + float sub_tri_area[3]; + SE_RPT3 sub_tri_area[r] = sub_tri_area_dy[r] * y + sub_tri_area_ref[r]; + for(float x = min_p[0]; x < max_p[0]; x += x_inc) { + + if(sub_tri_area[0] > 0 || sub_tri_area[1] > 0 || sub_tri_area[2] > 0) { + if(line_rendered) break; + SE_RPT3 sub_tri_area[r] += sub_tri_area_dx[r]; continue; } - line_rendered=true; + line_rendered = true; float bary_nopersp[3]; float bary[3]; - SE_RPT3 bary_nopersp[r] = sub_tri_area[(r+1)%3]/tri_area; - SE_RPT3 bary[r] = sub_tri_area[(r+1)%3]/v[r]->pos[3]; + SE_RPT3 bary_nopersp[r] = sub_tri_area[(r + 1) % 3] / tri_area; + SE_RPT3 bary[r] = sub_tri_area[(r + 1) % 3] / v[r]->pos[3]; - SE_RPT3 sub_tri_area[r]+=sub_tri_area_dx[r]; + SE_RPT3 sub_tri_area[r] += sub_tri_area_dx[r]; - float bary_area = bary[0]+bary[1]+bary[2]; + float bary_area = bary[0] + bary[1] + bary[2]; SE_RPT3 bary[r] /= bary_area; - float z = v[0]->pos[2]+bary[1]*(v[1]->pos[2]-v[0]->pos[2])+bary[2]*(v[2]->pos[2]-v[0]->pos[2]); - float w = v[0]->pos[3]+bary[1]*(v[1]->pos[3]-v[0]->pos[3])+bary[2]*(v[2]->pos[3]-v[0]->pos[3]); - //if(z<=0)continue; - - int ix = (x*0.5+0.5)*NDS_LCD_W; - int iy = (y*0.5+0.5)*NDS_LCD_H; - int p = ix+iy*NDS_LCD_W; - - if(nds->framebuffer_3d_depth[p]tex[r]+tex_i[r]*bary[1]+tex_j[r]*bary[2]; - - float tex_color[4]={1,1,1,1}; - bool discard = false; - if(tex_map)discard|=nds_sample_texture(nds, tex_color, uv); - if(discard)continue; - - float output_col[4]; - float col_v[4]; - SE_RPT3 col_v[r]=(v[0]->color[r]+color_i[r]*bary[1]+color_j[r]*bary[2])/255.; - col_v[3]= alpha/31.; - - if(polygon_mode==0){ - SE_RPT4 output_col[r]=tex_color[r]*col_v[r]; - }else if(polygon_mode==1){ - //Decal Mode - SE_RPT3 output_col[r]=(tex_color[r]*tex_color[3]+col_v[r]*(1-tex_color[3]+0.5)); - output_col[3]=col_v[3]; - }else if(polygon_mode==2){ - int toon_highlight_entry = floor(col_v[0]*255/8.); - //printf("toon entry: %d\n",toon_highlight_entry); - uint16_t color = nds9_io_read16(nds,NDS9_TOON_TABLE+toon_highlight_entry*2); - col_v[0]= SB_BFE(color,0,5)/31.; - col_v[1]= SB_BFE(color,5,5)/31.; - col_v[2]= SB_BFE(color,10,5)/31.; - if(shade_mode){ //Highlight shading - SE_RPT3 output_col[r]= tex_color[r]*col_v[r]+col_v[r]; - }else{ //Toon shading - SE_RPT3 output_col[r]= tex_color[r]*col_v[r]; + float z = v[0]->pos[2] + bary[1] * (v[1]->pos[2] - v[0]->pos[2]) + bary[2] * (v[2]->pos[2] - v[0]->pos[2]); + float w = v[0]->pos[3] + bary[1] * (v[1]->pos[3] - v[0]->pos[3]) + bary[2] * (v[2]->pos[3] - v[0]->pos[3]); + // if(z<=0)continue; + + int ix = (x * 0.5 + 0.5) * NDS_LCD_W; + int iy = (y * 0.5 + 0.5) * NDS_LCD_H; + int p = ix + iy * NDS_LCD_W; + + if(nds->framebuffer_3d_depth[p] < z * 0.999999) continue; + float uv[2]; + SE_RPT2 uv[r] = v[0]->tex[r] + tex_i[r] * bary[1] + tex_j[r] * bary[2]; + + float tex_color[4] = {1, 1, 1, 1}; + bool discard = false; + if(tex_map) discard |= nds_sample_texture(nds, tex_color, uv); + if(discard) continue; + + float output_col[4]; + float col_v[4]; + SE_RPT3 col_v[r] = (v[0]->color[r] + color_i[r] * bary[1] + color_j[r] * bary[2]) / 255.; + col_v[3] = alpha / 31.; + + if(polygon_mode == 0) { + SE_RPT4 output_col[r] = tex_color[r] * col_v[r]; + } else if(polygon_mode == 1) { + // Decal Mode + SE_RPT3 output_col[r] = (tex_color[r] * tex_color[3] + col_v[r] * (1 - tex_color[3] + 0.5)); + output_col[3] = col_v[3]; + } else if(polygon_mode == 2) { + int toon_highlight_entry = floor(col_v[0] * 255 / 8.); + // printf("toon entry: %d\n",toon_highlight_entry); + uint16_t color = nds9_io_read16(nds, NDS9_TOON_TABLE + toon_highlight_entry * 2); + col_v[0] = SB_BFE(color, 0, 5) / 31.; + col_v[1] = SB_BFE(color, 5, 5) / 31.; + col_v[2] = SB_BFE(color, 10, 5) / 31.; + if(shade_mode) { // Highlight shading + SE_RPT3 output_col[r] = tex_color[r] * col_v[r] + col_v[r]; + } else { // Toon shading + SE_RPT3 output_col[r] = tex_color[r] * col_v[r]; } - output_col[3]= col_v[3]*tex_color[3]; + output_col[3] = col_v[3] * tex_color[3]; } - SE_RPT4 if(output_col[r]>1.0)output_col[r]=1.; - SE_RPT4 if(output_col[r]<0.0)output_col[r]=0.; - float alpha_blend_factor = alpha_blend? output_col[3]: 1; - if(alpha_test){ - int alpha_test_ref = nds9_io_read8(nds,NDS9_ALPHA_TEST_REF)&0x1f; - if(output_col[3]<=alpha_test_ref/31.)continue; + SE_RPT4 if(output_col[r] > 1.0) output_col[r] = 1.; + SE_RPT4 if(output_col[r] < 0.0) output_col[r] = 0.; + float alpha_blend_factor = alpha_blend ? output_col[3] : 1; + if(alpha_test) { + int alpha_test_ref = nds9_io_read8(nds, NDS9_ALPHA_TEST_REF) & 0x1f; + if(output_col[3] <= alpha_test_ref / 31.) continue; } - if(translucent_has_depth||alpha_blend_factor>0.95)nds->framebuffer_3d_depth[p]=z; - for(int c=0;c<3;++c){ - nds->framebuffer_3d[p*4+c]=output_col[c]*255*alpha_blend_factor+(nds->framebuffer_3d[p*4+c])*(1.0-alpha_blend_factor); + if(translucent_has_depth || alpha_blend_factor > 0.95) nds->framebuffer_3d_depth[p] = z; + for(int c = 0; c < 3; ++c) { + nds->framebuffer_3d[p * 4 + c] = output_col[c] * 255 * alpha_blend_factor + (nds->framebuffer_3d[p * 4 + c]) * (1.0 - alpha_blend_factor); } - if(nds->framebuffer_3d[p*4+3]framebuffer_3d[p*4+3]=alpha_blend_factor*255; + if(nds->framebuffer_3d[p * 4 + 3] < alpha_blend_factor * 255) nds->framebuffer_3d[p * 4 + 3] = alpha_blend_factor * 255; } - tri_not_rendered&=!line_rendered; + tri_not_rendered &= !line_rendered; } return tri_not_rendered; } -static void nds_interp_wp_vert(nds_t*nds, int v_wp, int v_wn){ - nds_vert_t* vb = nds->gpu.vert_buffer; - float wn = vb[v_wn].pos[3]; - float wp = vb[v_wp].pos[3]; - float alpha = (-wn)/(wp-wn)+0.000001; - - SE_RPT4 vb[v_wn].pos[r] += (vb[v_wp].pos[r]-vb[v_wn].pos[r])*alpha; - SE_RPT3 vb[v_wn].color[r] += (vb[v_wp].color[r]-vb[v_wn].color[r])*alpha; - SE_RPT2 vb[v_wn].tex[r] += (vb[v_wp].tex[r]-vb[v_wn].tex[r])*alpha; - +static void nds_interp_wp_vert(nds_t *nds, int v_wp, int v_wn) { + nds_vert_t *vb = nds->gpu.vert_buffer; + float wn = vb[v_wn].pos[3]; + float wp = vb[v_wp].pos[3]; + float alpha = (-wn) / (wp - wn) + 0.000001; + + SE_RPT4 vb[v_wn].pos[r] += (vb[v_wp].pos[r] - vb[v_wn].pos[r]) * alpha; + SE_RPT3 vb[v_wn].color[r] += (vb[v_wp].color[r] - vb[v_wn].color[r]) * alpha; + SE_RPT2 vb[v_wn].tex[r] += (vb[v_wp].tex[r] - vb[v_wn].tex[r]) * alpha; } -static bool nds_gpu_clip_tri(nds_t* nds, int vi0, int vi1, int vi2){ - //nds_gpu_draw_tri(nds,vi0,vi1,vi2); - //return; - int inds[3] = {vi0,vi1,vi2}; - nds_vert_t* vb = nds->gpu.vert_buffer; - - if(vb[inds[0]].pos[3]>0.){ - if(vb[inds[2]].pos[3]>0.){ - if(vb[inds[1]].pos[3]>0.)return nds_gpu_draw_tri(nds,inds[0],inds[1],inds[2]); +static bool nds_gpu_clip_tri(nds_t *nds, int vi0, int vi1, int vi2) { + // nds_gpu_draw_tri(nds,vi0,vi1,vi2); + // return; + int inds[3] = {vi0, vi1, vi2}; + nds_vert_t *vb = nds->gpu.vert_buffer; + + if(vb[inds[0]].pos[3] > 0.) { + if(vb[inds[2]].pos[3] > 0.) { + if(vb[inds[1]].pos[3] > 0.) return nds_gpu_draw_tri(nds, inds[0], inds[1], inds[2]); int i = inds[0]; - inds[0]=inds[2]; - inds[2]=inds[1]; - inds[1]=i; + inds[0] = inds[2]; + inds[2] = inds[1]; + inds[1] = i; } - }else if(vb[inds[1]].pos[3]>0.){ + } else if(vb[inds[1]].pos[3] > 0.) { int i = inds[0]; - inds[0]=inds[1]; - inds[1]=inds[2]; - inds[2]=i; - }else if(vb[inds[2]].pos[3]>0.){ + inds[0] = inds[1]; + inds[1] = inds[2]; + inds[2] = i; + } else if(vb[inds[2]].pos[3] > 0.) { int i = inds[0]; - inds[0]=inds[2]; - inds[2]=inds[1]; - inds[1]=i; - }else return true; - - if(vb[inds[1]].pos[3]<0.){ - int extra_ind0 = NDS_MAX_VERTS-1; - int extra_ind1 = NDS_MAX_VERTS-2; - vb[extra_ind0]=vb[inds[1]]; - vb[extra_ind1]=vb[inds[2]]; - nds_interp_wp_vert(nds,inds[0],extra_ind0); - nds_interp_wp_vert(nds,inds[0],extra_ind1); - return nds_gpu_draw_tri(nds,inds[0],extra_ind0,extra_ind1); + inds[0] = inds[2]; + inds[2] = inds[1]; + inds[1] = i; + } else + return true; + + if(vb[inds[1]].pos[3] < 0.) { + int extra_ind0 = NDS_MAX_VERTS - 1; + int extra_ind1 = NDS_MAX_VERTS - 2; + vb[extra_ind0] = vb[inds[1]]; + vb[extra_ind1] = vb[inds[2]]; + nds_interp_wp_vert(nds, inds[0], extra_ind0); + nds_interp_wp_vert(nds, inds[0], extra_ind1); + return nds_gpu_draw_tri(nds, inds[0], extra_ind0, extra_ind1); } - int extra_ind0 = NDS_MAX_VERTS-1; - int extra_ind1 = NDS_MAX_VERTS-2; - vb[extra_ind0]=vb[inds[2]]; - vb[extra_ind1]=vb[inds[2]]; - nds_interp_wp_vert(nds,inds[0],extra_ind0); - nds_interp_wp_vert(nds,inds[1],extra_ind1); - bool culled = nds_gpu_draw_tri(nds,inds[0],inds[1],extra_ind1); - culled&=nds_gpu_draw_tri(nds,inds[0],extra_ind1,extra_ind0); + int extra_ind0 = NDS_MAX_VERTS - 1; + int extra_ind1 = NDS_MAX_VERTS - 2; + vb[extra_ind0] = vb[inds[2]]; + vb[extra_ind1] = vb[inds[2]]; + nds_interp_wp_vert(nds, inds[0], extra_ind0); + nds_interp_wp_vert(nds, inds[1], extra_ind1); + bool culled = nds_gpu_draw_tri(nds, inds[0], inds[1], extra_ind1); + culled &= nds_gpu_draw_tri(nds, inds[0], extra_ind1, extra_ind0); return culled; } -static void nds_gpu_process_vertex(nds_t*nds, int16_t vx,int16_t vy, int16_t vz){ - if(nds->gpu.curr_vert>=6144)return; - nds->gpu.last_vertex_pos[0]=vx; - nds->gpu.last_vertex_pos[1]=vy; - nds->gpu.last_vertex_pos[2]=vz; - - if(SB_UNLIKELY(nds->vert_log))fprintf(nds->vert_log,"Vertex {%d %d %d}\n",vx,vy,vz); - - float v[4] = {vx/4096.0,vy/4096.0,vz/4096.0,1.0}; +static void nds_gpu_process_vertex(nds_t *nds, int16_t vx, int16_t vy, int16_t vz) { + if(nds->gpu.curr_vert >= 6144) return; + nds->gpu.last_vertex_pos[0] = vx; + nds->gpu.last_vertex_pos[1] = vy; + nds->gpu.last_vertex_pos[2] = vz; + + if(SB_UNLIKELY(nds->vert_log)) fprintf(nds->vert_log, "Vertex {%d %d %d}\n", vx, vy, vz); + + float v[4] = {vx / 4096.0, vy / 4096.0, vz / 4096.0, 1.0}; float res[4]; - nds_mult_matrix_vector(res,nds->gpu.mv_matrix,v,4); - nds_mult_matrix_vector(v,nds->gpu.proj_matrix,res,4); - //printf("Vert <%f, %f, %f, %f> matrix_stack_ptr:%d\n",v[0],v[1],v[2],v[3],nds->gpu.mv_matrix_stack_ptr); - v[1]*=-1; + nds_mult_matrix_vector(res, nds->gpu.mv_matrix, v, 4); + nds_mult_matrix_vector(v, nds->gpu.proj_matrix, res, 4); + // printf("Vert <%f, %f, %f, %f> matrix_stack_ptr:%d\n",v[0],v[1],v[2],v[3],nds->gpu.mv_matrix_stack_ptr); + v[1] *= -1; /* float abs_w = v[3]; if(abs_w!=0){ @@ -4367,7 +5409,7 @@ static void nds_gpu_process_vertex(nds_t*nds, int16_t vx,int16_t vy, int16_t vz) res[2]=v[2]<0.?-INFINITY:INFINITY; res[3]=v[3]; } - + int x0 = (res[0]*0.5+0.5)*NDS_LCD_W; int y0 = (res[1]*0.5+0.5)*NDS_LCD_H; for(int px = -1;px<1;++px)for(int py=-1;py<1;++py){ @@ -4382,2366 +5424,2589 @@ static void nds_gpu_process_vertex(nds_t*nds, int16_t vx,int16_t vy, int16_t vz) if(res[3]<0)nds->framebuffer_3d[p*4+0]=0; } }*/ - nds_vert_t*vert = nds->gpu.vert_buffer+nds->gpu.curr_vert++; + nds_vert_t *vert = nds->gpu.vert_buffer + nds->gpu.curr_vert++; nds->gpu.curr_draw_vert++; uint32_t tex_param = nds->gpu.tex_image_param; - int coord_xform_mode = SB_BFE(tex_param,30,2); - float uv[4] = {nds->gpu.curr_tex_coord[0]/16.,nds->gpu.curr_tex_coord[1]/16.,0,1}; - switch(coord_xform_mode){ - case 0: break; - case 1:{ - float tex_p2[4]={uv[0],uv[1],1./16.,1./16.}; - nds_mult_matrix_vector(uv,nds->gpu.tex_matrix,tex_p2,4); - }break; - case 2:{ - SE_RPT4 uv[r]=nds->gpu.transformed_normal[r]; - }break; - default: - //printf("Unknown Tex Coord XForm mode:%d\n",coord_xform_mode); - break; + int coord_xform_mode = SB_BFE(tex_param, 30, 2); + float uv[4] = {nds->gpu.curr_tex_coord[0] / 16., nds->gpu.curr_tex_coord[1] / 16., 0, 1}; + switch(coord_xform_mode) { + case 0: break; + case 1: { + float tex_p2[4] = {uv[0], uv[1], 1. / 16., 1. / 16.}; + nds_mult_matrix_vector(uv, nds->gpu.tex_matrix, tex_p2, 4); + } break; + case 2: { + SE_RPT4 uv[r] = nds->gpu.transformed_normal[r]; + } break; + default: + // printf("Unknown Tex Coord XForm mode:%d\n",coord_xform_mode); + break; } - SE_RPT3 vert->color[r]=nds->gpu.curr_color[r]; - SE_RPT2 vert->tex[r]= uv[r]; + SE_RPT3 vert->color[r] = nds->gpu.curr_color[r]; + SE_RPT2 vert->tex[r] = uv[r]; SE_RPT4 vert->pos[r] = v[r]; - switch(nds->gpu.prim_type){ - /*Triangles */ case 0: - if((nds->gpu.curr_draw_vert%3)==0){ - bool culled = nds_gpu_clip_tri(nds,nds->gpu.curr_vert-3,nds->gpu.curr_vert-2,nds->gpu.curr_vert-1); - if(culled)nds->gpu.curr_vert-=3; - else nds->gpu.poly_ram_offset++; + switch(nds->gpu.prim_type) { + /*Triangles */ case 0: + if((nds->gpu.curr_draw_vert % 3) == 0) { + bool culled = nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 3, nds->gpu.curr_vert - 2, nds->gpu.curr_vert - 1); + if(culled) + nds->gpu.curr_vert -= 3; + else + nds->gpu.poly_ram_offset++; + } + break; + /*Quads */ case 1: + if((nds->gpu.curr_draw_vert % 4) == 0) { + bool culled = nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 4 + 0, nds->gpu.curr_vert - 4 + 1, nds->gpu.curr_vert - 4 + 2); + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 4 + 2, nds->gpu.curr_vert - 4 + 3, nds->gpu.curr_vert - 4 + 0); + if(culled) + nds->gpu.curr_vert -= 4; + else + nds->gpu.poly_ram_offset++; + } + break; + /*Tristrip */ case 2: + if(nds->gpu.curr_draw_vert >= 3) { + bool culled = true; + if(nds->gpu.curr_draw_vert & 1) + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 3, nds->gpu.curr_vert - 2, nds->gpu.curr_vert - 1); + else + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 3, nds->gpu.curr_vert - 1, nds->gpu.curr_vert - 2); + nds->gpu.rendered_primitive_tracker <<= 1; + if(culled) { + nds->gpu.rendered_primitive_tracker |= 1; + if((nds->gpu.rendered_primitive_tracker & 0x7) == 0x7) { + nds->gpu.vert_buffer[nds->gpu.curr_vert - 3] = nds->gpu.vert_buffer[nds->gpu.curr_vert - 2]; + nds->gpu.vert_buffer[nds->gpu.curr_vert - 2] = nds->gpu.vert_buffer[nds->gpu.curr_vert - 1]; + nds->gpu.curr_vert--; + } else + nds->gpu.poly_ram_offset++; } - break; - /*Quads */ case 1: - if((nds->gpu.curr_draw_vert%4)==0){ - bool culled=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-4+0,nds->gpu.curr_vert-4+1,nds->gpu.curr_vert-4+2); - culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-4+2,nds->gpu.curr_vert-4+3,nds->gpu.curr_vert-4+0); - if(culled)nds->gpu.curr_vert-=4; - else nds->gpu.poly_ram_offset++; - } - break; - /*Tristrip */ case 2: - if(nds->gpu.curr_draw_vert>=3){ - bool culled = true; - if(nds->gpu.curr_draw_vert&1)culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-3,nds->gpu.curr_vert-2,nds->gpu.curr_vert-1); - else culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-3,nds->gpu.curr_vert-1,nds->gpu.curr_vert-2); - nds->gpu.rendered_primitive_tracker<<=1; - if(culled){ - nds->gpu.rendered_primitive_tracker|=1; - if((nds->gpu.rendered_primitive_tracker&0x7)==0x7){ - nds->gpu.vert_buffer[nds->gpu.curr_vert-3]=nds->gpu.vert_buffer[nds->gpu.curr_vert-2]; - nds->gpu.vert_buffer[nds->gpu.curr_vert-2]=nds->gpu.vert_buffer[nds->gpu.curr_vert-1]; - nds->gpu.curr_vert--; - }else nds->gpu.poly_ram_offset++; - } + } + break; + /*Quadstrip */ case 3: + if(nds->gpu.curr_draw_vert >= 4 && (nds->gpu.curr_draw_vert % 2) == 0) { + nds->gpu.rendered_primitive_tracker <<= 1; + bool culled = true; + if(nds->gpu.curr_draw_vert % 4) { + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 6 + 2, nds->gpu.curr_vert - 6 + 3, nds->gpu.curr_vert - 6 + 5); + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 6 + 5, nds->gpu.curr_vert - 6 + 4, nds->gpu.curr_vert - 6 + 2); + } else { + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 4 + 0, nds->gpu.curr_vert - 4 + 1, nds->gpu.curr_vert - 4 + 3); + culled &= nds_gpu_clip_tri(nds, nds->gpu.curr_vert - 4 + 3, nds->gpu.curr_vert - 4 + 2, nds->gpu.curr_vert - 4 + 0); } - break; - /*Quadstrip */ case 3: - if(nds->gpu.curr_draw_vert>=4&&(nds->gpu.curr_draw_vert%2)==0){ - nds->gpu.rendered_primitive_tracker<<=1; - bool culled = true; - if(nds->gpu.curr_draw_vert%4){ - culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-6+2,nds->gpu.curr_vert-6+3,nds->gpu.curr_vert-6+5); - culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-6+5,nds->gpu.curr_vert-6+4,nds->gpu.curr_vert-6+2); - }else{ - culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-4+0,nds->gpu.curr_vert-4+1,nds->gpu.curr_vert-4+3); - culled&=nds_gpu_clip_tri(nds,nds->gpu.curr_vert-4+3,nds->gpu.curr_vert-4+2,nds->gpu.curr_vert-4+0); + if(culled) { + nds->gpu.rendered_primitive_tracker |= 1; + if((nds->gpu.rendered_primitive_tracker & 0x3) == 0x3) { + nds->gpu.vert_buffer[nds->gpu.curr_vert - 4] = nds->gpu.vert_buffer[nds->gpu.curr_vert - 2]; + nds->gpu.vert_buffer[nds->gpu.curr_vert - 3] = nds->gpu.vert_buffer[nds->gpu.curr_vert - 1]; + nds->gpu.curr_vert -= 2; } - if(culled){ - nds->gpu.rendered_primitive_tracker|=1; - if((nds->gpu.rendered_primitive_tracker&0x3)==0x3){ - nds->gpu.vert_buffer[nds->gpu.curr_vert-4]=nds->gpu.vert_buffer[nds->gpu.curr_vert-2]; - nds->gpu.vert_buffer[nds->gpu.curr_vert-3]=nds->gpu.vert_buffer[nds->gpu.curr_vert-1]; - nds->gpu.curr_vert-=2; - } - }else nds->gpu.poly_ram_offset++; - } - break; + } else + nds->gpu.poly_ram_offset++; + } + break; } - //printf("Vertex %f %f %f->%f %f %f\n",vx/65536.0,vy/65536.0,vz/65536.0,res[0],res[1],res[2]); + // printf("Vertex %f %f %f->%f %f %f\n",vx/65536.0,vy/65536.0,vz/65536.0,res[0],res[1],res[2]); } -static int nds_gpu_cmd_params(int cmd){ - switch(cmd){ - case 0x10:return 1 ; /*MTX_MODE - Set Matrix Mode (W)*/ - case 0x11:return 0 ; /*MTX_PUSH - Push Current Matrix on Stack (W)*/ - case 0x12:return 1 ; /*MTX_POP - Pop Current Matrix from Stack (W)*/ - case 0x13:return 1 ; /*MTX_STORE - Store Current Matrix on Stack (W)*/ - case 0x14:return 1 ; /*MTX_RESTORE - Restore Current Matrix from Stack (W)*/ - case 0x15:return 0 ; /*MTX_IDENTITY - Load Unit Matrix to Current Matrix (W)*/ - case 0x16:return 16; /*MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)*/ - case 0x17:return 12; /*MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)*/ - case 0x18:return 16; /*MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)*/ - case 0x19:return 12; /*MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)*/ - case 0x1A:return 9 ; /*MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)*/ - case 0x1B:return 3 ; /*MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)*/ - case 0x1C:return 3 ; /*MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W)*/ - case 0x20:return 1 ; /*COLOR - Directly Set Vertex Color (W)*/ - case 0x21:return 1 ; /*NORMAL - Set Normal Vector (W)*/ - case 0x22:return 1 ; /*TEXCOORD - Set Texture Coordinates (W)*/ - case 0x23:return 2 ; /*VTX_16 - Set Vertex XYZ Coordinates (W)*/ - case 0x24:return 1 ; /*VTX_10 - Set Vertex XYZ Coordinates (W)*/ - case 0x25:return 1 ; /*VTX_XY - Set Vertex XY Coordinates (W)*/ - case 0x26:return 1 ; /*VTX_XZ - Set Vertex XZ Coordinates (W)*/ - case 0x27:return 1 ; /*VTX_YZ - Set Vertex YZ Coordinates (W)*/ - case 0x28:return 1 ; /*VTX_DIFF - Set Relative Vertex Coordinates (W)*/ - case 0x29:return 1 ; /*POLYGON_ATTR - Set Polygon Attributes (W)*/ - case 0x2A:return 1 ; /*TEXIMAGE_PARAM - Set Texture Parameters (W)*/ - case 0x2B:return 1 ; /*PLTT_BASE - Set Texture Palette Base Address (W)*/ - case 0x30:return 1 ; /*DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)*/ - case 0x31:return 1 ; /*SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W)*/ - case 0x32:return 1 ; /*LIGHT_VECTOR - Set Light's Directional Vector (W)*/ - case 0x33:return 1 ; /*LIGHT_COLOR - Set Light Color (W)*/ - case 0x34:return 32; /*SHININESS - Specular Reflection Shininess Table (W)*/ - case 0x40:return 1 ; /*BEGIN_VTXS - Start of Vertex List (W)*/ - case 0x41:return 0 ; /*END_VTXS - End of Vertex List (W)*/ - case 0x50:return 1 ; /*SWAP_BUFFERS - Swap Rendering Engine Buffer (W)*/ - case 0x60:return 1 ; /*VIEWPORT - Set Viewport (W)*/ - case 0x70:return 3 ; /*BOX_TEST - Test if Cuboid Sits inside View Volume (W)*/ - case 0x71:return 2 ; /*POS_TEST - Set Position Coordinates for Test (W)*/ - case 0x72:return 1 ; /*VEC_TEST - Set Directional Vector for Test (W)*/ +static int nds_gpu_cmd_params(int cmd) { + switch(cmd) { + case 0x10: return 1; /*MTX_MODE - Set Matrix Mode (W)*/ + case 0x11: return 0; /*MTX_PUSH - Push Current Matrix on Stack (W)*/ + case 0x12: return 1; /*MTX_POP - Pop Current Matrix from Stack (W)*/ + case 0x13: return 1; /*MTX_STORE - Store Current Matrix on Stack (W)*/ + case 0x14: return 1; /*MTX_RESTORE - Restore Current Matrix from Stack (W)*/ + case 0x15: return 0; /*MTX_IDENTITY - Load Unit Matrix to Current Matrix (W)*/ + case 0x16: return 16; /*MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)*/ + case 0x17: return 12; /*MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)*/ + case 0x18: return 16; /*MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)*/ + case 0x19: return 12; /*MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)*/ + case 0x1A: return 9; /*MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)*/ + case 0x1B: return 3; /*MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)*/ + case 0x1C: return 3; /*MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W)*/ + case 0x20: return 1; /*COLOR - Directly Set Vertex Color (W)*/ + case 0x21: return 1; /*NORMAL - Set Normal Vector (W)*/ + case 0x22: return 1; /*TEXCOORD - Set Texture Coordinates (W)*/ + case 0x23: return 2; /*VTX_16 - Set Vertex XYZ Coordinates (W)*/ + case 0x24: return 1; /*VTX_10 - Set Vertex XYZ Coordinates (W)*/ + case 0x25: return 1; /*VTX_XY - Set Vertex XY Coordinates (W)*/ + case 0x26: return 1; /*VTX_XZ - Set Vertex XZ Coordinates (W)*/ + case 0x27: return 1; /*VTX_YZ - Set Vertex YZ Coordinates (W)*/ + case 0x28: return 1; /*VTX_DIFF - Set Relative Vertex Coordinates (W)*/ + case 0x29: return 1; /*POLYGON_ATTR - Set Polygon Attributes (W)*/ + case 0x2A: return 1; /*TEXIMAGE_PARAM - Set Texture Parameters (W)*/ + case 0x2B: return 1; /*PLTT_BASE - Set Texture Palette Base Address (W)*/ + case 0x30: return 1; /*DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)*/ + case 0x31: return 1; /*SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W)*/ + case 0x32: return 1; /*LIGHT_VECTOR - Set Light's Directional Vector (W)*/ + case 0x33: return 1; /*LIGHT_COLOR - Set Light Color (W)*/ + case 0x34: return 32; /*SHININESS - Specular Reflection Shininess Table (W)*/ + case 0x40: return 1; /*BEGIN_VTXS - Start of Vertex List (W)*/ + case 0x41: return 0; /*END_VTXS - End of Vertex List (W)*/ + case 0x50: return 1; /*SWAP_BUFFERS - Swap Rendering Engine Buffer (W)*/ + case 0x60: return 1; /*VIEWPORT - Set Viewport (W)*/ + case 0x70: return 3; /*BOX_TEST - Test if Cuboid Sits inside View Volume (W)*/ + case 0x71: return 2; /*POS_TEST - Set Position Coordinates for Test (W)*/ + case 0x72: return 1; /*VEC_TEST - Set Directional Vector for Test (W)*/ } - return 0; + return 0; } -static int nds_gpu_cmd_cycles(int cmd){ - //https://melonds.kuribo64.net/board/thread.php?id=141 - return 3; - switch(cmd){ - case 0x10:return 1 ; /*MTX_MODE - Set Matrix Mode (W)*/ - case 0x11:return 17 ; /*MTX_PUSH - Push Current Matrix on Stack (W)*/ - case 0x12:return 36 ; /*MTX_POP - Pop Current Matrix from Stack (W)*/ - case 0x13:return 17 ; /*MTX_STORE - Store Current Matrix on Stack (W)*/ - case 0x14:return 36 ; /*MTX_RESTORE - Restore Current Matrix from Stack (W)*/ - case 0x15:return 19 ; /*MTX_IDENTITY - Load Unit Matrix to Current Matrix (W)*/ - case 0x16:return 34 ; /*MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)*/ - case 0x17:return 30 ; /*MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)*/ - case 0x18:return 35 ; /*MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)*/ - case 0x19:return 31 ; /*MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)*/ - case 0x1A:return 28 ; /*MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)*/ - case 0x1B:return 22 ; /*MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)*/ - case 0x1C:return 22 ; /*MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W)*/ - case 0x20:return 1 ; /*COLOR - Directly Set Vertex Color (W)*/ - case 0x21:return 9 ; /*NORMAL - Set Normal Vector (W)*/ - case 0x22:return 1 ; /*TEXCOORD - Set Texture Coordinates (W)*/ - case 0x23:return 9 ; /*VTX_16 - Set Vertex XYZ Coordinates (W)*/ - case 0x24:return 8 ; /*VTX_10 - Set Vertex XYZ Coordinates (W)*/ - case 0x25:return 8 ; /*VTX_XY - Set Vertex XY Coordinates (W)*/ - case 0x26:return 8 ; /*VTX_XZ - Set Vertex XZ Coordinates (W)*/ - case 0x27:return 8 ; /*VTX_YZ - Set Vertex YZ Coordinates (W)*/ - case 0x28:return 8 ; /*VTX_DIFF - Set Relative Vertex Coordinates (W)*/ - case 0x29:return 1 ; /*POLYGON_ATTR - Set Polygon Attributes (W)*/ - case 0x2A:return 1 ; /*TEXIMAGE_PARAM - Set Texture Parameters (W)*/ - case 0x2B:return 1 ; /*PLTT_BASE - Set Texture Palette Base Address (W)*/ - case 0x30:return 4 ; /*DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)*/ - case 0x31:return 4 ; /*SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W)*/ - case 0x32:return 6 ; /*LIGHT_VECTOR - Set Light's Directional Vector (W)*/ - case 0x33:return 1 ; /*LIGHT_COLOR - Set Light Color (W)*/ - case 0x34:return 32 ; /*SHININESS - Specular Reflection Shininess Table (W)*/ - case 0x40:return 1 ; /*BEGIN_VTXS - Start of Vertex List (W)*/ - case 0x41:return 1 ; /*END_VTXS - End of Vertex List (W)*/ - case 0x50:return 392; /*SWAP_BUFFERS - Swap Rendering Engine Buffer (W)*/ - case 0x60:return 1 ; /*VIEWPORT - Set Viewport (W)*/ - case 0x70:return 103; /*BOX_TEST - Test if Cuboid Sits inside View Volume (W)*/ - case 0x71:return 9 ; /*POS_TEST - Set Position Coordinates for Test (W)*/ - case 0x72:return 5 ; /*VEC_TEST - Set Directional Vector for Test (W)*/ +static int nds_gpu_cmd_cycles(int cmd) { + // https://melonds.kuribo64.net/board/thread.php?id=141 + return 3; + switch(cmd) { + case 0x10: return 1; /*MTX_MODE - Set Matrix Mode (W)*/ + case 0x11: return 17; /*MTX_PUSH - Push Current Matrix on Stack (W)*/ + case 0x12: return 36; /*MTX_POP - Pop Current Matrix from Stack (W)*/ + case 0x13: return 17; /*MTX_STORE - Store Current Matrix on Stack (W)*/ + case 0x14: return 36; /*MTX_RESTORE - Restore Current Matrix from Stack (W)*/ + case 0x15: return 19; /*MTX_IDENTITY - Load Unit Matrix to Current Matrix (W)*/ + case 0x16: return 34; /*MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)*/ + case 0x17: return 30; /*MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)*/ + case 0x18: return 35; /*MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)*/ + case 0x19: return 31; /*MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)*/ + case 0x1A: return 28; /*MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)*/ + case 0x1B: return 22; /*MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)*/ + case 0x1C: return 22; /*MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W)*/ + case 0x20: return 1; /*COLOR - Directly Set Vertex Color (W)*/ + case 0x21: return 9; /*NORMAL - Set Normal Vector (W)*/ + case 0x22: return 1; /*TEXCOORD - Set Texture Coordinates (W)*/ + case 0x23: return 9; /*VTX_16 - Set Vertex XYZ Coordinates (W)*/ + case 0x24: return 8; /*VTX_10 - Set Vertex XYZ Coordinates (W)*/ + case 0x25: return 8; /*VTX_XY - Set Vertex XY Coordinates (W)*/ + case 0x26: return 8; /*VTX_XZ - Set Vertex XZ Coordinates (W)*/ + case 0x27: return 8; /*VTX_YZ - Set Vertex YZ Coordinates (W)*/ + case 0x28: return 8; /*VTX_DIFF - Set Relative Vertex Coordinates (W)*/ + case 0x29: return 1; /*POLYGON_ATTR - Set Polygon Attributes (W)*/ + case 0x2A: return 1; /*TEXIMAGE_PARAM - Set Texture Parameters (W)*/ + case 0x2B: return 1; /*PLTT_BASE - Set Texture Palette Base Address (W)*/ + case 0x30: return 4; /*DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)*/ + case 0x31: return 4; /*SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W)*/ + case 0x32: return 6; /*LIGHT_VECTOR - Set Light's Directional Vector (W)*/ + case 0x33: return 1; /*LIGHT_COLOR - Set Light Color (W)*/ + case 0x34: return 32; /*SHININESS - Specular Reflection Shininess Table (W)*/ + case 0x40: return 1; /*BEGIN_VTXS - Start of Vertex List (W)*/ + case 0x41: return 1; /*END_VTXS - End of Vertex List (W)*/ + case 0x50: return 392; /*SWAP_BUFFERS - Swap Rendering Engine Buffer (W)*/ + case 0x60: return 1; /*VIEWPORT - Set Viewport (W)*/ + case 0x70: return 103; /*BOX_TEST - Test if Cuboid Sits inside View Volume (W)*/ + case 0x71: return 9; /*POS_TEST - Set Position Coordinates for Test (W)*/ + case 0x72: return 5; /*VEC_TEST - Set Directional Vector for Test (W)*/ } - return 1; + return 1; } -static FORCE_INLINE int32_t nds_gxfifo_size(nds_t*nds){ - return (nds->gpu.fifo_write_ptr-nds->gpu.fifo_read_ptr)%(NDS_GXFIFO_MASK); +static FORCE_INLINE int32_t nds_gxfifo_size(nds_t *nds) { + return (nds->gpu.fifo_write_ptr - nds->gpu.fifo_read_ptr) % (NDS_GXFIFO_MASK); } -static FORCE_INLINE void nds_gxfifo_push(nds_t* nds, uint8_t cmd, uint32_t data){ - if(nds_gxfifo_size(nds)>=NDS_GXFIFO_STORAGE){ - printf("Error GX FIFO Overflow\n"); +static FORCE_INLINE void nds_gxfifo_push(nds_t *nds, uint8_t cmd, uint32_t data) { + if(nds_gxfifo_size(nds) >= NDS_GXFIFO_STORAGE) { + printf("Error GX FIFO Overflow\n"); return; } - if(cmd>=0x70&&cmd<=0x72)nds->gpu.test_busy++; - nds->gpu.fifo_cmd[nds->gpu.fifo_write_ptr%NDS_GXFIFO_STORAGE]=cmd; - nds->gpu.fifo_data[nds->gpu.fifo_write_ptr%NDS_GXFIFO_STORAGE]=data; + if(cmd >= 0x70 && cmd <= 0x72) nds->gpu.test_busy++; + nds->gpu.fifo_cmd[nds->gpu.fifo_write_ptr % NDS_GXFIFO_STORAGE] = cmd; + nds->gpu.fifo_data[nds->gpu.fifo_write_ptr % NDS_GXFIFO_STORAGE] = data; nds->gpu.fifo_write_ptr++; } -static float nds_point_plane_distance(float * point, float * plane){ - float dist = plane[3]; - SE_RPT3 dist+=point[r]*plane[r]; - return dist; +static float nds_point_plane_distance(float *point, float *plane) { + float dist = plane[3]; + SE_RPT3 dist += point[r] * plane[r]; + return dist; } -static void nds_vertex_lighting(nds_t * nds, int16_t nxi, int16_t nyi, int16_t nzi){ - float normal_object[4] = {nxi/32768.,nyi/32768.,nzi/32768.,0.}; - nds_gpu_t* gpu = &nds->gpu; - float *normal= gpu->transformed_normal; - nds_mult_matrix_vector(normal,gpu->direction_matrix,normal_object,4); - - float color[3]; - SE_RPT3 color[r]=gpu->curr_emission_color[r]/255.; - for(int i=0;i<4;++i){ - bool enabled = SB_BFE(gpu->poly_attr,i,1); - if(!enabled)continue; - float diffuse = 0, specular = 0; - SE_RPT3 diffuse-=normal[r]*gpu->light_vector[i*4+r]; - float half_vector[4]; - //LOS_Vector = (0,0,-1) - //half_vector = (light_vector+LOS_vector)*0.5; - SE_RPT4 half_vector[r]=gpu->light_vector[i*4+r]*0.5; - half_vector[2] -= 0.5; - SE_RPT3 specular-=normal[r]*half_vector[r]; - diffuse = fmax(0,diffuse); - specular= fmax(0,specular); - specular*=specular; - if(gpu->use_shininess_table){ - int entry = specular*127; - if(entry>127)entry = 127; - else if(entry<0)entry = 0; - specular = gpu->shininess_table[entry]/255.; +static void nds_vertex_lighting(nds_t *nds, int16_t nxi, int16_t nyi, int16_t nzi) { + float normal_object[4] = {nxi / 32768., nyi / 32768., nzi / 32768., 0.}; + nds_gpu_t *gpu = &nds->gpu; + float *normal = gpu->transformed_normal; + nds_mult_matrix_vector(normal, gpu->direction_matrix, normal_object, 4); + + float color[3]; + SE_RPT3 color[r] = gpu->curr_emission_color[r] / 255.; + for(int i = 0; i < 4; ++i) { + bool enabled = SB_BFE(gpu->poly_attr, i, 1); + if(!enabled) continue; + float diffuse = 0, specular = 0; + SE_RPT3 diffuse -= normal[r] * gpu->light_vector[i * 4 + r]; + float half_vector[4]; + // LOS_Vector = (0,0,-1) + // half_vector = (light_vector+LOS_vector)*0.5; + SE_RPT4 half_vector[r] = gpu->light_vector[i * 4 + r] * 0.5; + half_vector[2] -= 0.5; + SE_RPT3 specular -= normal[r] * half_vector[r]; + diffuse = fmax(0, diffuse); + specular = fmax(0, specular); + specular *= specular; + if(gpu->use_shininess_table) { + int entry = specular * 127; + if(entry > 127) + entry = 127; + else if(entry < 0) + entry = 0; + specular = gpu->shininess_table[entry] / 255.; } - SE_RPT3 color[r]+=((float)gpu->curr_diffuse_color[r])*(float)gpu->light_color[i*3+r]*diffuse/(255.*255.); - SE_RPT3 color[r]+=(float)gpu->curr_specular_color[r]*(float)gpu->light_color[i*3+r]*specular/(255.*255.); - SE_RPT3 color[r]+=(float)gpu->curr_ambient_color[r]*(float)gpu->light_color[i*3+r]/(255.*255.); + SE_RPT3 color[r] += ((float)gpu->curr_diffuse_color[r]) * (float)gpu->light_color[i * 3 + r] * diffuse / (255. * 255.); + SE_RPT3 color[r] += (float)gpu->curr_specular_color[r] * (float)gpu->light_color[i * 3 + r] * specular / (255. * 255.); + SE_RPT3 color[r] += (float)gpu->curr_ambient_color[r] * (float)gpu->light_color[i * 3 + r] / (255. * 255.); } - SE_RPT3 gpu->curr_color[r]= fmax(0.0,fmin(255.0,color[r]*255)); + SE_RPT3 gpu->curr_color[r] = fmax(0.0, fmin(255.0, color[r] * 255)); } -static FORCE_INLINE void nds_tick_gx(nds_t* nds){ - nds_gpu_t* gpu = &nds->gpu; - if(gpu->cmd_busy_cycles>0){gpu->cmd_busy_cycles--;return;} - if(gpu->pending_swap){nds_gpu_swap_buffers(nds);gpu->pending_swap=false;} +static FORCE_INLINE void nds_tick_gx(nds_t *nds) { + nds_gpu_t *gpu = &nds->gpu; + if(gpu->cmd_busy_cycles > 0) { + gpu->cmd_busy_cycles--; + return; + } + if(gpu->pending_swap) { + nds_gpu_swap_buffers(nds); + gpu->pending_swap = false; + } int sz = nds_gxfifo_size(nds); - if(sz<=NDS_GX_DMA_THRESHOLD){nds->activate_dmas|=nds->dma_wait_gx;} - uint32_t gxstat = nds9_io_read32(nds,NDS9_GXSTAT); - int irq_mode = SB_BFE(gxstat,30,2); - bool less_than_half_full = sz<128; - bool empty = sz<=0; - uint32_t if9 = nds9_io_read32(nds,NDS9_IF); - switch(irq_mode){ - case 1: if(less_than_half_full)if9|=(1<activate_dmas |= nds->dma_wait_gx; } + uint32_t gxstat = nds9_io_read32(nds, NDS9_GXSTAT); + int irq_mode = SB_BFE(gxstat, 30, 2); + bool less_than_half_full = sz < 128; + bool empty = sz <= 0; + uint32_t if9 = nds9_io_read32(nds, NDS9_IF); + switch(irq_mode) { + case 1: + if(less_than_half_full) if9 |= (1 << NDS9_INT_GX_FIFO); + break; + case 2: + if(empty) if9 |= (1 << NDS9_INT_GX_FIFO); + break; } - nds9_io_store32(nds,NDS9_IF,if9); - gxstat&= 0xc0000000; - gxstat|= (gpu->mv_matrix_stack_ptr&0x1f)<<8;//8-12 - gxstat|= (gpu->proj_matrix_stack_ptr&0x1)<<13; - if(gpu->box_test_result)gxstat|=(1<<1);//Box test - if(gpu->matrix_stack_error)gxstat|=1<<15; - gxstat|= (sz&0x1ff)<<16; - if(less_than_half_full)gxstat|= 1<<25; //Less than half full - if(empty)gxstat|= 1<<26; //Empty - uint8_t cmd = gpu->fifo_cmd[gpu->fifo_read_ptr%NDS_GXFIFO_STORAGE]; + nds9_io_store32(nds, NDS9_IF, if9); + gxstat &= 0xc0000000; + gxstat |= (gpu->mv_matrix_stack_ptr & 0x1f) << 8; // 8-12 + gxstat |= (gpu->proj_matrix_stack_ptr & 0x1) << 13; + if(gpu->box_test_result) gxstat |= (1 << 1); // Box test + if(gpu->matrix_stack_error) gxstat |= 1 << 15; + gxstat |= (sz & 0x1ff) << 16; + if(less_than_half_full) gxstat |= 1 << 25; // Less than half full + if(empty) gxstat |= 1 << 26; // Empty + uint8_t cmd = gpu->fifo_cmd[gpu->fifo_read_ptr % NDS_GXFIFO_STORAGE]; uint32_t cmd_params = nds_gpu_cmd_params(cmd); - if(sz!=0&&sz>=cmd_params)gxstat|= 1<<27;//is busy + if(sz != 0 && sz >= cmd_params) gxstat |= 1 << 27; // is busy - if(nds->gpu.test_busy>0)gxstat|= 1<<0; + if(nds->gpu.test_busy > 0) gxstat |= 1 << 0; - nds9_io_store32(nds,NDS9_GXSTAT,gxstat); - if(szfifo_data[(gpu->fifo_read_ptr++)%NDS_GXFIFO_STORAGE]; + for(int i = 0; i < cmd_params; ++i) + p[i] = gpu->fifo_data[(gpu->fifo_read_ptr++) % NDS_GXFIFO_STORAGE]; /* printf("GPU CMD: %02x fifo_size: %d Data: ",cmd,sz); for(int i=0;icmd_busy_cycles= nds_gpu_cmd_cycles(cmd); - - if(SB_UNLIKELY(nds->gx_log&&cmd)){ - fprintf(nds->gx_log,"GPU CMD: %02x\n",cmd); - fprintf(nds->gx_log,"mv_stack: %d proj_stack: %d\n",gpu->mv_matrix_stack_ptr, gpu->proj_matrix_stack_ptr); - fprintf(nds->gx_log,"proj: "); - for(int i=0;i<16;++i)fprintf(nds->gx_log,"%f ",gpu->proj_matrix[i]); - fprintf(nds->gx_log,"\nmv: "); - for(int i=0;i<16;++i)fprintf(nds->gx_log,"%f ",gpu->mv_matrix[i]); - fprintf(nds->gx_log,"\n"); + float fixed_to_float = 1.0 / (1 << 12); + gpu->cmd_busy_cycles = nds_gpu_cmd_cycles(cmd); + + if(SB_UNLIKELY(nds->gx_log && cmd)) { + fprintf(nds->gx_log, "GPU CMD: %02x\n", cmd); + fprintf(nds->gx_log, "mv_stack: %d proj_stack: %d\n", gpu->mv_matrix_stack_ptr, gpu->proj_matrix_stack_ptr); + fprintf(nds->gx_log, "proj: "); + for(int i = 0; i < 16; ++i) + fprintf(nds->gx_log, "%f ", gpu->proj_matrix[i]); + fprintf(nds->gx_log, "\nmv: "); + for(int i = 0; i < 16; ++i) + fprintf(nds->gx_log, "%f ", gpu->mv_matrix[i]); + fprintf(nds->gx_log, "\n"); } - - switch(cmd){ - case 0x0: /*NOP*/ break; - case 0x10:/*MTX_MODE*/ nds->gpu.matrix_mode = SB_BFE(p[0],0,2);break; - case 0x11:/*MTX_PUSH*/ - { - switch (gpu->matrix_mode){ - case NDS_MATRIX_MV: - case NDS_MATRIX_DIR: - if(gpu->mv_matrix_stack_ptr>31){gpu->matrix_stack_error=true;gpu->mv_matrix_stack_ptr=31;} - for(int i=0;i<16;++i){gpu->mv_matrix_stack[gpu->mv_matrix_stack_ptr*16+i]=gpu->mv_matrix[i];} - for(int i=0;i<16;++i){gpu->direction_matrix_stack[gpu->mv_matrix_stack_ptr*16+i]=gpu->direction_matrix[i];} - gpu->mv_matrix_stack_ptr++; - break; - case NDS_MATRIX_TEX: - if(gpu->tex_matrix_stack_ptr>=1){gpu->matrix_stack_error=true;gpu->tex_matrix_stack_ptr=0;} - for(int i=0;i<16;++i){gpu->tex_matrix_stack[i]=gpu->tex_matrix[i];} - gpu->tex_matrix_stack_ptr++; - break; - case NDS_MATRIX_PROJ: - if(gpu->proj_matrix_stack_ptr>=1){gpu->matrix_stack_error=true;gpu->proj_matrix_stack_ptr=0;} - for(int i=0;i<16;++i){gpu->proj_matrix_stack[i]=gpu->proj_matrix[i];} - gpu->proj_matrix_stack_ptr++; - break; - } + switch(cmd) { + case 0x0: /*NOP*/ break; + case 0x10: /*MTX_MODE*/ nds->gpu.matrix_mode = SB_BFE(p[0], 0, 2); break; + case 0x11: /*MTX_PUSH*/ + { + switch(gpu->matrix_mode) { + case NDS_MATRIX_MV: + case NDS_MATRIX_DIR: + if(gpu->mv_matrix_stack_ptr > 31) { + gpu->matrix_stack_error = true; + gpu->mv_matrix_stack_ptr = 31; } - break; - case 0x12:/*MTX_POP*/ - { - int32_t pop_cnt = SB_BFE(p[0],0,6); - if (pop_cnt & 32) pop_cnt -= 64; - switch (gpu->matrix_mode){ - case NDS_MATRIX_MV: - case NDS_MATRIX_DIR: - gpu->mv_matrix_stack_ptr-=pop_cnt; - if(gpu->mv_matrix_stack_ptr<0){ - gpu->matrix_stack_error=true;gpu->mv_matrix_stack_ptr=0; - } - if(gpu->mv_matrix_stack_ptr>31){gpu->matrix_stack_error=true;gpu->mv_matrix_stack_ptr=31;} - for(int i=0;i<16;++i){gpu->mv_matrix[i]=gpu->mv_matrix_stack[gpu->mv_matrix_stack_ptr*16+i];} - for(int i=0;i<16;++i){gpu->direction_matrix[i]=gpu->direction_matrix_stack[gpu->mv_matrix_stack_ptr*16+i];} - break; - case NDS_MATRIX_TEX: - gpu->tex_matrix_stack_ptr--; - if(gpu->tex_matrix_stack_ptr<0){ - gpu->matrix_stack_error=true;gpu->tex_matrix_stack_ptr=0; - } - for(int i=0;i<16;++i){gpu->tex_matrix[i]=gpu->tex_matrix_stack[i];} - break; - case NDS_MATRIX_PROJ: - gpu->proj_matrix_stack_ptr--; - if(gpu->proj_matrix_stack_ptr<0){ - gpu->matrix_stack_error=true;gpu->proj_matrix_stack_ptr=0; - } - for(int i=0;i<16;++i){gpu->proj_matrix[i]=gpu->proj_matrix_stack[i];} - break; + for(int i = 0; i < 16; ++i) { + gpu->mv_matrix_stack[gpu->mv_matrix_stack_ptr * 16 + i] = gpu->mv_matrix[i]; } - break; - } - case 0x13: {/*MTX_STORE*/ - float * m = nds_gpu_get_active_matrix(nds); - int new_stack = SB_BFE(p[0],0,5)*16; - switch (gpu->matrix_mode){ - case NDS_MATRIX_MV: - case NDS_MATRIX_DIR: - for(int i=0;i<16;++i)gpu->mv_matrix_stack[new_stack+i]=m[i]; - for(int i=0;i<16;++i)gpu->direction_matrix_stack[new_stack+i]=gpu->direction_matrix[i]; - break; - case NDS_MATRIX_TEX: - for(int i=0;i<16;++i)gpu->tex_matrix_stack[i]=m[i]; - break; - case NDS_MATRIX_PROJ: - for(int i=0;i<16;++i)gpu->proj_matrix_stack[i]=m[i]; - break; + for(int i = 0; i < 16; ++i) { + gpu->direction_matrix_stack[gpu->mv_matrix_stack_ptr * 16 + i] = gpu->direction_matrix[i]; } + gpu->mv_matrix_stack_ptr++; break; - } - case 0x14: {/*MTX_RESTORE*/ - float * m = nds_gpu_get_active_matrix(nds); - int new_stack = SB_BFE(p[0],0,5)*16; - switch (gpu->matrix_mode){ - case NDS_MATRIX_MV: - case NDS_MATRIX_DIR: - for(int i=0;i<16;++i)m[i]=gpu->mv_matrix_stack[new_stack+i]; - for(int i=0;i<16;++i)gpu->direction_matrix[i]=gpu->direction_matrix_stack[new_stack+i]; - break; - case NDS_MATRIX_TEX: - for(int i=0;i<16;++i)m[i]=gpu->tex_matrix_stack[i]; - break; - case NDS_MATRIX_PROJ: - for(int i=0;i<16;++i)m[i]=gpu->proj_matrix_stack[i]; - break; + case NDS_MATRIX_TEX: + if(gpu->tex_matrix_stack_ptr >= 1) { + gpu->matrix_stack_error = true; + gpu->tex_matrix_stack_ptr = 0; } - break; - } - case 0x15: /*MTX_IDENTITY - Load Unit Matrix to Current Matrix (W)*/ - nds_identity_matrix(nds_gpu_get_active_matrix(nds)); - if(gpu->matrix_mode==NDS_MATRIX_DIR)nds_identity_matrix(gpu->direction_matrix); - break; - case 0x16: /*MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)*/ - for(int i=0;i<16;++i)nds_gpu_get_active_matrix(nds)[i]=p[i]*fixed_to_float; - if(gpu->matrix_mode==NDS_MATRIX_DIR){ - for(int i=0;i<16;++i) gpu->direction_matrix[i]=p[i]*fixed_to_float; + for(int i = 0; i < 16; ++i) { + gpu->tex_matrix_stack[i] = gpu->tex_matrix[i]; } + gpu->tex_matrix_stack_ptr++; break; - case 0x17:{ /*MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)*/ - float m2[16]={ - p[0]*fixed_to_float, p[1]*fixed_to_float, p[2]*fixed_to_float,0, - p[3]*fixed_to_float, p[4]*fixed_to_float, p[5]*fixed_to_float,0, - p[6]*fixed_to_float ,p[7]*fixed_to_float, p[8]*fixed_to_float,0, - p[9]*fixed_to_float, p[10]*fixed_to_float,p[11]*fixed_to_float,1., - }; - float*m = nds_gpu_get_active_matrix(nds); - for(int i=0;i<16;++i)m[i]=m2[i]; - if(gpu->matrix_mode==NDS_MATRIX_DIR){ - for(int i=0;i<16;++i) gpu->direction_matrix[i]=m2[i]; + case NDS_MATRIX_PROJ: + if(gpu->proj_matrix_stack_ptr >= 1) { + gpu->matrix_stack_error = true; + gpu->proj_matrix_stack_ptr = 0; } - break; - } - case 0x18:{ /*MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)*/ - float m[16]={ - p[0]*fixed_to_float, p[1]*fixed_to_float, p[2]*fixed_to_float,p[3]*fixed_to_float, - p[4]*fixed_to_float, p[5]*fixed_to_float, p[6]*fixed_to_float,p[7]*fixed_to_float, - p[8]*fixed_to_float, p[9]*fixed_to_float, p[10]*fixed_to_float,p[11]*fixed_to_float, - p[12]*fixed_to_float, p[13]*fixed_to_float, p[14]*fixed_to_float,p[15]*fixed_to_float - }; - nds_mult_matrix4(nds_gpu_get_active_matrix(nds),m); - if(gpu->matrix_mode==NDS_MATRIX_DIR){ - nds_mult_matrix4(gpu->direction_matrix,m); - gpu->cmd_busy_cycles+=30; + for(int i = 0; i < 16; ++i) { + gpu->proj_matrix_stack[i] = gpu->proj_matrix[i]; } + gpu->proj_matrix_stack_ptr++; break; } - case 0x19:{ /*MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)*/ - float m[16]={ - p[0]*fixed_to_float, p[1]*fixed_to_float, p[2]*fixed_to_float,0, - p[3]*fixed_to_float, p[4]*fixed_to_float, p[5]*fixed_to_float,0, - p[6]*fixed_to_float,p[7]*fixed_to_float, p[8]*fixed_to_float,0, - p[9]*fixed_to_float, p[10]*fixed_to_float,p[11]*fixed_to_float,1., - }; - nds_mult_matrix4(nds_gpu_get_active_matrix(nds),m); - if(gpu->matrix_mode==NDS_MATRIX_DIR){ - nds_mult_matrix4(gpu->direction_matrix,m); - gpu->cmd_busy_cycles+=30; + } break; + case 0x12: /*MTX_POP*/ + { + int32_t pop_cnt = SB_BFE(p[0], 0, 6); + if(pop_cnt & 32) pop_cnt -= 64; + switch(gpu->matrix_mode) { + case NDS_MATRIX_MV: + case NDS_MATRIX_DIR: + gpu->mv_matrix_stack_ptr -= pop_cnt; + if(gpu->mv_matrix_stack_ptr < 0) { + gpu->matrix_stack_error = true; + gpu->mv_matrix_stack_ptr = 0; + } + if(gpu->mv_matrix_stack_ptr > 31) { + gpu->matrix_stack_error = true; + gpu->mv_matrix_stack_ptr = 31; + } + for(int i = 0; i < 16; ++i) { + gpu->mv_matrix[i] = gpu->mv_matrix_stack[gpu->mv_matrix_stack_ptr * 16 + i]; + } + for(int i = 0; i < 16; ++i) { + gpu->direction_matrix[i] = gpu->direction_matrix_stack[gpu->mv_matrix_stack_ptr * 16 + i]; } break; - } - - case 0x1a: { /*MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)*/ - float m[16]={ - p[0]*fixed_to_float, p[1]*fixed_to_float, p[2]*fixed_to_float,0, - p[3]*fixed_to_float, p[4]*fixed_to_float, p[5]*fixed_to_float,0, - p[6]*fixed_to_float, p[7]*fixed_to_float, p[8]*fixed_to_float,0, - 0,0,0,1., - }; - nds_mult_matrix4(nds_gpu_get_active_matrix(nds),m); - if(gpu->matrix_mode==NDS_MATRIX_DIR){ - nds_mult_matrix4(gpu->direction_matrix,m); - gpu->cmd_busy_cycles+=30; + case NDS_MATRIX_TEX: + gpu->tex_matrix_stack_ptr--; + if(gpu->tex_matrix_stack_ptr < 0) { + gpu->matrix_stack_error = true; + gpu->tex_matrix_stack_ptr = 0; + } + for(int i = 0; i < 16; ++i) { + gpu->tex_matrix[i] = gpu->tex_matrix_stack[i]; } break; - } - case 0x1c: /*MTX_TRAN*/ - if(nds->gpu.matrix_mode==NDS_MATRIX_DIR){ - gpu->cmd_busy_cycles+=30; - nds_translate_matrix(gpu->direction_matrix,p[0]*fixed_to_float, - p[1]*fixed_to_float, - p[2]*fixed_to_float); + case NDS_MATRIX_PROJ: + gpu->proj_matrix_stack_ptr--; + if(gpu->proj_matrix_stack_ptr < 0) { + gpu->matrix_stack_error = true; + gpu->proj_matrix_stack_ptr = 0; + } + for(int i = 0; i < 16; ++i) { + gpu->proj_matrix[i] = gpu->proj_matrix_stack[i]; } - nds_translate_matrix(nds_gpu_get_active_matrix(nds),p[0]*fixed_to_float, - p[1]*fixed_to_float, - p[2]*fixed_to_float);break; /*MTX_TRAN*/ - - case 0x1b: - if(nds->gpu.matrix_mode==NDS_MATRIX_DIR)gpu->cmd_busy_cycles+=30; - nds_scale_matrix(nds_gpu_get_active_matrix(nds),p[0]*fixed_to_float, - p[1]*fixed_to_float, - p[2]*fixed_to_float);break; /*MTX_SCALE*/ - case 0x20: /*COLOR - Directly Set Vertex Color (W)*/ - nds->gpu.curr_color[0]=SB_BFE(p[0],0,5)<<3; - nds->gpu.curr_color[1]=SB_BFE(p[0],5,5)<<3; - nds->gpu.curr_color[2]=SB_BFE(p[0],10,5)<<3; - nds->gpu.curr_color[3]=255; break; - case 0x21: - nds_vertex_lighting(nds, (int16_t)(SB_BFE(p[0],0,10)<<6u), - (int16_t)(SB_BFE(p[0],10,10)<<6u), - (int16_t)(SB_BFE(p[0],20,10)<<6u) - ); + } + break; + } + case 0x13: { /*MTX_STORE*/ + float *m = nds_gpu_get_active_matrix(nds); + int new_stack = SB_BFE(p[0], 0, 5) * 16; + switch(gpu->matrix_mode) { + case NDS_MATRIX_MV: + case NDS_MATRIX_DIR: + for(int i = 0; i < 16; ++i) + gpu->mv_matrix_stack[new_stack + i] = m[i]; + for(int i = 0; i < 16; ++i) + gpu->direction_matrix_stack[new_stack + i] = gpu->direction_matrix[i]; break; - case 0x22:/*TEXCOORD*/ - nds->gpu.curr_tex_coord[0] = SB_BFE(p[0],0,16); - nds->gpu.curr_tex_coord[1] = SB_BFE(p[0],16,16); + case NDS_MATRIX_TEX: + for(int i = 0; i < 16; ++i) + gpu->tex_matrix_stack[i] = m[i]; break; - case 0x23:/*VTX_16*/ nds_gpu_process_vertex(nds,SB_BFE(p[0],0,16), - SB_BFE(p[0],16,16), - SB_BFE(p[1],0,16));break; - - case 0x24:/*VTX_10*/ nds_gpu_process_vertex(nds,((int16_t)SB_BFE(p[0],0,10)<<6), - ((int16_t)SB_BFE(p[0],10,10)<<6), - ((int16_t)SB_BFE(p[0],20,10)<<6)); - break; - - case 0x25: /*VTX_XY*/ nds_gpu_process_vertex(nds,SB_BFE(p[0],0,16), - SB_BFE(p[0],16,16), - nds->gpu.last_vertex_pos[2]); - break; - case 0x26: /*VTX_XZ*/ nds_gpu_process_vertex(nds,SB_BFE(p[0],0,16), - nds->gpu.last_vertex_pos[1], - SB_BFE(p[0],16,16)); - break; - case 0x27: /*VTX_YZ*/ nds_gpu_process_vertex(nds,nds->gpu.last_vertex_pos[0], - SB_BFE(p[0],0,16), - SB_BFE(p[0],16,16)); - break; - case 0x28: /*VTX_DIFF*/ - nds_gpu_process_vertex(nds,(((int16_t)(SB_BFE(p[0],0,10)<<6))>>6)+nds->gpu.last_vertex_pos[0], - (((int16_t)(SB_BFE(p[0],10,10)<<6))>>6)+nds->gpu.last_vertex_pos[1], - (((int16_t)(SB_BFE(p[0],20,10)<<6))>>6)+nds->gpu.last_vertex_pos[2]); - break; - - case 0x29: /*POLYGON_ATTR*/ nds->gpu.poly_attr=p[0];break; - case 0x30: /*DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)*/ - { - nds->gpu.curr_diffuse_color[0] = SB_BFE(p[0],0,5)<<3; - nds->gpu.curr_diffuse_color[1] = SB_BFE(p[0],5,5)<<3; - nds->gpu.curr_diffuse_color[2] = SB_BFE(p[0],10,5)<<3; - bool set_vertex_color = SB_BFE(p[0],15,1); - if(set_vertex_color)SE_RPT3 nds->gpu.curr_color[r]=nds->gpu.curr_diffuse_color[r]; - nds->gpu.curr_ambient_color[0] = SB_BFE(p[0],16,5)<<3; - nds->gpu.curr_ambient_color[1] = SB_BFE(p[0],21,5)<<3; - nds->gpu.curr_ambient_color[2] = SB_BFE(p[0],26,5)<<3; - }break; - case 0x31: /*SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W)*/ - { - nds->gpu.curr_specular_color[0] = SB_BFE(p[0],0,5)<<3; - nds->gpu.curr_specular_color[1] = SB_BFE(p[0],5,5)<<3; - nds->gpu.curr_specular_color[2] = SB_BFE(p[0],10,5)<<3; - nds->gpu.use_shininess_table = SB_BFE(p[0],15,1); - nds->gpu.curr_emission_color[0] = SB_BFE(p[0],16,5)<<3; - nds->gpu.curr_emission_color[1] = SB_BFE(p[0],21,5)<<3; - nds->gpu.curr_emission_color[2] = SB_BFE(p[0],26,5)<<3; - }break; - case 0x32:{ /*LIGHT_VECTOR - Set Light Color (W)*/ - int16_t lvi[3]; - SE_RPT3 lvi[r]=SB_BFE(p[0],10*r,10)<<6; - float lv[4]={0}; - SE_RPT3 lv[r] = lvi[r]/32768.; - int light = SB_BFE(p[0],30,2); - nds_mult_matrix_vector(nds->gpu.light_vector+light*4,gpu->direction_matrix,lv,4); - } break; - case 0x33:{ /*LIGHT_COLOR - Set Light Color (W)*/ - int light = SB_BFE(p[0],30,2); - nds->gpu.light_color[light*3+0]= SB_BFE(p[0],0,5)<<3u; - nds->gpu.light_color[light*3+1]= SB_BFE(p[0],5,5)<<3u; - nds->gpu.light_color[light*3+2]= SB_BFE(p[0],10,5)<<3u; - } break; - case 0x34:{ - for(int i=0;i<32;++i){ - nds->gpu.shininess_table[i*4+0]=SB_BFE(p[i],0,8); - nds->gpu.shininess_table[i*4+1]=SB_BFE(p[i],8,8); - nds->gpu.shininess_table[i*4+2]=SB_BFE(p[i],16,8); - nds->gpu.shininess_table[i*4+3]=SB_BFE(p[i],24,8); - } + case NDS_MATRIX_PROJ: + for(int i = 0; i < 16; ++i) + gpu->proj_matrix_stack[i] = m[i]; break; } - case 0x2A:nds->gpu.tex_image_param = p[0];break; /*TEXIMAGE_PARAM - Set Texture Parameters*/ - case 0x2B:nds->gpu.tex_plt_base = p[0]; break; /*PLTT_BASE - Set Texture Palette Base Address (W)*/ - - case 0x40: /*BEGIN_VTXS*/ - nds->gpu.prim_type = SB_BFE(p[0],0,2); - nds->gpu.curr_draw_vert =0; + break; + } + case 0x14: { /*MTX_RESTORE*/ + float *m = nds_gpu_get_active_matrix(nds); + int new_stack = SB_BFE(p[0], 0, 5) * 16; + switch(gpu->matrix_mode) { + case NDS_MATRIX_MV: + case NDS_MATRIX_DIR: + for(int i = 0; i < 16; ++i) + m[i] = gpu->mv_matrix_stack[new_stack + i]; + for(int i = 0; i < 16; ++i) + gpu->direction_matrix[i] = gpu->direction_matrix_stack[new_stack + i]; break; - case 0x41: /*END_VTXS */ nds->gpu.curr_draw_vert =0; break; - case 0x50: - gpu->pending_swap=true; - nds->gpu.cmd_busy_cycles+=nds_cycles_till_vblank(nds); - break; //Swap buffers - case 0x60: /*SET_VIEWPORT*/ - { - int x0 = SB_BFE(p[0],0,8); - int y0 = SB_BFE(p[0],8,8); - int x1 = SB_BFE(p[0],16,8); - int y1 = SB_BFE(p[0],24,8); - //printf("Viewport %d %d %d %d\n",x0,y0,x1,y1); + case NDS_MATRIX_TEX: + for(int i = 0; i < 16; ++i) + m[i] = gpu->tex_matrix_stack[i]; + break; + case NDS_MATRIX_PROJ: + for(int i = 0; i < 16; ++i) + m[i] = gpu->proj_matrix_stack[i]; break; } - case 0x70:/*BOX_TEST*/{ - float m[16]; - for(int i=0;i<16;++i)m[i] = nds->gpu.proj_matrix[i]; - nds_mult_matrix4(m, nds->gpu.mv_matrix); - int16_t x_min = SB_BFE(p[0],0,16); - int16_t y_min = SB_BFE(p[0],16,16); - int16_t z_min = SB_BFE(p[1],0,16); - int16_t x_max = x_min+SB_BFE(p[1],16,16); - int16_t y_max = y_min+SB_BFE(p[2],0,16); - int16_t z_max = z_min+SB_BFE(p[2],16,16); - //Extract the view frustum planes from the camera - float planes[6*4]; - for(int p=0;p<3;++p){ - for (int i = 4; i--; ) planes[p*2*4+i] = m[i*4+3] + m[i*4+p]; - for (int i = 4; i--; ) planes[(p*2+1)*4+i] = m[i*4+3] - m[i*4+p]; - } - int box_position = 0; //0 =inside, 1=outside, 2=collides - for(int p=0;p<6;++p){ - float pos_vert[3]={ - (planes[p*4+0]<0? x_min: x_max)*fixed_to_float, - (planes[p*4+1]<0? y_min: y_max)*fixed_to_float, - (planes[p*4+2]<0? z_min: z_max)*fixed_to_float, - }; - float neg_vert[3]={ - (planes[p*4+0]>0? x_min: x_max)*fixed_to_float, - (planes[p*4+1]>0? y_min: y_max)*fixed_to_float, - (planes[p*4+2]>0? z_min: z_max)*fixed_to_float, - }; - if(nds_point_plane_distance(pos_vert,planes+p*4)<0.){box_position=1;break;}//outside - if(nds_point_plane_distance(neg_vert,planes+p*4)<0.)box_position=2;//collides - } - nds->gpu.box_test_result=box_position!=1; - nds->gpu.test_busy -= 3; - }break; - case 0x38: case 0x3c: break; - case 0x71: - nds->gpu.test_busy -= 1; - case 0x72: - nds->gpu.test_busy -= 1; - default: - - printf("Unhandled GPU CMD: %02x Data: ",cmd); - for(int i=0;imatrix_mode == NDS_MATRIX_DIR) nds_identity_matrix(gpu->direction_matrix); + break; + case 0x16: /*MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)*/ + for(int i = 0; i < 16; ++i) + nds_gpu_get_active_matrix(nds)[i] = p[i] * fixed_to_float; + if(gpu->matrix_mode == NDS_MATRIX_DIR) { + for(int i = 0; i < 16; ++i) + gpu->direction_matrix[i] = p[i] * fixed_to_float; + } + break; + case 0x17: { /*MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)*/ + float m2[16] = { + p[0] * fixed_to_float, + p[1] * fixed_to_float, + p[2] * fixed_to_float, + 0, + p[3] * fixed_to_float, + p[4] * fixed_to_float, + p[5] * fixed_to_float, + 0, + p[6] * fixed_to_float, + p[7] * fixed_to_float, + p[8] * fixed_to_float, + 0, + p[9] * fixed_to_float, + p[10] * fixed_to_float, + p[11] * fixed_to_float, + 1., + }; + float *m = nds_gpu_get_active_matrix(nds); + for(int i = 0; i < 16; ++i) + m[i] = m2[i]; + if(gpu->matrix_mode == NDS_MATRIX_DIR) { + for(int i = 0; i < 16; ++i) + gpu->direction_matrix[i] = m2[i]; + } + break; + } + case 0x18: { /*MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)*/ + float m[16] = { + p[0] * fixed_to_float, p[1] * fixed_to_float, p[2] * fixed_to_float, p[3] * fixed_to_float, + p[4] * fixed_to_float, p[5] * fixed_to_float, p[6] * fixed_to_float, p[7] * fixed_to_float, + p[8] * fixed_to_float, p[9] * fixed_to_float, p[10] * fixed_to_float, p[11] * fixed_to_float, + p[12] * fixed_to_float, p[13] * fixed_to_float, p[14] * fixed_to_float, p[15] * fixed_to_float}; + nds_mult_matrix4(nds_gpu_get_active_matrix(nds), m); + if(gpu->matrix_mode == NDS_MATRIX_DIR) { + nds_mult_matrix4(gpu->direction_matrix, m); + gpu->cmd_busy_cycles += 30; + } + break; + } + case 0x19: { /*MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)*/ + float m[16] = { + p[0] * fixed_to_float, + p[1] * fixed_to_float, + p[2] * fixed_to_float, + 0, + p[3] * fixed_to_float, + p[4] * fixed_to_float, + p[5] * fixed_to_float, + 0, + p[6] * fixed_to_float, + p[7] * fixed_to_float, + p[8] * fixed_to_float, + 0, + p[9] * fixed_to_float, + p[10] * fixed_to_float, + p[11] * fixed_to_float, + 1., + }; + nds_mult_matrix4(nds_gpu_get_active_matrix(nds), m); + if(gpu->matrix_mode == NDS_MATRIX_DIR) { + nds_mult_matrix4(gpu->direction_matrix, m); + gpu->cmd_busy_cycles += 30; + } + break; + } + + case 0x1a: { /*MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)*/ + float m[16] = { + p[0] * fixed_to_float, + p[1] * fixed_to_float, + p[2] * fixed_to_float, + 0, + p[3] * fixed_to_float, + p[4] * fixed_to_float, + p[5] * fixed_to_float, + 0, + p[6] * fixed_to_float, + p[7] * fixed_to_float, + p[8] * fixed_to_float, + 0, + 0, + 0, + 0, + 1., + }; + nds_mult_matrix4(nds_gpu_get_active_matrix(nds), m); + if(gpu->matrix_mode == NDS_MATRIX_DIR) { + nds_mult_matrix4(gpu->direction_matrix, m); + gpu->cmd_busy_cycles += 30; + } + break; + } + case 0x1c: /*MTX_TRAN*/ + if(nds->gpu.matrix_mode == NDS_MATRIX_DIR) { + gpu->cmd_busy_cycles += 30; + nds_translate_matrix(gpu->direction_matrix, p[0] * fixed_to_float, + p[1] * fixed_to_float, + p[2] * fixed_to_float); + } + nds_translate_matrix(nds_gpu_get_active_matrix(nds), p[0] * fixed_to_float, + p[1] * fixed_to_float, + p[2] * fixed_to_float); + break; /*MTX_TRAN*/ + + case 0x1b: + if(nds->gpu.matrix_mode == NDS_MATRIX_DIR) gpu->cmd_busy_cycles += 30; + nds_scale_matrix(nds_gpu_get_active_matrix(nds), p[0] * fixed_to_float, + p[1] * fixed_to_float, + p[2] * fixed_to_float); + break; /*MTX_SCALE*/ + case 0x20: /*COLOR - Directly Set Vertex Color (W)*/ + nds->gpu.curr_color[0] = SB_BFE(p[0], 0, 5) << 3; + nds->gpu.curr_color[1] = SB_BFE(p[0], 5, 5) << 3; + nds->gpu.curr_color[2] = SB_BFE(p[0], 10, 5) << 3; + nds->gpu.curr_color[3] = 255; + break; + case 0x21: + nds_vertex_lighting(nds, (int16_t)(SB_BFE(p[0], 0, 10) << 6u), + (int16_t)(SB_BFE(p[0], 10, 10) << 6u), + (int16_t)(SB_BFE(p[0], 20, 10) << 6u)); + break; + case 0x22: /*TEXCOORD*/ + nds->gpu.curr_tex_coord[0] = SB_BFE(p[0], 0, 16); + nds->gpu.curr_tex_coord[1] = SB_BFE(p[0], 16, 16); + break; + case 0x23: /*VTX_16*/ nds_gpu_process_vertex(nds, SB_BFE(p[0], 0, 16), + SB_BFE(p[0], 16, 16), + SB_BFE(p[1], 0, 16)); break; + + case 0x24: /*VTX_10*/ + nds_gpu_process_vertex(nds, ((int16_t)SB_BFE(p[0], 0, 10) << 6), + ((int16_t)SB_BFE(p[0], 10, 10) << 6), + ((int16_t)SB_BFE(p[0], 20, 10) << 6)); + break; + + case 0x25: /*VTX_XY*/ + nds_gpu_process_vertex(nds, SB_BFE(p[0], 0, 16), + SB_BFE(p[0], 16, 16), + nds->gpu.last_vertex_pos[2]); + break; + case 0x26: /*VTX_XZ*/ + nds_gpu_process_vertex(nds, SB_BFE(p[0], 0, 16), + nds->gpu.last_vertex_pos[1], + SB_BFE(p[0], 16, 16)); + break; + case 0x27: /*VTX_YZ*/ + nds_gpu_process_vertex(nds, nds->gpu.last_vertex_pos[0], + SB_BFE(p[0], 0, 16), + SB_BFE(p[0], 16, 16)); + break; + case 0x28: /*VTX_DIFF*/ + nds_gpu_process_vertex(nds, (((int16_t)(SB_BFE(p[0], 0, 10) << 6)) >> 6) + nds->gpu.last_vertex_pos[0], + (((int16_t)(SB_BFE(p[0], 10, 10) << 6)) >> 6) + nds->gpu.last_vertex_pos[1], + (((int16_t)(SB_BFE(p[0], 20, 10) << 6)) >> 6) + nds->gpu.last_vertex_pos[2]); + break; + + case 0x29: /*POLYGON_ATTR*/ nds->gpu.poly_attr = p[0]; break; + case 0x30: /*DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)*/ + { + nds->gpu.curr_diffuse_color[0] = SB_BFE(p[0], 0, 5) << 3; + nds->gpu.curr_diffuse_color[1] = SB_BFE(p[0], 5, 5) << 3; + nds->gpu.curr_diffuse_color[2] = SB_BFE(p[0], 10, 5) << 3; + bool set_vertex_color = SB_BFE(p[0], 15, 1); + if(set_vertex_color) SE_RPT3 nds->gpu.curr_color[r] = nds->gpu.curr_diffuse_color[r]; + nds->gpu.curr_ambient_color[0] = SB_BFE(p[0], 16, 5) << 3; + nds->gpu.curr_ambient_color[1] = SB_BFE(p[0], 21, 5) << 3; + nds->gpu.curr_ambient_color[2] = SB_BFE(p[0], 26, 5) << 3; + } break; + case 0x31: /*SPE_EMI - MaterialColor1 - Specular Ref. & Emission (W)*/ + { + nds->gpu.curr_specular_color[0] = SB_BFE(p[0], 0, 5) << 3; + nds->gpu.curr_specular_color[1] = SB_BFE(p[0], 5, 5) << 3; + nds->gpu.curr_specular_color[2] = SB_BFE(p[0], 10, 5) << 3; + nds->gpu.use_shininess_table = SB_BFE(p[0], 15, 1); + nds->gpu.curr_emission_color[0] = SB_BFE(p[0], 16, 5) << 3; + nds->gpu.curr_emission_color[1] = SB_BFE(p[0], 21, 5) << 3; + nds->gpu.curr_emission_color[2] = SB_BFE(p[0], 26, 5) << 3; + } break; + case 0x32: { /*LIGHT_VECTOR - Set Light Color (W)*/ + int16_t lvi[3]; + SE_RPT3 lvi[r] = SB_BFE(p[0], 10 * r, 10) << 6; + float lv[4] = {0}; + SE_RPT3 lv[r] = lvi[r] / 32768.; + int light = SB_BFE(p[0], 30, 2); + nds_mult_matrix_vector(nds->gpu.light_vector + light * 4, gpu->direction_matrix, lv, 4); + } break; + case 0x33: { /*LIGHT_COLOR - Set Light Color (W)*/ + int light = SB_BFE(p[0], 30, 2); + nds->gpu.light_color[light * 3 + 0] = SB_BFE(p[0], 0, 5) << 3u; + nds->gpu.light_color[light * 3 + 1] = SB_BFE(p[0], 5, 5) << 3u; + nds->gpu.light_color[light * 3 + 2] = SB_BFE(p[0], 10, 5) << 3u; + } break; + case 0x34: { + for(int i = 0; i < 32; ++i) { + nds->gpu.shininess_table[i * 4 + 0] = SB_BFE(p[i], 0, 8); + nds->gpu.shininess_table[i * 4 + 1] = SB_BFE(p[i], 8, 8); + nds->gpu.shininess_table[i * 4 + 2] = SB_BFE(p[i], 16, 8); + nds->gpu.shininess_table[i * 4 + 3] = SB_BFE(p[i], 24, 8); + } + break; + } + case 0x2A: nds->gpu.tex_image_param = p[0]; break; /*TEXIMAGE_PARAM - Set Texture Parameters*/ + case 0x2B: nds->gpu.tex_plt_base = p[0]; break; /*PLTT_BASE - Set Texture Palette Base Address (W)*/ + + case 0x40: /*BEGIN_VTXS*/ + nds->gpu.prim_type = SB_BFE(p[0], 0, 2); + nds->gpu.curr_draw_vert = 0; + break; + case 0x41: /*END_VTXS */ nds->gpu.curr_draw_vert = 0; break; + case 0x50: + gpu->pending_swap = true; + nds->gpu.cmd_busy_cycles += nds_cycles_till_vblank(nds); + break; // Swap buffers + case 0x60: /*SET_VIEWPORT*/ + { + int x0 = SB_BFE(p[0], 0, 8); + int y0 = SB_BFE(p[0], 8, 8); + int x1 = SB_BFE(p[0], 16, 8); + int y1 = SB_BFE(p[0], 24, 8); + // printf("Viewport %d %d %d %d\n",x0,y0,x1,y1); + break; + } + case 0x70: /*BOX_TEST*/ { + float m[16]; + for(int i = 0; i < 16; ++i) + m[i] = nds->gpu.proj_matrix[i]; + nds_mult_matrix4(m, nds->gpu.mv_matrix); + int16_t x_min = SB_BFE(p[0], 0, 16); + int16_t y_min = SB_BFE(p[0], 16, 16); + int16_t z_min = SB_BFE(p[1], 0, 16); + int16_t x_max = x_min + SB_BFE(p[1], 16, 16); + int16_t y_max = y_min + SB_BFE(p[2], 0, 16); + int16_t z_max = z_min + SB_BFE(p[2], 16, 16); + // Extract the view frustum planes from the camera + float planes[6 * 4]; + for(int p = 0; p < 3; ++p) { + for(int i = 4; i--;) + planes[p * 2 * 4 + i] = m[i * 4 + 3] + m[i * 4 + p]; + for(int i = 4; i--;) + planes[(p * 2 + 1) * 4 + i] = m[i * 4 + 3] - m[i * 4 + p]; + } + int box_position = 0; // 0 =inside, 1=outside, 2=collides + for(int p = 0; p < 6; ++p) { + float pos_vert[3] = { + (planes[p * 4 + 0] < 0 ? x_min : x_max) * fixed_to_float, + (planes[p * 4 + 1] < 0 ? y_min : y_max) * fixed_to_float, + (planes[p * 4 + 2] < 0 ? z_min : z_max) * fixed_to_float, + }; + float neg_vert[3] = { + (planes[p * 4 + 0] > 0 ? x_min : x_max) * fixed_to_float, + (planes[p * 4 + 1] > 0 ? y_min : y_max) * fixed_to_float, + (planes[p * 4 + 2] > 0 ? z_min : z_max) * fixed_to_float, + }; + if(nds_point_plane_distance(pos_vert, planes + p * 4) < 0.) { + box_position = 1; + break; + } // outside + if(nds_point_plane_distance(neg_vert, planes + p * 4) < 0.) box_position = 2; // collides + } + nds->gpu.box_test_result = box_position != 1; + nds->gpu.test_busy -= 3; + } break; + case 0x38: + case 0x3c: break; + case 0x71: + nds->gpu.test_busy -= 1; + case 0x72: + nds->gpu.test_busy -= 1; + default: + + printf("Unhandled GPU CMD: %02x Data: ", cmd); + for(int i = 0; i < cmd_params; ++i) + printf("%08x ", p[i]); + printf("\n"); + + break; } } -static void nds_gpu_write_packed_cmd(nds_t *nds, uint32_t data){ - nds_gpu_t* gpu = &nds->gpu; - if(gpu->packed_cmd){ +static void nds_gpu_write_packed_cmd(nds_t *nds, uint32_t data) { + nds_gpu_t *gpu = &nds->gpu; + if(gpu->packed_cmd) { bool param_consumed = false; - while(gpu->packed_cmd){ - uint8_t cmd = gpu->packed_cmd&0xff; - int params = nds_gpu_cmd_params(cmd); - if(params==0){ - nds_gxfifo_push(nds,cmd,data); - gpu->packed_cmd>>=8; - gpu->packed_cmd_param=0; - }else{ - if(param_consumed)break; - nds_gxfifo_push(nds,cmd,data); + while(gpu->packed_cmd) { + uint8_t cmd = gpu->packed_cmd & 0xff; + int params = nds_gpu_cmd_params(cmd); + if(params == 0) { + nds_gxfifo_push(nds, cmd, data); + gpu->packed_cmd >>= 8; + gpu->packed_cmd_param = 0; + } else { + if(param_consumed) break; + nds_gxfifo_push(nds, cmd, data); gpu->packed_cmd_param++; - if(gpu->packed_cmd_param>=params){ - gpu->packed_cmd>>=8;gpu->packed_cmd_param=0; + if(gpu->packed_cmd_param >= params) { + gpu->packed_cmd >>= 8; + gpu->packed_cmd_param = 0; } - param_consumed =true; + param_consumed = true; } } - }else{ - bool unpacked_cmd = SB_BFE(data,8,24)==0; - uint8_t cmd= SB_BFE(data,0,8); + } else { + bool unpacked_cmd = SB_BFE(data, 8, 24) == 0; + uint8_t cmd = SB_BFE(data, 0, 8); gpu->packed_cmd = data; - gpu->packed_cmd_param=0; - if(unpacked_cmd&&nds_gpu_cmd_params(cmd)==0){ + gpu->packed_cmd_param = 0; + if(unpacked_cmd && nds_gpu_cmd_params(cmd) == 0) { nds_gxfifo_push(nds, cmd, data); - gpu->packed_cmd=0; + gpu->packed_cmd = 0; } } } -static void nds_tick_ipc_fifo(nds_t* nds){ - for(int cpu=0;cpu<2;++cpu){ - int send_size = (nds->ipc[!cpu].write_ptr-nds->ipc[!cpu].read_ptr)&0x1f; - int recv_size = (nds->ipc[ cpu].write_ptr-nds->ipc[ cpu].read_ptr)&0x1f; - - bool send_fifo_empty = send_size ==0; - bool send_fifo_full = send_size ==16; - bool recv_fifo_empty = recv_size ==0; - bool recv_fifo_full = recv_size ==16; - - if(send_size==1){ - uint16_t cnt = nds_io_read16(nds,cpu,NDS_IPCFIFOCNT); - bool fifo_empty_irq = SB_BFE(cnt,2,1); - if(fifo_empty_irq){ - if(cpu==NDS_ARM9)nds9_send_interrupt(nds,4,1<ipc[!cpu].write_ptr - nds->ipc[!cpu].read_ptr) & 0x1f; + int recv_size = (nds->ipc[cpu].write_ptr - nds->ipc[cpu].read_ptr) & 0x1f; + + bool send_fifo_empty = send_size == 0; + bool send_fifo_full = send_size == 16; + bool recv_fifo_empty = recv_size == 0; + bool recv_fifo_full = recv_size == 16; + + if(send_size == 1) { + uint16_t cnt = nds_io_read16(nds, cpu, NDS_IPCFIFOCNT); + bool fifo_empty_irq = SB_BFE(cnt, 2, 1); + if(fifo_empty_irq) { + if(cpu == NDS_ARM9) + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); + else + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); } } - if(recv_size!=0){ - uint16_t cnt = nds_io_read16(nds,cpu,NDS_IPCFIFOCNT); - bool fifo_not_empty_irq = SB_BFE(cnt,10,1); - if(fifo_not_empty_irq){ - if(cpu==NDS_ARM9)nds9_send_interrupt(nds,4,1<= GBA_TM0CNT_L&&addr<=GBA_TM3CNT_H)nds_compute_timers(nds); - int cpu = (transaction_type&NDS_MEM_ARM9)? NDS_ARM9: NDS_ARM7; +static bool nds_preprocess_mmio(nds_t *nds, uint32_t addr, uint32_t data, int transaction_type) { + uint32_t word_mask = nds_word_mask(addr, transaction_type); + uint32_t baddr = addr; + addr &= ~3; + if(addr >= GBA_TM0CNT_L && addr <= GBA_TM3CNT_H) nds_compute_timers(nds); + int cpu = (transaction_type & NDS_MEM_ARM9) ? NDS_ARM9 : NDS_ARM7; /*if(addr!=0x04000208&&addr!=0x04000301&&addr!=0x04000138 &&addr!= 0x040001c0 && addr!=0x040001c2)printf("MMIO Read: %08x\n",addr);*/ - //if(addr>=0x4000620&&addr<0x04000800&&!(transaction_type&NDS_MEM_DEBUG))printf("MMIO Read: %08x\n",addr); + // if(addr>=0x4000620&&addr<0x04000800&&!(transaction_type&NDS_MEM_DEBUG))printf("MMIO Read: %08x\n",addr); - //Reading ClipMTX - if(addr>=NDS9_CLIPMTX_RESULT&&addr<=NDS9_CLIPMTX_RESULT+0x40&&cpu==NDS_ARM9){ + // Reading ClipMTX + if(addr >= NDS9_CLIPMTX_RESULT && addr <= NDS9_CLIPMTX_RESULT + 0x40 && cpu == NDS_ARM9) { float clipmtx[16]; - for(int i=0;i<16;++i)clipmtx[i] = nds->gpu.mv_matrix[i]; + for(int i = 0; i < 16; ++i) + clipmtx[i] = nds->gpu.mv_matrix[i]; nds_mult_matrix4(clipmtx, nds->gpu.proj_matrix); - for(int i=0;i<16;++i){ - float val = clipmtx[i]; - int32_t fixed_val = val*(1<<12); - nds9_io_store32(nds,NDS9_CLIPMTX_RESULT+i*4,fixed_val); + for(int i = 0; i < 16; ++i) { + float val = clipmtx[i]; + int32_t fixed_val = val * (1 << 12); + nds9_io_store32(nds, NDS9_CLIPMTX_RESULT + i * 4, fixed_val); } } - switch(addr){ - case NDS9_IF: /*case NDS7_IF: <- duplicate address*/ - if(transaction_type&NDS_MEM_WRITE){ - uint32_t mmio = nds_io_read32(nds,cpu,NDS9_IF); - data = nds_align_data(baddr,data,transaction_type); - mmio&=~data; - nds_io_store32(nds,cpu,addr,mmio); - nds_tick_ipc_fifo(nds); - return false; + switch(addr) { + case NDS9_IF: /*case NDS7_IF: <- duplicate address*/ + if(transaction_type & NDS_MEM_WRITE) { + uint32_t mmio = nds_io_read32(nds, cpu, NDS9_IF); + data = nds_align_data(baddr, data, transaction_type); + mmio &= ~data; + nds_io_store32(nds, cpu, addr, mmio); + nds_tick_ipc_fifo(nds); + return false; + } + break; + case NDS7_VRAMSTAT: { + if(cpu == NDS_ARM9) return true; + uint8_t vramcntc = nds9_io_read8(nds, NDS9_VRAMCNT_C); + uint8_t vramcntd = nds9_io_read8(nds, NDS9_VRAMCNT_D); + bool en_c = SB_BFE(vramcntc, 7, 1); + bool en_d = SB_BFE(vramcntd, 7, 1); + int mst_c = SB_BFE(vramcntc, 0, 3); + int mst_d = SB_BFE(vramcntd, 0, 3); + bool mapped_c = en_c && mst_c == 2; + bool mapped_d = en_d && mst_d == 2; + uint8_t vramstat = mapped_c | (mapped_d << 1); + nds7_io_store8(nds, NDS7_VRAMSTAT, vramstat); + + } break; + case NDS7_WRAMSTAT: { + if(cpu == NDS_ARM7) return true; + uint8_t wramcnt = nds9_io_read8(nds, NDS9_WRAMCNT); + nds7_io_store8(nds, NDS7_WRAMSTAT, wramcnt); + } break; + case NDS_IPCSYNC: { + uint32_t sync = nds_io_read16(nds, cpu, NDS_IPCSYNC); + sync &= 0x4f00; + sync |= nds->ipc[cpu].sync_data; + nds_io_store16(nds, cpu, NDS_IPCSYNC, sync); + } break; + + case NDS_IPCFIFOCNT: { + uint32_t cnt = nds_io_read16(nds, cpu, NDS_IPCFIFOCNT); + int send_size = (nds->ipc[!cpu].write_ptr - nds->ipc[!cpu].read_ptr) & 0x1f; + int recv_size = (nds->ipc[cpu].write_ptr - nds->ipc[cpu].read_ptr) & 0x1f; + + bool send_fifo_empty = send_size == 0; + bool send_fifo_full = send_size == 16; + bool recv_fifo_empty = recv_size == 0; + bool recv_fifo_full = recv_size == 16; + cnt &= 0xbc0c; + cnt |= (send_fifo_empty << 0) | (send_fifo_full << 1) | (recv_fifo_empty << 8) | (recv_fifo_full << 9); + cnt |= (nds->ipc[cpu].error << 14); + nds_io_store16(nds, cpu, NDS_IPCFIFOCNT, cnt); + if(send_size == 1) { + bool fifo_empty_irq = SB_BFE(cnt, 2, 1); + if(fifo_empty_irq) { + if(cpu == NDS_ARM9) + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); + else + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); } - break; - case NDS7_VRAMSTAT:{ - if(cpu==NDS_ARM9)return true; - uint8_t vramcntc = nds9_io_read8(nds,NDS9_VRAMCNT_C); - uint8_t vramcntd = nds9_io_read8(nds,NDS9_VRAMCNT_D); - bool en_c = SB_BFE(vramcntc,7,1); - bool en_d = SB_BFE(vramcntd,7,1); - int mst_c = SB_BFE(vramcntc,0,3); - int mst_d = SB_BFE(vramcntd,0,3); - bool mapped_c = en_c&& mst_c==2; - bool mapped_d = en_d&& mst_d==2; - uint8_t vramstat = mapped_c|(mapped_d<<1); - nds7_io_store8(nds,NDS7_VRAMSTAT,vramstat); - - }break; - case NDS7_WRAMSTAT:{ - if(cpu==NDS_ARM7)return true; - uint8_t wramcnt = nds9_io_read8(nds,NDS9_WRAMCNT); - nds7_io_store8(nds,NDS7_WRAMSTAT,wramcnt); - }break; - case NDS_IPCSYNC:{ - uint32_t sync =nds_io_read16(nds,cpu,NDS_IPCSYNC); - sync&=0x4f00; - sync|=nds->ipc[cpu].sync_data; - nds_io_store16(nds,cpu,NDS_IPCSYNC,sync); - }break; - - case NDS_IPCFIFOCNT:{ - uint32_t cnt =nds_io_read16(nds,cpu,NDS_IPCFIFOCNT); - int send_size = (nds->ipc[!cpu].write_ptr-nds->ipc[!cpu].read_ptr)&0x1f; - int recv_size = (nds->ipc[ cpu].write_ptr-nds->ipc[ cpu].read_ptr)&0x1f; - - bool send_fifo_empty = send_size ==0; - bool send_fifo_full = send_size ==16; - bool recv_fifo_empty = recv_size ==0; - bool recv_fifo_full = recv_size ==16; - cnt &=0xbc0c; - cnt |= (send_fifo_empty<<0)|(send_fifo_full<<1)|(recv_fifo_empty<<8)|(recv_fifo_full<<9); - cnt |= (nds->ipc[cpu].error<<14); - nds_io_store16(nds,cpu,NDS_IPCFIFOCNT,cnt); - if(send_size==1){ - bool fifo_empty_irq = SB_BFE(cnt,2,1); - if(fifo_empty_irq){ - if(cpu==NDS_ARM9)nds9_send_interrupt(nds,4,1<gpu.curr_vert); + nds9_io_store16(nds, NDS9_RAM_COUNT, nds->gpu.poly_ram_offset); + break; + case NDS9_POWCNT1: + if(cpu != NDS_ARM9) return true; + uint32_t d = nds9_io_read32(nds, NDS9_POWCNT1); + d |= 1; + nds9_io_store32(nds, NDS9_POWCNT1, d); + break; + case NDS_IPCFIFORECV | NDS_IO_MAP_041_OFFSET: { + uint32_t cnt = nds_io_read16(nds, cpu, NDS9_IPCFIFOCNT); + bool enabled = SB_BFE(cnt, 15, 1); + if(!enabled) return true; + + int size = (nds->ipc[cpu].write_ptr - nds->ipc[cpu].read_ptr) & 0x1f; + // Read empty error + if(size == 0) { + nds->ipc[cpu].error = true; + return true; + } + uint32_t data = nds->ipc[cpu].fifo[(nds->ipc[cpu].read_ptr++) & 0xf]; + nds_io_store32(nds, cpu, NDS_IPCFIFORECV, data); + if(size == 1) { + int other_cnt = nds_io_read16(nds, !cpu, NDS9_IPCFIFOCNT); + bool fifo_empty_irq = SB_BFE(other_cnt, 2, 1); + if(fifo_empty_irq) { + if(cpu == NDS_ARM7) + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); + else + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); } - }break; - case NDS9_RDLINES_COUNT:{ - if(cpu!=NDS_ARM9)return true; - nds9_io_store32(nds,NDS9_RDLINES_COUNT,46); + } + } break; + case NDS7_EXMEMSTAT: { + uint16_t r9 = nds9_io_read16(nds, NDS9_EXMEMCNT); + r9 |= (1 << 13); // Bit 13 is always set + nds9_io_store16(nds, NDS9_EXMEMCNT, r9); + + if(cpu != NDS_ARM7) return true; + uint16_t r7 = nds7_io_read16(nds, NDS7_EXMEMSTAT); + r7 &= 0x7f; + r7 |= r9 & 0xff80; + nds7_io_store16(nds, NDS7_EXMEMSTAT, r7); + } break; + case NDS_GC_BUS: nds_process_gc_bus_read(nds, cpu); break; + case NDS9_DIVCNT: + case NDS9_DIV_RESULT: + case NDS9_DIVREM_RESULT: + case NDS9_DIV_RESULT + 4: + case NDS9_DIVREM_RESULT + 4: { + if(cpu != NDS_ARM9) return true; + uint32_t cnt = nds9_io_read32(nds, NDS9_DIVCNT); + int mode = SB_BFE(cnt, 0, 2); + int64_t numer = nds9_io_read32(nds, NDS9_DIV_NUMER + 4); + numer <<= 32ll; + numer |= nds9_io_read32(nds, NDS9_DIV_NUMER); + bool busy = true; + + int64_t denom = nds9_io_read32(nds, NDS9_DIV_DENOM + 4); + denom <<= 32ll; + denom |= nds9_io_read32(nds, NDS9_DIV_DENOM); + bool div_zero = denom == 0; + int64_t result = 0; + int64_t mod_result = 0; + switch(mode) { + case 0: { + busy = nds->current_clock - nds->math.div_last_update_clock <= 18; + numer = (int32_t)numer; + denom = (int32_t)denom; break; } - case NDS9_RAM_COUNT: - if(cpu!=NDS_ARM9||(transaction_type&NDS_MEM_DEBUG))return true; - nds9_io_store16(nds,NDS9_RAM_COUNT+2,nds->gpu.curr_vert); - nds9_io_store16(nds,NDS9_RAM_COUNT,nds->gpu.poly_ram_offset); + case 1: + case 3: { + busy = nds->current_clock - nds->math.div_last_update_clock <= 34; + numer = (int64_t)numer; + denom = (int32_t)denom; break; - case NDS9_POWCNT1: - if(cpu!=NDS_ARM9)return true; - uint32_t d = nds9_io_read32(nds,NDS9_POWCNT1); - d|=1; - nds9_io_store32(nds,NDS9_POWCNT1,d); + } + case 2: { + busy = nds->current_clock - nds->math.div_last_update_clock <= 34; + numer = (int64_t)numer; + denom = (int64_t)denom; break; - case NDS_IPCFIFORECV|NDS_IO_MAP_041_OFFSET:{ - uint32_t cnt =nds_io_read16(nds,cpu,NDS9_IPCFIFOCNT); - bool enabled = SB_BFE(cnt,15,1); - if(!enabled)return true; - - int size = (nds->ipc[cpu].write_ptr-nds->ipc[cpu].read_ptr)&0x1f; - // Read empty error - if(size==0){ - nds->ipc[cpu].error=true; - return true; - } - uint32_t data = nds->ipc[cpu].fifo[(nds->ipc[cpu].read_ptr++)&0xf]; - nds_io_store32(nds,cpu,NDS_IPCFIFORECV,data); - if(size==1){ - int other_cnt = nds_io_read16(nds,!cpu,NDS9_IPCFIFOCNT); - bool fifo_empty_irq = SB_BFE(other_cnt,2,1); - if(fifo_empty_irq){ - if(cpu==NDS_ARM7)nds9_send_interrupt(nds,4,1<current_clock-nds->math.div_last_update_clock <= 18; - numer = (int32_t)numer; - denom = (int32_t)denom; - break; - } - case 1: case 3:{ - busy = nds->current_clock-nds->math.div_last_update_clock <= 34; - numer = (int64_t)numer; - denom = (int32_t)denom; - break; - } - case 2: { - busy = nds->current_clock-nds->math.div_last_update_clock <= 34; - numer = (int64_t)numer; - denom = (int64_t)denom; - break; - } - } - if(denom==0){ - mod_result = numer; - result = numer>-1?-1:1; - if(mode==0)result^=0xffffffff00000000ull; - }else{ - result = (numer)/(denom); - mod_result = (numer)%(denom); - } - cnt&=3; - cnt|= (busy<<15)|(div_zero<<14); - nds9_io_store32(nds,NDS9_DIVCNT,cnt); - if(!busy){ - nds9_io_store32(nds,NDS9_DIV_RESULT,SB_BFE(result,0,32)); - nds9_io_store32(nds,NDS9_DIV_RESULT+4,SB_BFE(result,32,32)); - nds9_io_store32(nds,NDS9_DIVREM_RESULT,SB_BFE(mod_result,0,32)); - nds9_io_store32(nds,NDS9_DIVREM_RESULT+4,SB_BFE(mod_result,32,32)); - } - }break; - case NDS9_SQRTCNT:case NDS9_SQRT_RESULT:case NDS9_SQRT_RESULT+4:{ - if(cpu!=NDS_ARM9)return true; - uint32_t cnt = nds9_io_read32(nds,NDS9_SQRTCNT); - int mode = SB_BFE(cnt,0,1); - int64_t numer = nds9_io_read32(nds,NDS9_SQRT_PARAM+4); - numer<<=32ll; - numer|= nds9_io_read32(nds,NDS9_SQRT_PARAM); - bool busy= nds->current_clock-nds->math.sqrt_last_update_clock<=13; - uint64_t result = 0; - switch(mode){ - case 0:result = nds_sqrt_u64((uint32_t)numer);break; - case 1:result = nds_sqrt_u64(numer);break; - } - cnt&=1; - cnt|= (busy<<15); - nds9_io_store32(nds,NDS9_SQRTCNT,cnt); - if(!busy){ - nds9_io_store32(nds,NDS9_SQRT_RESULT,SB_BFE(result,0,32)); - } - }break; - break; + } + } + if(denom == 0) { + mod_result = numer; + result = numer > -1 ? -1 : 1; + if(mode == 0) result ^= 0xffffffff00000000ull; + } else { + result = (numer) / (denom); + mod_result = (numer) % (denom); + } + cnt &= 3; + cnt |= (busy << 15) | (div_zero << 14); + nds9_io_store32(nds, NDS9_DIVCNT, cnt); + if(!busy) { + nds9_io_store32(nds, NDS9_DIV_RESULT, SB_BFE(result, 0, 32)); + nds9_io_store32(nds, NDS9_DIV_RESULT + 4, SB_BFE(result, 32, 32)); + nds9_io_store32(nds, NDS9_DIVREM_RESULT, SB_BFE(mod_result, 0, 32)); + nds9_io_store32(nds, NDS9_DIVREM_RESULT + 4, SB_BFE(mod_result, 32, 32)); + } + } break; + case NDS9_SQRTCNT: + case NDS9_SQRT_RESULT: + case NDS9_SQRT_RESULT + 4: { + if(cpu != NDS_ARM9) return true; + uint32_t cnt = nds9_io_read32(nds, NDS9_SQRTCNT); + int mode = SB_BFE(cnt, 0, 1); + int64_t numer = nds9_io_read32(nds, NDS9_SQRT_PARAM + 4); + numer <<= 32ll; + numer |= nds9_io_read32(nds, NDS9_SQRT_PARAM); + bool busy = nds->current_clock - nds->math.sqrt_last_update_clock <= 13; + uint64_t result = 0; + switch(mode) { + case 0: result = nds_sqrt_u64((uint32_t)numer); break; + case 1: result = nds_sqrt_u64(numer); break; + } + cnt &= 1; + cnt |= (busy << 15); + nds9_io_store32(nds, NDS9_SQRTCNT, cnt); + if(!busy) { + nds9_io_store32(nds, NDS9_SQRT_RESULT, SB_BFE(result, 0, 32)); + } + } break; + break; } - return true; + return true; } -static void nds_postprocess_mmio_write(nds_t * nds, uint32_t baddr, uint32_t data,int transaction_type){ - uint32_t addr=baddr&~3; - uint32_t mmio= (transaction_type&NDS_MEM_ARM9)? nds9_io_read32(nds,addr): nds7_io_read32(nds,addr); - int cpu = (transaction_type&NDS_MEM_ARM9)? NDS_ARM9: NDS_ARM7; - - if(addr>=GBA_DMA0SAD&&addr<=GBA_DMA3CNT_H)nds->activate_dmas=true; - if(addr>=0x4000440&& addr<0x40005CC &&cpu==NDS_ARM9){ - nds_gxfifo_push(nds, (addr-0x4000400)/4, nds_align_data(baddr,data,transaction_type)); - } - if(addr>=0x4000400&& addr<0x4000440 &&cpu==NDS_ARM9){ - nds_gpu_write_packed_cmd(nds,mmio); - } - if(addr>=NDS9_VRAMCNT_A&&addr<=NDS9_VRAMCNT_I)nds_update_vram_mapping(nds); - switch(addr){ - - case NDS7_HALTCNT&~3: - { - if(cpu!=NDS_ARM7)return; - bool halt = SB_BFE(mmio,(NDS7_HALTCNT&3)*8+6,2)>=2; - if(halt) nds->arm7.wait_for_interrupt=true; - } - break; - case NDS_IPCSYNC:{ - int data_out = SB_BFE(mmio,8,4); - bool send_irq = SB_BFE(mmio,13,1); - nds->ipc[!cpu].sync_data = data_out; - uint32_t sync =nds_io_read16(nds,!cpu,NDS_IPCSYNC); - bool recv_interrupt = SB_BFE(sync,14,1); - if(send_irq && recv_interrupt){ - if(cpu==NDS_ARM7)nds9_send_interrupt(nds,4,1<spi.last_device!=device){ - nds_deselect_spi(nds); - } - spicnt&= ~((busy<<7)); - nds7_io_store16(nds,NDS7_SPI_BUS_CTL,spicnt); - nds->spi.last_device = device; +static void nds_postprocess_mmio_write(nds_t *nds, uint32_t baddr, uint32_t data, int transaction_type) { + uint32_t addr = baddr & ~3; + uint32_t mmio = (transaction_type & NDS_MEM_ARM9) ? nds9_io_read32(nds, addr) : nds7_io_read32(nds, addr); + int cpu = (transaction_type & NDS_MEM_ARM9) ? NDS_ARM9 : NDS_ARM7; + if(addr >= GBA_DMA0SAD && addr <= GBA_DMA3CNT_H) nds->activate_dmas = true; + if(addr >= 0x4000440 && addr < 0x40005CC && cpu == NDS_ARM9) { + nds_gxfifo_push(nds, (addr - 0x4000400) / 4, nds_align_data(baddr, data, transaction_type)); + } + if(addr >= 0x4000400 && addr < 0x4000440 && cpu == NDS_ARM9) { + nds_gpu_write_packed_cmd(nds, mmio); + } + if(addr >= NDS9_VRAMCNT_A && addr <= NDS9_VRAMCNT_I) nds_update_vram_mapping(nds); + switch(addr) { + + case NDS7_HALTCNT & ~3: { + if(cpu != NDS_ARM7) return; + bool halt = SB_BFE(mmio, (NDS7_HALTCNT & 3) * 8 + 6, 2) >= 2; + if(halt) nds->arm7.wait_for_interrupt = true; + } break; + case NDS_IPCSYNC: { + int data_out = SB_BFE(mmio, 8, 4); + bool send_irq = SB_BFE(mmio, 13, 1); + nds->ipc[!cpu].sync_data = data_out; + uint32_t sync = nds_io_read16(nds, !cpu, NDS_IPCSYNC); + bool recv_interrupt = SB_BFE(sync, 14, 1); + if(send_irq && recv_interrupt) { + if(cpu == NDS_ARM7) + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_SYNC); + else + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_SYNC); + } + mmio &= 0x4f0f; + nds_io_store32(nds, cpu, addr, mmio); + } break; + case NDS7_SPI_BUS_CTL: { + if(cpu != NDS_ARM7) return; + uint16_t spicnt = nds7_io_read16(nds, NDS7_SPI_BUS_CTL); + if(nds_word_mask(baddr, transaction_type) & 0xffff) { + // printf("NDS SPI BUS CTRL:%04x\n",spicnt); + int busy = false; + uint8_t device = SB_BFE(spicnt, 8, 2); + bool enable = SB_BFE(spicnt, 15, 1); + if(!enable || nds->spi.last_device != device) { + nds_deselect_spi(nds); } - //printf("NDS SPI BUS CTRL\n"); - if(nds_word_mask(baddr,transaction_type)&0xff0000){ - int device = SB_BFE(spicnt,8,2); - bool keep_selected =SB_BFE(spicnt,11,1); - bool irq_en = SB_BFE(spicnt,14,1); - bool enable = SB_BFE(spicnt,15,1); - if(!enable)return; - uint8_t data = 0xff; - uint8_t cmd = nds7_io_read8(nds,NDS7_SPI_BUS_DATA); - // printf("NDS SPI BUS DATA: %d %02x %04x\n",device,cmd,spicnt); - switch(device){ - case NDS_SPI_POWER: /*TODO*/break; - case NDS_SPI_TOUCH: data = nds_process_touch_ctrl_write(nds,cmd); break; - case NDS_SPI_FIRMWARE: data = nds_process_flash_write(nds,cmd,&nds->firmware,nds->mem.firmware, NDS_FIRMWARE_SIZE); break; - default: break; - } - nds7_io_store8(nds,NDS7_SPI_BUS_DATA,data); - if(!keep_selected)nds_deselect_spi(nds); - if(irq_en)nds7_send_interrupt(nds,4,1<ipc[!cpu].write_ptr-nds->ipc[!cpu].read_ptr)&0x1f; - // Send full error - if(size>=16){ - nds->ipc[cpu].error=true; - return; - } - nds->ipc[!cpu].fifo[(nds->ipc[!cpu].write_ptr++)&0xf] = mmio; - int other_cnt = cpu==NDS_ARM7? nds9_io_read16(nds,NDS_IPCFIFOCNT):nds7_io_read16(nds,NDS_IPCFIFOCNT); - bool fifo_not_empty_irq = SB_BFE(other_cnt,10,1); - if(fifo_not_empty_irq){ - if(cpu==NDS_ARM7)nds9_send_interrupt(nds,4,1<ipc[!cpu].write_ptr=nds->ipc[!cpu].read_ptr=0; - nds->ipc[cpu].error=false; - cnt&=~(1<<3); - } - bool error = SB_BFE(cnt,14,1); - //Storing a 1 in the error bit clears it(rockwrestler) - if(error)nds->ipc[cpu].error=false; - int size = (nds->ipc[cpu].write_ptr-nds->ipc[cpu].read_ptr)&0x1f; - int other_size = (nds->ipc[!cpu].write_ptr-nds->ipc[!cpu].read_ptr)&0x1f; - - bool recv_fifo_not_empty_irq = SB_BFE(cnt,10,1); - if(recv_fifo_not_empty_irq&&size){ - if(cpu==NDS_ARM7)nds7_send_interrupt(nds,4,1<spi.last_device = device; + } + // printf("NDS SPI BUS CTRL\n"); + if(nds_word_mask(baddr, transaction_type) & 0xff0000) { + int device = SB_BFE(spicnt, 8, 2); + bool keep_selected = SB_BFE(spicnt, 11, 1); + bool irq_en = SB_BFE(spicnt, 14, 1); + bool enable = SB_BFE(spicnt, 15, 1); + if(!enable) return; + uint8_t data = 0xff; + uint8_t cmd = nds7_io_read8(nds, NDS7_SPI_BUS_DATA); + // printf("NDS SPI BUS DATA: %d %02x %04x\n",device,cmd,spicnt); + switch(device) { + case NDS_SPI_POWER: /*TODO*/ break; + case NDS_SPI_TOUCH: data = nds_process_touch_ctrl_write(nds, cmd); break; + case NDS_SPI_FIRMWARE: data = nds_process_flash_write(nds, cmd, &nds->firmware, nds->mem.firmware, NDS_FIRMWARE_SIZE); break; + default: break; } + nds7_io_store8(nds, NDS7_SPI_BUS_DATA, data); + if(!keep_selected) nds_deselect_spi(nds); + if(irq_en) nds7_send_interrupt(nds, 4, 1 << NDS7_INT_SPI); + } + } break; + case NDS7_RTC_BUS: + if(cpu != NDS_ARM7) return; + nds_process_rtc_state_machine(nds); + break; + case NDS_IPCFIFOSEND: { + uint32_t cnt = nds_io_read16(nds, cpu, NDS9_IPCFIFOCNT); + bool enabled = SB_BFE(cnt, 15, 1); + if(!enabled) return; + + int size = (nds->ipc[!cpu].write_ptr - nds->ipc[!cpu].read_ptr) & 0x1f; + // Send full error + if(size >= 16) { + nds->ipc[cpu].error = true; + return; + } + nds->ipc[!cpu].fifo[(nds->ipc[!cpu].write_ptr++) & 0xf] = mmio; + int other_cnt = cpu == NDS_ARM7 ? nds9_io_read16(nds, NDS_IPCFIFOCNT) : nds7_io_read16(nds, NDS_IPCFIFOCNT); + bool fifo_not_empty_irq = SB_BFE(other_cnt, 10, 1); + if(fifo_not_empty_irq) { + if(cpu == NDS_ARM7) + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_RECV); + else + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_RECV); + } + } break; + case NDS_IPCFIFOCNT: { + uint32_t cnt = nds_io_read16(nds, cpu, NDS_IPCFIFOCNT); + bool clear = SB_BFE(cnt, 3, 1); + if(clear) { + nds->ipc[!cpu].write_ptr = nds->ipc[!cpu].read_ptr = 0; + nds->ipc[cpu].error = false; + cnt &= ~(1 << 3); + } + bool error = SB_BFE(cnt, 14, 1); + // Storing a 1 in the error bit clears it(rockwrestler) + if(error) nds->ipc[cpu].error = false; + int size = (nds->ipc[cpu].write_ptr - nds->ipc[cpu].read_ptr) & 0x1f; + int other_size = (nds->ipc[!cpu].write_ptr - nds->ipc[!cpu].read_ptr) & 0x1f; + + bool recv_fifo_not_empty_irq = SB_BFE(cnt, 10, 1); + if(recv_fifo_not_empty_irq && size) { + if(cpu == NDS_ARM7) + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_RECV); + else + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_RECV); + } + bool send_fifo_empty_irq = SB_BFE(cnt, 2, 1); + if(send_fifo_empty_irq && other_size == 0) { + if(cpu == NDS_ARM7) + nds7_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); + else + nds9_send_interrupt(nds, 4, 1 << NDS_INT_IPC_FIFO_SEND); + } - nds_io_store16(nds,cpu,NDS_IPCFIFOCNT,cnt); - }break; - case NDS9_VRAMCNT_E:{ - if(cpu==NDS_ARM9){ - nds7_io_store8(nds,NDS7_WRAMSTAT,nds9_io_read8(nds,NDS9_WRAMCNT)); - } - }break; - case NDS9_DIVCNT:case NDS9_DIV_DENOM:case NDS9_DIV_DENOM+4:case NDS9_DIV_NUMER:case NDS9_DIV_NUMER+4: - if(cpu==NDS_ARM7)break; - nds->math.div_last_update_clock= nds->current_clock; - break; + nds_io_store16(nds, cpu, NDS_IPCFIFOCNT, cnt); + } break; + case NDS9_VRAMCNT_E: { + if(cpu == NDS_ARM9) { + nds7_io_store8(nds, NDS7_WRAMSTAT, nds9_io_read8(nds, NDS9_WRAMCNT)); + } + } break; + case NDS9_DIVCNT: + case NDS9_DIV_DENOM: + case NDS9_DIV_DENOM + 4: + case NDS9_DIV_NUMER: + case NDS9_DIV_NUMER + 4: + if(cpu == NDS_ARM7) break; + nds->math.div_last_update_clock = nds->current_clock; + break; - case NDS9_SQRTCNT:case NDS9_SQRT_PARAM:case NDS9_SQRT_PARAM+4: - if(cpu==NDS_ARM7)break; - nds->math.sqrt_last_update_clock= nds->current_clock; - break; - case NDS9_AUXSPICNT: - if(nds_word_mask(baddr,transaction_type)&0xff0000)nds_process_gc_spi(nds,cpu); break; - case NDS_GCBUS_CTL|NDS_IO_MAP_SPLIT_OFFSET: - case NDS_GCBUS_CTL: - nds->activate_dmas=true; - nds_process_gc_bus_ctl(nds,cpu); break; - case GBA_TM0CNT_L: - case GBA_TM1CNT_L: - case GBA_TM2CNT_L: - case GBA_TM3CNT_L: - if(nds_word_mask(baddr,transaction_type)&0xffff){ - int t = (addr-GBA_TM0CNT_L)/4; - nds->timers[cpu][t].pending_reload_value = nds_io_read16(nds,cpu,GBA_TM0CNT_L+t*4); - } - break; - case NDS9_GXSTAT: - if(cpu==NDS_ARM7)return; - data = nds_align_data(baddr,data,transaction_type); - bool reset_error = SB_BFE(data,15,1); - if(reset_error){ - nds->gpu.matrix_stack_error=false; - nds->gpu.mv_matrix_stack_ptr=0; - nds->gpu.tex_matrix_stack_ptr=0; - nds->gpu.proj_matrix_stack_ptr=0; - //Don't reinitizliae matrices as this breaks PMD explorers of Sky - } - break; - case NDS_DISP3DCNT: - if(cpu==NDS_ARM7)return; - data = nds_align_data(baddr,data,transaction_type); - //12 Color Buffer RDLINES Underflow (0=None, 1=Underflow/Acknowledge) - //13 Polygon/Vertex RAM Overflow (0=None, 1=Overflow/Acknowledge) - uint32_t error_ack_mask = (1<<12)|(1<<13); - uint32_t value = nds9_io_read32(nds,NDS_DISP3DCNT); - value&= ~(data&error_ack_mask); - nds9_io_store32(nds,NDS_DISP3DCNT,value); - break; + case NDS9_SQRTCNT: + case NDS9_SQRT_PARAM: + case NDS9_SQRT_PARAM + 4: + if(cpu == NDS_ARM7) break; + nds->math.sqrt_last_update_clock = nds->current_clock; + break; + case NDS9_AUXSPICNT: + if(nds_word_mask(baddr, transaction_type) & 0xff0000) nds_process_gc_spi(nds, cpu); + break; + case NDS_GCBUS_CTL | NDS_IO_MAP_SPLIT_OFFSET: + case NDS_GCBUS_CTL: + nds->activate_dmas = true; + nds_process_gc_bus_ctl(nds, cpu); + break; + case GBA_TM0CNT_L: + case GBA_TM1CNT_L: + case GBA_TM2CNT_L: + case GBA_TM3CNT_L: + if(nds_word_mask(baddr, transaction_type) & 0xffff) { + int t = (addr - GBA_TM0CNT_L) / 4; + nds->timers[cpu][t].pending_reload_value = nds_io_read16(nds, cpu, GBA_TM0CNT_L + t * 4); + } + break; + case NDS9_GXSTAT: + if(cpu == NDS_ARM7) return; + data = nds_align_data(baddr, data, transaction_type); + bool reset_error = SB_BFE(data, 15, 1); + if(reset_error) { + nds->gpu.matrix_stack_error = false; + nds->gpu.mv_matrix_stack_ptr = 0; + nds->gpu.tex_matrix_stack_ptr = 0; + nds->gpu.proj_matrix_stack_ptr = 0; + // Don't reinitizliae matrices as this breaks PMD explorers of Sky + } + break; + case NDS_DISP3DCNT: + if(cpu == NDS_ARM7) return; + data = nds_align_data(baddr, data, transaction_type); + // 12 Color Buffer RDLINES Underflow (0=None, 1=Underflow/Acknowledge) + // 13 Polygon/Vertex RAM Overflow (0=None, 1=Overflow/Acknowledge) + uint32_t error_ack_mask = (1 << 12) | (1 << 13); + uint32_t value = nds9_io_read32(nds, NDS_DISP3DCNT); + value &= ~(data & error_ack_mask); + nds9_io_store32(nds, NDS_DISP3DCNT, value); + break; } } #define NDS_CLOCKS_PER_DOT 6 -static FORCE_INLINE int nds_cycles_till_vblank(nds_t*nds){ +static FORCE_INLINE int nds_cycles_till_vblank(nds_t *nds) { int sc = nds->ppu[0].scan_clock; - int clocks_per_line = 355*NDS_CLOCKS_PER_DOT; - int clocks_til_trigger = 355*(NDS_LCD_H)*NDS_CLOCKS_PER_DOT; - if(sc<=clocks_til_trigger)return clocks_til_trigger - sc; + int clocks_per_line = 355 * NDS_CLOCKS_PER_DOT; + int clocks_til_trigger = 355 * (NDS_LCD_H)*NDS_CLOCKS_PER_DOT; + if(sc <= clocks_til_trigger) return clocks_til_trigger - sc; - int clocks_per_frame = 355*263*NDS_CLOCKS_PER_DOT; - return clocks_per_frame-sc +clocks_til_trigger; + int clocks_per_frame = 355 * 263 * NDS_CLOCKS_PER_DOT; + return clocks_per_frame - sc + clocks_til_trigger; } -//Returns true if the fast forward failed to be more efficient in main emu loop -static FORCE_INLINE int nds_ppu_compute_max_fast_forward(nds_t *nds){ - int scanline_clock = (nds->ppu[0].scan_clock)%(355*NDS_CLOCKS_PER_DOT); - //If inside hblank, can fastforward to outside of hblank - if(scanline_clock>=NDS_LCD_W*NDS_CLOCKS_PER_DOT&&scanline_clock<=355*NDS_CLOCKS_PER_DOT) return 355*NDS_CLOCKS_PER_DOT-scanline_clock-1; - //If inside hrender, can fastforward to hblank if not the first pixel and not visible - bool not_visible = nds->ppu[0].scan_clock>NDS_LCD_H*355*NDS_CLOCKS_PER_DOT|| NDS_SCANLINE_PPU; - if(not_visible&& (scanline_clock>=1 && scanline_clock<=NDS_LCD_W*NDS_CLOCKS_PER_DOT))return NDS_LCD_W*NDS_CLOCKS_PER_DOT-scanline_clock-1; - return (NDS_CLOCKS_PER_DOT-1)-((nds->ppu[0].scan_clock)%NDS_CLOCKS_PER_DOT); +// Returns true if the fast forward failed to be more efficient in main emu loop +static FORCE_INLINE int nds_ppu_compute_max_fast_forward(nds_t *nds) { + int scanline_clock = (nds->ppu[0].scan_clock) % (355 * NDS_CLOCKS_PER_DOT); + // If inside hblank, can fastforward to outside of hblank + if(scanline_clock >= NDS_LCD_W * NDS_CLOCKS_PER_DOT && scanline_clock <= 355 * NDS_CLOCKS_PER_DOT) return 355 * NDS_CLOCKS_PER_DOT - scanline_clock - 1; + // If inside hrender, can fastforward to hblank if not the first pixel and not visible + bool not_visible = nds->ppu[0].scan_clock > NDS_LCD_H * 355 * NDS_CLOCKS_PER_DOT || NDS_SCANLINE_PPU; + if(not_visible && (scanline_clock >= 1 && scanline_clock <= NDS_LCD_W * NDS_CLOCKS_PER_DOT)) return NDS_LCD_W * NDS_CLOCKS_PER_DOT - scanline_clock - 1; + return (NDS_CLOCKS_PER_DOT - 1) - ((nds->ppu[0].scan_clock) % NDS_CLOCKS_PER_DOT); } -static FORCE_INLINE void nds_tick_ppu(nds_t* nds,bool render){ - if(SB_LIKELY(nds->ppu_fast_forward_ticks-->0))return; - //if(SB_LIKELY(nds->ppu[0].scan_clock%NDS_CLOCKS_PER_DOT))return; - int clocks_per_frame = 355*263*NDS_CLOCKS_PER_DOT; - nds->ppu[0].scan_clock%=clocks_per_frame; - nds->ppu_fast_forward_ticks=nds_ppu_compute_max_fast_forward(nds); - int clocks_per_line = 355*NDS_CLOCKS_PER_DOT; - int lcd_y = (nds->ppu[0].scan_clock)/clocks_per_line; - int lcd_x = ((nds->ppu[0].scan_clock)%clocks_per_line)/NDS_CLOCKS_PER_DOT; - nds->ppu[0].scan_clock+=nds->ppu_fast_forward_ticks+1; - for(int ppu_id=0;ppu_id<2;++ppu_id){ - nds_ppu_t * ppu = nds->ppu+ppu_id; - uint32_t dispcapcnt = nds9_io_read32(nds,NDS_DISPCAPCNT); - - int reg_offset = ppu_id==0? 0: 0x00001000; - if(lcd_x==0||lcd_x==NDS_LCD_W){ - bool vblank = lcd_y>=NDS_LCD_H&&lcd_y<263; - bool hblank = lcd_x>=NDS_LCD_W; +static FORCE_INLINE void nds_tick_ppu(nds_t *nds, bool render) { + if(SB_LIKELY(nds->ppu_fast_forward_ticks-- > 0)) return; + // if(SB_LIKELY(nds->ppu[0].scan_clock%NDS_CLOCKS_PER_DOT))return; + int clocks_per_frame = 355 * 263 * NDS_CLOCKS_PER_DOT; + nds->ppu[0].scan_clock %= clocks_per_frame; + nds->ppu_fast_forward_ticks = nds_ppu_compute_max_fast_forward(nds); + int clocks_per_line = 355 * NDS_CLOCKS_PER_DOT; + int lcd_y = (nds->ppu[0].scan_clock) / clocks_per_line; + int lcd_x = ((nds->ppu[0].scan_clock) % clocks_per_line) / NDS_CLOCKS_PER_DOT; + nds->ppu[0].scan_clock += nds->ppu_fast_forward_ticks + 1; + for(int ppu_id = 0; ppu_id < 2; ++ppu_id) { + nds_ppu_t *ppu = nds->ppu + ppu_id; + uint32_t dispcapcnt = nds9_io_read32(nds, NDS_DISPCAPCNT); + + int reg_offset = ppu_id == 0 ? 0 : 0x00001000; + if(lcd_x == 0 || lcd_x == NDS_LCD_W) { + bool vblank = lcd_y >= NDS_LCD_H && lcd_y < 263; + bool hblank = lcd_x >= NDS_LCD_W; uint32_t new_if = 0; uint32_t new_if7 = 0; - if(ppu_id==0){ - uint16_t disp_stat = nds9_io_read16(nds, GBA_DISPSTAT)&~0x7; - uint16_t disp_stat7 = nds7_io_read16(nds, GBA_DISPSTAT)&~0x7; - uint16_t vcount_cmp = SB_BFE(disp_stat,8,8); - uint16_t vcount_cmp7 = SB_BFE(disp_stat7,8,8); - vcount_cmp|= SB_BFE(disp_stat,7,1)<<8; - vcount_cmp7|= SB_BFE(disp_stat7,7,1)<<8; - bool vcmp = lcd_y==vcount_cmp; - bool vcmp7 = lcd_y==vcount_cmp7; - disp_stat |= vblank ? 0x1: 0; - disp_stat |= hblank ? 0x2: 0; - disp_stat |= vcmp ? 0x4: 0; - disp_stat7 |= vblank ? 0x1: 0; - disp_stat7 |= hblank ? 0x2: 0; - disp_stat7 |= vcmp7 ? 0x4: 0; - nds7_io_store16(nds,GBA_VCOUNT,lcd_y); - nds9_io_store16(nds,GBA_VCOUNT,lcd_y); - nds9_io_store16(nds,GBA_DISPSTAT,disp_stat); - nds7_io_store16(nds,GBA_DISPSTAT,disp_stat7); - if(vcmp!=ppu->last_vcmp) { - ppu->last_vcmp=vcmp; - bool vcnt_irq_en = SB_BFE(disp_stat,5,1); - if(vcnt_irq_en)new_if |= (1<last_vcmp) { + ppu->last_vcmp = vcmp; + bool vcnt_irq_en = SB_BFE(disp_stat, 5, 1); + if(vcnt_irq_en) new_if |= (1 << GBA_INT_LCD_VCOUNT); } - if(vcmp7!=ppu->last_vcmp7) { - ppu->last_vcmp7=vcmp7; - bool vcnt_irq_en7 = SB_BFE(disp_stat7,5,1); - if(vcnt_irq_en7)new_if7 |= (1<last_vcmp7) { + ppu->last_vcmp7 = vcmp7; + bool vcnt_irq_en7 = SB_BFE(disp_stat7, 5, 1); + if(vcnt_irq_en7) new_if7 |= (1 << GBA_INT_LCD_VCOUNT); } - if(hblank&&!ppu->last_hblank){ - bool hblank_irq_en = SB_BFE(disp_stat,4,1); - bool hblank_irq_en7 = SB_BFE(disp_stat7,4,1); - if(hblank_irq_en) new_if|= (1<< GBA_INT_LCD_HBLANK); - if(hblank_irq_en7) new_if7|= (1<< GBA_INT_LCD_HBLANK); + if(hblank && !ppu->last_hblank) { + bool hblank_irq_en = SB_BFE(disp_stat, 4, 1); + bool hblank_irq_en7 = SB_BFE(disp_stat7, 4, 1); + if(hblank_irq_en) new_if |= (1 << GBA_INT_LCD_HBLANK); + if(hblank_irq_en7) new_if7 |= (1 << GBA_INT_LCD_HBLANK); } - if(vblank&&!ppu->last_vblank){ - bool vblank_irq_en = SB_BFE(disp_stat,3,1); - bool vblank_irq_en7 = SB_BFE(disp_stat7,3,1); - if(vblank_irq_en) new_if |= (1<< GBA_INT_LCD_VBLANK); - if(vblank_irq_en7) new_if7|= (1<< GBA_INT_LCD_VBLANK); + if(vblank && !ppu->last_vblank) { + bool vblank_irq_en = SB_BFE(disp_stat, 3, 1); + bool vblank_irq_en7 = SB_BFE(disp_stat7, 3, 1); + if(vblank_irq_en) new_if |= (1 << GBA_INT_LCD_VBLANK); + if(vblank_irq_en7) new_if7 |= (1 << GBA_INT_LCD_VBLANK); } - if(new_if)nds9_send_interrupt(nds,3,new_if); - if(new_if7)nds7_send_interrupt(nds,3,new_if7); + if(new_if) nds9_send_interrupt(nds, 3, new_if); + if(new_if7) nds7_send_interrupt(nds, 3, new_if7); } - if(hblank!=ppu->last_hblank){ + if(hblank != ppu->last_hblank) { ppu->last_hblank = hblank; - nds->activate_dmas|=nds->dma_wait_ppu; - if(!hblank){ - ppu->dispcnt_pipeline[0]=ppu->dispcnt_pipeline[1]; - ppu->dispcnt_pipeline[1]=ppu->dispcnt_pipeline[2]; - ppu->dispcnt_pipeline[2]=nds9_io_read16(nds, GBA_DISPCNT+reg_offset); - }else{ + nds->activate_dmas |= nds->dma_wait_ppu; + if(!hblank) { + ppu->dispcnt_pipeline[0] = ppu->dispcnt_pipeline[1]; + ppu->dispcnt_pipeline[1] = ppu->dispcnt_pipeline[2]; + ppu->dispcnt_pipeline[2] = nds9_io_read16(nds, GBA_DISPCNT + reg_offset); + } else { uint16_t dispcnt = ppu->dispcnt_pipeline[0]; - int bg_mode = SB_BFE(dispcnt,0,3); + int bg_mode = SB_BFE(dispcnt, 0, 3); // From Mirei: Affine registers are only incremented when bg_mode is not 0 // and the bg is enabled. - if(bg_mode!=0){ - for(int aff=0;aff<2;++aff){ - bool bg_en = SB_BFE(dispcnt,8+aff+2,1); - if(!bg_en)continue; - int32_t b = (int16_t)nds9_io_read16(nds,GBA_BG2PB+(aff)*0x10+reg_offset); - int32_t d = (int16_t)nds9_io_read16(nds,GBA_BG2PD+(aff)*0x10+reg_offset); - uint16_t bgcnt = nds9_io_read16(nds, GBA_BG2CNT+aff*2+reg_offset); - bool mosaic = SB_BFE(bgcnt,6,1); - if(mosaic){ - uint16_t mos_reg = nds9_io_read16(nds,GBA_MOSAIC+reg_offset); - int mos_y = SB_BFE(mos_reg,4,4)+1; - if((lcd_y%mos_y)==0){ - ppu->aff[aff].internal_bgx+=b*mos_y; - ppu->aff[aff].internal_bgy+=d*mos_y; + if(bg_mode != 0) { + for(int aff = 0; aff < 2; ++aff) { + bool bg_en = SB_BFE(dispcnt, 8 + aff + 2, 1); + if(!bg_en) continue; + int32_t b = (int16_t)nds9_io_read16(nds, GBA_BG2PB + (aff)*0x10 + reg_offset); + int32_t d = (int16_t)nds9_io_read16(nds, GBA_BG2PD + (aff)*0x10 + reg_offset); + uint16_t bgcnt = nds9_io_read16(nds, GBA_BG2CNT + aff * 2 + reg_offset); + bool mosaic = SB_BFE(bgcnt, 6, 1); + if(mosaic) { + uint16_t mos_reg = nds9_io_read16(nds, GBA_MOSAIC + reg_offset); + int mos_y = SB_BFE(mos_reg, 4, 4) + 1; + if((lcd_y % mos_y) == 0) { + ppu->aff[aff].internal_bgx += b * mos_y; + ppu->aff[aff].internal_bgy += d * mos_y; } - }else{ - ppu->aff[aff].internal_bgx+=b; - ppu->aff[aff].internal_bgy+=d; + } else { + ppu->aff[aff].internal_bgx += b; + ppu->aff[aff].internal_bgy += d; } } } } } - if(vblank!=ppu->last_vblank){ + if(vblank != ppu->last_vblank) { ppu->last_vblank = vblank; - if(vblank){ - //Done with capture - dispcapcnt&=~(1<<31); - nds9_io_store32(nds,NDS_DISPCAPCNT,dispcapcnt); - ppu->new_frame=true; - }else{ - for(int aff=0;aff<2;++aff){ - ppu->aff[aff].internal_bgx=nds9_io_read32(nds,GBA_BG2X+(aff)*0x10+reg_offset); - ppu->aff[aff].internal_bgy=nds9_io_read32(nds,GBA_BG2Y+(aff)*0x10+reg_offset); - - ppu->aff[aff].internal_bgx = SB_BFE(ppu->aff[aff].internal_bgx,0,28); - ppu->aff[aff].internal_bgy = SB_BFE(ppu->aff[aff].internal_bgy,0,28); - - ppu->aff[aff].internal_bgx = (ppu->aff[aff].internal_bgx<<4)>>4; - ppu->aff[aff].internal_bgy = (ppu->aff[aff].internal_bgy<<4)>>4; + if(vblank) { + // Done with capture + dispcapcnt &= ~(1 << 31); + nds9_io_store32(nds, NDS_DISPCAPCNT, dispcapcnt); + ppu->new_frame = true; + } else { + for(int aff = 0; aff < 2; ++aff) { + ppu->aff[aff].internal_bgx = nds9_io_read32(nds, GBA_BG2X + (aff)*0x10 + reg_offset); + ppu->aff[aff].internal_bgy = nds9_io_read32(nds, GBA_BG2Y + (aff)*0x10 + reg_offset); + + ppu->aff[aff].internal_bgx = SB_BFE(ppu->aff[aff].internal_bgx, 0, 28); + ppu->aff[aff].internal_bgy = SB_BFE(ppu->aff[aff].internal_bgy, 0, 28); + + ppu->aff[aff].internal_bgx = (ppu->aff[aff].internal_bgx << 4) >> 4; + ppu->aff[aff].internal_bgy = (ppu->aff[aff].internal_bgy << 4) >> 4; } } - uint16_t powcnt1 = nds9_io_read16(nds,NDS9_POWCNT1); - nds->display_flip = SB_BFE(powcnt1,15,1); - nds->activate_dmas|=nds->dma_wait_ppu; + uint16_t powcnt1 = nds9_io_read16(nds, NDS9_POWCNT1); + nds->display_flip = SB_BFE(powcnt1, 15, 1); + nds->activate_dmas |= nds->dma_wait_ppu; } - ppu->last_lcd_y = lcd_y; + ppu->last_lcd_y = lcd_y; } - uint32_t dispcnt = nds9_io_read32(nds, GBA_DISPCNT+reg_offset); - int display_mode = SB_BFE(dispcnt,16,2); - bool enable_capture = SB_BFE(dispcapcnt,31,1)&&ppu_id==0; - render|=enable_capture; - int forced_blank = SB_BFE(dispcnt,7,1); - render&= !forced_blank; - if(!render)continue; - - bool enable_3d = ppu_id==0&&SB_BFE(dispcnt,3,1); - int bg_mode = SB_BFE(dispcnt,0,3); - bool visible = lcd_xwindow,default_window_control,NDS_LCD_W); - - bool display_obj = SB_BFE(dispcnt,12,1); - if(display_obj){ + uint32_t dispcnt = nds9_io_read32(nds, GBA_DISPCNT + reg_offset); + int display_mode = SB_BFE(dispcnt, 16, 2); + bool enable_capture = SB_BFE(dispcapcnt, 31, 1) && ppu_id == 0; + render |= enable_capture; + int forced_blank = SB_BFE(dispcnt, 7, 1); + render &= !forced_blank; + if(!render) continue; + + bool enable_3d = ppu_id == 0 && SB_BFE(dispcnt, 3, 1); + int bg_mode = SB_BFE(dispcnt, 0, 3); + bool visible = lcd_x < NDS_LCD_W && lcd_y < NDS_LCD_H; + // Render sprites over scanline when it completes + if(lcd_y < NDS_LCD_H && lcd_x == 0) { + int obj_vram_map_2d = !SB_BFE(dispcnt, 6, 1); + // Render sprites over scanline when it completes + uint8_t default_window_control = 0x3f; // bitfield [0-3:bg0-bg3 enable 4:obj enable, 5: special effect enable] + bool winout_enable = SB_BFE(dispcnt, 13, 3) != 0; + uint16_t WINOUT = nds9_io_read16(nds, GBA_WINOUT + reg_offset); + if(winout_enable) default_window_control = SB_BFE(WINOUT, 0, 8); + + memset(ppu->window, default_window_control, NDS_LCD_W); + + bool display_obj = SB_BFE(dispcnt, 12, 1); + if(display_obj) { uint8_t obj_window_control = default_window_control; - bool obj_window_enable = SB_BFE(dispcnt,15,1); - if(obj_window_enable)obj_window_control = SB_BFE(WINOUT,8,6); - int oam_offset = ppu_id*1024; - int obj_vram_base = ppu_id ==0? 0x06400000: 0x06600000; - for(int o=0;o<128;++o){ - uint16_t attr0 = *(uint16_t*)(nds->mem.oam+o*8+0+oam_offset); - //Attr0 - uint8_t y_coord = SB_BFE(attr0,0,8); - bool rot_scale = SB_BFE(attr0,8,1); - bool double_size = SB_BFE(attr0,9,1)&&rot_scale; - bool obj_disable = SB_BFE(attr0,9,1)&&!rot_scale; - if(obj_disable) continue; - - int obj_mode = SB_BFE(attr0,10,2); //(0=Normal, 1=Semi-Transparent, 2=OBJ Window, 3=bitmap) - bool mosaic = SB_BFE(attr0,12,1); - bool colors_or_palettes = SB_BFE(attr0,13,1); - int obj_shape = SB_BFE(attr0,14,2);//(0=Square,1=Horizontal,2=Vertical,3=Prohibited) - uint16_t attr1 = *(uint16_t*)(nds->mem.oam+o*8+2+oam_offset); - - int rotscale_param = SB_BFE(attr1,9,5); - bool h_flip = SB_BFE(attr1,12,1)&&!rot_scale; - bool v_flip = SB_BFE(attr1,13,1)&&!rot_scale; - int obj_size = SB_BFE(attr1,14,2); + bool obj_window_enable = SB_BFE(dispcnt, 15, 1); + if(obj_window_enable) obj_window_control = SB_BFE(WINOUT, 8, 6); + int oam_offset = ppu_id * 1024; + int obj_vram_base = ppu_id == 0 ? 0x06400000 : 0x06600000; + for(int o = 0; o < 128; ++o) { + uint16_t attr0 = *(uint16_t *)(nds->mem.oam + o * 8 + 0 + oam_offset); + // Attr0 + uint8_t y_coord = SB_BFE(attr0, 0, 8); + bool rot_scale = SB_BFE(attr0, 8, 1); + bool double_size = SB_BFE(attr0, 9, 1) && rot_scale; + bool obj_disable = SB_BFE(attr0, 9, 1) && !rot_scale; + if(obj_disable) continue; + + int obj_mode = SB_BFE(attr0, 10, 2); //(0=Normal, 1=Semi-Transparent, 2=OBJ Window, 3=bitmap) + bool mosaic = SB_BFE(attr0, 12, 1); + bool colors_or_palettes = SB_BFE(attr0, 13, 1); + int obj_shape = SB_BFE(attr0, 14, 2); //(0=Square,1=Horizontal,2=Vertical,3=Prohibited) + uint16_t attr1 = *(uint16_t *)(nds->mem.oam + o * 8 + 2 + oam_offset); + + int rotscale_param = SB_BFE(attr1, 9, 5); + bool h_flip = SB_BFE(attr1, 12, 1) && !rot_scale; + bool v_flip = SB_BFE(attr1, 13, 1) && !rot_scale; + int obj_size = SB_BFE(attr1, 14, 2); // Size Square Horizontal Vertical // 0 8x8 16x8 8x16 // 1 16x16 32x8 8x32 // 2 32x32 32x16 16x32 // 3 64x64 64x32 32x64 - const int xsize_lookup[16]={ - 8,16,8,0, - 16,32,8,0, - 32,32,16,0, - 64,64,32,0 - }; - const int ysize_lookup[16]={ - 8,8,16,0, - 16,8,32,0, - 32,16,32,0, - 64,32,64,0 - }; - - int y_size = ysize_lookup[obj_size*4+obj_shape]; - - if(((lcd_y-y_coord)&0xff) =0?x_coord:0; - int x_end = x_coord+x_size*(double_size?2:1); - if(x_end>=NDS_LCD_W)x_end=NDS_LCD_W; - //Attr2 - //Skip objects disabled by window - uint16_t attr2 = *(uint16_t*)(nds->mem.oam+o*8+4 +oam_offset); - int tile_base = SB_BFE(attr2,0,10); + const int xsize_lookup[16] = { + 8, 16, 8, 0, + 16, 32, 8, 0, + 32, 32, 16, 0, + 64, 64, 32, 0}; + const int ysize_lookup[16] = { + 8, 8, 16, 0, + 16, 8, 32, 0, + 32, 16, 32, 0, + 64, 32, 64, 0}; + + int y_size = ysize_lookup[obj_size * 4 + obj_shape]; + + if(((lcd_y - y_coord) & 0xff) < y_size * (double_size ? 2 : 1)) { + + int16_t x_coord = SB_BFE(attr1, 0, 9); + if(SB_BFE(x_coord, 8, 1)) x_coord |= 0xfe00; + + int x_size = xsize_lookup[obj_size * 4 + obj_shape]; + int x_start = x_coord >= 0 ? x_coord : 0; + int x_end = x_coord + x_size * (double_size ? 2 : 1); + if(x_end >= NDS_LCD_W) x_end = NDS_LCD_W; + // Attr2 + // Skip objects disabled by window + uint16_t attr2 = *(uint16_t *)(nds->mem.oam + o * 8 + 4 + oam_offset); + int tile_base = SB_BFE(attr2, 0, 10); // Always place sprites as the highest priority - int priority = SB_BFE(attr2,10,2); - int palette = SB_BFE(attr2,12,4); - for(int x = x_start; x< x_end;++x){ - int sx = (x-x_coord); - int sy = (lcd_y-y_coord)&0xff; - if(mosaic){ - uint16_t mos_reg = nds9_io_read16(nds,GBA_MOSAIC+reg_offset); - int mos_x = SB_BFE(mos_reg,8,4)+1; - int mos_y = SB_BFE(mos_reg,12,4)+1; - sx = ((x/mos_x)*mos_x-x_coord); - sy = (((lcd_y/mos_y)*mos_y-y_coord)&0xff); + int priority = SB_BFE(attr2, 10, 2); + int palette = SB_BFE(attr2, 12, 4); + for(int x = x_start; x < x_end; ++x) { + int sx = (x - x_coord); + int sy = (lcd_y - y_coord) & 0xff; + if(mosaic) { + uint16_t mos_reg = nds9_io_read16(nds, GBA_MOSAIC + reg_offset); + int mos_x = SB_BFE(mos_reg, 8, 4) + 1; + int mos_y = SB_BFE(mos_reg, 12, 4) + 1; + sx = ((x / mos_x) * mos_x - x_coord); + sy = (((lcd_y / mos_y) * mos_y - y_coord) & 0xff); } - if(rot_scale){ - uint32_t param_base = rotscale_param*0x20+oam_offset; - int32_t a = *(int16_t*)(nds->mem.oam+param_base+0x6); - int32_t b = *(int16_t*)(nds->mem.oam+param_base+0xe); - int32_t c = *(int16_t*)(nds->mem.oam+param_base+0x16); - int32_t d = *(int16_t*)(nds->mem.oam+param_base+0x1e); - - int64_t x1 = sx<<8; - int64_t y1 = sy<<8; - int64_t objref_x = (x_size<<(double_size?8:7)); - int64_t objref_y = (y_size<<(double_size?8:7)); - - int64_t x2 = a*(x1-objref_x) + b*(y1-objref_y)+(x_size<<15); - int64_t y2 = c*(x1-objref_x) + d*(y1-objref_y)+(y_size<<15); - - sx = (x2>>16); - sy = (y2>>16); - if(sx>=x_size||sy>=y_size||sx<0||sy<0)continue; - }else{ - if(h_flip)sx=x_size-sx-1; - if(v_flip)sy=y_size-sy-1; + if(rot_scale) { + uint32_t param_base = rotscale_param * 0x20 + oam_offset; + int32_t a = *(int16_t *)(nds->mem.oam + param_base + 0x6); + int32_t b = *(int16_t *)(nds->mem.oam + param_base + 0xe); + int32_t c = *(int16_t *)(nds->mem.oam + param_base + 0x16); + int32_t d = *(int16_t *)(nds->mem.oam + param_base + 0x1e); + + int64_t x1 = sx << 8; + int64_t y1 = sy << 8; + int64_t objref_x = (x_size << (double_size ? 8 : 7)); + int64_t objref_y = (y_size << (double_size ? 8 : 7)); + + int64_t x2 = a * (x1 - objref_x) + b * (y1 - objref_y) + (x_size << 15); + int64_t y2 = c * (x1 - objref_x) + d * (y1 - objref_y) + (y_size << 15); + + sx = (x2 >> 16); + sy = (y2 >> 16); + if(sx >= x_size || sy >= y_size || sx < 0 || sy < 0) continue; + } else { + if(h_flip) sx = x_size - sx - 1; + if(v_flip) sy = y_size - sy - 1; } - uint32_t col =0; - if(obj_mode==3){ - - bool linear = SB_BFE(dispcnt,6,1); - //TODO: Bitmap sprites - if(linear){ - int boundry = SB_BFE(dispcnt,22,1); - tile_base *= boundry? 256: 128; - int p = sx+sy*x_size; - col = nds_ppu_read16(nds,obj_vram_base+tile_base+p*2); - }else{ - bool size = SB_BFE(dispcnt,5,1); - int p = 0; - if(size){ - int tile_x=SB_BFE(tile_base,0,5); - int tile_y=SB_BFE(tile_base,5,5); - p = (tile_x*8+sx)+(tile_y*8+sy)*32*8; - }else{ - int tile_x=SB_BFE(tile_base,0,4); - int tile_y=SB_BFE(tile_base,4,6); - p = (tile_x*8+sx)+(tile_y*8+sy)*16*8; + uint32_t col = 0; + if(obj_mode == 3) { + + bool linear = SB_BFE(dispcnt, 6, 1); + // TODO: Bitmap sprites + if(linear) { + int boundry = SB_BFE(dispcnt, 22, 1); + tile_base *= boundry ? 256 : 128; + int p = sx + sy * x_size; + col = nds_ppu_read16(nds, obj_vram_base + tile_base + p * 2); + } else { + bool size = SB_BFE(dispcnt, 5, 1); + int p = 0; + if(size) { + int tile_x = SB_BFE(tile_base, 0, 5); + int tile_y = SB_BFE(tile_base, 5, 5); + p = (tile_x * 8 + sx) + (tile_y * 8 + sy) * 32 * 8; + } else { + int tile_x = SB_BFE(tile_base, 0, 4); + int tile_y = SB_BFE(tile_base, 4, 6); + p = (tile_x * 8 + sx) + (tile_y * 8 + sy) * 16 * 8; } - col = nds_ppu_read16(nds,obj_vram_base+p*2); - if(!SB_BFE(col,15,1))continue; + col = nds_ppu_read16(nds, obj_vram_base + p * 2); + if(!SB_BFE(col, 15, 1)) continue; } - }else{ - int tx = sx%8; - int ty = sy%8; - bool tile_obj_mapping = SB_BFE(dispcnt,4,1); - - int y_tile_stride = obj_vram_map_2d? 32 : x_size/8*(colors_or_palettes? 2:1); + } else { + int tx = sx % 8; + int ty = sy % 8; + bool tile_obj_mapping = SB_BFE(dispcnt, 4, 1); + + int y_tile_stride = obj_vram_map_2d ? 32 : x_size / 8 * (colors_or_palettes ? 2 : 1); int tile_boundry = 32; - if(tile_obj_mapping ==true){ - int tile_obj_1d_boundry = SB_BFE(dispcnt,20,2); - tile_boundry = 32<>((tx&1)*4))&0xf; - if(palette_id==0)continue; - palette_id+=palette*16; - use_obj_ext_palettes=false; //Not supported in 16 color mode - }else{ - palette_id=nds_ppu_read8(nds,obj_vram_base+tile*32+tx+ty*8); - if(palette_id==0)continue; + bool use_obj_ext_palettes = SB_BFE(dispcnt, 31, 1); + if(colors_or_palettes == false) { + palette_id = nds_ppu_read8(nds, obj_vram_base + tile * 32 + tx / 2 + ty * 4); + palette_id = (palette_id >> ((tx & 1) * 4)) & 0xf; + if(palette_id == 0) continue; + palette_id += palette * 16; + use_obj_ext_palettes = false; // Not supported in 16 color mode + } else { + palette_id = nds_ppu_read8(nds, obj_vram_base + tile * 32 + tx + ty * 8); + if(palette_id == 0) continue; } - if(use_obj_ext_palettes){ - palette_id=(palette)*256+palette_id; - uint32_t read_addr = (ppu_id?NDS_VRAM_OBJB_SLOT0:NDS_VRAM_OBJA_SLOT0)+palette_id*2; + if(use_obj_ext_palettes) { + palette_id = (palette)*256 + palette_id; + uint32_t read_addr = (ppu_id ? NDS_VRAM_OBJB_SLOT0 : NDS_VRAM_OBJA_SLOT0) + palette_id * 2; col = nds_ppu_read16(nds, read_addr); - }else{ - uint32_t pallete_offset = ppu_id?0x600:0x200; - col = *(uint16_t*)(nds->mem.palette+pallete_offset+palette_id*2); + } else { + uint32_t pallete_offset = ppu_id ? 0x600 : 0x200; + col = *(uint16_t *)(nds->mem.palette + pallete_offset + palette_id * 2); } } - //Handle window objects(not displayed but control the windowing of other things) - if(obj_mode==2){ppu->window[x]=obj_window_control; - }else{ - int type =4; - col=col|(type<<17)|((5-priority)<<28)|((0x7)<<25); - if(obj_mode==1)col|=1<<16; - if((col>>17)>(ppu->first_target_buffer[x]>>17))ppu->first_target_buffer[x]=col; - } + // Handle window objects(not displayed but control the windowing of other things) + if(obj_mode == 2) { + ppu->window[x] = obj_window_control; + } else { + int type = 4; + col = col | (type << 17) | ((5 - priority) << 28) | ((0x7) << 25); + if(obj_mode == 1) col |= 1 << 16; + if((col >> 17) > (ppu->first_target_buffer[x] >> 17)) ppu->first_target_buffer[x] = col; + } } } } } - int enabled_windows = SB_BFE(dispcnt,13,3); // [0: win0, 1:win1, 2: objwin] - if(enabled_windows){ - for(int win=1;win>=0;--win){ - bool win_enable = SB_BFE(dispcnt,13+win,1); - if(!win_enable)continue; - uint16_t WINH = nds9_io_read16(nds, GBA_WIN0H+2*win+reg_offset); - uint16_t WINV = nds9_io_read16(nds, GBA_WIN0V+2*win+reg_offset); - int win_xmin = SB_BFE(WINH,8,8); - int win_xmax = SB_BFE(WINH,0,8); - int win_ymin = SB_BFE(WINV,8,8); - int win_ymax = SB_BFE(WINV,0,8); + int enabled_windows = SB_BFE(dispcnt, 13, 3); // [0: win0, 1:win1, 2: objwin] + if(enabled_windows) { + for(int win = 1; win >= 0; --win) { + bool win_enable = SB_BFE(dispcnt, 13 + win, 1); + if(!win_enable) continue; + uint16_t WINH = nds9_io_read16(nds, GBA_WIN0H + 2 * win + reg_offset); + uint16_t WINV = nds9_io_read16(nds, GBA_WIN0V + 2 * win + reg_offset); + int win_xmin = SB_BFE(WINH, 8, 8); + int win_xmax = SB_BFE(WINH, 0, 8); + int win_ymin = SB_BFE(WINV, 8, 8); + int win_ymax = SB_BFE(WINV, 0, 8); // Garbage values of X2>240 or X1>X2 are interpreted as X2=240. - // Garbage values of Y2>160 or Y1>Y2 are interpreted as Y2=160. - if(win_xmin>win_xmax)win_xmax=NDS_LCD_W; - if(win_ymin>win_ymax)win_ymax=NDS_LCD_H+1; - if(win_xmax>NDS_LCD_W)win_xmax=NDS_LCD_W; - if(lcd_y=win_ymax)continue; - uint16_t winin = nds9_io_read16(nds,GBA_WININ+reg_offset); - uint8_t win_value = SB_BFE(winin,win*8,6); - memset(ppu->window+win_xmin,win_value,win_xmax-win_xmin); + // Garbage values of Y2>160 or Y1>Y2 are interpreted as Y2=160. + if(win_xmin > win_xmax) win_xmax = NDS_LCD_W; + if(win_ymin > win_ymax) win_ymax = NDS_LCD_H + 1; + if(win_xmax > NDS_LCD_W) win_xmax = NDS_LCD_W; + if(lcd_y < win_ymin || lcd_y >= win_ymax) continue; + uint16_t winin = nds9_io_read16(nds, GBA_WININ + reg_offset); + uint8_t win_value = SB_BFE(winin, win * 8, 6); + memset(ppu->window + win_xmin, win_value, win_xmax - win_xmin); } - int backdrop_type = 5; - uint32_t backdrop_col = (*(uint16_t*)(nds->mem.palette + GBA_BG_PALETTE+0*2+ppu_id*1024))|(backdrop_type<<17); - for(int x=0;xmem.palette + GBA_BG_PALETTE + 0 * 2 + ppu_id * 1024)) | (backdrop_type << 17); + for(int x = 0; x < NDS_LCD_W; ++x) { uint8_t window_control = ppu->window[x]; - if(SB_BFE(window_control,4,1)==0)ppu->first_target_buffer[x]=backdrop_col; + if(SB_BFE(window_control, 4, 1) == 0) ppu->first_target_buffer[x] = backdrop_col; } } } - if(visible){ - #if NDS_SCANLINE_PPU == 1 - if(lcd_x==0){while(lcd_xwindow[lcd_x]; - bool render_backgrounds = true; //TODO hook up power management - if(render_backgrounds){ - for(int bg = 3; bg>=0;--bg){ - #define NDS_BG_TEXT 0 - #define NDS_BG_AFFINE 1 - #define NDS_BG_BITMAP 2 - #define NDS_BG_LARGE_BITMAP 3 - #define NDS_BG_INVALID 4 - - const int bg_mode_table[8*4]={ - /* mode 0: */NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_TEXT, - /* mode 1: */NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_AFFINE, - /* mode 2: */NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_AFFINE,NDS_BG_AFFINE, - /* mode 3: */NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_BITMAP, - /* mode 4: */NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_AFFINE,NDS_BG_BITMAP, - /* mode 5: */NDS_BG_TEXT,NDS_BG_TEXT,NDS_BG_BITMAP,NDS_BG_BITMAP, - /* mode 6: */NDS_BG_TEXT,NDS_BG_INVALID,NDS_BG_LARGE_BITMAP,NDS_BG_INVALID, - /* mode 7: */NDS_BG_INVALID,NDS_BG_INVALID,NDS_BG_INVALID,NDS_BG_INVALID, - }; - const int bg_size_table[4*4*2]={ - /* TEXT: */ - 256,256, - 512,256, - 256,512, - 512,512, - /* AFFINE: */ - 128,128, - 256,256, - 512,512, - 1024,1024, - /* BITMAP: */ - 128,128, - 256,256, - 512,256, - 512,512, - /* LARGE BITMAP: */ - 512,1024, - 1024,512, - 0,0, //INVALID - 0,0, //INVALID - }; - int bg_type = bg_mode_table[bg_mode*4+bg]; - uint32_t col =0; - bool bg_en = SB_BFE(dispcnt,8+bg,1)&&SB_BFE(ppu->dispcnt_pipeline[0],8+bg,1)&&bg_type!=NDS_BG_INVALID; - if(!bg_en || SB_BFE(window_control,bg,1)==0)continue; - - bool rot_scale = bg_type!=NDS_BG_TEXT; - uint16_t bgcnt = nds9_io_read16(nds, GBA_BG0CNT+bg*2+reg_offset); - int priority = SB_BFE(bgcnt,0,2); - int character_base = SB_BFE(bgcnt,2,4); - bool mosaic = SB_BFE(bgcnt,6,1); - bool colors = SB_BFE(bgcnt,7,1); - int screen_base = SB_BFE(bgcnt,8,5); - bool display_overflow =SB_BFE(bgcnt,13,1); - int screen_size = SB_BFE(bgcnt,14,2); - - if(SB_UNLIKELY(enable_3d&&bg==0)){ - int p = lcd_x+lcd_y*NDS_LCD_W; - col = SB_BFE(nds->framebuffer_3d_disp[p*4+0],3,5); - col |= SB_BFE(nds->framebuffer_3d_disp[p*4+1],3,5)<<5; - col |= SB_BFE(nds->framebuffer_3d_disp[p*4+2],3,5)<<10; - if(SB_BFE(nds->framebuffer_3d_disp[p*4+3],3,5)==0)continue; - }else{ - bool bitmap_mode = SB_BFE(bgcnt,7,1)&&(bg_type==NDS_BG_BITMAP||bg_type==NDS_BG_LARGE_BITMAP); - bool extended_bgmap=!SB_BFE(bgcnt,7,1)&&(bg_type==NDS_BG_BITMAP||bg_type==NDS_BG_LARGE_BITMAP); - //NDS can have an affine "bitmap" that is really a large affine tile map - uint32_t bg_type_for_size = (bg_type==2&&!bitmap_mode)? 1: bg_type; - int screen_size_x = bg_size_table[(bg_type_for_size*4+screen_size)*2+0]; - int screen_size_y = bg_size_table[(bg_type_for_size*4+screen_size)*2+1]; - - int bg_x = 0; - int bg_y = 0; - uint32_t pallete_offset = ppu_id?0x400:0; - - bool use_ext_palettes = SB_BFE(dispcnt,30,1); - - if(rot_scale){ - colors = true; - - int32_t bgx = ppu->aff[bg-2].internal_bgx; - int32_t bgy = ppu->aff[bg-2].internal_bgy; - - int32_t a = (int16_t)nds9_io_read16(nds,GBA_BG2PA+(bg-2)*0x10+reg_offset); - int32_t c = (int16_t)nds9_io_read16(nds,GBA_BG2PC+(bg-2)*0x10+reg_offset); - - // Shift lcd_coords into fixed point - int64_t x2 = a*lcd_x + (((int64_t)bgx)); - int64_t y2 = c*lcd_x + (((int64_t)bgy)); - if(mosaic){ - int16_t mos_reg = nds9_io_read16(nds,GBA_MOSAIC+reg_offset); - int mos_x = SB_BFE(mos_reg,0,4)+1; - x2 = a*((lcd_x/mos_x)*mos_x) + (((int64_t)bgx)); - y2 = c*((lcd_x/mos_x)*mos_x) + (((int64_t)bgy)); - } - bg_x = (x2>>8); - bg_y = (y2>>8); - - if(display_overflow==0){ - if(bg_x<0||bg_x>=screen_size_x||bg_y<0||bg_y>=screen_size_y)continue; - }else{ - bg_x%=screen_size_x; - bg_y%=screen_size_y; - } - }else{ - int16_t hoff = SB_BFE(nds9_io_read16(nds,GBA_BG0HOFS+bg*4+reg_offset),0,9); - int16_t voff = SB_BFE(nds9_io_read16(nds,GBA_BG0VOFS+bg*4+reg_offset),0,9); - hoff=(hoff<<7)>>7; - voff=(voff<<7)>>7; - bg_x = (hoff+lcd_x); - bg_y = (voff+lcd_y); - if(mosaic){ - uint16_t mos_reg = nds9_io_read16(nds,GBA_MOSAIC+reg_offset); - int mos_x = SB_BFE(mos_reg,0,4)+1; - int mos_y = SB_BFE(mos_reg,4,4)+1; - bg_x = hoff+(lcd_x/mos_x)*mos_x; - bg_y = voff+(lcd_y/mos_y)*mos_y; - } - } - int screen_base_addr = screen_base*2*1024; - int character_base_addr = character_base*16*1024; - - int32_t bg_base = ppu_id? 0x06200000:0x06000000; - if(bitmap_mode){ - screen_base_addr=screen_base*16*1024; - int p = bg_x+(bg_y)*screen_size_x; - if(bitmap_mode){ - bool direct_color = SB_BFE(bgcnt,2,1); - if(direct_color){ - col = nds_ppu_read16(nds,bg_base+screen_base_addr+p*2); - if(!SB_BFE(col,15,1))continue; + if(visible) { +#if NDS_SCANLINE_PPU == 1 + if(lcd_x == 0) { + while(lcd_x < NDS_LCD_W) { +#endif + uint8_t window_control = ppu->window[lcd_x]; + bool render_backgrounds = true; // TODO hook up power management + if(render_backgrounds) { + for(int bg = 3; bg >= 0; --bg) { +#define NDS_BG_TEXT 0 +#define NDS_BG_AFFINE 1 +#define NDS_BG_BITMAP 2 +#define NDS_BG_LARGE_BITMAP 3 +#define NDS_BG_INVALID 4 + + const int bg_mode_table[8 * 4] = { + /* mode 0: */ NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_TEXT, + /* mode 1: */ NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_AFFINE, + /* mode 2: */ NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_AFFINE, + NDS_BG_AFFINE, + /* mode 3: */ NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_BITMAP, + /* mode 4: */ NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_AFFINE, + NDS_BG_BITMAP, + /* mode 5: */ NDS_BG_TEXT, + NDS_BG_TEXT, + NDS_BG_BITMAP, + NDS_BG_BITMAP, + /* mode 6: */ NDS_BG_TEXT, + NDS_BG_INVALID, + NDS_BG_LARGE_BITMAP, + NDS_BG_INVALID, + /* mode 7: */ NDS_BG_INVALID, + NDS_BG_INVALID, + NDS_BG_INVALID, + NDS_BG_INVALID, + }; + const int bg_size_table[4 * 4 * 2] = { + /* TEXT: */ + 256, 256, + 512, 256, + 256, 512, + 512, 512, + /* AFFINE: */ + 128, 128, + 256, 256, + 512, 512, + 1024, 1024, + /* BITMAP: */ + 128, 128, + 256, 256, + 512, 256, + 512, 512, + /* LARGE BITMAP: */ + 512, 1024, + 1024, 512, + 0, 0, // INVALID + 0, 0, // INVALID + }; + int bg_type = bg_mode_table[bg_mode * 4 + bg]; + uint32_t col = 0; + bool bg_en = SB_BFE(dispcnt, 8 + bg, 1) && SB_BFE(ppu->dispcnt_pipeline[0], 8 + bg, 1) && bg_type != NDS_BG_INVALID; + if(!bg_en || SB_BFE(window_control, bg, 1) == 0) continue; + + bool rot_scale = bg_type != NDS_BG_TEXT; + uint16_t bgcnt = nds9_io_read16(nds, GBA_BG0CNT + bg * 2 + reg_offset); + int priority = SB_BFE(bgcnt, 0, 2); + int character_base = SB_BFE(bgcnt, 2, 4); + bool mosaic = SB_BFE(bgcnt, 6, 1); + bool colors = SB_BFE(bgcnt, 7, 1); + int screen_base = SB_BFE(bgcnt, 8, 5); + bool display_overflow = SB_BFE(bgcnt, 13, 1); + int screen_size = SB_BFE(bgcnt, 14, 2); + + if(SB_UNLIKELY(enable_3d && bg == 0)) { + int p = lcd_x + lcd_y * NDS_LCD_W; + col = SB_BFE(nds->framebuffer_3d_disp[p * 4 + 0], 3, 5); + col |= SB_BFE(nds->framebuffer_3d_disp[p * 4 + 1], 3, 5) << 5; + col |= SB_BFE(nds->framebuffer_3d_disp[p * 4 + 2], 3, 5) << 10; + if(SB_BFE(nds->framebuffer_3d_disp[p * 4 + 3], 3, 5) == 0) continue; + } else { + bool bitmap_mode = SB_BFE(bgcnt, 7, 1) && (bg_type == NDS_BG_BITMAP || bg_type == NDS_BG_LARGE_BITMAP); + bool extended_bgmap = !SB_BFE(bgcnt, 7, 1) && (bg_type == NDS_BG_BITMAP || bg_type == NDS_BG_LARGE_BITMAP); + // NDS can have an affine "bitmap" that is really a large affine tile map + uint32_t bg_type_for_size = (bg_type == 2 && !bitmap_mode) ? 1 : bg_type; + int screen_size_x = bg_size_table[(bg_type_for_size * 4 + screen_size) * 2 + 0]; + int screen_size_y = bg_size_table[(bg_type_for_size * 4 + screen_size) * 2 + 1]; + + int bg_x = 0; + int bg_y = 0; + uint32_t pallete_offset = ppu_id ? 0x400 : 0; + + bool use_ext_palettes = SB_BFE(dispcnt, 30, 1); + + if(rot_scale) { + colors = true; + + int32_t bgx = ppu->aff[bg - 2].internal_bgx; + int32_t bgy = ppu->aff[bg - 2].internal_bgy; + + int32_t a = (int16_t)nds9_io_read16(nds, GBA_BG2PA + (bg - 2) * 0x10 + reg_offset); + int32_t c = (int16_t)nds9_io_read16(nds, GBA_BG2PC + (bg - 2) * 0x10 + reg_offset); + + // Shift lcd_coords into fixed point + int64_t x2 = a * lcd_x + (((int64_t)bgx)); + int64_t y2 = c * lcd_x + (((int64_t)bgy)); + if(mosaic) { + int16_t mos_reg = nds9_io_read16(nds, GBA_MOSAIC + reg_offset); + int mos_x = SB_BFE(mos_reg, 0, 4) + 1; + x2 = a * ((lcd_x / mos_x) * mos_x) + (((int64_t)bgx)); + y2 = c * ((lcd_x / mos_x) * mos_x) + (((int64_t)bgy)); + } + bg_x = (x2 >> 8); + bg_y = (y2 >> 8); + + if(display_overflow == 0) { + if(bg_x < 0 || bg_x >= screen_size_x || bg_y < 0 || bg_y >= screen_size_y) continue; + } else { + bg_x %= screen_size_x; + bg_y %= screen_size_y; + } + } else { + int16_t hoff = SB_BFE(nds9_io_read16(nds, GBA_BG0HOFS + bg * 4 + reg_offset), 0, 9); + int16_t voff = SB_BFE(nds9_io_read16(nds, GBA_BG0VOFS + bg * 4 + reg_offset), 0, 9); + hoff = (hoff << 7) >> 7; + voff = (voff << 7) >> 7; + bg_x = (hoff + lcd_x); + bg_y = (voff + lcd_y); + if(mosaic) { + uint16_t mos_reg = nds9_io_read16(nds, GBA_MOSAIC + reg_offset); + int mos_x = SB_BFE(mos_reg, 0, 4) + 1; + int mos_y = SB_BFE(mos_reg, 4, 4) + 1; + bg_x = hoff + (lcd_x / mos_x) * mos_x; + bg_y = voff + (lcd_y / mos_y) * mos_y; + } } - else{ - int pallete_id = nds_ppu_read8(nds,bg_base+screen_base_addr+p); - if(pallete_id==0)continue; - col = *(uint16_t*)(nds->mem.palette+pallete_offset+pallete_id*2); + int screen_base_addr = screen_base * 2 * 1024; + int character_base_addr = character_base * 16 * 1024; + + int32_t bg_base = ppu_id ? 0x06200000 : 0x06000000; + if(bitmap_mode) { + screen_base_addr = screen_base * 16 * 1024; + int p = bg_x + (bg_y)*screen_size_x; + if(bitmap_mode) { + bool direct_color = SB_BFE(bgcnt, 2, 1); + if(direct_color) { + col = nds_ppu_read16(nds, bg_base + screen_base_addr + p * 2); + if(!SB_BFE(col, 15, 1)) continue; + } else { + int pallete_id = nds_ppu_read8(nds, bg_base + screen_base_addr + p); + if(pallete_id == 0) continue; + col = *(uint16_t *)(nds->mem.palette + pallete_offset + pallete_id * 2); + } + } else { + col = nds_ppu_read16(nds, bg_base + screen_base_addr + p * 2); + } + } else { + bg_x = bg_x & (screen_size_x - 1); + bg_y = bg_y & (screen_size_y - 1); + int bg_tile_x = bg_x / 8; + int bg_tile_y = bg_y / 8; + + int tile_off = bg_tile_y * (screen_size_x / 8) + bg_tile_x; + + // engine A screen base: BGxCNT.bits*2K + DISPCNT.bits*64K + // engine A char base: BGxCNT.bits*16K + DISPCNT.bits*64K + if(ppu_id == 0) { + character_base_addr += SB_BFE(dispcnt, 24, 3) * 64 * 1024; + screen_base_addr += SB_BFE(dispcnt, 27, 3) * 64 * 1024; + } + uint16_t tile_data = 0; + + int px = bg_x % 8; + int py = bg_y % 8; + + if(extended_bgmap) { + tile_data = nds_ppu_read16(nds, bg_base + screen_base_addr + tile_off * 2); + int h_flip = SB_BFE(tile_data, 10, 1); + int v_flip = SB_BFE(tile_data, 11, 1); + if(h_flip) px = 7 - px; + if(v_flip) py = 7 - py; + } else if(rot_scale) { + tile_data = nds_ppu_read8(nds, bg_base + screen_base_addr + tile_off); + use_ext_palettes = false; // Not supported for 8bit bg map + } else { + int tile_off = (bg_tile_y % 32) * 32 + (bg_tile_x % 32); + if(bg_tile_x >= 32) tile_off += 32 * 32; + if(bg_tile_y >= 32) tile_off += 32 * 32 * (screen_size == 3 ? 2 : 1); + tile_data = nds_ppu_read16(nds, bg_base + screen_base_addr + tile_off * 2); + // printf("tx:%d ty:%d tile_off:%08x data:%08x\n",bg_tile_x,bg_tile_y,bg_base+screen_base_addr+tile_off,tile_data); + int h_flip = SB_BFE(tile_data, 10, 1); + int v_flip = SB_BFE(tile_data, 11, 1); + if(h_flip) px = 7 - px; + if(v_flip) py = 7 - py; + } + int tile_id = SB_BFE(tile_data, 0, 10); + int palette = SB_BFE(tile_data, 12, 4); + + uint8_t tile_d = tile_id; + if(colors == false) { + tile_d = nds_ppu_read8(nds, bg_base + character_base_addr + tile_id * 8 * 4 + px / 2 + py * 4); + tile_d = (tile_d >> ((px & 1) * 4)) & 0xf; + if(tile_d == 0) continue; + tile_d += palette * 16; + use_ext_palettes = false; + } else { + tile_d = nds_ppu_read8(nds, bg_base + character_base_addr + tile_id * 8 * 8 + px + py * 8); + if(tile_d == 0) continue; + } + uint32_t palette_id = tile_d; + if(use_ext_palettes) { + palette_id = (palette)*256 + tile_d; + int ext_palette_slot = bg; + if(bg < 2) ext_palette_slot += SB_BFE(bgcnt, 13, 1) * 2; + uint32_t read_addr = (ppu_id ? NDS_VRAM_BGB_SLOT0 : NDS_VRAM_BGA_SLOT0) + palette_id * 2 + 0x2000 * (ext_palette_slot); + col = nds_ppu_read16(nds, read_addr); + } else + col = *(uint16_t *)(nds->mem.palette + pallete_offset + palette_id * 2); } - }else{ - col = nds_ppu_read16(nds,bg_base+screen_base_addr+p*2); - } - }else{ - bg_x = bg_x&(screen_size_x-1); - bg_y = bg_y&(screen_size_y-1); - int bg_tile_x = bg_x/8; - int bg_tile_y = bg_y/8; - - int tile_off = bg_tile_y*(screen_size_x/8)+bg_tile_x; - - //engine A screen base: BGxCNT.bits*2K + DISPCNT.bits*64K - //engine A char base: BGxCNT.bits*16K + DISPCNT.bits*64K - if(ppu_id==0){ - character_base_addr+=SB_BFE(dispcnt,24,3)*64*1024; - screen_base_addr+=SB_BFE(dispcnt,27,3)*64*1024; } - uint16_t tile_data =0; - - int px = bg_x%8; - int py = bg_y%8; - - if(extended_bgmap){ - tile_data=nds_ppu_read16(nds,bg_base+screen_base_addr+tile_off*2); - int h_flip = SB_BFE(tile_data,10,1); - int v_flip = SB_BFE(tile_data,11,1); - if(h_flip)px=7-px; - if(v_flip)py=7-py; - }else if(rot_scale){ - tile_data=nds_ppu_read8(nds,bg_base+screen_base_addr+tile_off); - use_ext_palettes=false; //Not supported for 8bit bg map - }else{ - int tile_off = (bg_tile_y%32)*32+(bg_tile_x%32); - if(bg_tile_x>=32)tile_off+=32*32; - if(bg_tile_y>=32)tile_off+=32*32*(screen_size==3?2:1); - tile_data=nds_ppu_read16(nds,bg_base+screen_base_addr+tile_off*2); - //printf("tx:%d ty:%d tile_off:%08x data:%08x\n",bg_tile_x,bg_tile_y,bg_base+screen_base_addr+tile_off,tile_data); - int h_flip = SB_BFE(tile_data,10,1); - int v_flip = SB_BFE(tile_data,11,1); - if(h_flip)px=7-px; - if(v_flip)py=7-py; + col |= (bg << 17) | ((5 - priority) << 28) | ((4 - bg) << 25); + if(col > ppu->first_target_buffer[lcd_x]) { + uint32_t t = ppu->first_target_buffer[lcd_x]; + ppu->first_target_buffer[lcd_x] = col; + col = t; } - int tile_id = SB_BFE(tile_data,0,10); - int palette = SB_BFE(tile_data,12,4); - - uint8_t tile_d=tile_id; - if(colors==false){ - tile_d=nds_ppu_read8(nds,bg_base+character_base_addr+tile_id*8*4+px/2+py*4); - tile_d= (tile_d>>((px&1)*4))&0xf; - if(tile_d==0)continue; - tile_d+=palette*16; - use_ext_palettes=false; - }else{ - tile_d=nds_ppu_read8(nds,bg_base+character_base_addr+tile_id*8*8+px+py*8); - if(tile_d==0)continue; - } - uint32_t palette_id = tile_d; - if(use_ext_palettes){ - palette_id=(palette)*256+tile_d; - int ext_palette_slot = bg; - if(bg<2)ext_palette_slot+=SB_BFE(bgcnt,13,1)*2; - uint32_t read_addr = (ppu_id?NDS_VRAM_BGB_SLOT0:NDS_VRAM_BGA_SLOT0)+palette_id*2+0x2000*(ext_palette_slot); - col = nds_ppu_read16(nds, read_addr); - }else col = *(uint16_t*)(nds->mem.palette+pallete_offset+palette_id*2); + if(col > ppu->second_target_buffer[lcd_x]) ppu->second_target_buffer[lcd_x] = col; } } - col |= (bg<<17) | ((5-priority)<<28)|((4-bg)<<25); - if(col>ppu->first_target_buffer[lcd_x]){ - uint32_t t = ppu->first_target_buffer[lcd_x]; - ppu->first_target_buffer[lcd_x]=col; - col = t; - } - if(col>ppu->second_target_buffer[lcd_x])ppu->second_target_buffer[lcd_x]=col; - } - } - uint32_t col = ppu->first_target_buffer[lcd_x]; - int r = SB_BFE(col,0,5); - int g = SB_BFE(col,5,5); - int b = SB_BFE(col,10,5); - uint32_t type = SB_BFE(col,17,3); - - bool effect_enable = SB_BFE(window_control,5,1); - uint16_t bldcnt = nds9_io_read16(nds,GBA_BLDCNT+reg_offset); - int mode = SB_BFE(bldcnt,6,2); - - //Semitransparent objects are always selected for blending - if(SB_BFE(col,16,1)){ - uint32_t col2 = ppu->second_target_buffer[lcd_x]; - uint32_t type2 = SB_BFE(col2,17,3); - bool blend = SB_BFE(bldcnt,8+type2,1); - if(blend){mode=1;effect_enable=true;} - else effect_enable &= SB_BFE(bldcnt,type,1); - }else effect_enable &= SB_BFE(bldcnt,type,1); - if(effect_enable){ - uint16_t bldy = nds9_io_read16(nds,GBA_BLDY+reg_offset); - float evy = SB_BFE(bldy,0,5)/16.; - if(evy>1.0)evy=1; - switch(mode){ - case 0: break; //None - case 1: { + uint32_t col = ppu->first_target_buffer[lcd_x]; + int r = SB_BFE(col, 0, 5); + int g = SB_BFE(col, 5, 5); + int b = SB_BFE(col, 10, 5); + uint32_t type = SB_BFE(col, 17, 3); + + bool effect_enable = SB_BFE(window_control, 5, 1); + uint16_t bldcnt = nds9_io_read16(nds, GBA_BLDCNT + reg_offset); + int mode = SB_BFE(bldcnt, 6, 2); + + // Semitransparent objects are always selected for blending + if(SB_BFE(col, 16, 1)) { uint32_t col2 = ppu->second_target_buffer[lcd_x]; - uint32_t type2 = SB_BFE(col2,17,3); - bool blend = SB_BFE(bldcnt,8+type2,1); - if(blend){ - uint16_t bldalpha= nds9_io_read16(nds,GBA_BLDALPHA+reg_offset); - //3d engines alpha blend based on the 3d alpha - - int r2 = SB_BFE(col2,0,5); - int g2 = SB_BFE(col2,5,5); - int b2 = SB_BFE(col2,10,5); - int eva = SB_BFE(bldalpha,0,5); - int evb = SB_BFE(bldalpha,8,5); - if(enable_3d&&type==0){ - eva = nds->framebuffer_3d_disp[(lcd_x+lcd_y*NDS_LCD_W)*4+3]/16; - if(eva==15)eva=16; - evb = 16-eva; + uint32_t type2 = SB_BFE(col2, 17, 3); + bool blend = SB_BFE(bldcnt, 8 + type2, 1); + if(blend) { + mode = 1; + effect_enable = true; + } else + effect_enable &= SB_BFE(bldcnt, type, 1); + } else + effect_enable &= SB_BFE(bldcnt, type, 1); + if(effect_enable) { + uint16_t bldy = nds9_io_read16(nds, GBA_BLDY + reg_offset); + float evy = SB_BFE(bldy, 0, 5) / 16.; + if(evy > 1.0) evy = 1; + switch(mode) { + case 0: break; // None + case 1: { + uint32_t col2 = ppu->second_target_buffer[lcd_x]; + uint32_t type2 = SB_BFE(col2, 17, 3); + bool blend = SB_BFE(bldcnt, 8 + type2, 1); + if(blend) { + uint16_t bldalpha = nds9_io_read16(nds, GBA_BLDALPHA + reg_offset); + // 3d engines alpha blend based on the 3d alpha + + int r2 = SB_BFE(col2, 0, 5); + int g2 = SB_BFE(col2, 5, 5); + int b2 = SB_BFE(col2, 10, 5); + int eva = SB_BFE(bldalpha, 0, 5); + int evb = SB_BFE(bldalpha, 8, 5); + if(enable_3d && type == 0) { + eva = nds->framebuffer_3d_disp[(lcd_x + lcd_y * NDS_LCD_W) * 4 + 3] / 16; + if(eva == 15) eva = 16; + evb = 16 - eva; + } + if(eva > 16) eva = 16; + if(evb > 16) evb = 16; + r = (r * eva + r2 * evb) / 16; + g = (g * eva + g2 * evb) / 16; + b = (b * eva + b2 * evb) / 16; + if(r > 31) r = 31; + if(g > 31) g = 31; + if(b > 31) b = 31; } - if(eva>16)eva=16; - if(evb>16)evb=16; - r = (r*eva+r2*evb)/16; - g = (g*eva+g2*evb)/16; - b = (b*eva+b2*evb)/16; - if(r>31)r = 31; - if(g>31)g = 31; - if(b>31)b = 31; + } break; // Alpha Blend + case 2: // Lighten + r = r + (31 - r) * evy; + g = g + (31 - g) * evy; + b = b + (31 - b) * evy; + break; + case 3: // Darken + r = r - (r)*evy; + g = g - (g)*evy; + b = b - (b)*evy; + break; } - }break; //Alpha Blend - case 2: //Lighten - r = r+(31-r)*evy; - g = g+(31-g)*evy; - b = b+(31-b)*evy; - break; - case 3: //Darken - r = r-(r)*evy; - g = g-(g)*evy; - b = b-(b)*evy; - break; - } - } + } - if(display_mode==2&&ppu_id==0){ - int vram_block = SB_BFE(dispcnt,18,2); - uint16_t value = ((uint16_t*)nds->mem.vram)[lcd_x+lcd_y*NDS_LCD_W+vram_block*64*1024]; - r = SB_BFE(value,0,5); - g = SB_BFE(value,5,5); - b = SB_BFE(value,10,5); - }else if(display_mode==0){ - r=31; - g=31; - b=31; - } + if(display_mode == 2 && ppu_id == 0) { + int vram_block = SB_BFE(dispcnt, 18, 2); + uint16_t value = ((uint16_t *)nds->mem.vram)[lcd_x + lcd_y * NDS_LCD_W + vram_block * 64 * 1024]; + r = SB_BFE(value, 0, 5); + g = SB_BFE(value, 5, 5); + b = SB_BFE(value, 10, 5); + } else if(display_mode == 0) { + r = 31; + g = 31; + b = 31; + } - if(enable_capture){ - int size = SB_BFE(dispcapcnt, 20,2); - int szx = 128; int szy = 128; - if(size!=0){szx=256; szy= size*64;} - if(lcd_xframebuffer_3d_disp[p*4+0],3,5); - color |= SB_BFE(nds->framebuffer_3d_disp[p*4+1],3,5)<<5; - color |= SB_BFE(nds->framebuffer_3d_disp[p*4+2],3,5)<<10; + if(enable_capture) { + int size = SB_BFE(dispcapcnt, 20, 2); + int szx = 128; + int szy = 128; + if(size != 0) { + szx = 256; + szy = size * 64; + } + if(lcd_x < szx && lcd_y < szy) { + uint16_t color = (((uint16_t)r & 0x1f)) | (((uint16_t)g & 0x1f) << 5) | (((uint16_t)b & 0x1f) << 10); + // TODO: EVA/EVB, sources other than 0 + int write_block = SB_BFE(dispcapcnt, 16, 2); + int write_offset = SB_BFE(dispcapcnt, 18, 2); + bool source_a = SB_BFE(dispcapcnt, 24, 1); + if(source_a && lcd_x < NDS_LCD_W && lcd_y < NDS_LCD_H) { + int p = lcd_x + lcd_y * NDS_LCD_W; + color = SB_BFE(nds->framebuffer_3d_disp[p * 4 + 0], 3, 5); + color |= SB_BFE(nds->framebuffer_3d_disp[p * 4 + 1], 3, 5) << 5; + color |= SB_BFE(nds->framebuffer_3d_disp[p * 4 + 2], 3, 5) << 10; + } + int capture_mode = SB_BFE(dispcapcnt, 29, 2); + + if(capture_mode >= 2) { + int r = SB_BFE(color, 0, 5); + int g = SB_BFE(color, 5, 5); + int b = SB_BFE(color, 10, 5); + int read_offset = SB_BFE(dispcapcnt, 26, 2); + uint32_t read_address = 0x06800000; + read_address += read_offset * 0x08000; + read_address += lcd_y * szx * 2 + lcd_x * 2; + uint16_t color2 = nds_ppu_read16(nds, read_address); + if(display_mode == 2) color2 = ppu->first_target_buffer[lcd_x]; + + int r2 = SB_BFE(color2, 0, 5); + int g2 = SB_BFE(color2, 5, 5); + int b2 = SB_BFE(color2, 10, 5); + int eva = SB_BFE(dispcapcnt, 0, 5); + int evb = SB_BFE(dispcapcnt, 8, 5); + + if(eva > 16) eva = 16; + if(evb > 16) evb = 16; + r = (r * eva + r2 * evb) / 16; + g = (g * eva + g2 * evb) / 16; + b = (b * eva + b2 * evb) / 16; + if(r > 31) r = 31; + if(g > 31) g = 31; + if(b > 31) b = 31; + color = SB_BFE(r, 0, 5); + color |= SB_BFE(g, 0, 5) << 5; + color |= SB_BFE(b, 0, 5) << 10; + } + uint32_t write_address = 0x06800000; + write_address += write_block * 128 * 1024; + write_address += write_offset * 0x08000; + write_address += lcd_y * szx * 2 + lcd_x * 2; + color |= 0x8000; // TODO: Confirm that captured alpha is always 1 + nds9_write16(nds, write_address, color); + } } - int capture_mode = SB_BFE(dispcapcnt,29,2); - - if(capture_mode>=2){ - int r = SB_BFE(color,0,5); - int g = SB_BFE(color,5,5); - int b = SB_BFE(color,10,5); - int read_offset = SB_BFE(dispcapcnt, 26,2); - uint32_t read_address = 0x06800000; - read_address+=read_offset*0x08000; - read_address+=lcd_y*szx*2+lcd_x*2; - uint16_t color2=nds_ppu_read16(nds,read_address); - if(display_mode==2)color2=ppu->first_target_buffer[lcd_x]; - - int r2 = SB_BFE(color2,0,5); - int g2 = SB_BFE(color2,5,5); - int b2 = SB_BFE(color2,10,5); - int eva = SB_BFE(dispcapcnt,0,5); - int evb = SB_BFE(dispcapcnt,8,5); - - if(eva>16)eva=16; - if(evb>16)evb=16; - r = (r*eva+r2*evb)/16; - g = (g*eva+g2*evb)/16; - b = (b*eva+b2*evb)/16; - if(r>31)r = 31; - if(g>31)g = 31; - if(b>31)b = 31; - color = SB_BFE(r,0,5); - color |= SB_BFE(g,0,5)<<5; - color |= SB_BFE(b,0,5)<<10; - } - uint32_t write_address = 0x06800000; - write_address+=write_block*128*1024; - write_address+=write_offset*0x08000; - write_address+=lcd_y*szx*2+lcd_x*2; - color|=0x8000;//TODO: Confirm that captured alpha is always 1 - nds9_write16(nds,write_address,color); - } - } - int disp_r = r; - int disp_g = g; - int disp_b = b; - { - uint16_t master_brightness= nds9_io_read16(nds,ppu_id==0?NDS_A_MASTER_BRIGHT:NDS9_B_MASTER_BRIGHT); - int factor = SB_BFE(master_brightness,0,5); - int mode = SB_BFE(master_brightness,14,2); - if(factor>16)factor=16; - if(mode==1){ - disp_r += (63-disp_r)*factor/16; - disp_g += (63-disp_g)*factor/16; - disp_b += (63-disp_b)*factor/16; - }else if(mode==2){ - disp_r -= disp_r*factor/16; - disp_g -= disp_g*factor/16; - disp_b -= disp_b*factor/16; - } - if(disp_r<0)r=0; - if(disp_g<0)g=0; - if(disp_b<0)b=0; + int disp_r = r; + int disp_g = g; + int disp_b = b; + { + uint16_t master_brightness = nds9_io_read16(nds, ppu_id == 0 ? NDS_A_MASTER_BRIGHT : NDS9_B_MASTER_BRIGHT); + int factor = SB_BFE(master_brightness, 0, 5); + int mode = SB_BFE(master_brightness, 14, 2); + if(factor > 16) factor = 16; + if(mode == 1) { + disp_r += (63 - disp_r) * factor / 16; + disp_g += (63 - disp_g) * factor / 16; + disp_b += (63 - disp_b) * factor / 16; + } else if(mode == 2) { + disp_r -= disp_r * factor / 16; + disp_g -= disp_g * factor / 16; + disp_b -= disp_b * factor / 16; + } + if(disp_r < 0) r = 0; + if(disp_g < 0) g = 0; + if(disp_b < 0) b = 0; - if(disp_r>31)disp_r=31; - if(disp_g>31)disp_g=31; - if(disp_b>31)disp_b=31; + if(disp_r > 31) disp_r = 31; + if(disp_g > 31) disp_g = 31; + if(disp_b > 31) disp_b = 31; + } + int p = (lcd_x + lcd_y * NDS_LCD_W) * 4; + float screen_blend_factor = 1.0 - (0.3 * nds->ghosting_strength); + if(screen_blend_factor > 1.0) screen_blend_factor = 1; + if(screen_blend_factor < 0.0) screen_blend_factor = 0; + + uint8_t *framebuffer = (ppu_id == 0) ^ nds->display_flip ? nds->framebuffer_bottom : nds->framebuffer_top; + framebuffer[p + 0] = disp_r * 7 * screen_blend_factor + framebuffer[p + 0] * (1.0 - screen_blend_factor); + framebuffer[p + 1] = disp_g * 7 * screen_blend_factor + framebuffer[p + 1] * (1.0 - screen_blend_factor); + framebuffer[p + 2] = disp_b * 7 * screen_blend_factor + framebuffer[p + 2] * (1.0 - screen_blend_factor); + int backdrop_type = 5; + uint32_t backdrop_col = (*(uint16_t *)(nds->mem.palette + GBA_BG_PALETTE + 0 * 2 + ppu_id * 1024)) | (backdrop_type << 17); + + ppu->first_target_buffer[lcd_x] = backdrop_col; + ppu->second_target_buffer[lcd_x] = backdrop_col; +#if NDS_SCANLINE_PPU == 1 + lcd_x++; + } + lcd_x = 0; } - int p = (lcd_x+lcd_y*NDS_LCD_W)*4; - float screen_blend_factor = 1.0-(0.3*nds->ghosting_strength); - if(screen_blend_factor>1.0)screen_blend_factor=1; - if(screen_blend_factor<0.0)screen_blend_factor=0; - - uint8_t *framebuffer = (ppu_id==0)^nds->display_flip?nds->framebuffer_bottom: nds->framebuffer_top; - framebuffer[p+0] = disp_r*7*screen_blend_factor+framebuffer[p+0]*(1.0-screen_blend_factor); - framebuffer[p+1] = disp_g*7*screen_blend_factor+framebuffer[p+1]*(1.0-screen_blend_factor); - framebuffer[p+2] = disp_b*7*screen_blend_factor+framebuffer[p+2]*(1.0-screen_blend_factor); - int backdrop_type = 5; - uint32_t backdrop_col = (*(uint16_t*)(nds->mem.palette + GBA_BG_PALETTE+0*2+ppu_id*1024))|(backdrop_type<<17); - - ppu->first_target_buffer[lcd_x] = backdrop_col; - ppu->second_target_buffer[lcd_x] = backdrop_col; - #if NDS_SCANLINE_PPU == 1 - lcd_x++; - } - lcd_x = 0; - } - #endif +#endif } } } -static void nds_tick_keypad(sb_joy_t*joy, nds_t* nds){ - for(int cpu=0;cpu<2;++cpu){ +static void nds_tick_keypad(sb_joy_t *joy, nds_t *nds) { + for(int cpu = 0; cpu < 2; ++cpu) { uint16_t reg_value = 0; - //Null joy updates are used to tick the joypad when mmios are set - if(joy){ - reg_value|= !(joy->inputs[SE_KEY_A]>0.3) <<0; - reg_value|= !(joy->inputs[SE_KEY_B]>0.3) <<1; - reg_value|= !(joy->inputs[SE_KEY_SELECT]>0.3)<<2; - reg_value|= !(joy->inputs[SE_KEY_START]>0.3) <<3; - reg_value|= !(joy->inputs[SE_KEY_RIGHT]>0.3) <<4; - reg_value|= !(joy->inputs[SE_KEY_LEFT]>0.3) <<5; - reg_value|= !(joy->inputs[SE_KEY_UP]>0.3) <<6; - reg_value|= !(joy->inputs[SE_KEY_DOWN]>0.3) <<7; - reg_value|= !(joy->inputs[SE_KEY_R]>0.3) <<8; - reg_value|= !(joy->inputs[SE_KEY_L]>0.3) <<9; - nds_io_store16(nds, cpu,GBA_KEYINPUT, reg_value); - }else reg_value = nds_io_read16(nds, cpu,GBA_KEYINPUT); - - uint16_t keycnt = nds_io_read16(nds,cpu,GBA_KEYCNT); - bool irq_enable = SB_BFE(keycnt,14,1); - bool irq_condition = SB_BFE(keycnt,15,1);//[0: any key, 1: all keys] - int if_bit = 0; - if(irq_enable){ - uint16_t pressed = SB_BFE(reg_value,0,10)^0x3ff; - uint16_t mask = SB_BFE(keycnt,0,10); - - if(irq_condition&&((pressed&mask)==mask))if_bit|= 1<prev_key_interrupt){ - if(cpu)nds9_send_interrupt(nds,4,if_bit); - else nds7_send_interrupt(nds,4,if_bit); + // Null joy updates are used to tick the joypad when mmios are set + if(joy) { + reg_value |= !(joy->inputs[SE_KEY_A] > 0.3) << 0; + reg_value |= !(joy->inputs[SE_KEY_B] > 0.3) << 1; + reg_value |= !(joy->inputs[SE_KEY_SELECT] > 0.3) << 2; + reg_value |= !(joy->inputs[SE_KEY_START] > 0.3) << 3; + reg_value |= !(joy->inputs[SE_KEY_RIGHT] > 0.3) << 4; + reg_value |= !(joy->inputs[SE_KEY_LEFT] > 0.3) << 5; + reg_value |= !(joy->inputs[SE_KEY_UP] > 0.3) << 6; + reg_value |= !(joy->inputs[SE_KEY_DOWN] > 0.3) << 7; + reg_value |= !(joy->inputs[SE_KEY_R] > 0.3) << 8; + reg_value |= !(joy->inputs[SE_KEY_L] > 0.3) << 9; + nds_io_store16(nds, cpu, GBA_KEYINPUT, reg_value); + } else + reg_value = nds_io_read16(nds, cpu, GBA_KEYINPUT); + + uint16_t keycnt = nds_io_read16(nds, cpu, GBA_KEYCNT); + bool irq_enable = SB_BFE(keycnt, 14, 1); + bool irq_condition = SB_BFE(keycnt, 15, 1); //[0: any key, 1: all keys] + int if_bit = 0; + if(irq_enable) { + uint16_t pressed = SB_BFE(reg_value, 0, 10) ^ 0x3ff; + uint16_t mask = SB_BFE(keycnt, 0, 10); + + if(irq_condition && ((pressed & mask) == mask)) if_bit |= 1 << GBA_INT_KEYPAD; + if(!irq_condition && ((pressed & mask) != 0)) if_bit |= 1 << GBA_INT_KEYPAD; + + if(if_bit && !nds->prev_key_interrupt) { + if(cpu) + nds9_send_interrupt(nds, 4, if_bit); + else + nds7_send_interrupt(nds, 4, if_bit); nds->prev_key_interrupt = true; - }else nds->prev_key_interrupt = false; - + } else + nds->prev_key_interrupt = false; } } - uint16_t ext_key = 0; - if(joy){ - ext_key|= !(joy->inputs[SE_KEY_X]>0.3) <<0; - ext_key|= !(joy->inputs[SE_KEY_Y]>0.3) <<1; - ext_key|= !(joy->inputs[SE_KEY_PEN_DOWN]>0.3)<<6; - ext_key|= (joy->inputs[SE_KEY_FOLD_SCREEN]>0.3) <<7; - ext_key|= (1 <<2)|(1 <<4)|(1 <<5); //always set - nds7_io_store16(nds,NDS7_EXTKEYIN,ext_key); + uint16_t ext_key = 0; + if(joy) { + ext_key |= !(joy->inputs[SE_KEY_X] > 0.3) << 0; + ext_key |= !(joy->inputs[SE_KEY_Y] > 0.3) << 1; + ext_key |= !(joy->inputs[SE_KEY_PEN_DOWN] > 0.3) << 6; + ext_key |= (joy->inputs[SE_KEY_FOLD_SCREEN] > 0.3) << 7; + ext_key |= (1 << 2) | (1 << 4) | (1 << 5); // always set + nds7_io_store16(nds, NDS7_EXTKEYIN, ext_key); } } -static void nds_tick_touch(sb_joy_t*joy, nds_t* nds){ - bool is_touched = joy->inputs[SE_KEY_PEN_DOWN]; - int x = joy->touch_pos[0]*NDS_LCD_W; - int y = joy->touch_pos[1]*NDS_LCD_H; - uint8_t* firm_data = nds->mem.firmware; - uint32_t user_data_off = (firm_data[0x21]<<8)|(firm_data[0x20]); - uint32_t tsc_data_off = user_data_off*8+0x58; - - int scr_x1 = 0, scr_x2 = 0, adc_x1 = 0, adc_x2 = 0; - int scr_y1 = 0, scr_y2 = 0, adc_y1 = 0, adc_y2 = 0; - - if(tsc_data_off+12>=NDS_FIRMWARE_SIZE){ +static void nds_tick_touch(sb_joy_t *joy, nds_t *nds) { + bool is_touched = joy->inputs[SE_KEY_PEN_DOWN]; + int x = joy->touch_pos[0] * NDS_LCD_W; + int y = joy->touch_pos[1] * NDS_LCD_H; + uint8_t *firm_data = nds->mem.firmware; + uint32_t user_data_off = (firm_data[0x21] << 8) | (firm_data[0x20]); + uint32_t tsc_data_off = user_data_off * 8 + 0x58; + + int scr_x1 = 0, scr_x2 = 0, adc_x1 = 0, adc_x2 = 0; + int scr_y1 = 0, scr_y2 = 0, adc_y1 = 0, adc_y2 = 0; + + if(tsc_data_off + 12 >= NDS_FIRMWARE_SIZE) { printf("TSC Data off is outside of firmware\n"); - }else{ - uint8_t* tsc_data = firm_data +tsc_data_off; - adc_x1 = (tsc_data[0] << 0)| (tsc_data[1] << 8); - adc_y1 = (tsc_data[2] << 0)| (tsc_data[3] << 8); + } else { + uint8_t *tsc_data = firm_data + tsc_data_off; + adc_x1 = (tsc_data[0] << 0) | (tsc_data[1] << 8); + adc_y1 = (tsc_data[2] << 0) | (tsc_data[3] << 8); scr_x1 = tsc_data[4]; scr_y1 = tsc_data[5]; - - adc_x2 = (tsc_data[6] << 0)| (tsc_data[7] << 8); - adc_y2 = (tsc_data[8] << 0)| (tsc_data[9] << 8); + adc_x2 = (tsc_data[6] << 0) | (tsc_data[7] << 8); + adc_y2 = (tsc_data[8] << 0) | (tsc_data[9] << 8); scr_x2 = tsc_data[10]; scr_y2 = tsc_data[11]; } - if(is_touched){ - nds->touch.x_reg = ((x - scr_x1 + 1) * (adc_x2 - adc_x1) / (scr_x2 - scr_x1) + adc_x1)<<3; - nds->touch.y_reg = ((y - scr_y1 + 1) * (adc_y2 - adc_y1) / (scr_y2 - scr_y1) + adc_y1)<<3; - }else{ + if(is_touched) { + nds->touch.x_reg = ((x - scr_x1 + 1) * (adc_x2 - adc_x1) / (scr_x2 - scr_x1) + adc_x1) << 3; + nds->touch.y_reg = ((y - scr_y1 + 1) * (adc_y2 - adc_y1) / (scr_y2 - scr_y1) + adc_y1) << 3; + } else { nds->touch.x_reg = 0; - nds->touch.y_reg = 0xFFF<<3; + nds->touch.y_reg = 0xFFF << 3; } - } -static FORCE_INLINE void nds_tick_dma(nds_t*nds, int last_tick){ - if(nds->activate_dmas==false)return; - nds->activate_dmas=false; +static FORCE_INLINE void nds_tick_dma(nds_t *nds, int last_tick) { + if(nds->activate_dmas == false) return; + nds->activate_dmas = false; nds->dma_wait_gx = false; - nds->dma_wait_ppu= false; - for(int cpu = 0;cpu<2;++cpu){ - nds->dma_processed[cpu]=false; - for(int i=0;i<4;++i){ - uint16_t cnt_h=nds_io_read16(nds,cpu, GBA_DMA0CNT_H+12*i); - bool enable = SB_BFE(cnt_h,15,1); - if(enable){ - bool type = SB_BFE(cnt_h,10,1); // 0: 16b 1:32b - - if(!nds->dma[cpu][i].last_enable){ + nds->dma_wait_ppu = false; + for(int cpu = 0; cpu < 2; ++cpu) { + nds->dma_processed[cpu] = false; + for(int i = 0; i < 4; ++i) { + uint16_t cnt_h = nds_io_read16(nds, cpu, GBA_DMA0CNT_H + 12 * i); + bool enable = SB_BFE(cnt_h, 15, 1); + if(enable) { + bool type = SB_BFE(cnt_h, 10, 1); // 0: 16b 1:32b + + if(!nds->dma[cpu][i].last_enable) { nds->dma[cpu][i].last_enable = enable; - nds->dma[cpu][i].source_addr=nds_io_read32(nds,cpu,GBA_DMA0SAD+12*i); - nds->dma[cpu][i].dest_addr=nds_io_read32(nds,cpu,GBA_DMA0DAD+12*i); - //GBA Suite says that these need to be force aligned - if(type){ - nds->dma[cpu][i].dest_addr&=~3; - nds->dma[cpu][i].source_addr&=~3; - }else{ - nds->dma[cpu][i].dest_addr&=~1; - nds->dma[cpu][i].source_addr&=~1; + nds->dma[cpu][i].source_addr = nds_io_read32(nds, cpu, GBA_DMA0SAD + 12 * i); + nds->dma[cpu][i].dest_addr = nds_io_read32(nds, cpu, GBA_DMA0DAD + 12 * i); + // GBA Suite says that these need to be force aligned + if(type) { + nds->dma[cpu][i].dest_addr &= ~3; + nds->dma[cpu][i].source_addr &= ~3; + } else { + nds->dma[cpu][i].dest_addr &= ~1; + nds->dma[cpu][i].source_addr &= ~1; } - nds->dma[cpu][i].current_transaction=0; - nds->dma[cpu][i].startup_delay=0; - nds->dma[cpu][i].trigger_mode = SB_BFE(cnt_h,11,3); + nds->dma[cpu][i].current_transaction = 0; + nds->dma[cpu][i].startup_delay = 0; + nds->dma[cpu][i].trigger_mode = SB_BFE(cnt_h, 11, 3); } - int dst_addr_ctl = SB_BFE(cnt_h,5,2); // 0: incr 1: decr 2: fixed 3: incr reload - int src_addr_ctl = SB_BFE(cnt_h,7,2); // 0: incr 1: decr 2: fixed 3: not allowed - bool dma_repeat = SB_BFE(cnt_h,9,1); + int dst_addr_ctl = SB_BFE(cnt_h, 5, 2); // 0: incr 1: decr 2: fixed 3: incr reload + int src_addr_ctl = SB_BFE(cnt_h, 7, 2); // 0: incr 1: decr 2: fixed 3: not allowed + bool dma_repeat = SB_BFE(cnt_h, 9, 1); int mode = nds->dma[cpu][i].trigger_mode; - if(cpu==NDS_ARM7)mode= SB_BFE(cnt_h,12,2); - bool irq_enable = SB_BFE(cnt_h,14,1); + if(cpu == NDS_ARM7) mode = SB_BFE(cnt_h, 12, 2); + bool irq_enable = SB_BFE(cnt_h, 14, 1); bool force_first_write_sequential = false; - int transfer_bytes = type? 4:2; + int transfer_bytes = type ? 4 : 2; bool skip_dma = false; - if(nds->dma[cpu][i].current_transaction==0){ - if(nds->dma[cpu][i].startup_delay>=0){ - nds->dma[cpu][i].startup_delay-=last_tick; - if(nds->dma[cpu][i].startup_delay>=0){ - nds->activate_dmas=true; + if(nds->dma[cpu][i].current_transaction == 0) { + if(nds->dma[cpu][i].startup_delay >= 0) { + nds->dma[cpu][i].startup_delay -= last_tick; + if(nds->dma[cpu][i].startup_delay >= 0) { + nds->activate_dmas = true; continue; } - nds->dma[cpu][i].startup_delay=-1; + nds->dma[cpu][i].startup_delay = -1; } - if(dst_addr_ctl==3){ - nds->dma[cpu][i].dest_addr=nds_io_read32(nds,cpu,GBA_DMA0DAD+12*i); + if(dst_addr_ctl == 3) { + nds->dma[cpu][i].dest_addr = nds_io_read32(nds, cpu, GBA_DMA0DAD + 12 * i); } bool last_vblank = nds->dma[cpu][i].last_vblank; bool last_hblank = nds->dma[cpu][i].last_hblank; nds->dma[cpu][i].last_vblank = nds->ppu[0].last_vblank; nds->dma[cpu][i].last_hblank = nds->ppu[0].last_hblank; - if(mode ==1 && (!nds->ppu[0].last_vblank||last_vblank)){ - nds->dma_wait_ppu=true; - continue; - } - if(mode==2){ - nds->dma_wait_ppu=true; - uint16_t vcount = nds_io_read16(nds,cpu,GBA_VCOUNT); - if(vcount>=NDS_LCD_H||!nds->ppu[0].last_hblank||last_hblank)continue; + if(mode == 1 && (!nds->ppu[0].last_vblank || last_vblank)) { + nds->dma_wait_ppu = true; + continue; } - //Video dma - if((mode==3)&&cpu==NDS_ARM9){ - nds->dma_wait_ppu=true; - uint16_t vcount = nds_io_read16(nds,cpu,GBA_VCOUNT); - if(!nds->ppu[0].last_hblank||last_hblank)continue; - //Video dma starts at scanline 2 - if(vcount<2)continue; - if(vcount==NDS_LCD_H+1)dma_repeat=false; + if(mode == 2) { + nds->dma_wait_ppu = true; + uint16_t vcount = nds_io_read16(nds, cpu, GBA_VCOUNT); + if(vcount >= NDS_LCD_H || !nds->ppu[0].last_hblank || last_hblank) continue; } - //GC Card DMA - if((mode==5&&cpu==NDS_ARM9)||(mode==2&&cpu==NDS_ARM7)){ - uint32_t ctl= nds_io_read32(nds,cpu,NDS_GCBUS_CTL); - uint32_t ready_mask = (1u<<31)|(1<<23); //Block Status = Word Status = 1; - if((ctl&ready_mask)!=ready_mask)continue; + // Video dma + if((mode == 3) && cpu == NDS_ARM9) { + nds->dma_wait_ppu = true; + uint16_t vcount = nds_io_read16(nds, cpu, GBA_VCOUNT); + if(!nds->ppu[0].last_hblank || last_hblank) continue; + // Video dma starts at scanline 2 + if(vcount < 2) continue; + if(vcount == NDS_LCD_H + 1) dma_repeat = false; } - if(dst_addr_ctl==3){ - nds->dma[cpu][i].dest_addr=nds_io_read32(nds,cpu,GBA_DMA0DAD+12*i); - //GBA Suite says that these need to be force aligned - if(type) nds->dma[cpu][i].dest_addr&=~3; - else nds->dma[cpu][i].dest_addr&=~1; + // GC Card DMA + if((mode == 5 && cpu == NDS_ARM9) || (mode == 2 && cpu == NDS_ARM7)) { + uint32_t ctl = nds_io_read32(nds, cpu, NDS_GCBUS_CTL); + uint32_t ready_mask = (1u << 31) | (1 << 23); // Block Status = Word Status = 1; + if((ctl & ready_mask) != ready_mask) continue; } - if(nds->dma[cpu][i].source_addr>=0x08000000&&nds->dma[cpu][i].dest_addr>=0x08000000){ - force_first_write_sequential=true; + if(dst_addr_ctl == 3) { + nds->dma[cpu][i].dest_addr = nds_io_read32(nds, cpu, GBA_DMA0DAD + 12 * i); + // GBA Suite says that these need to be force aligned + if(type) + nds->dma[cpu][i].dest_addr &= ~3; + else + nds->dma[cpu][i].dest_addr &= ~1; } - nds->last_transaction_dma=true; - uint32_t cnt = nds_io_read16(nds,cpu,GBA_DMA0CNT_L+12*i); - - if(cpu==NDS_ARM7){ - static const uint32_t src_mask[] = { 0x07FFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; - static const uint32_t dst_mask[] = { 0x07FFFFFF, 0x07FFFFFF, 0x07FFFFFF, 0x0FFFFFFF}; - static const uint32_t len_mask[] = { 0x3FFF, 0x3FFF,0x3FFF, 0x1FFFFF}; - nds->dma[cpu][i].source_addr&=src_mask[i]; - nds->dma[cpu][i].dest_addr &=dst_mask[i]; - cnt&=len_mask[i]; - if(cnt==0)cnt =len_mask[i]+1; - }else{ - static const uint32_t src_mask[] = { 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; - static const uint32_t dst_mask[] = { 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; - nds->dma[cpu][i].source_addr&=src_mask[i]; - nds->dma[cpu][i].dest_addr &=dst_mask[i]; - cnt&=0x1FFFFF; - if(cnt==0)cnt =0x200000; + if(nds->dma[cpu][i].source_addr >= 0x08000000 && nds->dma[cpu][i].dest_addr >= 0x08000000) { + force_first_write_sequential = true; } - nds_io_store16(nds,cpu,GBA_DMA0CNT_L+12*i,cnt); - if(nds->dma_log)fprintf(nds->dma_log,"DMA[%d][%d]: Src: 0x%08x DST: 0x%08x Cnt:%d mode: %d\n",cpu,i,nds->dma[cpu][i].source_addr,nds->dma[cpu][i].dest_addr,cnt,mode); - //printf("DMA[%d][%d]: Src: 0x%08x DST: 0x%08x Cnt:%d mode: %d\n",cpu,i,nds->dma[cpu][i].source_addr,nds->dma[cpu][i].dest_addr,cnt,mode); + nds->last_transaction_dma = true; + uint32_t cnt = nds_io_read16(nds, cpu, GBA_DMA0CNT_L + 12 * i); + + if(cpu == NDS_ARM7) { + static const uint32_t src_mask[] = {0x07FFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; + static const uint32_t dst_mask[] = {0x07FFFFFF, 0x07FFFFFF, 0x07FFFFFF, 0x0FFFFFFF}; + static const uint32_t len_mask[] = {0x3FFF, 0x3FFF, 0x3FFF, 0x1FFFFF}; + nds->dma[cpu][i].source_addr &= src_mask[i]; + nds->dma[cpu][i].dest_addr &= dst_mask[i]; + cnt &= len_mask[i]; + if(cnt == 0) cnt = len_mask[i] + 1; + } else { + static const uint32_t src_mask[] = {0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; + static const uint32_t dst_mask[] = {0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF}; + nds->dma[cpu][i].source_addr &= src_mask[i]; + nds->dma[cpu][i].dest_addr &= dst_mask[i]; + cnt &= 0x1FFFFF; + if(cnt == 0) cnt = 0x200000; + } + nds_io_store16(nds, cpu, GBA_DMA0CNT_L + 12 * i, cnt); + if(nds->dma_log) fprintf(nds->dma_log, "DMA[%d][%d]: Src: 0x%08x DST: 0x%08x Cnt:%d mode: %d\n", cpu, i, nds->dma[cpu][i].source_addr, nds->dma[cpu][i].dest_addr, cnt, mode); + // printf("DMA[%d][%d]: Src: 0x%08x DST: 0x%08x Cnt:%d mode: %d\n",cpu,i,nds->dma[cpu][i].source_addr,nds->dma[cpu][i].dest_addr,cnt,mode); } - - const static int dir_lookup[4]={1,-1,0,1}; - int src_dir = dir_lookup[src_addr_ctl]; - int dst_dir = dir_lookup[dst_addr_ctl]; + + const static int dir_lookup[4] = {1, -1, 0, 1}; + int src_dir = dir_lookup[src_addr_ctl]; + int dst_dir = dir_lookup[dst_addr_ctl]; uint32_t src = nds->dma[cpu][i].source_addr; uint32_t dst = nds->dma[cpu][i].dest_addr; - uint32_t cnt = nds_io_read16(nds,cpu,GBA_DMA0CNT_L+12*i); + uint32_t cnt = nds_io_read16(nds, cpu, GBA_DMA0CNT_L + 12 * i); - if(mode==0x7&&cpu==NDS_ARM9){ + if(mode == 0x7 && cpu == NDS_ARM9) { nds->dma_wait_gx = true; - if(nds->dma[cpu][i].gx_dma_subtransfer<=0){ - if(nds_gxfifo_size(nds)>=NDS_GX_DMA_THRESHOLD){ + if(nds->dma[cpu][i].gx_dma_subtransfer <= 0) { + if(nds_gxfifo_size(nds) >= NDS_GX_DMA_THRESHOLD) { continue; } - nds->dma[cpu][i].gx_dma_subtransfer=111; - }else{ + nds->dma[cpu][i].gx_dma_subtransfer = 111; + } else { nds->dma[cpu][i].gx_dma_subtransfer--; - } + } } // ROM ignores direction and always increments - if(src>=0x08000000&&src<0x0e000000) src_dir=1; - if(dst>=0x08000000&&dst<0x0e000000) dst_dir=1; + if(src >= 0x08000000 && src < 0x0e000000) src_dir = 1; + if(dst >= 0x08000000 && dst < 0x0e000000) dst_dir = 1; - if(!skip_dma){ + if(!skip_dma) { // This code is complicated to handle the per channel DMA latches that are present // Correct implementation is needed to pass latch.gba, Pokemon Pinball (intro explosion), // and the text in Lufia // TODO: There in theory should be separate latches per DMA, but that breaks Hello Kitty // and Tomb Raider - if(nds->dma[cpu][i].current_transactiondma_processed[cpu]|=true; - nds->activate_dmas|=true; + if(nds->dma[cpu][i].current_transaction < cnt) { + nds->dma_processed[cpu] |= true; + nds->activate_dmas |= true; int x = nds->dma[cpu][i].current_transaction++; - int dst_addr = dst+x*transfer_bytes*dst_dir; - int src_addr = src+x*transfer_bytes*src_dir; - if(type){ - if(src_addr>=0x02000000){ - if(cpu==NDS_ARM7)nds->dma[cpu][i].latched_transfer = nds7_read32(nds,src_addr); - else nds->dma[cpu][i].latched_transfer = nds9_read32(nds,src_addr); + int dst_addr = dst + x * transfer_bytes * dst_dir; + int src_addr = src + x * transfer_bytes * src_dir; + if(type) { + if(src_addr >= 0x02000000) { + if(cpu == NDS_ARM7) + nds->dma[cpu][i].latched_transfer = nds7_read32(nds, src_addr); + else + nds->dma[cpu][i].latched_transfer = nds9_read32(nds, src_addr); } - if(cpu==NDS_ARM7)nds7_write32(nds,dst_addr,nds->dma[cpu][i].latched_transfer); - else nds9_write32(nds,dst_addr,nds->dma[cpu][i].latched_transfer); - }else{ + if(cpu == NDS_ARM7) + nds7_write32(nds, dst_addr, nds->dma[cpu][i].latched_transfer); + else + nds9_write32(nds, dst_addr, nds->dma[cpu][i].latched_transfer); + } else { int v = 0; - if(src_addr>=0x02000000){ - if(cpu==NDS_ARM7)v=nds->dma[cpu][i].latched_transfer = nds7_read16(nds,src_addr)&0xffff; - else v=nds->dma[cpu][i].latched_transfer = nds9_read16(nds,src_addr)&0xffff; - nds->dma[cpu][i].latched_transfer |= nds->dma[cpu][i].latched_transfer<<16; - }else v = nds->dma[cpu][i].latched_transfer>>(((dst_addr)&0x3)*8); - if(cpu==NDS_ARM7)nds7_write16(nds,dst_addr,nds->dma[cpu][i].latched_transfer); - else nds9_write16(nds,dst_addr,nds->dma[cpu][i].latched_transfer); + if(src_addr >= 0x02000000) { + if(cpu == NDS_ARM7) + v = nds->dma[cpu][i].latched_transfer = nds7_read16(nds, src_addr) & 0xffff; + else + v = nds->dma[cpu][i].latched_transfer = nds9_read16(nds, src_addr) & 0xffff; + nds->dma[cpu][i].latched_transfer |= nds->dma[cpu][i].latched_transfer << 16; + } else + v = nds->dma[cpu][i].latched_transfer >> (((dst_addr)&0x3) * 8); + if(cpu == NDS_ARM7) + nds7_write16(nds, dst_addr, nds->dma[cpu][i].latched_transfer); + else + nds9_write16(nds, dst_addr, nds->dma[cpu][i].latched_transfer); } } } - if(nds->dma[cpu][i].current_transaction>=cnt){ - if(dst_addr_ctl==0||dst_addr_ctl==3) dst+=cnt*transfer_bytes; - else if(dst_addr_ctl==1)dst-=cnt*transfer_bytes; - if(src_addr_ctl==0) src+=cnt*transfer_bytes; - else if(src_addr_ctl==1)src-=cnt*transfer_bytes; - - nds->dma[cpu][i].source_addr=src; - nds->dma[cpu][i].dest_addr=dst; - if(irq_enable){ - uint32_t if_bit = 1<<(GBA_INT_DMA0+i); - if(cpu==NDS_ARM7)nds7_send_interrupt(nds,4,if_bit); - else if(cpu==NDS_ARM9)nds9_send_interrupt(nds,4,if_bit); + if(nds->dma[cpu][i].current_transaction >= cnt) { + if(dst_addr_ctl == 0 || dst_addr_ctl == 3) + dst += cnt * transfer_bytes; + else if(dst_addr_ctl == 1) + dst -= cnt * transfer_bytes; + if(src_addr_ctl == 0) + src += cnt * transfer_bytes; + else if(src_addr_ctl == 1) + src -= cnt * transfer_bytes; + + nds->dma[cpu][i].source_addr = src; + nds->dma[cpu][i].dest_addr = dst; + if(irq_enable) { + uint32_t if_bit = 1 << (GBA_INT_DMA0 + i); + if(cpu == NDS_ARM7) + nds7_send_interrupt(nds, 4, if_bit); + else if(cpu == NDS_ARM9) + nds9_send_interrupt(nds, 4, if_bit); } - if(!dma_repeat||mode==0||(mode==4&&cpu==NDS_ARM9)){ - cnt_h&=0x7fff; - //Reload on incr reload - enable =false; - nds_io_store16(nds, cpu, GBA_DMA0CNT_H+12*i,cnt_h); - }else{ - nds->dma[cpu][i].current_transaction=0; + if(!dma_repeat || mode == 0 || (mode == 4 && cpu == NDS_ARM9)) { + cnt_h &= 0x7fff; + // Reload on incr reload + enable = false; + nds_io_store16(nds, cpu, GBA_DMA0CNT_H + 12 * i, cnt_h); + } else { + nds->dma[cpu][i].current_transaction = 0; } } } nds->dma[cpu][i].last_enable = enable; - if(nds->activate_dmas)break; + if(nds->activate_dmas) break; } nds->last_transaction_dma = nds->activate_dmas; } -} -static FORCE_INLINE void nds_tick_sio(nds_t* nds){ - //Just a stub for now; - uint16_t siocnt = nds9_io_read16(nds,GBA_SIOCNT); - bool active = SB_BFE(siocnt,7,1); - bool irq_enabled = SB_BFE(siocnt,14,1); - if(active){ - - if(irq_enabled){ - uint16_t if_bit = 1<<(GBA_INT_SERIAL); - nds9_send_interrupt(nds,4,if_bit); +} +static FORCE_INLINE void nds_tick_sio(nds_t *nds) { + // Just a stub for now; + uint16_t siocnt = nds9_io_read16(nds, GBA_SIOCNT); + bool active = SB_BFE(siocnt, 7, 1); + bool irq_enabled = SB_BFE(siocnt, 14, 1); + if(active) { + + if(irq_enabled) { + uint16_t if_bit = 1 << (GBA_INT_SERIAL); + nds9_send_interrupt(nds, 4, if_bit); } - siocnt&= ~(1<<7); - nds9_io_store16(nds,GBA_SIOCNT,siocnt); + siocnt &= ~(1 << 7); + nds9_io_store16(nds, GBA_SIOCNT, siocnt); } } -static FORCE_INLINE void nds_tick_timers(nds_t* nds){ - if(nds->current_clock>=nds->next_timer_clock)nds_compute_timers(nds); +static FORCE_INLINE void nds_tick_timers(nds_t *nds) { + if(nds->current_clock >= nds->next_timer_clock) nds_compute_timers(nds); } -static void nds_compute_timers(nds_t* nds){ - - int ticks = nds->current_clock-nds->last_timer_clock; - nds->last_timer_clock=nds->current_clock; - int timer_ticks_before_event = 32768; - for(int cpu=0;cpu<2;++cpu){ - int last_timer_overflow = 0; - for(int t=0;t<4;++t){ - uint16_t tm_cnt_h = nds_io_read16(nds,cpu,GBA_TM0CNT_H+t*4); - bool enable = SB_BFE(tm_cnt_h,7,1); - nds_timer_t* timer = &(nds->timers[cpu][t]); - if(enable){ - int compensated_ticks = ticks; - uint16_t prescale = SB_BFE(tm_cnt_h,0,2); - bool count_up = SB_BFE(tm_cnt_h,2,1)&&t!=0; - bool irq_en = SB_BFE(tm_cnt_h,6,1); - uint16_t value = nds_io_read16(nds,cpu,GBA_TM0CNT_L+t*4); - if(enable!=timer->last_enable&&enable){ - timer->startup_delay=2; +static void nds_compute_timers(nds_t *nds) { + + int ticks = nds->current_clock - nds->last_timer_clock; + nds->last_timer_clock = nds->current_clock; + int timer_ticks_before_event = 32768; + for(int cpu = 0; cpu < 2; ++cpu) { + int last_timer_overflow = 0; + for(int t = 0; t < 4; ++t) { + uint16_t tm_cnt_h = nds_io_read16(nds, cpu, GBA_TM0CNT_H + t * 4); + bool enable = SB_BFE(tm_cnt_h, 7, 1); + nds_timer_t *timer = &(nds->timers[cpu][t]); + if(enable) { + int compensated_ticks = ticks; + uint16_t prescale = SB_BFE(tm_cnt_h, 0, 2); + bool count_up = SB_BFE(tm_cnt_h, 2, 1) && t != 0; + bool irq_en = SB_BFE(tm_cnt_h, 6, 1); + uint16_t value = nds_io_read16(nds, cpu, GBA_TM0CNT_L + t * 4); + if(enable != timer->last_enable && enable) { + timer->startup_delay = 2; value = timer->reload_value; - nds_io_store16(nds,cpu,GBA_TM0CNT_L+t*4,value); + nds_io_store16(nds, cpu, GBA_TM0CNT_L + t * 4, value); } - if(timer->startup_delay>=0){ - timer->startup_delay-=ticks; + if(timer->startup_delay >= 0) { + timer->startup_delay -= ticks; timer->last_enable = enable; - if(timer->startup_delay>=0){ - if(timer->startup_delaystartup_delay; + if(timer->startup_delay >= 0) { + if(timer->startup_delay < timer_ticks_before_event && irq_en) timer_ticks_before_event = timer->startup_delay; continue; } - compensated_ticks=-timer->startup_delay; - timer->startup_delay=-1; - timer->prescaler_timer=0; + compensated_ticks = -timer->startup_delay; + timer->startup_delay = -1; + timer->prescaler_timer = 0; } - if(count_up){ - if(last_timer_overflow){ - uint32_t v= value; - v+=last_timer_overflow; - last_timer_overflow=0; - while(v>0xffff){ - v=(v+timer->reload_value)-0x10000; + if(count_up) { + if(last_timer_overflow) { + uint32_t v = value; + v += last_timer_overflow; + last_timer_overflow = 0; + while(v > 0xffff) { + v = (v + timer->reload_value) - 0x10000; last_timer_overflow++; } - value=v; + value = v; } - }else{ - last_timer_overflow=0; + } else { + last_timer_overflow = 0; int prescale_time = timer->prescaler_timer; - prescale_time+=compensated_ticks; - const int prescaler_lookup[]={0,6,8,10}; - int prescale_duty = prescaler_lookup[prescale]; - - int increment = prescale_time>>prescale_duty; - prescale_time = prescale_time&((1<0xffff){ - v=(v+timer->reload_value)-0x10000; + prescale_time += compensated_ticks; + const int prescaler_lookup[] = {0, 6, 8, 10}; + int prescale_duty = prescaler_lookup[prescale]; + + int increment = prescale_time >> prescale_duty; + prescale_time = prescale_time & ((1 << prescale_duty) - 1); + int v = value + increment; + while(v > 0xffff) { + v = (v + timer->reload_value) - 0x10000; last_timer_overflow++; } - value = v; - timer->prescaler_timer=prescale_time; - int ticks_before_overflow = (int)(0xffff-value)<<(prescale_duty); - if(ticks_before_overflowprescaler_timer = prescale_time; + int ticks_before_overflow = (int)(0xffff - value) << (prescale_duty); + if(ticks_before_overflow < timer_ticks_before_event && irq_en) timer_ticks_before_event = ticks_before_overflow; } - timer->reload_value=timer->pending_reload_value; - if(last_timer_overflow && irq_en){ - uint16_t if_bit = 1<<(GBA_INT_TIMER0+t); - if(cpu==NDS_ARM9)nds9_send_interrupt(nds,4,if_bit); - else nds7_send_interrupt(nds,4,if_bit); + timer->reload_value = timer->pending_reload_value; + if(last_timer_overflow && irq_en) { + uint16_t if_bit = 1 << (GBA_INT_TIMER0 + t); + if(cpu == NDS_ARM9) + nds9_send_interrupt(nds, 4, if_bit); + else + nds7_send_interrupt(nds, 4, if_bit); } - nds_io_store16(nds,cpu,GBA_TM0CNT_L+t*4,value); - }else last_timer_overflow=0; + nds_io_store16(nds, cpu, GBA_TM0CNT_L + t * 4, value); + } else + last_timer_overflow = 0; timer->last_enable = enable; } } - nds->next_timer_clock=nds->current_clock+timer_ticks_before_event; + nds->next_timer_clock = nds->current_clock + timer_ticks_before_event; } -static FORCE_INLINE float nds_compute_vol_env_slope(int length_of_step,int dir){ - float step_time = length_of_step/64.0; - float slope = 1./step_time; - if(dir==0)slope*=-1; - if(length_of_step==0)slope=0; - return slope/16.; -} -static FORCE_INLINE float nds_polyblep(float t,float dt){ - if(t<=dt){ - t = t/dt; - return t+t-t*t-1.0;; - }else if (t >= 1-dt){ - t=(t-1.0)/dt; - return t*t+t+t+1.0; - }else return 0; +static FORCE_INLINE float nds_compute_vol_env_slope(int length_of_step, int dir) { + float step_time = length_of_step / 64.0; + float slope = 1. / step_time; + if(dir == 0) slope *= -1; + if(length_of_step == 0) slope = 0; + return slope / 16.; } -static FORCE_INLINE float nds_bandlimited_square(float t, float duty_cycle,float dt){ +static FORCE_INLINE float nds_polyblep(float t, float dt) { + if(t <= dt) { + t = t / dt; + return t + t - t * t - 1.0; + ; + } else if(t >= 1 - dt) { + t = (t - 1.0) / dt; + return t * t + t + t + 1.0; + } else + return 0; +} +static FORCE_INLINE float nds_bandlimited_square(float t, float duty_cycle, float dt) { float t2 = t - duty_cycle; - if(t2< 0.0)t2 +=1.0; + if(t2 < 0.0) t2 += 1.0; float y = t < duty_cycle ? -1 : 1; - y -= nds_polyblep(t,dt); - y += nds_polyblep(t2,dt); + y -= nds_polyblep(t, dt); + y += nds_polyblep(t2, dt); return y; } -static FORCE_INLINE void nds_tick_interrupts(nds_t*nds){ - if(nds->active_if_pipe_stages){ +static FORCE_INLINE void nds_tick_interrupts(nds_t *nds) { + if(nds->active_if_pipe_stages) { uint32_t if_bit = nds->nds9_pipelined_if[0]; - if(if_bit){ - uint32_t if_val = nds9_io_read32(nds,NDS9_IF); + if(if_bit) { + uint32_t if_val = nds9_io_read32(nds, NDS9_IF); if_val |= if_bit; - nds9_io_store32(nds,NDS9_IF,if_val); + nds9_io_store32(nds, NDS9_IF, if_val); } if_bit = nds->nds7_pipelined_if[0]; - if(if_bit){ - uint32_t if_val = nds7_io_read32(nds,NDS7_IF); + if(if_bit) { + uint32_t if_val = nds7_io_read32(nds, NDS7_IF); if_val |= if_bit; - nds7_io_store32(nds,NDS7_IF,if_val); + nds7_io_store32(nds, NDS7_IF, if_val); } - nds->nds9_pipelined_if[0]=nds->nds9_pipelined_if[1]; - nds->nds9_pipelined_if[1]=nds->nds9_pipelined_if[2]; - nds->nds9_pipelined_if[2]=nds->nds9_pipelined_if[3]; - nds->nds9_pipelined_if[3]=nds->nds9_pipelined_if[4]; - nds->nds9_pipelined_if[4]=0; - - nds->nds7_pipelined_if[0]=nds->nds7_pipelined_if[1]; - nds->nds7_pipelined_if[1]=nds->nds7_pipelined_if[2]; - nds->nds7_pipelined_if[2]=nds->nds7_pipelined_if[3]; - nds->nds7_pipelined_if[3]=nds->nds7_pipelined_if[4]; - nds->nds7_pipelined_if[4]=0; - - nds->active_if_pipe_stages>>=1; + nds->nds9_pipelined_if[0] = nds->nds9_pipelined_if[1]; + nds->nds9_pipelined_if[1] = nds->nds9_pipelined_if[2]; + nds->nds9_pipelined_if[2] = nds->nds9_pipelined_if[3]; + nds->nds9_pipelined_if[3] = nds->nds9_pipelined_if[4]; + nds->nds9_pipelined_if[4] = 0; + + nds->nds7_pipelined_if[0] = nds->nds7_pipelined_if[1]; + nds->nds7_pipelined_if[1] = nds->nds7_pipelined_if[2]; + nds->nds7_pipelined_if[2] = nds->nds7_pipelined_if[3]; + nds->nds7_pipelined_if[3] = nds->nds7_pipelined_if[4]; + nds->nds7_pipelined_if[4] = 0; + + nds->active_if_pipe_stages >>= 1; } } -static uint8_t nds_bin_to_bcd(uint8_t bin){ - bin%=100; - return (bin%10)|((bin/10)<<4); +static uint8_t nds_bin_to_bcd(uint8_t bin) { + bin %= 100; + return (bin % 10) | ((bin / 10) << 4); } -void nds_tick_rtc(nds_t*nds){ - time_t time_secs= time(NULL); - struct tm * tm = localtime(&time_secs); +void nds_tick_rtc(nds_t *nds) { + time_t time_secs = time(NULL); + struct tm *tm = localtime(&time_secs); nds->rtc.second = nds_bin_to_bcd(tm->tm_sec); nds->rtc.minute = nds_bin_to_bcd(tm->tm_min); - nds->rtc.hour = nds_bin_to_bcd(tm->tm_hour); - nds->rtc.day = nds_bin_to_bcd(tm->tm_mday); - nds->rtc.month = nds_bin_to_bcd(tm->tm_mon+1); - nds->rtc.year = nds_bin_to_bcd(tm->tm_year%100); - nds->rtc.day_of_week=nds_bin_to_bcd(tm->tm_wday); + nds->rtc.hour = nds_bin_to_bcd(tm->tm_hour); + nds->rtc.day = nds_bin_to_bcd(tm->tm_mday); + nds->rtc.month = nds_bin_to_bcd(tm->tm_mon + 1); + nds->rtc.year = nds_bin_to_bcd(tm->tm_year % 100); + nds->rtc.day_of_week = nds_bin_to_bcd(tm->tm_wday); } -static FORCE_INLINE void nds_tick_audio(nds_t*nds, sb_emu_state_t*emu, double delta_time, int cycles){ +static FORCE_INLINE void nds_tick_audio(nds_t *nds, sb_emu_state_t *emu, double delta_time, int cycles) { + + nds_audio_t *audio = &nds->audio; + if(delta_time > 1.0 / 60.) delta_time = 1.0 / 60.; + audio->current_sim_time += delta_time; + float sample_delta_t = 1.0 / SE_AUDIO_SAMPLE_RATE; - nds_audio_t* audio = &nds->audio; - if(delta_time>1.0/60.)delta_time = 1.0/60.; - audio->current_sim_time +=delta_time; - float sample_delta_t = 1.0/SE_AUDIO_SAMPLE_RATE; + while(audio->current_sample_generated_time < audio->current_sim_time) { + uint64_t current_cycles = audio->current_sample_generated_time * 33513982; - while(audio->current_sample_generated_time < audio->current_sim_time){ - uint64_t current_cycles = audio->current_sample_generated_time*33513982; + audio->current_sample_generated_time += sample_delta_t; + uint64_t next_cycles = audio->current_sample_generated_time * 33513982; + audio->cycles_since_tick = next_cycles - current_cycles; - audio->current_sample_generated_time+=sample_delta_t; - uint64_t next_cycles = audio->current_sample_generated_time*33513982; - audio->cycles_since_tick=next_cycles-current_cycles; - const float lowpass_coef = 0.999; - float l = 0, r = 0; - for(int c = 0; c<16;++c){ - uint32_t cnt = nds7_io_read32(nds,NDS7_SOUND0_CNT+c*16); - bool enable = SB_BFE(cnt,31,1); - uint32_t tmr = nds7_io_read16(nds,NDS7_SOUND0_TMR+c*16)*2; - int format = SB_BFE(cnt,29,2);//(0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise); - if(!enable){ - audio->channel[c].sample=0; + float l = 0, r = 0; + for(int c = 0; c < 16; ++c) { + uint32_t cnt = nds7_io_read32(nds, NDS7_SOUND0_CNT + c * 16); + bool enable = SB_BFE(cnt, 31, 1); + uint32_t tmr = nds7_io_read16(nds, NDS7_SOUND0_TMR + c * 16) * 2; + int format = SB_BFE(cnt, 29, 2); //(0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise); + if(!enable) { + audio->channel[c].sample = 0; audio->channel[c].lfsr = 0x7FFF; audio->channel[c].timer = tmr; - emu->audio_channel_output[c] = emu->audio_channel_output[c]*lowpass_coef; + emu->audio_channel_output[c] = emu->audio_channel_output[c] * lowpass_coef; continue; } - uint32_t sad = nds7_io_read32(nds,NDS7_SOUND0_SAD+c*16); - uint16_t pnt = nds7_io_read16(nds,NDS7_SOUND0_PNT+c*16); - uint16_t len = nds7_io_read32(nds,NDS7_SOUND0_LEN+c*16); - uint32_t tot_samps = len*4; - switch(format){ - case 0: tot_samps = (len+pnt)*4; pnt*=4;break; - case 1: tot_samps = (len+pnt)*2; pnt*=2;break; - case 2: tot_samps = 8*(len+pnt-1); pnt=(pnt-1)*8;break; - case 3: tot_samps = 8; break; + uint32_t sad = nds7_io_read32(nds, NDS7_SOUND0_SAD + c * 16); + uint16_t pnt = nds7_io_read16(nds, NDS7_SOUND0_PNT + c * 16); + uint16_t len = nds7_io_read32(nds, NDS7_SOUND0_LEN + c * 16); + uint32_t tot_samps = len * 4; + switch(format) { + case 0: + tot_samps = (len + pnt) * 4; + pnt *= 4; + break; + case 1: + tot_samps = (len + pnt) * 2; + pnt *= 2; + break; + case 2: + tot_samps = 8 * (len + pnt - 1); + pnt = (pnt - 1) * 8; + break; + case 3: tot_samps = 8; break; } - if(enable){ - float v = 0; - switch(format){ - case 0: v= ((int8_t)nds7_read8(nds,sad+audio->channel[c].sample))/128.;break; - case 1: v= ((int16_t)nds7_read16(nds,sad+audio->channel[c].sample*2))/32768.;break; - case 2: v= ((int16_t)audio->channel[c].adpcm_sample) / 32768.0;break; - case 3: - if(c>=8&&c<=13)v= (audio->channel[c].samplechannel[c].lfsr&1){ + if(enable) { + float v = 0; + switch(format) { + case 0: v = ((int8_t)nds7_read8(nds, sad + audio->channel[c].sample)) / 128.; break; + case 1: v = ((int16_t)nds7_read16(nds, sad + audio->channel[c].sample * 2)) / 32768.; break; + case 2: v = ((int16_t)audio->channel[c].adpcm_sample) / 32768.0; break; + case 3: + if(c >= 8 && c <= 13) + v = (audio->channel[c].sample < SB_BFE(cnt, 24, 3)) * 2. - 1.; // Todo: add antialiasing + else if(c == 14 || c == 15) { // PSG Noise + if(audio->channel[c].lfsr & 1) { v = -1.; - audio->channel[c].lfsr^=0x6000<<1; - }else v= 1; - audio->channel[c].lfsr>>=1; + audio->channel[c].lfsr ^= 0x6000 << 1; + } else + v = 1; + audio->channel[c].lfsr >>= 1; } - break; + break; } - uint32_t vol_mul = SB_BFE(cnt,0,7); - uint32_t vol_div = SB_BFE(cnt,8,2); - uint16_t pan = SB_BFE(cnt,16,7); - float div_table[4]={1.0,0.5,0.25,1.0/16.}; - v*=vol_mul*div_table[vol_div]/128.; - emu->audio_channel_output[c] = emu->audio_channel_output[c]*lowpass_coef + fabs(v)*(1.0-lowpass_coef); - r+=v*pan/128.; - l+=v*(128-pan)/128.; + uint32_t vol_mul = SB_BFE(cnt, 0, 7); + uint32_t vol_div = SB_BFE(cnt, 8, 2); + uint16_t pan = SB_BFE(cnt, 16, 7); + float div_table[4] = {1.0, 0.5, 0.25, 1.0 / 16.}; + v *= vol_mul * div_table[vol_div] / 128.; + emu->audio_channel_output[c] = emu->audio_channel_output[c] * lowpass_coef + fabs(v) * (1.0 - lowpass_coef); + r += v * pan / 128.; + l += v * (128 - pan) / 128.; } - audio->channel[c].timer+=audio->cycles_since_tick; - while(audio->channel[c].timer>0x1ffff){ - audio->channel[c].timer-=0x20000; - audio->channel[c].timer+=tmr; - if(audio->channel[c].sample+1>=tot_samps){ - int repeat_mode = SB_BFE(cnt,27,2); - switch(repeat_mode){ - case 0: audio->channel[c].sample=0; enable=false;break; //Manual (TODO: Does this repeat?) - case 1: - audio->channel[c].sample=pnt; - if(format==2){//ADPCM - audio->channel[c].adpcm_sample = audio->channel[c].adpcm_sample_latch; - audio->channel[c].adpcm_index = audio->channel[c].adpcm_index_latch; - } - break; //Infinite - case 2: audio->channel[c].sample=0;enable=false; break; //One Shot - case 3: audio->channel[c].sample=0;enable=false; break; //Reserved + audio->channel[c].timer += audio->cycles_since_tick; + while(audio->channel[c].timer > 0x1ffff) { + audio->channel[c].timer -= 0x20000; + audio->channel[c].timer += tmr; + if(audio->channel[c].sample + 1 >= tot_samps) { + int repeat_mode = SB_BFE(cnt, 27, 2); + switch(repeat_mode) { + case 0: + audio->channel[c].sample = 0; + enable = false; + break; // Manual (TODO: Does this repeat?) + case 1: + audio->channel[c].sample = pnt; + if(format == 2) { // ADPCM + audio->channel[c].adpcm_sample = audio->channel[c].adpcm_sample_latch; + audio->channel[c].adpcm_index = audio->channel[c].adpcm_index_latch; + } + break; // Infinite + case 2: + audio->channel[c].sample = 0; + enable = false; + break; // One Shot + case 3: + audio->channel[c].sample = 0; + enable = false; + break; // Reserved } - if(format==3){enable=true;audio->channel[c].sample=0;} - if(!enable){ - cnt&=~(1u<<31); - nds7_io_store32(nds,NDS7_SOUND0_CNT+c*16,cnt); + if(format == 3) { + enable = true; + audio->channel[c].sample = 0; + } + if(!enable) { + cnt &= ~(1u << 31); + nds7_io_store32(nds, NDS7_SOUND0_CNT + c * 16, cnt); } } - if(format==2){ - if(audio->channel[c].sample==pnt){ - audio->channel[c].adpcm_index_latch=audio->channel[c].adpcm_index; - audio->channel[c].adpcm_sample_latch=audio->channel[c].adpcm_sample; - } - static const int16_t adpcm_table[89] ={ - 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, - 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, + if(format == 2) { + if(audio->channel[c].sample == pnt) { + audio->channel[c].adpcm_index_latch = audio->channel[c].adpcm_index; + audio->channel[c].adpcm_sample_latch = audio->channel[c].adpcm_sample; + } + static const int16_t adpcm_table[89] = { + 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, + 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, - 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, + 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133, 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, @@ -6749,246 +8014,251 @@ static FORCE_INLINE void nds_tick_audio(nds_t*nds, sb_emu_state_t*emu, double de 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, 0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, - 0x7FFF - }; - static const int adpcm_indextable[8]={ -1, -1, -1, -1, 2, 4, 6, 8 }; - if(audio->channel[c].sample==0){ - uint32_t header = nds7_read32(nds,sad); - audio->channel[c].adpcm_sample = (int16_t)(header & 0xFFFF); - audio->channel[c].adpcm_index = (header >> 16) & 0x7F; - if(audio->channel[c].adpcm_index>88)audio->channel[c].adpcm_index=88; - } - uint8_t data = nds7_read8(nds,sad+audio->channel[c].sample/2+4); - data = (data>>((audio->channel[c].sample&1)*4))&0xf; - - int16_t entry = adpcm_table[audio->channel[c].adpcm_index]; - int16_t diff = entry >> 3; - if (data & 1) diff += entry >> 2; - if (data & 2) diff += entry >> 1; - if (data & 4) diff += entry; - - if (data & 8) audio->channel[c].adpcm_sample = audio->channel[c].adpcm_sample - diff; - else audio->channel[c].adpcm_sample = audio->channel[c].adpcm_sample + diff; - if(audio->channel[c].adpcm_sample>+0x7FFF)audio->channel[c].adpcm_sample=0x7fff; - if(audio->channel[c].adpcm_sample<-0x7FFF)audio->channel[c].adpcm_sample=-0x7fff; - int new_index = audio->channel[c].adpcm_index + adpcm_indextable[data & 7]; - if(new_index>88)new_index=88; - if(new_index<0)new_index=0; - audio->channel[c].adpcm_index =new_index; + 0x7FFF}; + static const int adpcm_indextable[8] = {-1, -1, -1, -1, 2, 4, 6, 8}; + if(audio->channel[c].sample == 0) { + uint32_t header = nds7_read32(nds, sad); + audio->channel[c].adpcm_sample = (int16_t)(header & 0xFFFF); + audio->channel[c].adpcm_index = (header >> 16) & 0x7F; + if(audio->channel[c].adpcm_index > 88) audio->channel[c].adpcm_index = 88; + } + uint8_t data = nds7_read8(nds, sad + audio->channel[c].sample / 2 + 4); + data = (data >> ((audio->channel[c].sample & 1) * 4)) & 0xf; + + int16_t entry = adpcm_table[audio->channel[c].adpcm_index]; + int16_t diff = entry >> 3; + if(data & 1) diff += entry >> 2; + if(data & 2) diff += entry >> 1; + if(data & 4) diff += entry; + + if(data & 8) + audio->channel[c].adpcm_sample = audio->channel[c].adpcm_sample - diff; + else + audio->channel[c].adpcm_sample = audio->channel[c].adpcm_sample + diff; + if(audio->channel[c].adpcm_sample > +0x7FFF) audio->channel[c].adpcm_sample = 0x7fff; + if(audio->channel[c].adpcm_sample < -0x7FFF) audio->channel[c].adpcm_sample = -0x7fff; + int new_index = audio->channel[c].adpcm_index + adpcm_indextable[data & 7]; + if(new_index > 88) new_index = 88; + if(new_index < 0) new_index = 0; + audio->channel[c].adpcm_index = new_index; } - audio->channel[c].sample+=1; + audio->channel[c].sample += 1; } } // Clipping - if(l>1.0)l=1; - if(r>1.0)r=1; - if(l<-1.0)l=-1; - if(r<-1.0)r=-1; - l*=0.5; - r*=0.5; - - if((sb_ring_buffer_size(&emu->audio_ring_buff)+3>SB_AUDIO_RING_BUFFER_SIZE)) continue; + if(l > 1.0) l = 1; + if(r > 1.0) r = 1; + if(l < -1.0) l = -1; + if(r < -1.0) r = -1; + l *= 0.5; + r *= 0.5; + + if((sb_ring_buffer_size(&emu->audio_ring_buff) + 3 > SB_AUDIO_RING_BUFFER_SIZE)) continue; // Quantization - unsigned write_entry0 = (emu->audio_ring_buff.write_ptr++)%SB_AUDIO_RING_BUFFER_SIZE; - unsigned write_entry1 = (emu->audio_ring_buff.write_ptr++)%SB_AUDIO_RING_BUFFER_SIZE; - - emu->mix_l_volume = emu->mix_l_volume*lowpass_coef + fabs(l)*(1.0-lowpass_coef); - emu->mix_r_volume = emu->mix_r_volume*lowpass_coef + fabs(r)*(1.0-lowpass_coef); + unsigned write_entry0 = (emu->audio_ring_buff.write_ptr++) % SB_AUDIO_RING_BUFFER_SIZE; + unsigned write_entry1 = (emu->audio_ring_buff.write_ptr++) % SB_AUDIO_RING_BUFFER_SIZE; + emu->mix_l_volume = emu->mix_l_volume * lowpass_coef + fabs(l) * (1.0 - lowpass_coef); + emu->mix_r_volume = emu->mix_r_volume * lowpass_coef + fabs(r) * (1.0 - lowpass_coef); - emu->audio_ring_buff.data[write_entry0] = l*32760; - emu->audio_ring_buff.data[write_entry1] = r*32760; - audio->cycles_since_tick=0; + emu->audio_ring_buff.data[write_entry0] = l * 32760; + emu->audio_ring_buff.data[write_entry1] = r * 32760; + audio->cycles_since_tick = 0; } } - -void nds_tick(sb_emu_state_t* emu, nds_t* nds, nds_scratch_t* scratch){ - //printf("#####New Frame#####\n"); +void nds_tick(sb_emu_state_t *emu, nds_t *nds, nds_scratch_t *scratch) { + // printf("#####New Frame#####\n"); nds->ghosting_strength = emu->screen_ghosting_strength; - nds->arm7.read8 = nds7_arm_read8; - nds->arm7.read16 = nds7_arm_read16; - nds->arm7.read32 = nds7_arm_read32; + nds->arm7.read8 = nds7_arm_read8; + nds->arm7.read16 = nds7_arm_read16; + nds->arm7.read32 = nds7_arm_read32; nds->arm7.read16_seq = nds7_arm_read16_seq; nds->arm7.read32_seq = nds7_arm_read32_seq; - nds->arm7.write8 = nds7_arm_write8; - nds->arm7.write16 = nds7_arm_write16; - nds->arm7.write32 = nds7_arm_write32; - nds->arm9.read8 = nds9_arm_read8; - nds->arm9.read16 = nds9_arm_read16; - nds->arm9.read32 = nds9_arm_read32; + nds->arm7.write8 = nds7_arm_write8; + nds->arm7.write16 = nds7_arm_write16; + nds->arm7.write32 = nds7_arm_write32; + nds->arm9.read8 = nds9_arm_read8; + nds->arm9.read16 = nds9_arm_read16; + nds->arm9.read32 = nds9_arm_read32; nds->arm9.read16_seq = nds9_arm_read16_seq; nds->arm9.read32_seq = nds9_arm_read32_seq; - nds->arm9.write8 = nds9_arm_write8; - nds->arm9.write16 = nds9_arm_write16; - nds->arm9.write32 = nds9_arm_write32; - nds->arm9.coprocessor_read = nds->arm7.coprocessor_read =nds_coprocessor_read; - nds->arm9.coprocessor_write= nds->arm7.coprocessor_write=nds_coprocessor_write; - - nds->arm7.user_data = (void*)nds; - nds->arm9.user_data = (void*)nds; - - nds->mem.nds7_bios=scratch->nds7_bios; - nds->mem.nds9_bios=scratch->nds9_bios; - nds->mem.firmware=scratch->firmware; + nds->arm9.write8 = nds9_arm_write8; + nds->arm9.write16 = nds9_arm_write16; + nds->arm9.write32 = nds9_arm_write32; + nds->arm9.coprocessor_read = nds->arm7.coprocessor_read = nds_coprocessor_read; + nds->arm9.coprocessor_write = nds->arm7.coprocessor_write = nds_coprocessor_write; + + nds->arm7.user_data = (void *)nds; + nds->arm9.user_data = (void *)nds; + + nds->mem.nds7_bios = scratch->nds7_bios; + nds->mem.nds9_bios = scratch->nds9_bios; + nds->mem.firmware = scratch->firmware; nds->mem.save_data = scratch->save_data; nds->mem.card_data = emu->rom_data; nds->mem.card_size = emu->rom_size; - nds->framebuffer_top=scratch->framebuffer_top; - nds->framebuffer_bottom=scratch->framebuffer_bottom; - nds->framebuffer_3d_depth=scratch->framebuffer_3d_depth; - nds->framebuffer_3d=scratch->framebuffer_3d; - nds->framebuffer_3d_disp=scratch->framebuffer_3d_disp; - nds->gpu.vert_buffer=scratch->vert_buffer; + nds->framebuffer_top = scratch->framebuffer_top; + nds->framebuffer_bottom = scratch->framebuffer_bottom; + nds->framebuffer_3d_depth = scratch->framebuffer_3d_depth; + nds->framebuffer_3d = scratch->framebuffer_3d; + nds->framebuffer_3d_disp = scratch->framebuffer_3d_disp; + nds->gpu.vert_buffer = scratch->vert_buffer; nds_tick_rtc(nds); - nds_tick_keypad(&emu->joy,nds); - nds_tick_touch(&emu->joy,nds); - bool prev_vblank=true; + nds_tick_keypad(&emu->joy, nds); + nds_tick_touch(&emu->joy, nds); + bool prev_vblank = true; - uint64_t* d = (uint64_t*)nds->mem.mmio_debug_access_buffer; - for(int i=0;imem.mmio_debug_access_buffer)/8;++i){ - d[i]&=0x9191919191919191ULL; + uint64_t *d = (uint64_t *)nds->mem.mmio_debug_access_buffer; + for(int i = 0; i < sizeof(nds->mem.mmio_debug_access_buffer) / 8; ++i) { + d[i] &= 0x9191919191919191ULL; } - nds->ppu[0].new_frame=false; - while(!nds->ppu[0].new_frame){ - bool gx_fifo_full = nds_gxfifo_size(nds)>=NDS_GXFIFO_SIZE; - if(!gx_fifo_full){ - nds_tick_dma(nds,true); - if(SB_LIKELY(!nds->dma_processed[0] &&!nds->mem.slow_bus_cycles)){ - uint32_t int7_if = nds7_io_read32(nds,NDS7_IF); - if(int7_if){ - uint32_t ie = nds7_io_read32(nds,NDS7_IE); - uint32_t ime = nds7_io_read32(nds,NDS7_IME); - int7_if&=ie; - if((ime&0x1)&&int7_if) arm7_process_interrupts(&nds->arm7, int7_if); + nds->ppu[0].new_frame = false; + while(!nds->ppu[0].new_frame) { + bool gx_fifo_full = nds_gxfifo_size(nds) >= NDS_GXFIFO_SIZE; + if(!gx_fifo_full) { + nds_tick_dma(nds, true); + if(SB_LIKELY(!nds->dma_processed[0] && !nds->mem.slow_bus_cycles)) { + uint32_t int7_if = nds7_io_read32(nds, NDS7_IF); + if(int7_if) { + uint32_t ie = nds7_io_read32(nds, NDS7_IE); + uint32_t ime = nds7_io_read32(nds, NDS7_IME); + int7_if &= ie; + if((ime & 0x1) && int7_if) arm7_process_interrupts(&nds->arm7, int7_if); } - if(SB_UNLIKELY(nds->arm7.registers[PC]== emu->pc_breakpoint))nds->arm7.trigger_breakpoint=true; - else arm7_exec_instruction(&nds->arm7); + if(SB_UNLIKELY(nds->arm7.registers[PC] == emu->pc_breakpoint)) + nds->arm7.trigger_breakpoint = true; + else + arm7_exec_instruction(&nds->arm7); } - if(SB_LIKELY(!nds->dma_processed[1])){ - uint32_t int9_if = nds9_io_read32(nds,NDS9_IF); - if(int9_if){ - int9_if &= nds9_io_read32(nds,NDS9_IE); - uint32_t ime = nds9_io_read32(nds,NDS9_IME); - if((ime&0x1)&&int9_if) arm7_process_interrupts(&nds->arm9, int9_if); + if(SB_LIKELY(!nds->dma_processed[1])) { + uint32_t int9_if = nds9_io_read32(nds, NDS9_IF); + if(int9_if) { + int9_if &= nds9_io_read32(nds, NDS9_IE); + uint32_t ime = nds9_io_read32(nds, NDS9_IME); + if((ime & 0x1) && int9_if) arm7_process_interrupts(&nds->arm9, int9_if); } - if(SB_LIKELY(!nds->arm9.wait_for_interrupt)){ - if(SB_UNLIKELY(nds->arm9.registers[PC]== emu->pc_breakpoint))nds->arm9.trigger_breakpoint=true; - else{ - nds->arm9.i_cycles=0; + if(SB_LIKELY(!nds->arm9.wait_for_interrupt)) { + if(SB_UNLIKELY(nds->arm9.registers[PC] == emu->pc_breakpoint)) + nds->arm9.trigger_breakpoint = true; + else { + nds->arm9.i_cycles = 0; arm9_exec_instruction(&nds->arm9); - if(SB_UNLIKELY(nds->arm9.registers[PC]== emu->pc_breakpoint))nds->arm9.trigger_breakpoint=true; - else if(!nds->arm9.i_cycles)arm9_exec_instruction(&nds->arm9); - nds->mem.slow_bus_cycles+=nds->arm9.i_cycles/2; + if(SB_UNLIKELY(nds->arm9.registers[PC] == emu->pc_breakpoint)) + nds->arm9.trigger_breakpoint = true; + else if(!nds->arm9.i_cycles) + arm9_exec_instruction(&nds->arm9); + nds->mem.slow_bus_cycles += nds->arm9.i_cycles / 2; } } } - if(SB_UNLIKELY(nds->arm7.trigger_breakpoint||nds->arm9.trigger_breakpoint)){ + if(SB_UNLIKELY(nds->arm7.trigger_breakpoint || nds->arm9.trigger_breakpoint)) { emu->run_mode = SB_MODE_PAUSE; - nds->arm7.trigger_breakpoint=false; - nds->arm9.trigger_breakpoint=false; + nds->arm7.trigger_breakpoint = false; + nds->arm9.trigger_breakpoint = false; break; } - } + } int ticks = 1; - if(nds->mem.slow_bus_cycles){ + if(nds->mem.slow_bus_cycles) { ticks = nds->mem.slow_bus_cycles; - nds->mem.slow_bus_cycles = 0; + nds->mem.slow_bus_cycles = 0; } - while(ticks){ + while(ticks) { int ppu_fast_forward = nds->ppu_fast_forward_ticks; - if(nds->gpu.cmd_busy_cycles&&nds->gpu.cmd_busy_cycles<=ppu_fast_forward)ppu_fast_forward=nds->gpu.cmd_busy_cycles; - int timer_fast_forward = nds->next_timer_clock-nds->current_clock; - int fast_forward_ticks=ppu_fast_forwardarm9.wait_for_interrupt&&nds->arm7.wait_for_interrupt)&&fast_forward_ticks>ticks)&&!gx_fifo_full)fast_forward_ticks=ticks; - nds->ppu_fast_forward_ticks-=fast_forward_ticks; - if(SB_UNLIKELY(nds->active_if_pipe_stages)){ - for(int i=0;igpu.cmd_busy_cycles && nds->gpu.cmd_busy_cycles <= ppu_fast_forward) ppu_fast_forward = nds->gpu.cmd_busy_cycles; + int timer_fast_forward = nds->next_timer_clock - nds->current_clock; + int fast_forward_ticks = ppu_fast_forward < timer_fast_forward ? ppu_fast_forward : timer_fast_forward; + if(SB_LIKELY(fast_forward_ticks)) { + if(SB_LIKELY(!(nds->arm9.wait_for_interrupt && nds->arm7.wait_for_interrupt) && fast_forward_ticks > ticks) && !gx_fifo_full) fast_forward_ticks = ticks; + nds->ppu_fast_forward_ticks -= fast_forward_ticks; + if(SB_UNLIKELY(nds->active_if_pipe_stages)) { + for(int i = 0; i < fast_forward_ticks; ++i) + nds_tick_interrupts(nds); } - if(nds->gpu.cmd_busy_cycles){ - nds->gpu.cmd_busy_cycles-=fast_forward_ticks-1; + if(nds->gpu.cmd_busy_cycles) { + nds->gpu.cmd_busy_cycles -= fast_forward_ticks - 1; } nds_tick_gx(nds); - nds->current_clock+=fast_forward_ticks; - ticks =ticks<=fast_forward_ticks?0:ticks-fast_forward_ticks; + nds->current_clock += fast_forward_ticks; + ticks = ticks <= fast_forward_ticks ? 0 : ticks - fast_forward_ticks; } - int audio_ticks = fast_forward_ticks+(ticks!=0); - for(int i=0;icurrent_clock+=1; + if(SB_UNLIKELY(ticks)) { + nds->current_clock += 1; nds_tick_interrupts(nds); nds_tick_timers(nds); - nds_tick_ppu(nds,emu->render_frame); + nds_tick_ppu(nds, emu->render_frame); nds_tick_gx(nds); - ticks-=1; + ticks -= 1; } } } } // See: http://merry.usamimi.org/archex/SysReg_v84A_xml-00bet7/enc_index.xml#mcr_mrc_32 -uint32_t nds_coprocessor_read(void* user_data, int coproc,int opcode,int Cn, int Cm,int Cp){ - if(coproc!=15){ - printf("Coprocessor read from unsupported coprocessor:%d\n",coproc); - return 0; +uint32_t nds_coprocessor_read(void *user_data, int coproc, int opcode, int Cn, int Cm, int Cp) { + if(coproc != 15) { + printf("Coprocessor read from unsupported coprocessor:%d\n", coproc); + return 0; } - if(opcode!=0)printf("Unsupported opcode(%x) for coproc %d\n",opcode,coproc); - nds_t * nds = (nds_t*)(user_data); - return nds->cp15.reg[(Cn*16+Cm)*8+Cp]; + if(opcode != 0) printf("Unsupported opcode(%x) for coproc %d\n", opcode, coproc); + nds_t *nds = (nds_t *)(user_data); + return nds->cp15.reg[(Cn * 16 + Cm) * 8 + Cp]; } -void nds_coprocessor_write(void* user_data, int coproc,int opcode,int Cn, int Cm,int Cp,uint32_t data){ - if(coproc!=15){ - printf("Coprocessor write to unsupported coprocessor:%d\n",coproc); - return; +void nds_coprocessor_write(void *user_data, int coproc, int opcode, int Cn, int Cm, int Cp, uint32_t data) { + if(coproc != 15) { + printf("Coprocessor write to unsupported coprocessor:%d\n", coproc); + return; } - if(opcode!=0)printf("Unsupported opcode(%x) for coproc %d\n",opcode,coproc); - nds_t * nds = (nds_t*)(user_data); - nds->cp15.reg[(Cn*16+Cm)*8+Cp]=data; - //C9,C1,0 - Data TCM Size/Base (R/W) - //C9,C1,1 - Instruction TCM Size/Base (R/W) - if(Cn==1&&Cm==0){ - //C1,C0,0 - Control Register (R/W, or R=Fixed) - nds->mem.dtcm_enable = SB_BFE(data, 16,1); - nds->mem.dtcm_load_mode= SB_BFE(data, 17,1); - nds->mem.itcm_enable = SB_BFE(data, 18,1); - nds->mem.itcm_load_mode= SB_BFE(data, 19,1); - }else if(Cn==9&&Cm==1){ - int size = SB_BFE(data,1,5); - int base = SB_BFE(data,12,20); - if(Cp==0){ - nds->mem.dtcm_start_address = base<<12; - nds->mem.dtcm_end_address = nds->mem.dtcm_start_address+ (512<cp15.reg[(Cn*16+Cm)*8+Cp]=data&(0x3f); - - nds->mem.itcm_start_address = base<<12; - nds->mem.itcm_end_address = nds->mem.itcm_start_address+ (512<mem.itcm_start_address,nds->mem.itcm_end_address); + if(opcode != 0) printf("Unsupported opcode(%x) for coproc %d\n", opcode, coproc); + nds_t *nds = (nds_t *)(user_data); + nds->cp15.reg[(Cn * 16 + Cm) * 8 + Cp] = data; + // C9,C1,0 - Data TCM Size/Base (R/W) + // C9,C1,1 - Instruction TCM Size/Base (R/W) + if(Cn == 1 && Cm == 0) { + // C1,C0,0 - Control Register (R/W, or R=Fixed) + nds->mem.dtcm_enable = SB_BFE(data, 16, 1); + nds->mem.dtcm_load_mode = SB_BFE(data, 17, 1); + nds->mem.itcm_enable = SB_BFE(data, 18, 1); + nds->mem.itcm_load_mode = SB_BFE(data, 19, 1); + } else if(Cn == 9 && Cm == 1) { + int size = SB_BFE(data, 1, 5); + int base = SB_BFE(data, 12, 20); + if(Cp == 0) { + nds->mem.dtcm_start_address = base << 12; + nds->mem.dtcm_end_address = nds->mem.dtcm_start_address + (512 << size); + } else if(Cp == 1) { + base = 0; + // ITCM base is read only on the NDS + nds->cp15.reg[(Cn * 16 + Cm) * 8 + Cp] = data & (0x3f); + + nds->mem.itcm_start_address = base << 12; + nds->mem.itcm_end_address = nds->mem.itcm_start_address + (512 << size); + printf("ITCM Start:0x%08x End: 0x%08x\n", nds->mem.itcm_start_address, nds->mem.itcm_end_address); } - }else if(Cn==7){ - int size = SB_BFE(data,1,5); - int base = SB_BFE(data,12,20); - if((Cm==0&&Cp==4)||(Cm==8&&Cp==2)){ - nds->arm9.wait_for_interrupt = true; + } else if(Cn == 7) { + int size = SB_BFE(data, 1, 5); + int base = SB_BFE(data, 12, 20); + if((Cm == 0 && Cp == 4) || (Cm == 8 && Cp == 2)) { + nds->arm9.wait_for_interrupt = true; } - }else{ - printf("Unhandled: Cn:%d Cm:%d Cp:%d\n",Cn,Cm,Cp); + } else { + printf("Unhandled: Cn:%d Cm:%d Cp:%d\n", Cn, Cm, Cp); } } -static bool nds_run_ar_cheat(nds_t* nds, const uint32_t* buffer, uint32_t size){ - if(!buffer){ +static bool nds_run_ar_cheat(nds_t *nds, const uint32_t *buffer, uint32_t size) { + if(!buffer) { printf("Invalid Action Replay cheat buffer\n"); return false; } - if(size%2!=0){ - printf("Invalid Action Replay cheat size:%d\n",size); + if(size % 2 != 0) { + printf("Invalid Action Replay cheat size:%d\n", size); return false; } @@ -6996,315 +8266,314 @@ static bool nds_run_ar_cheat(nds_t* nds, const uint32_t* buffer, uint32_t size){ // stack for if statements // the first element is always true - bool if_stack[32] = {true}; + bool if_stack[32] = {true}; size_t if_stack_index = 0; // repeat blocks can't be nested uint32_t repeat_count = 0; - size_t repeat_block_index = 0; - size_t repeat_if_stack_index = 0; + size_t repeat_block_index = 0; + size_t repeat_if_stack_index = 0; - uint8_t current_code = 0; + uint8_t current_code = 0; uint16_t current_byte = 0; - for(int i=0;i> 28; current_byte = buffer[i] >> 24; // check if we're in an if that has evaluated to false, and the current instruction // isn't an "End-if" or an "End-code" - if (!if_stack[if_stack_index] && current_byte != 0xD0 && current_byte != 0xD2) { + if(!if_stack[if_stack_index] && current_byte != 0xD0 && current_byte != 0xD2) { // skip this instruction continue; } - switch(current_code){ - case 0x0:{ - // 0XXXXXXX YYYYYYYY - // 32bit write of YYYYYYYY to location: (xxxxxxx + ‘offset’) - uint32_t address = buffer[i] & 0x0fffffff; - uint32_t data = buffer[i+1]; - address += offset_register; - nds9_debug_write32(nds,address,data); + switch(current_code) { + case 0x0: { + // 0XXXXXXX YYYYYYYY + // 32bit write of YYYYYYYY to location: (xxxxxxx + ‘offset’) + uint32_t address = buffer[i] & 0x0fffffff; + uint32_t data = buffer[i + 1]; + address += offset_register; + nds9_debug_write32(nds, address, data); + break; + } + case 0x1: { + // 1XXXXXXX ????YYYY + // 16bit write of YYYY to location: (xxxxxxx + ‘offset’) + uint32_t address = buffer[i] & 0x0fffffff; + uint16_t data = buffer[i + 1] & 0x0000ffff; + address += offset_register; + nds9_debug_write16(nds, address, data); + break; + } + case 0x2: { + // 2XXXXXXX ??????YY + // 8bit write of YY to location: (xxxxxxx + ‘offset’) + uint32_t address = buffer[i] & 0x0fffffff; + uint8_t data = buffer[i + 1] & 0x000000ff; + address += offset_register; + nds9_debug_write8(nds, address, data); + break; + } + case 0x3: { + // 3XXXXXXX YYYYYYYY 32bit ‘If less-than’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) < YYYYYYYY then + // execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint32_t data = buffer[i + 1]; + if(address == 0) address = offset_register; + uint32_t value = nds9_debug_read32(nds, address); + bool condition = value < data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0x4: { + // 4XXXXXXX YYYYYYYY 32bit ‘If greater-than’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) > YYYYYYYY then + // execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint32_t data = buffer[i + 1]; + if(address == 0) address = offset_register; + uint32_t value = nds9_debug_read32(nds, address); + bool condition = value > data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0x5: { + // 5XXXXXXX YYYYYYYY 32bit ‘If equal’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) == YYYYYYYY then + // execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint32_t data = buffer[i + 1]; + if(address == 0) address = offset_register; + uint32_t value = nds9_debug_read32(nds, address); + bool condition = value == data; + if_stack_index++; + if_stack[if_stack_index] = condition; + printf("%08x %08x %d\n", value, data, condition); + break; + } + case 0x6: { + // 6XXXXXXX YYYYYYYY 32bit ‘If not equal’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) != YYYYYYYY then + // execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint32_t data = buffer[i + 1]; + if(address == 0) address = offset_register; + uint32_t value = nds9_debug_read32(nds, address); + bool condition = value != data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0x7: { + // 7XXXXXXX ZZZZYYYY 16bit ‘If less-than’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ < + // YYYY then execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint16_t data = buffer[i + 1] & 0x0000ffff; + uint16_t mask = ~(buffer[i + 1] >> 16); + if(address == 0) address = offset_register; + uint16_t value = nds9_debug_read16(nds, address); + bool condition = (value & mask) < data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0x8: { + // 8XXXXXXX ZZZZYYYY 16bit ‘If greater-than’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ > + // YYYY then execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint16_t data = buffer[i + 1] & 0x0000ffff; + uint16_t mask = ~(buffer[i + 1] >> 16); + if(address == 0) address = offset_register; + uint16_t value = nds9_debug_read16(nds, address); + bool condition = (value & mask) > data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0x9: { + // 9XXXXXXX ZZZZYYYY 16bit ‘If equal’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ == + // YYYY then execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint16_t data = buffer[i + 1] & 0x0000ffff; + uint16_t mask = ~(buffer[i + 1] >> 16); + if(address == 0) address = offset_register; + uint16_t value = nds9_debug_read16(nds, address); + bool condition = (value & mask) == data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0xA: { + // AXXXXXXX ZZZZYYYY 16bit ‘If not equal’ instruction + // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ != + // YYYY then execute the following block of instructions + uint32_t address = buffer[i] & 0x0fffffff; + uint16_t data = buffer[i + 1] & 0x0000ffff; + uint16_t mask = ~(buffer[i + 1] >> 16); + if(address == 0) address = offset_register; + uint16_t value = nds9_debug_read16(nds, address); + bool condition = (value & mask) != data; + if_stack_index++; + if_stack[if_stack_index] = condition; + break; + } + case 0xB: { + // BXXXXXXX ???????? + // Loads the offset register with the data at address (XXXXXXX + ‘offset’) + uint32_t address = buffer[i] & 0x0fffffff; + address += offset_register; + offset_register = nds9_debug_read32(nds, address); + break; + } + case 0xC: { + // C??????? NNNNNNNN + // Repeat operation, repeats a block of codes for NNNNNNNN times + // Repeats blocks cannot contain further repeats + uint32_t count = buffer[i + 1]; + repeat_count = buffer[i + 1]; + repeat_block_index = i; + repeat_if_stack_index = if_stack_index; + break; + } + case 0xD: { + switch(current_byte) { + case 0xD0: { + // End-if instruction + if_stack_index--; break; } - case 0x1:{ - // 1XXXXXXX ????YYYY - // 16bit write of YYYY to location: (xxxxxxx + ‘offset’) - uint32_t address = buffer[i] & 0x0fffffff; - uint16_t data = buffer[i+1] & 0x0000ffff; - address += offset_register; - nds9_debug_write16(nds,address,data); + case 0xD1: { + // End-repeat instruction + // Also implicitly ends any conditional instructions inside the repeat block + if(repeat_count > 0) { + repeat_count--; + i = repeat_block_index; + if_stack_index = repeat_if_stack_index; + } break; } - case 0x2:{ - // 2XXXXXXX ??????YY - // 8bit write of YY to location: (xxxxxxx + ‘offset’) - uint32_t address = buffer[i] & 0x0fffffff; - uint8_t data = buffer[i+1] & 0x000000ff; - address += offset_register; - nds9_debug_write8(nds,address,data); + case 0xD2: { + // End-code instruction + if(repeat_count > 0) { + repeat_count--; + i = repeat_block_index; + } else { + if_stack_index = 0; + } break; } - case 0x3:{ - // 3XXXXXXX YYYYYYYY 32bit ‘If less-than’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) < YYYYYYYY then - // execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint32_t data = buffer[i+1]; - if (address == 0) address = offset_register; - uint32_t value = nds9_debug_read32(nds,address); - bool condition = value < data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xD3: { + // Set offset register + offset_register = buffer[i + 1]; break; } - case 0x4:{ - // 4XXXXXXX YYYYYYYY 32bit ‘If greater-than’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) > YYYYYYYY then - // execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint32_t data = buffer[i+1]; - if (address == 0) address = offset_register; - uint32_t value = nds9_debug_read32(nds,address); - bool condition = value > data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xD4: { + // Add to stored register + stored_register += buffer[i + 1]; break; } - case 0x5:{ - // 5XXXXXXX YYYYYYYY 32bit ‘If equal’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) == YYYYYYYY then - // execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint32_t data = buffer[i+1]; - if (address == 0) address = offset_register; - uint32_t value = nds9_debug_read32(nds,address); - bool condition = value == data; - if_stack_index++; - if_stack[if_stack_index] = condition; - printf("%08x %08x %d\n",value,data,condition); + case 0xD5: { + // Set stored register + stored_register = buffer[i + 1]; break; } - case 0x6:{ - // 6XXXXXXX YYYYYYYY 32bit ‘If not equal’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) != YYYYYYYY then - // execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint32_t data = buffer[i+1]; - if (address == 0) address = offset_register; - uint32_t value = nds9_debug_read32(nds,address); - bool condition = value != data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xD6: { + // 32 bit store and increment + uint32_t address = buffer[i + 1]; + address += offset_register; + nds9_debug_write32(nds, address, stored_register); + offset_register += 4; break; } - case 0x7:{ - // 7XXXXXXX ZZZZYYYY 16bit ‘If less-than’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ < - // YYYY then execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint16_t data = buffer[i+1] & 0x0000ffff; - uint16_t mask = ~(buffer[i+1] >> 16); - if (address == 0) address = offset_register; - uint16_t value = nds9_debug_read16(nds,address); - bool condition = (value & mask) < data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xD7: { + // 16 bit store and increment + uint32_t address = buffer[i + 1]; + address += offset_register; + nds9_debug_write16(nds, address, stored_register); + offset_register += 2; break; } - case 0x8:{ - // 8XXXXXXX ZZZZYYYY 16bit ‘If greater-than’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ > - // YYYY then execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint16_t data = buffer[i+1] & 0x0000ffff; - uint16_t mask = ~(buffer[i+1] >> 16); - if (address == 0) address = offset_register; - uint16_t value = nds9_debug_read16(nds,address); - bool condition = (value & mask) > data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xD8: { + // 8 bit store and increment + uint32_t address = buffer[i + 1]; + address += offset_register; + nds9_debug_write8(nds, address, stored_register); + offset_register += 1; break; } - case 0x9:{ - // 9XXXXXXX ZZZZYYYY 16bit ‘If equal’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ == - // YYYY then execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint16_t data = buffer[i+1] & 0x0000ffff; - uint16_t mask = ~(buffer[i+1] >> 16); - if (address == 0) address = offset_register; - uint16_t value = nds9_debug_read16(nds,address); - bool condition = (value & mask) == data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xD9: { + // 32 bit load into stored register + uint32_t address = buffer[i + 1]; + address += offset_register; + stored_register = nds9_debug_read32(nds, address); break; } - case 0xA:{ - // AXXXXXXX ZZZZYYYY 16bit ‘If not equal’ instruction - // If the value at (XXXXXXX or ‘offset’ when address is 0) masked by ZZZZ != - // YYYY then execute the following block of instructions - uint32_t address = buffer[i] & 0x0fffffff; - uint16_t data = buffer[i+1] & 0x0000ffff; - uint16_t mask = ~(buffer[i+1] >> 16); - if (address == 0) address = offset_register; - uint16_t value = nds9_debug_read16(nds,address); - bool condition = (value & mask) != data; - if_stack_index++; - if_stack[if_stack_index] = condition; + case 0xDA: { + // 16 bit load into stored register + uint32_t address = buffer[i + 1]; + address += offset_register; + stored_register = nds9_debug_read16(nds, address); break; } - case 0xB:{ - // BXXXXXXX ???????? - // Loads the offset register with the data at address (XXXXXXX + ‘offset’) - uint32_t address = buffer[i] & 0x0fffffff; + case 0xDB: { + // 8 bit load into stored register + uint32_t address = buffer[i + 1]; address += offset_register; - offset_register = nds9_debug_read32(nds,address); + stored_register = nds9_debug_read8(nds, address); break; } - case 0xC:{ - // C??????? NNNNNNNN - // Repeat operation, repeats a block of codes for NNNNNNNN times - // Repeats blocks cannot contain further repeats - uint32_t count = buffer[i+1]; - repeat_count = buffer[i+1]; - repeat_block_index = i; - repeat_if_stack_index = if_stack_index; + case 0xDC: { + // increment offset register + offset_register += buffer[i + 1]; break; } - case 0xD:{ - switch(current_byte){ - case 0xD0:{ - // End-if instruction - if_stack_index--; - break; - } - case 0xD1:{ - // End-repeat instruction - // Also implicitly ends any conditional instructions inside the repeat block - if (repeat_count > 0){ - repeat_count--; - i = repeat_block_index; - if_stack_index = repeat_if_stack_index; - } - break; - } - case 0xD2:{ - // End-code instruction - if (repeat_count > 0){ - repeat_count--; - i = repeat_block_index; - } else { - if_stack_index=0; - } - break; - } - case 0xD3:{ - // Set offset register - offset_register = buffer[i+1]; - break; - } - case 0xD4:{ - // Add to stored register - stored_register += buffer[i+1]; - break; - } - case 0xD5:{ - // Set stored register - stored_register = buffer[i+1]; - break; - } - case 0xD6:{ - // 32 bit store and increment - uint32_t address = buffer[i+1]; - address += offset_register; - nds9_debug_write32(nds,address,stored_register); - offset_register += 4; - break; - } - case 0xD7:{ - // 16 bit store and increment - uint32_t address = buffer[i+1]; - address += offset_register; - nds9_debug_write16(nds,address,stored_register); - offset_register += 2; - break; - } - case 0xD8:{ - // 8 bit store and increment - uint32_t address = buffer[i+1]; - address += offset_register; - nds9_debug_write8(nds,address,stored_register); - offset_register += 1; - break; - } - case 0xD9:{ - // 32 bit load into stored register - uint32_t address = buffer[i+1]; - address += offset_register; - stored_register = nds9_debug_read32(nds,address); - break; - } - case 0xDA:{ - // 16 bit load into stored register - uint32_t address = buffer[i+1]; - address += offset_register; - stored_register = nds9_debug_read16(nds,address); - break; - } - case 0xDB:{ - // 8 bit load into stored register - uint32_t address = buffer[i+1]; - address += offset_register; - stored_register = nds9_debug_read8(nds,address); - break; - } - case 0xDC:{ - // increment offset register - offset_register += buffer[i+1]; - break; - } - default:{ - // Unknown instruction - printf("Unknown instruction: %08X %08X\n", buffer[i], buffer[i+1]); - return false; - } - } - break; + default: { + // Unknown instruction + printf("Unknown instruction: %08X %08X\n", buffer[i], buffer[i + 1]); + return false; } - case 0xE:{ - // EXXXXXXX NNNNNNNN Direct memory write - // VVVVVVVV VVVVVVVV - // ... (NNNNNNNN times) - // Writes NNNNNNNN bytes from the list of values VVVVVVVV to the addresses - // starting at (XXXXXXX + ‘offset’) - uint32_t address = buffer[i] & 0x0fffffff; - address += offset_register; - uint32_t count = buffer[i+1]; - for (uint32_t j=0;j=size)return false; - nds9_debug_write32(nds,address+j, buffer[ind]); - } - i+=count/4; - if (i % 2 == 1) i++; - break; } - case 0xF:{ - // FXXXXXXX NNNNNNNN Memory copy - // Copies NNNNNNNN bytes from addresses starting at the ‘offset’ register to - // addresses starting at XXXXXXXX - uint32_t address = buffer[i] & 0x0fffffff; - uint32_t count = buffer[i+1]; - for(uint32_t j=0; j= size) return false; + nds9_debug_write32(nds, address + j, buffer[ind]); + } + i += count / 4; + if(i % 2 == 1) i++; + break; + } + case 0xF: { + // FXXXXXXX NNNNNNNN Memory copy + // Copies NNNNNNNN bytes from addresses starting at the ‘offset’ register to + // addresses starting at XXXXXXXX + uint32_t address = buffer[i] & 0x0fffffff; + uint32_t count = buffer[i + 1]; + for(uint32_t j = 0; j < count; j++) { + uint8_t value = nds9_debug_read8(nds, offset_register + j); + nds9_debug_write8(nds, address + j, value); } + break; + } } - } return true;