akkera 102
/
gba_rpc
GameBoy Advance Multiboot & RPC
multiboot.cpp@0:147f4cedc929, 2014-12-09 (annotated)
- Committer:
- akkera102
- Date:
- Tue Dec 09 08:58:06 2014 +0000
- Revision:
- 0:147f4cedc929
GameBoy Advance Multiboot & Dumper
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
akkera102 | 0:147f4cedc929 | 1 | // mbed GBA Loader - Boot up a GameBoy Advance using Multiboot (no cart req.) |
akkera102 | 0:147f4cedc929 | 2 | // |
akkera102 | 0:147f4cedc929 | 3 | // Ken Kaarvik kkaarvik@yahoo.com Nov 13, 2010 |
akkera102 | 0:147f4cedc929 | 4 | // akkera102 Nov 08, 2014(modified) |
akkera102 | 0:147f4cedc929 | 5 | // |
akkera102 | 0:147f4cedc929 | 6 | // mbed(LPC1768) gba serial port(color) |
akkera102 | 0:147f4cedc929 | 7 | // p1-0V 6-GND (blue) |
akkera102 | 0:147f4cedc929 | 8 | // p5-mosi 3-SI (orange) |
akkera102 | 0:147f4cedc929 | 9 | // p6-miso 2-SO (red) |
akkera102 | 0:147f4cedc929 | 10 | // p7-sck 5-SC (green) |
akkera102 | 0:147f4cedc929 | 11 | // |
akkera102 | 0:147f4cedc929 | 12 | // The GBA file that you wish to load into the GBA is stored on the mbed's local file system. |
akkera102 | 0:147f4cedc929 | 13 | // Apply power to the mbed (or reset) before turning on the GBA. |
akkera102 | 0:147f4cedc929 | 14 | |
akkera102 | 0:147f4cedc929 | 15 | #include "multiboot.h" |
akkera102 | 0:147f4cedc929 | 16 | |
akkera102 | 0:147f4cedc929 | 17 | static LocalFileSystem local("local"); |
akkera102 | 0:147f4cedc929 | 18 | static Serial pc(USBTX, USBRX); |
akkera102 | 0:147f4cedc929 | 19 | static SPI spi(p5, p6, p7); |
akkera102 | 0:147f4cedc929 | 20 | |
akkera102 | 0:147f4cedc929 | 21 | |
akkera102 | 0:147f4cedc929 | 22 | uint32_t WriteSPI32(uint32_t w, char* msg) |
akkera102 | 0:147f4cedc929 | 23 | { |
akkera102 | 0:147f4cedc929 | 24 | uint32_t r = WriteSPI32NoDebug(w); |
akkera102 | 0:147f4cedc929 | 25 | |
akkera102 | 0:147f4cedc929 | 26 | pc.printf("0x%08x 0x%08x ; %s\n",r , w, msg); |
akkera102 | 0:147f4cedc929 | 27 | return r; |
akkera102 | 0:147f4cedc929 | 28 | } |
akkera102 | 0:147f4cedc929 | 29 | |
akkera102 | 0:147f4cedc929 | 30 | uint32_t WriteSPI32NoDebug(uint32_t w) |
akkera102 | 0:147f4cedc929 | 31 | { |
akkera102 | 0:147f4cedc929 | 32 | uint16_t w1 = w >> 16; |
akkera102 | 0:147f4cedc929 | 33 | uint16_t w2 = w & 0xffff; |
akkera102 | 0:147f4cedc929 | 34 | |
akkera102 | 0:147f4cedc929 | 35 | uint32_t r; |
akkera102 | 0:147f4cedc929 | 36 | r = spi.write(w1) << 16; |
akkera102 | 0:147f4cedc929 | 37 | r = spi.write(w2) | r; |
akkera102 | 0:147f4cedc929 | 38 | |
akkera102 | 0:147f4cedc929 | 39 | return r; |
akkera102 | 0:147f4cedc929 | 40 | } |
akkera102 | 0:147f4cedc929 | 41 | |
akkera102 | 0:147f4cedc929 | 42 | void WaitSPI32(uint32_t w, uint32_t comp, char* msg) |
akkera102 | 0:147f4cedc929 | 43 | { |
akkera102 | 0:147f4cedc929 | 44 | pc.printf("%s 0x%08x\n", msg, comp); |
akkera102 | 0:147f4cedc929 | 45 | uint32_t r; |
akkera102 | 0:147f4cedc929 | 46 | |
akkera102 | 0:147f4cedc929 | 47 | do |
akkera102 | 0:147f4cedc929 | 48 | { |
akkera102 | 0:147f4cedc929 | 49 | r = WriteSPI32NoDebug(w); |
akkera102 | 0:147f4cedc929 | 50 | wait(0.01); |
akkera102 | 0:147f4cedc929 | 51 | |
akkera102 | 0:147f4cedc929 | 52 | } while(r != comp); |
akkera102 | 0:147f4cedc929 | 53 | } |
akkera102 | 0:147f4cedc929 | 54 | |
akkera102 | 0:147f4cedc929 | 55 | int MultiBoot(char* filename) |
akkera102 | 0:147f4cedc929 | 56 | { |
akkera102 | 0:147f4cedc929 | 57 | spi.format(16, 3); |
akkera102 | 0:147f4cedc929 | 58 | spi.frequency(100000); // 100 kHz |
akkera102 | 0:147f4cedc929 | 59 | |
akkera102 | 0:147f4cedc929 | 60 | |
akkera102 | 0:147f4cedc929 | 61 | FILE *fp = fopen(filename, "rb"); |
akkera102 | 0:147f4cedc929 | 62 | if(fp == NULL) |
akkera102 | 0:147f4cedc929 | 63 | { |
akkera102 | 0:147f4cedc929 | 64 | pc.printf("Err: Can't open file\n"); |
akkera102 | 0:147f4cedc929 | 65 | return 1; |
akkera102 | 0:147f4cedc929 | 66 | } |
akkera102 | 0:147f4cedc929 | 67 | |
akkera102 | 0:147f4cedc929 | 68 | fseek(fp, 0L, SEEK_END); |
akkera102 | 0:147f4cedc929 | 69 | long fsize = (ftell(fp) + 0x0f) & 0xfffffff0; |
akkera102 | 0:147f4cedc929 | 70 | |
akkera102 | 0:147f4cedc929 | 71 | if(fsize > 0x40000) |
akkera102 | 0:147f4cedc929 | 72 | { |
akkera102 | 0:147f4cedc929 | 73 | pc.printf("Err: Max file size 256kB\n"); |
akkera102 | 0:147f4cedc929 | 74 | return 1; |
akkera102 | 0:147f4cedc929 | 75 | } |
akkera102 | 0:147f4cedc929 | 76 | |
akkera102 | 0:147f4cedc929 | 77 | fseek(fp, 0L, SEEK_SET); |
akkera102 | 0:147f4cedc929 | 78 | long fcnt = 0; |
akkera102 | 0:147f4cedc929 | 79 | |
akkera102 | 0:147f4cedc929 | 80 | |
akkera102 | 0:147f4cedc929 | 81 | uint32_t r, w, w2; |
akkera102 | 0:147f4cedc929 | 82 | int i, bit; |
akkera102 | 0:147f4cedc929 | 83 | |
akkera102 | 0:147f4cedc929 | 84 | WaitSPI32(0x00006202, 0x72026202, "Looking for GBA"); |
akkera102 | 0:147f4cedc929 | 85 | |
akkera102 | 0:147f4cedc929 | 86 | r = WriteSPI32(0x00006202, "Found GBA"); |
akkera102 | 0:147f4cedc929 | 87 | r = WriteSPI32(0x00006102, "Recognition OK"); |
akkera102 | 0:147f4cedc929 | 88 | |
akkera102 | 0:147f4cedc929 | 89 | pc.printf("Send Header(NoDebug)\n"); |
akkera102 | 0:147f4cedc929 | 90 | for(i=0; i<=0x5f; i++) |
akkera102 | 0:147f4cedc929 | 91 | { |
akkera102 | 0:147f4cedc929 | 92 | w = getc(fp); |
akkera102 | 0:147f4cedc929 | 93 | w = getc(fp) << 8 | w; |
akkera102 | 0:147f4cedc929 | 94 | fcnt += 2; |
akkera102 | 0:147f4cedc929 | 95 | |
akkera102 | 0:147f4cedc929 | 96 | r = WriteSPI32NoDebug(w); |
akkera102 | 0:147f4cedc929 | 97 | } |
akkera102 | 0:147f4cedc929 | 98 | |
akkera102 | 0:147f4cedc929 | 99 | r = WriteSPI32(0x00006200, "Transfer of header data complete"); |
akkera102 | 0:147f4cedc929 | 100 | r = WriteSPI32(0x00006202, "Exchange master/slave info again"); |
akkera102 | 0:147f4cedc929 | 101 | |
akkera102 | 0:147f4cedc929 | 102 | r = WriteSPI32(0x000063d1, "Send palette data"); |
akkera102 | 0:147f4cedc929 | 103 | r = WriteSPI32(0x000063d1, "Send palette data, receive 0x73hh****"); |
akkera102 | 0:147f4cedc929 | 104 | |
akkera102 | 0:147f4cedc929 | 105 | uint32_t m = ((r & 0x00ff0000) >> 8) + 0xffff00d1; |
akkera102 | 0:147f4cedc929 | 106 | uint32_t h = ((r & 0x00ff0000) >> 16) + 0xf; |
akkera102 | 0:147f4cedc929 | 107 | |
akkera102 | 0:147f4cedc929 | 108 | r = WriteSPI32((((r >> 16) + 0xf) & 0xff) | 0x00006400, "Send handshake data"); |
akkera102 | 0:147f4cedc929 | 109 | r = WriteSPI32((fsize - 0x190) / 4, "Send length info, receive seed 0x**cc****"); |
akkera102 | 0:147f4cedc929 | 110 | |
akkera102 | 0:147f4cedc929 | 111 | uint32_t f = (((r & 0x00ff0000) >> 8) + h) | 0xffff0000; |
akkera102 | 0:147f4cedc929 | 112 | uint32_t c = 0x0000c387; |
akkera102 | 0:147f4cedc929 | 113 | |
akkera102 | 0:147f4cedc929 | 114 | |
akkera102 | 0:147f4cedc929 | 115 | pc.printf("Send encrypted data(NoDebug)\n"); |
akkera102 | 0:147f4cedc929 | 116 | |
akkera102 | 0:147f4cedc929 | 117 | while(fcnt < fsize) |
akkera102 | 0:147f4cedc929 | 118 | { |
akkera102 | 0:147f4cedc929 | 119 | w = getc(fp); |
akkera102 | 0:147f4cedc929 | 120 | w = getc(fp) << 8 | w; |
akkera102 | 0:147f4cedc929 | 121 | w = getc(fp) << 16 | w; |
akkera102 | 0:147f4cedc929 | 122 | w = getc(fp) << 24 | w; |
akkera102 | 0:147f4cedc929 | 123 | |
akkera102 | 0:147f4cedc929 | 124 | w2 = w; |
akkera102 | 0:147f4cedc929 | 125 | |
akkera102 | 0:147f4cedc929 | 126 | for(bit=0; bit<32; bit++) |
akkera102 | 0:147f4cedc929 | 127 | { |
akkera102 | 0:147f4cedc929 | 128 | if((c ^ w) & 0x01) |
akkera102 | 0:147f4cedc929 | 129 | { |
akkera102 | 0:147f4cedc929 | 130 | c = (c >> 1) ^ 0x0000c37b; |
akkera102 | 0:147f4cedc929 | 131 | } |
akkera102 | 0:147f4cedc929 | 132 | else |
akkera102 | 0:147f4cedc929 | 133 | { |
akkera102 | 0:147f4cedc929 | 134 | c = c >> 1; |
akkera102 | 0:147f4cedc929 | 135 | } |
akkera102 | 0:147f4cedc929 | 136 | |
akkera102 | 0:147f4cedc929 | 137 | w = w >> 1; |
akkera102 | 0:147f4cedc929 | 138 | } |
akkera102 | 0:147f4cedc929 | 139 | |
akkera102 | 0:147f4cedc929 | 140 | m = (0x6f646573 * m) + 1; |
akkera102 | 0:147f4cedc929 | 141 | WriteSPI32NoDebug(w2 ^ ((~(0x02000000 + fcnt)) + 1) ^m ^0x43202f2f); |
akkera102 | 0:147f4cedc929 | 142 | |
akkera102 | 0:147f4cedc929 | 143 | fcnt = fcnt + 4; |
akkera102 | 0:147f4cedc929 | 144 | } |
akkera102 | 0:147f4cedc929 | 145 | fclose(fp); |
akkera102 | 0:147f4cedc929 | 146 | |
akkera102 | 0:147f4cedc929 | 147 | |
akkera102 | 0:147f4cedc929 | 148 | for(bit=0; bit<32; bit++) |
akkera102 | 0:147f4cedc929 | 149 | { |
akkera102 | 0:147f4cedc929 | 150 | if((c ^ f) & 0x01) |
akkera102 | 0:147f4cedc929 | 151 | { |
akkera102 | 0:147f4cedc929 | 152 | c =( c >> 1) ^ 0x0000c37b; |
akkera102 | 0:147f4cedc929 | 153 | } |
akkera102 | 0:147f4cedc929 | 154 | else |
akkera102 | 0:147f4cedc929 | 155 | { |
akkera102 | 0:147f4cedc929 | 156 | c = c >> 1; |
akkera102 | 0:147f4cedc929 | 157 | } |
akkera102 | 0:147f4cedc929 | 158 | |
akkera102 | 0:147f4cedc929 | 159 | f = f >> 1; |
akkera102 | 0:147f4cedc929 | 160 | } |
akkera102 | 0:147f4cedc929 | 161 | |
akkera102 | 0:147f4cedc929 | 162 | WaitSPI32(0x00000065, 0x00750065, "Wait for GBA to respond with CRC"); |
akkera102 | 0:147f4cedc929 | 163 | |
akkera102 | 0:147f4cedc929 | 164 | r = WriteSPI32(0x00000066, "GBA ready with CRC"); |
akkera102 | 0:147f4cedc929 | 165 | r = WriteSPI32(c, "Let's exchange CRC!"); |
akkera102 | 0:147f4cedc929 | 166 | |
akkera102 | 0:147f4cedc929 | 167 | pc.printf("CRC ...hope they match!\n"); |
akkera102 | 0:147f4cedc929 | 168 | pc.printf("MulitBoot done\n"); |
akkera102 | 0:147f4cedc929 | 169 | |
akkera102 | 0:147f4cedc929 | 170 | return 0; |
akkera102 | 0:147f4cedc929 | 171 | } |