Bug Summary

File:/home/anal/dolphin-emu/Source/Core/Core/Src/DSP/assemble.cpp
Location:line 154, column 3
Description:Value stored to 'buf_ptr' is never read

Annotated Source Code

1/*====================================================================
2
3$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $
4
5project: GameCube DSP Tool (gcdsp)
6mail: duddie@walla.com
7
8Copyright (c) 2005 Duddie
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24Revision 1.4 2008/10/04 10:30:00 Hermes
25added function to export the code to .h file
26added support for '/ *' '* /' and '//' for comentaries
27added some sintax detection when use registers
28
29$Log: not supported by cvs2svn $
30Revision 1.2 2005/09/14 02:19:29 wntrmute
31added header guards
32use standard main function
33
34Revision 1.1 2005/08/24 22:13:34 wntrmute
35Initial import
36
37
38====================================================================*/
39
40#include <cstdio>
41#include <cstdlib>
42
43#include <map>
44#include <iostream>
45#include <fstream>
46
47#include "Common.h"
48#include "FileUtil.h"
49#include "DSPInterpreter.h"
50#include "DSPTables.h"
51#include "disassemble.h"
52#include "assemble.h"
53
54static const char *err_string[] =
55{
56 "",
57 "Unknown Error",
58 "Unknown opcode",
59 "Not enough parameters",
60 "Too many parameters",
61 "Wrong parameter",
62 "Expected parameter of type 'string'",
63 "Expected parameter of type 'value'",
64 "Expected parameter of type 'register'",
65 "Expected parameter of type 'memory pointer'",
66 "Expected parameter of type 'immediate'",
67 "Incorrect binary value",
68 "Incorrect hexadecimal value",
69 "Incorrect decimal value",
70 "Label already exists",
71 "Label not defined",
72 "No matching brackets",
73 "This opcode cannot be extended",
74 "Given extending params for non extensible opcode",
75 "Wrong parameter: must be accumulator register",
76 "Wrong parameter: must be mid accumulator register",
77 "Invalid register",
78 "Number out of range"
79};
80
81DSPAssembler::DSPAssembler(const AssemblerSettings &settings) :
82 gdg_buffer(NULL__null),
83 m_cur_addr(0),
84 m_cur_pass(0),
85 m_current_param(0),
86 settings_(settings)
87
88{
89}
90
91DSPAssembler::~DSPAssembler()
92{
93 if(gdg_buffer)
94 free(gdg_buffer);
95}
96
97bool DSPAssembler::Assemble(const char *text, std::vector<u16> &code, std::vector<int> *line_numbers)
98{
99 if (line_numbers)
100 line_numbers->clear();
101 const char *fname = "tmp.asm";
102 if (!File::WriteStringToFile(true, text, fname))
103 return false;
104 InitPass(1);
105 if (!AssembleFile(fname, 1))
106 return false;
107
108 // We now have the size of the output buffer
109 if (m_totalSize > 0)
110 {
111 gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4);
112 if(!gdg_buffer)
113 return false;
114
115 memset(gdg_buffer, 0, m_totalSize * sizeof(u16));
116 } else
117 return false;
118
119 InitPass(2);
120 if (!AssembleFile(fname, 2))
121 return false;
122
123 code.resize(m_totalSize);
124 for (int i = 0; i < m_totalSize; i++) {
125 code[i] = *(u16 *)(gdg_buffer + i * 2);
126 }
127
128 if(gdg_buffer) {
129 free(gdg_buffer);
130 gdg_buffer = NULL__null;
131 }
132
133 last_error_str = "(no errors)";
134 last_error = ERR_OK;
135
136 return true;
137}
138
139void DSPAssembler::ShowError(err_t err_code, const char *extra_info)
140{
141
142 if (!settings_.force)
143 failed = true;
144
145 char error_buffer[1024];
146 char *buf_ptr = error_buffer;
147 buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str());
148 if (!extra_info)
149 extra_info = "-";
150
151 if (m_current_param == 0)
152 buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
153 else
154 buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n",
Value stored to 'buf_ptr' is never read
155 err_string[err_code], code_line, m_current_param, extra_info);
156 last_error_str = error_buffer;
157 last_error = err_code;
158}
159
160char *skip_spaces(char *ptr)
161{
162 while (*ptr == ' ')
163 ptr++;
164 return ptr;
165}
166
167const char *skip_spaces(const char *ptr)
168{
169 while (*ptr == ' ')
170 ptr++;
171 return ptr;
172}
173
174// Parse a standalone value - it can be a number in one of several formats or a label.
175s32 DSPAssembler::ParseValue(const char *str)
176{
177 bool negative = false;
178 s32 val = 0;
179 const char *ptr = str;
180
181 if (ptr[0] == '#')
182 {
183 ptr++;
184 negative = true; // Wow! Double # (needed one to get in here) negates???
185 }
186 if (ptr[0] == '-')
187 {
188 ptr++;
189 negative = true;
190 }
191 if (ptr[0] == '0')
192 {
193 if (ptr[1] >= '0' && ptr[1] <= '9')
194 {
195 for (int i = 0; ptr[i] != 0; i++)
196 {
197 val *= 10;
198 if (ptr[i] >= '0' && ptr[i] <= '9')
199 val += ptr[i] - '0';
200 else
201 ShowError(ERR_INCORRECT_DEC, str);
202 }
203 }
204 else
205 {
206 switch (ptr[1])
207 {
208 case 'X': // hex
209 for (int i = 2 ; ptr[i] != 0 ; i++)
210 {
211 val <<= 4;
212 if (ptr[i] >= 'a' && ptr[i] <= 'f')
213 val += (ptr[i]-'a'+10);
214 else if (ptr[i] >= 'A' && ptr[i] <= 'F')
215 val += (ptr[i]-'A'+10);
216 else if (ptr[i] >= '0' && ptr[i] <= '9')
217 val += (ptr[i] - '0');
218 else
219 ShowError(ERR_INCORRECT_HEX, str);
220 }
221 break;
222 case '\'': // binary
223 for (int i = 2; ptr[i] != 0; i++)
224 {
225 val *=2;
226 if(ptr[i] >= '0' && ptr[i] <= '1')
227 val += ptr[i] - '0';
228 else
229 ShowError(ERR_INCORRECT_BIN, str);
230 }
231 break;
232 default:
233 // value is 0 or error
234 val = 0;
235 break;
236 }
237 }
238 }
239 else
240 {
241 // Symbol starts with a digit - it's a dec number.
242 if (ptr[0] >= '0' && ptr[0] <= '9')
243 {
244 for (int i = 0; ptr[i] != 0; i++)
245 {
246 val *= 10;
247 if (ptr[i] >= '0' && ptr[i] <= '9')
248 val += ptr[i] - '0';
249 else
250 ShowError(ERR_INCORRECT_DEC, str);
251 }
252 }
253 else // Everything else is a label.
254 {
255 // Lookup label
256 u16 value;
257 if (labels.GetLabelValue(ptr, &value))
258 return value;
259 if (m_cur_pass == 2)
260 ShowError(ERR_UNKNOWN_LABEL, str);
261 }
262 }
263 if (negative)
264 return -val;
265 return val;
266}
267
268// Modifies both src and dst!
269// What does it do, really??
270char *DSPAssembler::FindBrackets(char *src, char *dst)
271{
272 s32 len = (s32) strlen(src);
273 s32 first = -1;
274 s32 count = 0;
275 s32 i, j;
276 j = 0;
277 for (i = 0 ; i < len ; i++)
278 {
279 if (src[i] == '(')
280 {
281 if (first < 0)
282 {
283 count = 1;
284 src[i] = 0x0;
285 first = i;
286 }
287 else
288 {
289 count++;
290 dst[j++] = src[i];
291 }
292 }
293 else if (src[i] == ')')
294 {
295 if (--count == 0)
296 {
297 dst[j] = 0;
298 return &src[i+1];
299 }
300 else
301 {
302 dst[j++] = src[i];
303 }
304 }
305 else
306 {
307 if (first >= 0)
308 dst[j++] = src[i];
309 }
310 }
311 if (count)
312 ShowError(ERR_NO_MATCHING_BRACKETS);
313 return NULL__null;
314}
315
316// Bizarre in-place expression evaluator.
317u32 DSPAssembler::ParseExpression(const char *ptr)
318{
319 char *pbuf;
320 s32 val = 0;
321
322 char *d_buffer = (char *)malloc(1024);
323 char *s_buffer = (char *)malloc(1024);
324 strcpy(s_buffer, ptr);
325
326 while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL__null)
327 {
328 val = ParseExpression(d_buffer);
329 sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf);
330 strcpy(s_buffer, d_buffer);
331 }
332
333 int j = 0;
334 for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++)
335 {
336 char c = s_buffer[i];
337 if (c != ' ')
338 d_buffer[j++] = c;
339 }
340
341 for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++)
342 {
343 char c = d_buffer[i];
344 if (c == '-')
345 {
346 if (i == 0)
347 c = '#';
348 else
349 {
350 switch (d_buffer[i - 1])
351 {
352 case '/':
353 case '%':
354 case '*':
355 c = '#';
356 }
357 }
358 }
359 d_buffer[i] = c;
360 }
361
362 while ((pbuf = strstr(d_buffer, "+")) != NULL__null)
363 {
364 *pbuf = 0x0;
365 val = ParseExpression(d_buffer) + ParseExpression(pbuf+1);
366 sprintf(d_buffer, "%d", val);
367 }
368
369 while ((pbuf = strstr(d_buffer, "-")) != NULL__null)
370 {
371 *pbuf = 0x0;
372 val = ParseExpression(d_buffer) - ParseExpression(pbuf+1);
373 if (val < 0)
374 {
375 val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf
376 fprintf(stderrstderr, "WARNING: Number Underflow at Line: %d \n", code_line);
377 }
378 sprintf(d_buffer, "%d", val);
379 }
380
381 while ((pbuf = strstr(d_buffer, "*")) != NULL__null)
382 {
383 *pbuf = 0x0;
384 val = ParseExpression(d_buffer) * ParseExpression(pbuf+1);
385 sprintf(d_buffer, "%d", val);
386 }
387
388 while ((pbuf = strstr(d_buffer, "/")) != NULL__null)
389 {
390 *pbuf = 0x0;
391 val = ParseExpression(d_buffer) / ParseExpression(pbuf+1);
392 sprintf(d_buffer, "%d", val);
393 }
394
395 while ((pbuf = strstr(d_buffer, "|")) != NULL__null)
396 {
397 *pbuf = 0x0;
398 val = ParseExpression(d_buffer) | ParseExpression(pbuf+1);
399 sprintf(d_buffer, "%d", val);
400 }
401
402 while ((pbuf = strstr(d_buffer, "&")) != NULL__null)
403 {
404 *pbuf = 0x0;
405 val = ParseExpression(d_buffer) & ParseExpression(pbuf+1);
406 sprintf(d_buffer, "%d", val);
407 }
408
409 val = ParseValue(d_buffer);
410 free(d_buffer);
411 free(s_buffer);
412 return val;
413}
414
415// Destroys parstr
416u32 DSPAssembler::GetParams(char *parstr, param_t *par)
417{
418 u32 count = 0;
419 char *tmpstr = skip_spaces(parstr);
420 tmpstr = strtok(tmpstr, ",\x00");
421 for (int i = 0; i < 10; i++)
422 {
423 if (tmpstr == NULL__null)
424 break;
425 tmpstr = skip_spaces(tmpstr);
426 if (strlen(tmpstr) == 0)
427 break;
428 if (tmpstr)
429 count++;
430 else
431 break;
432
433 par[i].type = P_NONE;
434 switch (tmpstr[0])
435 {
436 case '"':
437 par[i].str = strtok(tmpstr, "\"");
438 par[i].type = P_STR;
439 break;
440 case '#':
441 par[i].val = ParseExpression(tmpstr + 1);
442 par[i].type = P_IMM;
443 break;
444 case '@':
445 if (tmpstr[1] == '$')
446 {
447 par[i].val = ParseExpression(tmpstr + 2);
448 par[i].type = P_PRG;
449 }
450 else
451 {
452 par[i].val = ParseExpression(tmpstr + 1);
453 par[i].type = P_MEM;
454 }
455 break;
456 case '$':
457 par[i].val = ParseExpression(tmpstr + 1);
458 par[i].type = P_REG;
459 break;
460
461 default:
462 par[i].val = ParseExpression(tmpstr);
463 par[i].type = P_VAL;
464 break;
465 }
466 tmpstr = strtok(NULL__null, ",\x00");
467 }
468 return count;
469}
470
471const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size)
472{
473 if (opcode[0] == 'C' && opcode[1] == 'W')
474 return &cw;
475
476 AliasMap::const_iterator alias_iter = aliases.find(opcode);
477 if (alias_iter != aliases.end())
478 opcode = alias_iter->second.c_str();
479 for (int i = 0; i < opcod_size; i++)
480 {
481 const opc_t *opc = &opcod[i];
482 if (strcmp(opc->name, opcode) == 0)
483 {
484 if (par_count < opc->param_count)
485 {
486 ShowError(ERR_NOT_ENOUGH_PARAMETERS);
487 }
488 if (par_count > opc->param_count)
489 {
490 ShowError(ERR_TOO_MANY_PARAMETERS);
491 }
492 return opc;
493 }
494 }
495 ShowError(ERR_UNKNOWN_OPCODE);
496 return NULL__null;
497}
498
499// weird...
500u16 get_mask_shifted_down(u16 mask)
501{
502 while (!(mask & 1))
503 mask >>= 1;
504 return mask;
505}
506
507bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext)
508{
509 for (int i = 0; i < count; i++)
510 {
511 const int current_param = i + 1; // just for display.
512 if (opc->params[i].type != par[i].type || (par[i].type & P_REG))
513 {
514 if (par[i].type == P_VAL &&
515 (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D))
516 {
517 // Data and instruction addresses are valid as VAL values.
518 continue;
519 }
520
521 if ((opc->params[i].type & P_REG) && (par[i].type & P_REG))
522 {
523 // Just a temp. Should be replaced with more purposeful vars.
524 int value;
525
526 // modified by Hermes: test the register range
527 switch ((unsigned)opc->params[i].type)
528 {
529 case P_REG18:
530 case P_REG19:
531 case P_REG1A:
532 value = (opc->params[i].type >> 8) & 31;
533 if ((int)par[i].val < value ||
534 (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask))
535 {
536 if (ext) fprintf(stderrstderr, "(ext) ");
537 fprintf(stderrstderr, "%s (param %i)", cur_line.c_str(), current_param);
538 ShowError(ERR_INVALID_REGISTER);
539 }
540 break;
541 case P_PRG:
542 if ((int)par[i].val < 0 || (int)par[i].val > 0x3)
543 {
544 if (ext) fprintf(stderrstderr, "(ext) ");
545 fprintf(stderrstderr, "%s (param %i)", cur_line.c_str(), current_param);
546 ShowError(ERR_INVALID_REGISTER);
547 }
548 break;
549 case P_ACC:
550 if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21)
551 {
552 if (ext) fprintf(stderrstderr, "(ext) ");
553 if (par[i].val >= 0x1e && par[i].val <= 0x1f) {
554 fprintf(stderrstderr, "%i : %s ", code_line, cur_line.c_str());
555 fprintf(stderrstderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n",
556 (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext);
557 }
558 else if (par[i].val >= 0x1c && par[i].val <= 0x1d) {
559 fprintf(stderrstderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n",
560 (par[i].val & 1), (par[i].val & 1), code_line, current_param);
561 }
562 else
563 ShowError(ERR_WRONG_PARAMETER_ACC);
564 }
565 break;
566 case P_ACCM:
567 if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
568 {
569 if (ext) fprintf(stderrstderr, "(ext) ");
570 if (par[i].val >= 0x1c && par[i].val <= 0x1d)
571 fprintf(stderrstderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n",
572 (par[i].val & 1), (par[i].val & 1), code_line, current_param);
573 else if (par[i].val >= 0x20 && par[i].val <= 0x21)
574 fprintf(stderrstderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n",
575 (par[i].val & 1), (par[i].val & 1), code_line, current_param);
576 else
577 ShowError(ERR_WRONG_PARAMETER_ACC);
578 }
579 break;
580
581 case P_ACCL:
582 if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d)
583 {
584 if (ext) fprintf(stderrstderr, "(ext) ");
585 if (par[i].val >= 0x1e && par[i].val <= 0x1f)
586 {
587 fprintf(stderrstderr, "%s ", cur_line.c_str());
588 fprintf(stderrstderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n",
589 (par[i].val & 1), (par[i].val & 1), code_line, current_param);
590 }
591 else if (par[i].val >= 0x20 && par[i].val <= 0x21) {
592 fprintf(stderrstderr, "%s ", cur_line.c_str());
593 fprintf(stderrstderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n",
594 (par[i].val & 1), (par[i].val & 1), code_line, current_param);
595 }
596 else
597 ShowError(ERR_WRONG_PARAMETER_ACC);
598 }
599 break;
600/* case P_ACCM_D: //P_ACC_MID:
601 if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f)
602 {
603 ShowError(ERR_WRONG_PARAMETER_MID_ACC);
604 }
605 break;*/
606 }
607 continue;
608 }
609
610 switch (par[i].type & (P_REG | 7))
611 {
612 case P_REG:
613 if (ext) fprintf(stderrstderr, "(ext) ");
614 ShowError(ERR_EXPECTED_PARAM_REG);
615 break;
616 case P_MEM:
617 if (ext) fprintf(stderrstderr, "(ext) ");
618 ShowError(ERR_EXPECTED_PARAM_MEM);
619 break;
620 case P_VAL:
621 if (ext) fprintf(stderrstderr, "(ext) ");
622 ShowError(ERR_EXPECTED_PARAM_VAL);
623 break;
624 case P_IMM:
625 if (ext) fprintf(stderrstderr, "(ext) ");
626 ShowError(ERR_EXPECTED_PARAM_IMM);
627 break;
628 }
629 ShowError(ERR_WRONG_PARAMETER);
630 break;
631 }
632 else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0)
633 {
634 // modified by Hermes: test NUMBER range
635 int value = get_mask_shifted_down(opc->params[i].mask);
636 unsigned int valueu = 0xffff & ~(value >> 1);
637 if ((int)par[i].val < 0)
638 {
639 if (value == 7) // value 7 por sbclr/sbset
640 {
641 fprintf(stderrstderr,"Value must be from 0x0 to 0x%x\n", value);
642 ShowError(ERR_OUT_RANGE_NUMBER);
643 }
644 else if (opc->params[i].type == P_MEM)
645 {
646 if (value < 256)
647 fprintf(stderrstderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1));
648 else
649 fprintf(stderrstderr, "Address value must be from 0x0 to 0x%x\n", value);
650
651 ShowError(ERR_OUT_RANGE_NUMBER);
652 }
653 else if ((int)par[i].val < -((value >> 1) + 1))
654 {
655 if (value < 128)
656 fprintf(stderrstderr, "Value must be from -0x%x to 0x%x, is %i\n",
657 (value >> 1) + 1, value >> 1, par[i].val);
658 else
659 fprintf(stderrstderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n",
660 (value >> 1) + 1, value >> 1, value, par[i].val);
661
662 ShowError(ERR_OUT_RANGE_NUMBER);
663 }
664 }
665 else
666 {
667 if (value == 7) // value 7 por sbclr/sbset
668 {
669 if (par[i].val > (unsigned)value)
670 {
671 fprintf(stderrstderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val);
672 ShowError(ERR_OUT_RANGE_NUMBER);
673 }
674 }
675 else if (opc->params[i].type == P_MEM)
676 {
677 if (value < 256)
678 value >>= 1; // addressing 8 bit with sign
679 if (par[i].val > (unsigned)value &&
680 (par[i].val < valueu || par[i].val > (unsigned)0xffff))
681 {
682 if (value < 256)
683 fprintf(stderrstderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val);
684 else
685 fprintf(stderrstderr,"Address value must be minor of 0x%x\n", value+1);
686 ShowError(ERR_OUT_RANGE_NUMBER);
687 }
688 }
689 else
690 {
691 if (value < 128)
692 value >>= 1; // special case ASL/ASR/LSL/LSR
693 if (par[i].val > (unsigned)value)
694 {
695 if (value < 64)
696 fprintf(stderrstderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val);
697 else
698 fprintf(stderrstderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val);
699 ShowError(ERR_OUT_RANGE_NUMBER);
700 }
701 }
702 }
703 continue;
704 }
705 }
706 m_current_param = 0;
707 return true;
708}
709
710
711// Merge opcode with params.
712void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
713{
714 outbuf[m_cur_addr] |= opc->opcode;
715 for (u32 i = 0; i < par_count; i++)
716 {
717 // Ignore the "reverse" parameters since they are implicit.
718 if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D)
719 {
720 u16 t16 = outbuf[m_cur_addr + opc->params[i].loc];
721 u16 v16 = par[i].val;
722 if (opc->params[i].lshift > 0)
723 v16 <<= opc->params[i].lshift;
724 else
725 v16 >>= -opc->params[i].lshift;
726 v16 &= opc->params[i].mask;
727 outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16;
728 }
729 }
730}
731
732void DSPAssembler::InitPass(int pass)
733{
734 failed = false;
735 if (pass == 1)
736 {
737 // Reset label table. Pre-populate with hw addresses and registers.
738 labels.Clear();
739 labels.RegisterDefaults();
740 aliases.clear();
741 aliases["S15"] = "SET15";
742 aliases["S16"] = "SET16";
743 aliases["S40"] = "SET40";
744 }
745 m_cur_addr = 0;
746 m_totalSize = 0;
747 cur_segment = SEGMENT_CODE;
748 segment_addr[SEGMENT_CODE] = 0;
749 segment_addr[SEGMENT_DATA] = 0;
750 segment_addr[SEGMENT_OVERLAY] = 0;
751}
752
753bool DSPAssembler::AssembleFile(const char *fname, int pass)
754{
755 int disable_text = 0; // modified by Hermes
756
757 std::ifstream fsrc;
758 OpenFStream(fsrc, fname, std::ios_base::in);
759
760 if (fsrc.fail())
761 {
762 std::cerr << "Cannot open file " << fname << std::endl;
763 return false;
764 }
765
766 //printf("%s: Pass %d\n", fname, pass);
767 code_line = 0;
768 m_cur_pass = pass;
769
770#define LINEBUF_SIZE1024 1024
771 char line[LINEBUF_SIZE1024] = {0};
772 while (!failed && !fsrc.fail() && !fsrc.eof())
773 {
774 int opcode_size = 0;
775 fsrc.getline(line, LINEBUF_SIZE1024);
776 if(fsrc.fail())
777 break;
778
779 cur_line = line;
780 //printf("A: %s\n", line);
781 code_line++;
782
783 param_t params[10] = {{0, P_NONE, NULL__null}};
784 param_t params_ext[10] = {{0, P_NONE, NULL__null}};
785
786 bool upper = true;
787 for (int i = 0; i < LINEBUF_SIZE1024; i++)
788 {
789 char c = line[i];
790 // This stuff handles /**/ and // comments.
791 // modified by Hermes : added // and /* */ for long commentaries
792 if (c == '/')
793 {
794 if (i < 1023)
795 {
796 if (line[i+1] == '/')
797 c = 0x00;
798 else if (line[i+1] == '*')
799 {
800 // toggle comment mode.
801 disable_text = !disable_text;
802 }
803 }
804 }
805 else if (c == '*')
806 {
807 if (i < 1023 && line[i+1] == '/' && disable_text)
808 {
809 disable_text = 0;
810 c = 32;
811 line[i + 1] = 32;
812 }
813 }
814
815 // turn text into spaces if disable_text is on (in a comment).
816 if (disable_text && ((unsigned char)c) > 32) c = 32;
817
818 if (c == 0x0a || c == 0x0d || c == ';')
819 c = 0x00;
820 if (c == 0x09) // tabs to spaces
821 c = ' ';
822 if (c == '"')
823 upper = !upper;
824 if (upper && c >= 'a' && c <= 'z') // convert to uppercase
825 c = c - 'a' + 'A';
826 line[i] = c;
827 if (c == 0)
828 break; // modified by Hermes
829 }
830 char *ptr = line;
831
832 std::string label;
833
834 size_t col_pos = std::string(line).find(":");
835 if (col_pos != std::string::npos)
836 {
837 bool valid = true;
838
839 for(int j = 0; j < (int)col_pos; j++)
840 {
841 if (j == 0)
842 if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
843 valid = false;
844 if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_')))
845 valid = false;
846 }
847 if (valid)
848 {
849 label = std::string(line).substr(0, col_pos);
850 ptr += col_pos + 1;
851 }
852 }
853
854 char *opcode = NULL__null;
855 opcode = strtok(ptr, " ");
856 char *opcode_ext = NULL__null;
857
858 u32 params_count = 0;
859 u32 params_count_ext = 0;
860 if (opcode)
861 {
862 if ((opcode_ext = strstr(opcode, "'")) != NULL__null)
863 {
864 opcode_ext[0] = '\0';
865 opcode_ext++;
866 if (strlen(opcode_ext) == 0)
867 opcode_ext = NULL__null;
868 }
869 // now we have opcode and label
870
871 params_count = 0;
872 params_count_ext = 0;
873
874 char *paramstr = strtok(NULL__null, "\0");
875 char *paramstr_ext = 0;
876 // there is valid opcode so probably we have parameters
877
878 if (paramstr)
879 {
880 if ((paramstr_ext = strstr(paramstr, ":")) != NULL__null)
881 {
882 paramstr_ext[0] = '\0';
883 paramstr_ext++;
884 }
885 }
886
887 if (paramstr)
888 params_count = GetParams(paramstr, params);
889 if (paramstr_ext)
890 params_count_ext = GetParams(paramstr_ext, params_ext);
891 }
892
893 if (!label.empty())
894 {
895 // there is a valid label so lets store it in labels table
896 u32 lval = m_cur_addr;
897 if (opcode)
898 {
899 if (strcmp(opcode, "EQU") == 0)
900 {
901 lval = params[0].val;
902 opcode = NULL__null;
903 }
904 }
905 if (pass == 1)
906 labels.RegisterLabel(label, lval);
907 }
908
909 if (opcode == NULL__null)
910 continue;
911
912 // check if opcode is reserved compiler word
913 if (strcmp("INCLUDE", opcode) == 0)
914 {
915 if (params[0].type == P_STR)
916 {
917 char *tmpstr;
918 u32 thisCodeline = code_line;
919
920 if (include_dir.size())
921 {
922 tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2);
923 sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str);
924 }
925 else
926 {
927 tmpstr = (char *)malloc(strlen(params[0].str) + 1);
928 strcpy(tmpstr, params[0].str);
929 }
930
931 AssembleFile(tmpstr, pass);
932
933 code_line = thisCodeline;
934
935 free(tmpstr);
936 }
937 else
938 ShowError(ERR_EXPECTED_PARAM_STR);
939 continue;
940 }
941
942 if (strcmp("INCDIR", opcode) == 0)
943 {
944 if (params[0].type == P_STR)
945 include_dir = params[0].str;
946 else
947 ShowError(ERR_EXPECTED_PARAM_STR);
948 continue;
949 }
950
951 if (strcmp("ORG", opcode) == 0)
952 {
953 if (params[0].type == P_VAL)
954 m_cur_addr = params[0].val;
955 else
956 ShowError(ERR_EXPECTED_PARAM_VAL);
957 continue;
958 }
959
960 if (strcmp("SEGMENT", opcode) == 0)
961 {
962 if (params[0].type == P_STR)
963 {
964 segment_addr[cur_segment] = m_cur_addr;
965 if (strcmp("DATA", params[0].str) == 0)
966 cur_segment = SEGMENT_DATA;
967 if (strcmp("CODE", params[0].str) == 0)
968 cur_segment = SEGMENT_CODE;
969 m_cur_addr = segment_addr[cur_segment];
970 }
971 else
972 ShowError(ERR_EXPECTED_PARAM_STR);
973 continue;
974 }
975
976 const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size);
977 if (!opc)
978 opc = &cw;
979
980 opcode_size = opc->size;
981
982 VerifyParams(opc, params, params_count);
983
984 const opc_t *opc_ext = NULL__null;
985 // Check for opcode extensions.
986 if (opc->extended)
987 {
988 if (opcode_ext)
989 {
990 opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size);
991 VerifyParams(opc_ext, params_ext, params_count_ext, true);
992 }
993 else if (params_count_ext)
994 ShowError(ERR_EXT_PAR_NOT_EXT);
995 }
996 else
997 {
998 if (opcode_ext)
999 ShowError(ERR_EXT_CANT_EXTEND_OPCODE);
1000 if (params_count_ext)
1001 ShowError(ERR_EXT_PAR_NOT_EXT);
1002 }
1003
1004 if (pass == 2)
1005 {
1006 // generate binary
1007 ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000;
1008 BuildCode(opc, params, params_count, (u16 *)gdg_buffer);
1009 if (opc_ext)
1010 BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer);
1011 }
1012
1013 m_cur_addr += opcode_size;
1014 m_totalSize += opcode_size;
1015 };
1016
1017 if (!failed)
1018 fsrc.close();
1019
1020 return !failed;
1021}