bootromfun/dtprog: programmer fuers BootROM \o/
[calu.git] / tools / dtprog.py
1 #!/usr/bin/env python
2 """
3 Aufruf:
4 ./dtprog.py <dthexfile> [-d /dev/ttyXXX]
5
6 bootROM, a very small bootloader for $NAME
7
8 protocol details:
9 abbrv: H = Host, CPU = C
10
11 value/cmd              | direction | comment
12 ------------------------------------------------------------
13 'H'                    | H -> C    | enter bootROM ("HI")
14 'O'                    | C -> H    | ack bootROM entry ("OH HAI")
15
16 'W'0xZZZZZZZZ0xYYYYYYYY| H -> C    | write instr (0xYY...Y) to
17                                    | address (0xZZ...Z)
18 'D'                    | C -> H    | instr write done
19
20 'R'0xZZZZZZZZ          | H -> C    | read instr from address (0xZZ..Z)
21 'F'0xYYYYYYYY          | C -> H    | instr read done and return instr
22
23 'Q'0xZZZZZZZZ0xYYYYYYYY| H -> C    | write data (0xYY...Y) to
24                                    | address (0xZZ...Z)
25 'A'                    | C -> H    | data write done
26
27 'T'0xZZZZZZZZ          | H -> C    | read data from address (0xZZ..Z)
28 'G'0xYYYYYYYY          | C -> H    | read done and return data
29
30 'J'0xZZZZZZZZ          | H -> C    | jump to address (0xZZ...Z)
31 """
32 import sys, time
33 from SerialPort_linux import SerialPort, SerialPortException
34
35 BAUDRATE = 9600
36 SPLIT = 30
37
38 class RAMSequence(object):
39         def __init__(self, type, address, data):
40                 self.type = type
41                 self.addr = address
42                 self.data = data
43
44 def sendbyte(byte):
45         """
46         send a byte to the TTY-device
47         """
48         tty.write(chr(byte))
49
50 def sendword(word):
51         """
52         send a word to the TTY-device
53         """
54         sendbyte(word & 0xFF)
55         sendbyte((word >> 8) & 0xFF)
56
57 def senddword(dword):
58         """
59         send a dword to the TTY-device
60         """
61         sendbyte((dword >> 24) & 0xFF)
62         sendbyte((dword >> 16) & 0xFF)
63         sendbyte((dword >> 8) & 0xFF)
64         sendbyte(dword & 0xFF)
65
66 def recvbyte():
67         """
68         receive a byte from the TTY-device
69         """
70         return ord(tty.read())
71
72 def recvword():
73         return (recvbyte() << 24) & (recvbyte() << 16) & (recvbyte() << 8) & recvbyte()
74
75 def bootromexec():
76         sendbyte(0x4a) # 'J'
77
78 def brwriteinstr(address, data):
79         """
80         send a WRITE-command (instr) to the bootROM-firmware
81         """
82         # send WRITE instr command
83         sendbyte(0x57) # 'W'
84         # time.sleep(0.01)
85         if (recvbyte() != 0x57): # 'W'
86                 print "host: write instr fail (1)"
87                 raise Exception
88         senddword(address)
89         senddword(data)
90         time.sleep(0.01)
91         if (recvbyte() != 0x44): # 'D'
92                 print "host: write instr fail (2)"
93                 raise Exception
94
95 def brwritedata(address, data):
96         """
97         send a WRITE-command (data) to the bootROM-firmware
98         """
99         # send WRITE instr command
100         sendbyte(0x51) # 'Q'
101         # time.sleep(0.01)
102         if (recvbyte() != 0x51): # 'Q'
103                 print "host: write data fail (1)"
104                 raise Exception
105         senddword(address)
106         senddword(data)
107         time.sleep(0.01)
108         if (recvbyte() != 0x41): # 'A'
109                 print "host: write data fail (2)"
110                 raise Exception
111
112 def readdthexfile(filename): # desired dthex filename
113         """
114         proceeds a dthex file
115         """
116         filep = open(filename, "r")
117         retval = [] # returns a list of FlashSequence objects
118         linecount = 0
119         for line in filep:
120                 linecount += 1
121                 # get rid of newline characters
122                 line = line.strip()
123
124                 # we're only interested in 0 or 1
125                 if line[0:1] == "0" or line[0:1] == "1":
126                         # TODO: checks...
127                         type = int(line[0:1], 10)
128                         addr = int(line[2:10], 16)/4
129                         data = int(line[11:19], 16)
130                         # print "type: ", type, "; addr: ", hex(addr), "; data: ", hex(data)
131                         retval.append(RAMSequence(type, addr, data))
132         filep.close()
133         return retval
134
135 def usage(execf):
136         """
137         print usage of dtprog
138         """
139         print "Usage: " + execf + " <target dthex-file> [-d DEVICE]"
140
141 def main(argv=None):
142         """
143         main function of frprog
144         """
145         # check command line arguments
146         if argv is None:
147                 argv = sys.argv
148
149         if len(argv) == 2 and (argv[1] == "-v" or argv[1] == "--version"):
150                 print "Version: lulz"
151                 return 0
152
153         if len(argv) != 2 and len(argv) != 4:
154                 usage(argv[0])
155                 return 1
156
157         # standard serial device to communicate with
158         device = "/dev/ttyS0"
159
160         # overrule standard device if provided with -d
161         if len(argv) == 4:
162                 if argv[2] == "-d":
163                         device = argv[3]
164                 else:
165                         usage(argv[0])
166                         return 1
167
168         # read in data from mhx-files before starting
169         try:
170                 ramseqs = readdthexfile(argv[1])
171         except IOError, error:
172                 print argv[0] + ": Error - couldn't open file " + error.filename + "!"
173                 return 1
174
175         print "Initializing serial port... (", device, ")"
176         global tty
177         tty = SerialPort(device, 100, BAUDRATE)
178
179         while True:
180                 tty.write('H')
181                 tty.flush()
182                 try:
183                         if tty.read() == 'O':
184                                 break
185                 except SerialPortException:
186                         # timeout happened, who cares ;-)
187                         print "host: cpu in BootROM?"
188                         pass
189         print "bootrom: OH HAI!"
190
191         # save time at this point for evaluating the duration at the end
192         starttime = time.time()
193         time.sleep(0.1)
194
195         sdots = SPLIT
196         print "host: Transfering program to BootROM",
197         print #TODO: remove ;)
198         # let the fun begin!
199         for seq in ramseqs:
200                 print "RAMing(", seq.type, ") ", hex(seq.data), " at address ",
201                 if seq.type == 1:
202                         # instruction
203                         print "", hex(seq.addr)
204                         print "host: writing instr"
205                         brwriteinstr(seq.addr, seq.data)
206                 elif seq.type == 0:
207                         # data
208                         print "", hex(seq.addr*4)
209                         print "host: writing data"
210                         brwritedata(seq.addr * 4, seq.data)
211                 tty.flush()
212
213                 sdots = sdots - 1
214                 if sdots == 0:
215                         sys.stdout.write(".")
216                         sys.stdout.flush()
217                         sdots = SPLIT
218         print
219
220         bootromexec()
221         print "Program was started. Have fun!"
222         duration = time.time() - starttime
223         print "Procedure complete, took", round(duration, 2), "seconds."
224
225 if __name__ == '__main__':
226         sys.exit(main())