1 #include <stdint.h>
2 #include <cstring>
3 #include <string>
4
5 #include "bootloader.h"
6
7 namespace gambatte {
8
Bootloader()9 Bootloader::Bootloader() {
10 get_raw_bootloader_data = NULL;
11 }
12
patch_gbc_to_gba_mode()13 void Bootloader::patch_gbc_to_gba_mode() {
14 /*moves one jump over another and puts ld b,0x01 into the original position*/
15 uint16_t patchloc = 0xF2;
16 uint8_t patch[0x7] = {0xCD,0xD0,0x05/*<-call systemsetup*/,0x06,0x01/*<-ld b,0x1*/,0x00/*<-nop*/,0x00/*<-nop*/};
17 std::memcpy(bootromswapspace + patchloc, patch, 0x7);
18 }
19
load(bool isgbc,bool isgba)20 void Bootloader::load(bool isgbc, bool isgba) {
21 if (get_raw_bootloader_data == NULL) {
22 using_bootloader = false;
23 return;
24 }
25
26 //the gba only uses the gbc bios
27 if (isgba)
28 isgbc = true;
29
30 bool bootloaderavail = get_raw_bootloader_data((void*)this, isgbc, bootromswapspace, 0x900/*buf_size*/);
31 if (!bootloaderavail) {
32 using_bootloader = false;
33 return;
34 }
35
36 if (isgbc)
37 bootloadersize = 0x900;
38 else
39 bootloadersize = 0x100;
40
41 if (isgba)//patch bootloader to fake gba mode
42 patch_gbc_to_gba_mode();
43
44 //backup rom segment that is shared with bootloader
45 std::memcpy(rombackup, (uint8_t*)addrspace_start, bootloadersize);
46
47 //put back cartridge data in a 256 byte window of the bios that is not mapped(GBC only)
48 if (isgbc)
49 std::memcpy(bootromswapspace + 0x100, rombackup + 0x100, 0x100);
50
51 //put bootloader in main memory
52 std::memcpy((uint8_t*)addrspace_start, bootromswapspace, bootloadersize);
53
54 using_bootloader = true;
55 }
56
reset()57 void Bootloader::reset() {
58 bootloadersize = 0;
59 has_called_FF50 = false;
60 addrspace_start = NULL;
61 using_bootloader = false;
62 }
63
set_bootloader_getter(bool (* getter)(void * userdata,bool isgbc,uint8_t * data,uint32_t buf_size))64 void Bootloader::set_bootloader_getter(bool (*getter)(void* userdata, bool isgbc, uint8_t* data, uint32_t buf_size)) {
65 get_raw_bootloader_data = getter;
66 }
67
set_address_space_start(void * start)68 void Bootloader::set_address_space_start(void* start) {
69 addrspace_start = start;
70 }
71
choosebank(bool inbootloader)72 void Bootloader::choosebank(bool inbootloader) {
73 //inbootloader = (state.mem.ioamhram.get()[0x150] != 0xFF);//do not uncomment this is just for reference
74 if (using_bootloader) {
75
76 //switching from game to bootloader with savestate
77 if (inbootloader && has_called_FF50)
78 uncall_FF50();
79
80 //switching from bootloader to game with savestate
81 else if (!inbootloader && !has_called_FF50)
82 call_FF50();
83
84 //switching from game to game or bootloader to bootloader needs no changes
85
86 }
87 }
88
call_FF50()89 void Bootloader::call_FF50() {
90 if (!has_called_FF50 && using_bootloader) {
91 //put rom back in main memory when bootloader has finished
92 std::memcpy((uint8_t*)addrspace_start, rombackup, bootloadersize);
93 has_called_FF50 = true;
94 }
95 }
96
97 //this is a developer function only,a real gameboy can never undo calling 0xFF50,this function is for savestate functionality
uncall_FF50()98 void Bootloader::uncall_FF50() {
99 std::memcpy((uint8_t*)addrspace_start, bootromswapspace, bootloadersize);
100 has_called_FF50 = false;
101 }
102
103 }
104