forked from bartjakobs/GBA-Multiboot-Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
multiboot.py
executable file
·161 lines (129 loc) · 3.91 KB
/
multiboot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python3
from pyftdi.spi import SpiController, SpiIOError
import time
import math
import sys
from monitor import *
import signal
def signal_handler(signal, frame):
print("\nprogram exiting gracefully")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler) # Install signal handler
help_msg = '''usage: {}
-h show this help message
-s skip multiboot upload
-w wait for serial monitor using 0xCAFEFACE
-m monitor SIO printf messages
'''
try:
ctrl= SpiController() #spi
ctrl.configure('ftdi://ftdi:232h/1') # Assuming there is only one FT232H.
spi = ctrl.get_port(cs=0, freq=8E5, mode=1) # Assuming D3 is used for chip select.
except:
print("error: missing FTDI F232H device")
sys.exit(1)
def WriteSPI32(w):
buf = [0,0,0,0]
buf[3] = (w & 0x000000ff)
buf[2] = (w & 0x0000ff00) >> 8
buf[1] = (w & 0x00ff0000) >> 16
buf[0] = (w & 0xff000000) >> 24
buf = spi.exchange(buf, 4, start=False, stop=False, duplex=True)
r = 0
r += buf[0] << 24
r += buf[1] << 16
r += buf[2] << 8
r += buf[3]
return r ^ 0x80000000
def WaitSPI32(w, comp):
r=-1
while(r!=comp):
r = WriteSPI32(w)
time.sleep(0.01)
def getNext(fp):
n = fp.read(1)
if(len(n) == 0):
return 0
return n[0]
def upload():
filename = sys.argv[1]
print("Filename "+filename)
fp = open(filename,'rb')
fp.seek(0,2)
fsize = (fp.tell() + 0x0f) & 0xfffffff0
print("fsize, ", fsize)
if (fsize > 0x40000):
print("Err: Max file size 256kB\n")
return
fp.seek(0)
print("Looking for Gameboy")
WaitSPI32(0x00006202, 0x72026202) # Look for gba
print("Found GBA!")
r = WriteSPI32(0x00006202)
r = WriteSPI32(0x00006102)
fcnt = 0
print("Send Header");
for i in range(0, 0x5f+1):
w = fp.read(1)[0]
w = fp.read(1)[0] << 8 | w
fcnt += 2
r = WriteSPI32(w)
print("Sent!")
r = WriteSPI32(0x00006200) # Transfer complete
print("Exchange master/slave info again")
r = WriteSPI32(0x00006202)
print("Send palette data")
r = WriteSPI32(0x000063d1)
r = WriteSPI32(0x000063d1)
m = ((r & 0x00ff0000) >> 8) + 0xffff00d1
h = ((r & 0x00ff0000) >> 16) + 0xf
print("Send handshake")
r = WriteSPI32((((r >> 16) + 0xf) & 0xff) | 0x00006400)
print("Send game length")
r = WriteSPI32(int(math.ceil((fsize - 0x190) / 4)))
f = (((r & 0x00ff0000) >> 8) + h) | 0xffff0000
c = 0x0000c387
print("Send encrypted data")
while (fcnt < fsize):
w = getNext(fp)
w = getNext(fp) << 8 | w
w = getNext(fp) << 16 | w
w = getNext(fp) << 24 | w
w2 = w
for bit in range(0, 32):
if ((c ^ w) & 0x01):
c = (c >> 1) ^ 0x0000c37b
else:
c = c >> 1
w = w >> 1
w = w & 0xffffffff
m = ((0xffffffff & (0x6f646573 * m)) + 1)
WriteSPI32(0xffffffff & (w2 ^ ((~(0x02000000 + fcnt)) + 1) ^ m ^ 0x43202f2f))
fcnt = fcnt + 4
print("Sent")
fp.close()
for bit in range(0, 32):
if ((c ^ f) & 0x01):
c = (c >> 1) ^ 0x0000c37b
else:
c = c >> 1
f = f >> 1
print("Wait for GBA to respond with CRC")
WaitSPI32(0x00000065, 0x00750065)
print("GBA ready with CRC, exchanging")
r = WriteSPI32(0x00000066)
r = WriteSPI32(c)
print("CRC ...hope they match!")
print("MulitBoot done")
if __name__ == "__main__":
if '-h' in sys.argv:
print(help_msg.format(sys.argv[0]), end='')
sys.exit(0)
if '-s' not in sys.argv:
upload()
time.sleep(0.5)
if '-w' in sys.argv or '-mw' in sys.argv or '-wm' in sys.argv:
serial(spi)
time.sleep(0.5)
if '-m' in sys.argv or '-mw' in sys.argv or '-wm' in sys.argv:
monitor(spi)