-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbdmdriver.cpp
More file actions
455 lines (418 loc) · 14.5 KB
/
bdmdriver.cpp
File metadata and controls
455 lines (418 loc) · 14.5 KB
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
/*******************************************************************************
bdmdriver.cpp
(c) 2014 by Sophie Dexter
BD32 like 'syscall' processor for BDM resident driver functions
********************************************************************************
WARNING: Use at your own risk, sadly this software comes with no guarantees.
This software is provided 'free' and in good faith, but the author does not
accept liability for any damage arising from its use.
*******************************************************************************/
#include "bdmdriver.h"
#include "interfaces.h"
#include "bdmcpu32.h"
FILE *fp = NULL;
//private functions
bool bdmSyscallPuts (void);
bool bdmSyscallPutchar(void);
bool bdmSyscallGets(void);
bool bdmSyscallGetchar(void);
bool bdmSyscallGetstat(void);
bool bdmSyscallFopen(void);
bool bdmSyscallFclose(void);
bool bdmSyscallFread(void);
bool bdmSyscallFwrite(void);
bool bdmSyscallFtell(void);
bool bdmSyscallFseek(void);
bool bdmSyscallFgets(void);
bool bdmSyscallFputs(void);
bool bdmSyscallEval(void);
bool bdmSyscallFreadsrec(void);
//-----------------------------------------------------------------------------
/**
Loads the contenst of a uint8_t array into the target's memory starting at the
specified address
@param dataArray[] uint8_t array conataining data for BDM tartget
@param startAddress Start address to load BDM memory to
@return succ / fail
*/
bool bdmLoadMemory(uint8_t dataArray[], uint32_t startAddress, uint32_t dataArraySize)
{
// for (uint32_t i = 0; i < sizeof(residentDriver); i++) {
// if(memwrite_byte(&driverAddress, residentDriver[i]) != TERM_OK) return false;
// driverAddress++;
// }
uint32_t driverSize = dataArraySize;
uint32_t driverOffset = 0;
uint32_t driverLong = 0;
uint16_t driverWord = 0;
uint8_t driverByte = 0;
// Check that there is something to send
if (driverSize == 0) return false;
// Send the first 1-4 bytes as efficiently as possible over BDM
switch (driverSize % 4) {
case 3:
driverWord = (dataArray[driverOffset++] << 8) | dataArray[driverOffset++];
if(memwrite_word(&startAddress, driverWord) != TERM_OK) return false;
driverByte = dataArray[driverOffset++];
if(memfill_byte(driverByte) != TERM_OK) return false;
break;
case 2:
driverWord = (dataArray[driverOffset++] << 8) | dataArray[driverOffset++];
if(memwrite_word(&startAddress, driverWord) != TERM_OK) return false;
break;
case 1:
driverByte = dataArray[driverOffset++];
if(memwrite_byte(&startAddress, driverByte) != TERM_OK) return false;
break;
case 0:
for (uint32_t i = 0; i < 4; i++) {
driverLong <<= 8;
driverLong |= dataArray[driverOffset++];
}
if(memwrite_long(&startAddress, &driverLong) != TERM_OK) return false;
break;
// default: // There shouldn't be a default case
}
// transfer the rest as 'longs' to make best use of BDM transfer speed
// printf("driverOffset 0x%08x, driverSize 0x%08x\r\n", driverOffset, driverSize);
while (driverOffset < driverSize) {
for (uint32_t i = 0; i < 4; i++) {
driverLong <<= 8;
driverLong |= dataArray[driverOffset++];
}
if(memfill_long(&driverLong) != TERM_OK) return false;
}
// printf("driverOffset 0x%08x, driverSize 0x%08x\r\n", driverOffset, driverSize);
return true;
}
//-----------------------------------------------------------------------------
/**
Starts a BDM resident driver at the current PC (Program Counter) or a specified
if given. The driver is allowed to run for a maximum period, maxtime, specified
as milliseconds.
@param addr BDM driver address (0 to continue from current PC)
@param maxtime how long to allow driver to execute (milliseconds)
@return succ / fail
*/
bool bdmRunDriver(uint32_t addr, uint32_t maxtime)
{
// Start BDM driver and allow it up to 200 milliseconds to update 256 Bytes
// Upto 25 pulses per byte, 16us per pulse, 256 Bytes
// 25 * 16 * 256 = 102,400us plus overhead for driver code execution time
// Allowing up to 200 milliseconds seems like a good allowance.
if (run_chip(&addr) != TERM_OK) {
printf("Failed to start BDM driver.\r\n");
return false;
}
timeout.reset();
timeout.start();
// T5 ECUs' BDM interface seem to have problems when the running the CPU and
// sometimes shows the CPU briefly switching between showing BDM mode or that
// the CPU is running.
// I 'debounce' the interface state to workaround this erratic bahaviour
for (uint32_t debounce = 0; debounce < 5; debounce++) {
while (IS_RUNNING) {
debounce = 0;
if (timeout.read_ms() > maxtime) {
printf("Driver did not return to BDM mode.\r\n");
timeout.stop();
return false;
}
}
wait_us(1);
}
timeout.stop();
return true;
}
//-----------------------------------------------------------------------------
/**
Starts a BDM resident driver at the current PC (Program Counter) or a specified
if given. The driver is allowed to run for a maximum period, maxtime, specified
as milliseconds.
@param addr BDM driver address (0 to continue from current PC)
@param maxtime how long to allow driver to execute (milliseconds)
@return DONE, CONTINUE, ERROR
*/
uint8_t bdmProcessSyscall(void)
{
uint32_t syscall = 0xFFFFFFFF;
if (adreg_read(&syscall, 0x0) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return ERROR;
}
syscall &= 0xFF;
// printf("SYSCALL 0x%08x\r\n", syscall);
switch (syscall) {
case QUIT:
if (adreg_read(&syscall, 0x1) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return ERROR;
}
return DONE;
case PUTS:
if (!bdmSyscallPuts()) return ERROR;
break;
case PUTCHAR:
if (!bdmSyscallPutchar()) return ERROR;
break;
case GETS:
if (!bdmSyscallGets()) return ERROR;
break;
case GETCHAR:
if (!bdmSyscallGetchar()) return ERROR;
break;
case GETSTAT:
if (!bdmSyscallGetstat()) return ERROR;
break;
case FOPEN:
if (!bdmSyscallFopen()) return ERROR;
break;
case FCLOSE:
if (!bdmSyscallFclose()) return ERROR;
break;
case FREAD:
if (!bdmSyscallFread()) return ERROR;
break;
case FWRITE:
if (!bdmSyscallFwrite()) return ERROR;
break;
case FTELL:
if (!bdmSyscallFtell()) return ERROR;
break;
case FSEEK:
if (!bdmSyscallFseek()) return ERROR;
break;
case FGETS:
if (!bdmSyscallFgets()) return ERROR;
break;
case FPUTS:
if (!bdmSyscallFputs()) return ERROR;
break;
case EVAL:
if (!bdmSyscallEval()) return ERROR;
break;
case FREADSREC:
if (!bdmSyscallFreadsrec()) return ERROR;
break;
default:
printf("!!! Unknown BDM Syscall !!!\r\n");
return ERROR;
}
return CONTINUE;
}
bool bdmSyscallPuts()
{
uint32_t bdm_string_address = 0, bdm_return = 0;
if (adreg_read(&bdm_string_address, 0x8) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
// a loop to read chars from BDM into a string
char bdm_string[256];
for (uint32_t i = 0; i < sizeof(bdm_string); i++) {
bdm_string[i] = 0x0;
}
uint32_t i = 0;
do {
if (memread_byte((uint8_t*)(bdm_string+i), &bdm_string_address) != TERM_OK) {
printf("Failed to read BDM memory at address 0x%08lx.\r\n", bdm_string_address);
return false;
}
bdm_string_address++;
} while ( (bdm_string[i++] != 0x0) && (i < sizeof(bdm_string)) );
// print the string to stdout (USB virtual serial port)
printf("%s", bdm_string);
// Send BDM return code in D0 (always 0x0 for PUTS)
if (adreg_write(0x0, &bdm_return) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallPutchar()
{
uint32_t bdm_character = 0, bdm_return = 0;
// read char from BDM
if (adreg_read(&bdm_character, 0x1) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
// print the char to USB virtual serial port
pc.putc((char)bdm_character);
// Send BDM return code in D0 (always 0x0 for PUTCHAR)
if (adreg_write(0x0, &bdm_return) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallGets()
{
printf("BDM GETS Syscall not supported.\r\n");
return ERROR;
}
bool bdmSyscallGetchar()
{
// get a char from the USB virtual serial port
uint32_t bdm_return = (uint32_t)pc.getc();
// Send the char to BDM in D0
if (adreg_write(0x0, &bdm_return) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallGetstat(void)
{
printf("BDM GETSTAT Syscall not supported.\r\n");
return false;
}
bool bdmSyscallFopen(void)
{
uint32_t bdm_filename_address = 0, bdm_filemode_address = 0;
if (adreg_read(&bdm_filename_address, 0x8) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
if (adreg_read(&bdm_filemode_address, 0x9) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
// a loop to initialise the strings to 0x0
char filename_string[80], filemode_string[5];
uint32_t i = 0;
for (i = 0; i < sizeof(filename_string); i++) {
filename_string[i] = 0x0;
}
for (i = 0; i < sizeof(filemode_string); i++) {
filemode_string[i] = 0x0;
}
i = 0;
// a loop to read chars from BDM into a string
do {
if (memread_byte((uint8_t*) &filename_string[i], &bdm_filename_address) != TERM_OK) {
printf("Failed to read BDM memory at address 0x%08lx.\r\n", bdm_filename_address);
return false;
}
bdm_filename_address++;
} while ( (filename_string[i++] != 0x0) && (i < sizeof(filename_string)) );
do {
if (memread_byte((uint8_t*) &filemode_string[i], &bdm_filemode_address) != TERM_OK) {
printf("Failed to read BDM memory at address 0x%08lx.\r\n", bdm_filemode_address);
return false;
}
bdm_filemode_address++;
} while ( (filemode_string[i++] != 0x0) && (i < sizeof(filemode_string)) );
// Open the file
fp = fopen(filename_string, filemode_string); // Open "modified.hex" on the local file system for reading
// Send BDM return code in D0
if (adreg_write(0x0, (uint32_t*)fp) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallFclose(void)
{
uint32_t close_result = fclose(fp);
// Send BDM return code in D0
if (adreg_write(0x0, &close_result) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallFread(void)
{
uint32_t bdm_byte_count, bdm_buffer_address, bdm_file_handle = NULL;
if (adreg_read(&bdm_file_handle, 0x1) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
if (adreg_read(&bdm_byte_count, 0x2) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
if (adreg_read(&bdm_buffer_address, 0x9) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
uint32_t bytes_read = fread(&file_buffer[0],1,bdm_byte_count,fp);
for (uint32_t byte_count = 0; byte_count < bytes_read; byte_count++) {
if (byte_count == 0x0) {
if(memwrite_byte(&bdm_buffer_address, file_buffer[byte_count]) != TERM_OK) return false;
} else {
if(memfill_byte(file_buffer[byte_count]) != TERM_OK) return false;
}
}
if (adreg_write(0x0, &bytes_read) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallFwrite(void)
{
printf("BDM FWRITE Syscall not supported.\r\n");
return false;
}
bool bdmSyscallFtell(void)
{
printf("BDM FTELL Syscall not supported.\r\n");
return false;
}
bool bdmSyscallFseek(void)
{
uint32_t bdm_byte_offset, bdm_file_origin, bdm_file_handle = NULL;
if (adreg_read(&bdm_file_handle, 0x1) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
if (adreg_read(&bdm_byte_offset, 0x2) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
if (adreg_read(&bdm_file_origin, 0x3) != TERM_OK) {
printf("Failed to read BDM register.\r\n");
return false;
}
uint32_t origin;
switch (bdm_file_origin) {
case 0x2:
origin = SEEK_END;
break;
case 0x1:
origin = SEEK_CUR;
break;
case 0x0:
default:
origin = SEEK_SET;
break;
}
uint32_t fseek_result = fseek ( fp ,bdm_byte_offset ,origin );
if (adreg_write(0x0, &fseek_result) != TERM_OK) {
printf("Failed to write BDM register.\r\n");
return false;
}
return true;
}
bool bdmSyscallFgets(void)
{
printf("BDM FGETS Syscall not supported.\r\n");
return false;
}
bool bdmSyscallFputs(void)
{
printf("BDM FPUTS Syscall not supported.\r\n");
return false;
}
bool bdmSyscallEval(void)
{
printf("BDM EVAL Syscall not supported.\r\n");
return false;
}
bool bdmSyscallFreadsrec(void)
{
printf("BDM FREADSREC Syscall not supported.\r\n");
return false;
}