dtprog: support for optional baudrate
[calu.git] / tools / dtprog.py
1 #!/usr/bin/env python2
2 """
3 Aufruf:
4 ./dtprog.py <dthexfile> [-d /dev/ttyXXX] [-b <baudrate>]
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 SPLIT = 30
36
37 class RAMSequence(object):
38         def __init__(self, type, address, data):
39                 self.type = type
40                 self.addr = address
41                 self.data = data
42
43 def sendbyte(byte):
44         """
45         send a byte to the TTY-device
46         """
47         tty.write(chr(byte))
48
49 def sendword(word):
50         """
51         send a word to the TTY-device
52         """
53         sendbyte(word & 0xFF)
54         sendbyte((word >> 8) & 0xFF)
55
56 def senddword(dword):
57         """
58         send a dword to the TTY-device
59         """
60         sendbyte((dword >> 24) & 0xFF)
61         sendbyte((dword >> 16) & 0xFF)
62         sendbyte((dword >> 8) & 0xFF)
63         sendbyte(dword & 0xFF)
64
65 def recvbyte():
66         """
67         receive a byte from the TTY-device
68         """
69         return ord(tty.read())
70
71 def recvword():
72         return (recvbyte() << 24) & (recvbyte() << 16) & (recvbyte() << 8) & recvbyte()
73
74 def bootromexec():
75         sendbyte(0x4a) # 'J'
76
77 def brwriteinstr(address, data):
78         """
79         send a WRITE-command (instr) to the bootROM-firmware
80         """
81         # send WRITE instr command
82         sendbyte(0x57) # 'W'
83         # time.sleep(0.01)
84         if (recvbyte() != 0x57): # 'W'
85                 print "host: write instr fail (1)"
86                 raise Exception
87         senddword(address)
88         senddword(data)
89         time.sleep(0.01)
90         if (recvbyte() != 0x44): # 'D'
91                 print "host: write instr fail (2)"
92                 raise Exception
93
94 def brwritedata(address, data):
95         """
96         send a WRITE-command (data) to the bootROM-firmware
97         """
98         # send WRITE instr command
99         sendbyte(0x51) # 'Q'
100         # time.sleep(0.01)
101         if (recvbyte() != 0x51): # 'Q'
102                 print "host: write data fail (1)"
103                 raise Exception
104         senddword(address)
105         senddword(data)
106         time.sleep(0.01)
107         if (recvbyte() != 0x41): # 'A'
108                 print "host: write data fail (2)"
109                 raise Exception
110
111 def readdthexfile(filename): # desired dthex filename
112         """
113         proceeds a dthex file
114         """
115         filep = open(filename, "r")
116         retval = [] # returns a list of FlashSequence objects
117         linecount = 0
118         for line in filep:
119                 linecount += 1
120                 # get rid of newline characters
121                 line = line.strip()
122
123                 # we're only interested in 0 or 1
124                 if line[0:1] == "0" or line[0:1] == "1":
125                         # TODO: checks...
126                         type = int(line[0:1], 10)
127                         addr = int(line[2:10], 16)/4
128                         data = int(line[11:19], 16)
129                         # print "type: ", type, "; addr: ", hex(addr), "; data: ", hex(data)
130                         retval.append(RAMSequence(type, addr, data))
131         filep.close()
132         return retval
133
134 def usage(execf):
135         """
136         print usage of dtprog
137         """
138         print "Usage: " + execf + " <target dthex-file> [-d DEVICE] [-b BAUDRATE]"
139         print "maybe arg-eval fail. fix the source!"
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 and len(argv) != 6:
154                 usage(argv[0])
155                 return 1
156
157         # standard baudrate
158         baudrate = 9200
159         # standard serial device to communicate with
160         device = "/dev/ttyS0"
161
162         print "argv: ", argv
163         # overrule standard device if provided with -d
164         if len(argv) >= 4:
165                 if argv[2] == "-d":
166                         device = argv[3]
167                 else:
168                         usage(argv[0])
169                         return 1
170
171         # overrule standard baudrate if provided with -b
172         if len(argv) == 6:
173                 if argv[4] == "-b":
174                         baudrate = int(argv[5],10)
175                 else:
176                         usage(argv[0])
177                         return 1
178
179         # read in data from mhx-files before starting
180         try:
181                 ramseqs = readdthexfile(argv[1])
182         except IOError, error:
183                 print argv[0] + ": Error - couldn't open file " + error.filename + "!"
184                 return 1
185
186         print "Initializing serial port... (", device, ")"
187         global tty
188         tty = SerialPort(device, 100, baudrate)
189
190         while True:
191                 tty.write('H')
192                 tty.flush()
193                 try:
194                         if tty.read() == 'O':
195                                 break
196                 except SerialPortException:
197                         # timeout happened, who cares ;-)
198                         print "host: cpu in BootROM?"
199                         pass
200         print "bootrom: OH HAI!"
201
202         # save time at this point for evaluating the duration at the end
203         starttime = time.time()
204         time.sleep(0.1)
205
206         sdots = SPLIT
207         print "host: Transfering program to BootROM",
208         print #TODO: remove ;)
209         # let the fun begin!
210         for seq in ramseqs:
211                 print "RAMing(", seq.type, ") ", hex(seq.data), " at address ",
212                 if seq.type == 1:
213                         # instruction
214                         print "", hex(seq.addr)
215                         print "host: writing instr"
216                         brwriteinstr(seq.addr, seq.data)
217                 elif seq.type == 0:
218                         # data
219                         print "", hex(seq.addr*4)
220                         print "host: writing data"
221                         brwritedata(seq.addr * 4, seq.data)
222                 tty.flush()
223
224                 sdots = sdots - 1
225                 if sdots == 0:
226                         sys.stdout.write(".")
227                         sys.stdout.flush()
228                         sdots = SPLIT
229         print
230
231         bootromexec()
232         print "Program was started. Have fun!"
233         duration = time.time() - starttime
234         print "Procedure complete, took", round(duration, 2), "seconds."
235
236 if __name__ == '__main__':
237         sys.exit(main())