1 /*
2 * pasm.c
3 *
4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the
17 * distribution.
18 *
19 * Neither the name of Texas Instruments Incorporated nor the names of
20 * its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 /*===========================================================================
38 * Copyright (c) Texas Instruments Inc 2010-12
39 *
40 * Use of this software is controlled by the terms and conditions found in the
41 * license agreement under which this software has been supplied or provided.
42 * ============================================================================
43 */
44
45 /*===========================================================================
46 // PASM - PRU Assembler
47 //---------------------------------------------------------------------------
48 //
49 // File : pasm.c
50 //
51 // Description:
52 // Main assembler control program.
53 // - Processes command line and flags
54 // - Runs the main assembler engine (dual pass)
55 // - Handles error reporting
56 // - Handles label creation and matching
57 // - Handle output file generation
58 //
59 //---------------------------------------------------------------------------
60 // Revision:
61 // 21-Jun-13: 0.84 - Open source version
62 ============================================================================*/
63
64 #include <stdio.h>
65 #include <stdarg.h>
66 #include <string.h>
67 #if !defined(__APPLE__) && !defined(__FreeBSD__)
68 #include <malloc.h>
69 #else
70 #include <stdlib.h>
71 #endif
72 #include <ctype.h>
73 #include "pasm.h"
74 #include "pasmdbg.h"
75
76 /*
77 // Multiple Core Revision Support
78 // ------------------------------
79 //
80 // -V0 PRU Legacy (same as -x)
81 // -V1 PRU Generation 1 (default)
82 // Adds [LMBD,SCAN,HALT,ZERO(1),MVI(1),SLP(1)] Removes [LFC,STC]
83 // -V2 PRU Generation 2 (same as -X)
84 // Adds [ZERO(2),FILL,XIN,XOUT,XCHG,MVI(2)] Removes [SCAN]
85 // -V3 PRU Generation 3
86 // Adds [SLP(2),LOOP,ILOOP,SXIN,SXOUT,SXCHG,NOPx]
87 //
88 // ZERO(1) : Zero is multi-cycle pseudo op encoded via moves
89 // ZERO(2) : Zero is single-cycle pseudo op encoded via XFR
90 //
91 // MVI(1) : Pseudo op forms of MVI only
92 // MVI(2) : Pseudo op forms of MVI only
93 //
94 // SLP(1) : SLP with trailing NOP
95 // SLP(2) : SLP without trailing NOP
96 */
97
98
99 /* ---------- Local Macro Definitions ----------- */
100
101 #define PROCESSOR_NAME_STRING ("PRU")
102 #define VERSION_STRING ("0.84")
103
104 #define MAXFILE (256) /* Max file length for output files */
105 #define MAX_PROGRAM (16384) /* Max instruction count */
106 #define MAX_CMD_EQUATE (8) /* Max equates that can be put on command line */
107
108 #define RET_ERROR (1)
109 #define RET_SUCCESS (0)
110
111 /* Big/Little Endian Conversions */
112 #define HNC16(a) ((((a)>>8)&0xff)+(((a)<<8)&0xff00))
113 #define HNC32(a) ((((a)>>24)&0xff)+(((a)>>8)&0xff00)+(((a)<<8)&0xff0000)+(((a)<<24)&0xff000000))
114
115 /* User Options */
116 unsigned int Options = 0;
117 unsigned int Core = CORE_NONE;
118 FILE *ListingFile = 0;
119
120 /* Assembler Engine */
121 int Pass; /* Pass 1 or 2 of parser */
122 int HaveEntry; /* Entrypont flag (init to 0) */
123 int EntryPoint; /* Entrypont (init to -1) */
124 int CodeOffset; /* Current instruction "word" offset (zero based) */
125 int Errors; /* Total number or errors */
126 int FatalError; /* Set on fatal error */
127 int Warnings; /* Total number of warnings */
128 uint RetRegValue; /* Return register index */
129 uint RetRegField; /* Return register field */
130
131 LABEL *pLabelList=0; /* List of installed labels */
132 int LabelCount=0;
133
134 CODEGEN ProgramImage[MAX_PROGRAM];
135
136 SOURCEFILE cmdLine = { 0, 0, 0, 0, 0, 0, 0, 0, "[CommandLine]", "" };
137 char cmdLineName[MAX_CMD_EQUATE][EQUATE_NAME_LEN];
138 char cmdLineData[MAX_CMD_EQUATE][EQUATE_DATA_LEN];
139 int cmdLineEquates = 0;
140
141 char nameCArray[EQUATE_DATA_LEN];
142 int nameCArraySet = 0;
143
144 /* Local Support Funtions */
145 static int ValidateOffset( SOURCEFILE *ps );
146 static int PrintLine( FILE *pfOut, SOURCEFILE *ps );
147 static int GetInfoFromAddr( uint address, uint *pIndex, uint *pLineNo, uint *pCodeWord );
148 static int ListFile( FILE *pfOut, SOURCEFILE *ps );
149
150 /*
151 // Main Assembler Entry Point
152 //
153 */
main(int argc,char * argv[])154 int main(int argc, char *argv[])
155 {
156 int i,j;
157 int CodeOffsetPass1 = 0;
158 char *infile, *outfile, *flags;
159 SOURCEFILE *mainsource;
160 char outbase[MAXFILE],outfilename[MAXFILE];
161
162 printf("\n\n%s Assembler Version %s\n",PROCESSOR_NAME_STRING, VERSION_STRING);
163 printf("Copyright (C) 2005-2013 by Texas Instruments Inc.\n\n");
164
165 /* Scan argv[0] to the final '/' in program name */
166 i=0;
167 j=-1;
168 while( argv[0][i] )
169 {
170 if( argv[0][i] == '/' || argv[0][i] == '\\')
171 j=i;
172 i++;
173 }
174 argv[0]+=(j+1);
175
176 /*
177 // Process command line
178 */
179 infile=0;
180 flags=0;
181 outfile=0;
182
183 if( argc<2 )
184 {
185 USAGE:
186 printf("Usage: %s [-V#EBbcmLldz] [-Dname=value] [-Cname] InFile [OutFileBase]\n\n",argv[0]);
187 printf(" V# - Specify core version (V0,V1,V2,V3). (Default is V1)\n");
188 printf(" E - Assemble for big endian core\n");
189 printf(" B - Create big endian binary output (*.bib)\n");
190 printf(" b - Create little endian binary output (*.bin)\n");
191 printf(" c - Create 'C array' binary output (*_bin.h)\n");
192 printf(" m - Create 'image' binary output (*.img)\n");
193 printf(" L - Create annotated source file style listing (*.txt)\n");
194 printf(" l - Create raw listing file (*.lst)\n");
195 printf(" d - Create pView debug file (*.dbg)\n");
196 printf(" z - Enable debug messages\n");
197 printf("\n D - Set equate 'name' to 1 using '-Dname', or to any\n");
198 printf(" value using '-Dname=value'\n");
199 printf(" C - Name the C array in 'C array' binary output\n");
200 printf(" to 'name' using '-Cname'\n");
201 printf("\n");
202 return(RET_ERROR);
203 }
204
205 /* Get all non-flag arguments */
206 for( i=1; i<argc; i++ )
207 {
208 if( argv[i][0] != '-' )
209 {
210 if( !infile )
211 infile = argv[i];
212 else if( !outfile )
213 outfile = argv[i];
214 else
215 goto USAGE;
216 }
217 }
218
219 /* Get all flag arguments */
220 for( i=1; i<argc; i++ )
221 {
222 if( argv[i][0] == '-' )
223 {
224 flags = argv[i];
225 flags++;
226 while( *flags )
227 {
228 if( *flags == 'D' )
229 {
230 flags++;
231 if( cmdLineEquates==MAX_CMD_EQUATE )
232 {
233 printf("\nToo many command line equates\n\n");
234 goto USAGE;
235 }
236 j=0;
237 while( j<EQUATE_NAME_LEN && *flags && *flags!='=' )
238 cmdLineName[cmdLineEquates][j++]=*flags++;
239 if( j==EQUATE_NAME_LEN )
240 {
241 printf("\nCommand line equate name too long\n\n");
242 goto USAGE;
243 }
244 strcpy( cmdLineData[cmdLineEquates], "1" );
245 if( *flags=='=' )
246 {
247 flags++;
248 j=0;
249 while( j<EQUATE_DATA_LEN && *flags )
250 cmdLineData[cmdLineEquates][j++]=*flags++;
251 if( j==EQUATE_DATA_LEN )
252 {
253 printf("\nCommand line equate data too long\n\n");
254 goto USAGE;
255 }
256 }
257 cmdLineEquates++;
258 break;
259 }
260 else if( *flags == 'C' )
261 {
262 flags++;
263 j = 0;
264 while( j<EQUATE_DATA_LEN && *flags )
265 {
266 nameCArray[j++]=*flags++;
267 }
268 if( j==EQUATE_DATA_LEN )
269 {
270 printf("\nCArray name too long\n\n");
271 goto USAGE;
272 }
273 nameCArraySet = 1;
274 break;
275 }
276 else if( *flags == 'V' )
277 {
278 flags++;
279 if( *flags<'0' || *flags>'3' )
280 {
281 printf("\nExpected a number (0-3) after option 'V'\n\n");
282 goto USAGE;
283 }
284 if( Core != CORE_NONE )
285 {
286 printf("\nDo not specify more than one core version or use -V with -X or -x\n\n");
287 goto USAGE;
288 }
289 Core = CORE_V0 + *flags - '0';
290 }
291 else if( *flags == 'x' )
292 {
293 if( Core != CORE_NONE )
294 {
295 printf("\nDo not use -x with -X or -V\n\n");
296 goto USAGE;
297 }
298 Core = CORE_V0;
299 }
300 else if( *flags == 'X' )
301 {
302 if( Core != CORE_NONE )
303 {
304 printf("\nDo not use -X with -x or -V\n\n");
305 goto USAGE;
306 }
307 Core = CORE_V2;
308 }
309 else if( *flags == 'E' )
310 Options |= OPTION_BIGENDIAN;
311 else if( *flags == 'b' )
312 Options |= OPTION_BINARY;
313 else if( *flags == 'B' )
314 Options |= OPTION_BINARYBIG;
315 else if( *flags == 'c' )
316 Options |= OPTION_CARRAY;
317 else if( *flags == 'm' )
318 Options |= OPTION_IMGFILE;
319 else if( *flags == 'l' )
320 Options |= OPTION_LISTING;
321 else if( *flags == 'L' )
322 Options |= OPTION_SOURCELISTING;
323 else if( *flags == 'd' )
324 Options |= OPTION_DBGFILE;
325 else if( *flags == 'z' )
326 Options |= OPTION_DEBUG;
327 else
328 {
329 printf("\nUnknown flag '%c'\n\n",*flags);
330 goto USAGE;
331 }
332 flags++;
333 }
334 }
335 }
336
337 if( Core==CORE_NONE )
338 Core = CORE_V1;
339
340 /* Check input file */
341 if( !infile )
342 goto USAGE;
343
344 /* Check output file base - make sure no '.' */
345 if( outfile )
346 {
347 if( strlen(outfile) > (MAXFILE-5) )
348 { Report(0,REP_ERROR,"Outfile name too long"); return(RET_ERROR); }
349 i=0;
350 while( outfile[i] )
351 {
352 if( outfile[i]=='.' )
353 {
354 if( outfile[i+1]=='.' )
355 i++;
356 else
357 { Report(0,REP_ERROR,"Outfile should be basename only - no '.'"); return(RET_ERROR); }
358 }
359 i++;
360 }
361 strcpy( outbase, outfile );
362 }
363
364 /* Test opening the main source file */
365 if( !(mainsource=InitSourceFile(0,infile)) )
366 return(RET_ERROR);
367
368 /* Setup outfile base */
369 if( !outfile )
370 {
371 for(i=0; mainsource->SourceName[i] && mainsource->SourceName[i]!='.'; i++ )
372 outbase[i]=mainsource->SourceName[i];
373 outbase[i] = 0;
374 }
375 if( Options & OPTION_DEBUG )
376 printf("Output base filename: '%s'\n",outbase);
377
378 /* Close the source file for now */
379 CloseSourceFile( mainsource );
380
381 /* If no output specified, default to 'C' array */
382 if( !(Options & (OPTION_BINARY|OPTION_CARRAY|OPTION_BINARYBIG|OPTION_IMGFILE|OPTION_DBGFILE)) )
383 {
384 printf("Note: Using default output '-c' (C array *_bin.h)\n\n");
385 Options |= OPTION_CARRAY;
386 }
387
388 /* Open listing file */
389 if( Options & OPTION_LISTING )
390 {
391 strcpy( outfilename, outbase );
392 strcat( outfilename, ".lst" );
393 if (!(ListingFile = fopen(outfilename,"wb")))
394 { Report(0,REP_ERROR,"Unable to open output file: %s",outfilename); return(RET_ERROR); }
395 }
396
397 /* Clear the binary image */
398 memset( ProgramImage, 0, sizeof(ProgramImage) );
399
400 /* Make 2 assembler passes */
401 Pass = 0;
402 Errors = 0;
403 Warnings = 0;
404 FatalError = 0;
405 RetRegValue = DEFAULT_RETREGVAL;
406 RetRegField = DEFAULT_RETREGFLD;
407 while( !Errors && Pass<2 )
408 {
409 Pass++;
410 CodeOffset = -1;
411 HaveEntry = 0;
412 EntryPoint = -1;
413
414 /* Initialize the PP and DOT modules */
415 for(i=0; i<cmdLineEquates; i++ )
416 EquateCreate( &cmdLine, cmdLineName[i], cmdLineData[i] );
417 DotInitialize(Pass);
418
419 /* Process the main source file */
420 if( !(mainsource=InitSourceFile(0,infile)) )
421 break;
422 ProcessSourceFile( mainsource );
423 CloseSourceFile( mainsource );
424
425 /* Cleanup the PP and DOT modules */
426 ppCleanup(Pass);
427 DotCleanup(Pass);
428
429 if( Pass==1 )
430 {
431 CodeOffsetPass1 = CodeOffset;
432 }
433 }
434
435 /* Close the listing file */
436 if( ListingFile )
437 fclose( ListingFile );
438
439 /* Make sure user didn't do something silly */
440 if( CodeOffsetPass1!=CodeOffset )
441 {
442 printf("Error: Offset changed between pass 1 and pass 2\n");
443 Errors++;
444 }
445
446 /* Process the results */
447 printf("\nPass %d : %d Error(s), %d Warning(s)\n\n",Pass,Errors,Warnings);
448 if( Errors || CodeOffset<=0 )
449 Options = 0;
450 else
451 printf("Writing Code Image of %d word(s)\n\n",CodeOffset);
452
453 /* Create the output files */
454 if( Options & OPTION_CARRAY )
455 {
456 FILE *Outfile;
457
458 strcpy( outfilename, outbase );
459 strcat( outfilename, "_bin.h" );
460 if (!(Outfile = fopen(outfilename,"wb")))
461 Report(0,REP_ERROR,"Unable to open output file: %s",outfilename);
462 else
463 {
464 fprintf( Outfile, "\n\n"
465 "/* This file contains the %s instructions in a C array which are to */\n"
466 "/* be downloaded from the host CPU to the %s instruction memory. */\n"
467 "/* This file is generated by the %s assembler. */\n",
468 PROCESSOR_NAME_STRING, PROCESSOR_NAME_STRING, PROCESSOR_NAME_STRING);
469 if( !nameCArraySet )
470 fprintf(Outfile,"\nconst unsigned int %scode[] = {\n",PROCESSOR_NAME_STRING);
471 else
472 fprintf(Outfile,"\nconst unsigned int %s[] = {\n",nameCArray);
473 for(i=0;i<(CodeOffset-1);i++)
474 fprintf(Outfile," 0x%08x,\n",ProgramImage[i].CodeWord);
475 fprintf(Outfile," 0x%08x };\n\n",ProgramImage[CodeOffset-1].CodeWord);
476 fclose( Outfile );
477 }
478 }
479 if( Options & OPTION_IMGFILE )
480 {
481 FILE *Outfile;
482
483 strcpy( outfilename, outbase );
484 strcat( outfilename, ".img" );
485 if (!(Outfile = fopen(outfilename,"wb")))
486 Report(0,REP_ERROR,"Unable to open output file: %s",outfilename);
487 else
488 {
489 for(i=0;i<CodeOffset;i++)
490 fprintf(Outfile,"%08x\n",ProgramImage[i].CodeWord);
491 fclose( Outfile );
492 }
493 }
494 if( Options & OPTION_DBGFILE )
495 {
496 FILE *Outfile;
497 uint BigEndian;
498
499 BigEndian = 0;
500 *(unsigned char *)&BigEndian = 1;
501 if( BigEndian != 1 )
502 BigEndian = 1;
503 else
504 BigEndian = 0;
505
506 strcpy( outfilename, outbase );
507 strcat( outfilename, ".dbg" );
508 if (!(Outfile = fopen(outfilename,"wb")))
509 Report(0,REP_ERROR,"Unable to open output file: %s",outfilename);
510 else
511 {
512 DBGFILE_HEADER hdr;
513 DBGFILE_HEADER hdr_write;
514 DBGFILE_LABEL lbl;
515 DBGFILE_FILE file;
516 DBGFILE_CODE code;
517 LABEL *pLabel;
518 unsigned int file_offset;
519 int i;
520
521 memset( &hdr, 0, sizeof(DBGFILE_HEADER) );
522 hdr.FileID = DBGFILE_FILEID_VER3;
523 file_offset = sizeof(DBGFILE_HEADER);
524 hdr.LabelCount = LabelCount;
525 hdr.LabelOffset = file_offset;
526 file_offset += hdr.LabelCount * sizeof(DBGFILE_LABEL);
527 hdr.FileCount = sfIndex;
528 hdr.FileOffset = file_offset;
529 file_offset += hdr.FileCount * sizeof(DBGFILE_FILE);
530 hdr.CodeCount = CodeOffset;
531 hdr.CodeOffset = file_offset;
532 hdr.EntryPoint = EntryPoint;
533
534 if( Options & OPTION_BIGENDIAN )
535 hdr.Flags |= DBGHDR_FLAGS_BIGENDIAN;
536
537 if(!BigEndian)
538 hdr_write = hdr;
539 else
540 {
541 hdr_write.FileID = HNC32(hdr.FileID);
542 hdr_write.LabelCount = HNC32(hdr.LabelCount);
543 hdr_write.LabelOffset = HNC32(hdr.LabelOffset);
544 hdr_write.FileCount = HNC32(hdr.FileCount);
545 hdr_write.FileOffset = HNC32(hdr.FileOffset);
546 hdr_write.CodeCount = HNC32(hdr.CodeCount);
547 hdr_write.CodeOffset = HNC32(hdr.CodeOffset);
548 hdr_write.EntryPoint = HNC32(hdr.EntryPoint);
549 hdr_write.Flags = HNC32(hdr.Flags);
550 }
551 if( fwrite(&hdr_write,1,sizeof(DBGFILE_HEADER),Outfile) != sizeof(DBGFILE_HEADER) )
552 Report(0,REP_ERROR,"File write error");
553
554 pLabel = pLabelList;
555 for( i=0; i<(int)hdr.LabelCount; i++ )
556 {
557 memset( &lbl, 0, sizeof(DBGFILE_LABEL) );
558 if( !pLabel )
559 Report(0,REP_ERROR,"Fatal label tracking error");
560 else
561 {
562 lbl.AddrOffset = pLabel->Offset;
563 strcpy(lbl.Name,pLabel->Name);
564 if(BigEndian)
565 lbl.AddrOffset = HNC32(lbl.AddrOffset);
566 if( fwrite(&lbl,1,sizeof(DBGFILE_LABEL),Outfile) != sizeof(DBGFILE_LABEL) )
567 Report(0,REP_ERROR,"File write error");
568 pLabel = pLabel->pNext;
569 }
570 }
571
572 for(i=0; i<(int)hdr.FileCount; i++)
573 {
574 memset( &file, 0, sizeof(DBGFILE_FILE) );
575 if( !strcmp( sfArray[i].SourceBaseDir,"./") ||
576 ((strlen(sfArray[i].SourceName)+strlen(sfArray[i].SourceBaseDir)) >= DBGFILE_NAMELEN_SHORT) )
577 strcpy(file.SourceName,sfArray[i].SourceName);
578 else
579 {
580 strcpy(file.SourceName,sfArray[i].SourceBaseDir);
581 strcat(file.SourceName,sfArray[i].SourceName);
582 }
583 if( fwrite(&file,1,sizeof(DBGFILE_FILE),Outfile) != sizeof(DBGFILE_FILE) )
584 Report(0,REP_ERROR,"File write error");
585 }
586
587 for(i=0; i<(int)hdr.CodeCount; i++)
588 {
589 memset( &code, 0, sizeof(DBGFILE_CODE) );
590 code.Flags = ProgramImage[i].Flags;
591 code.Resv8 = ProgramImage[i].Resv8;
592 code.FileIndex = ProgramImage[i].FileIndex;
593 code.Line = ProgramImage[i].Line;
594 code.AddrOffset = ProgramImage[i].AddrOffset;
595 code.CodeWord = ProgramImage[i].CodeWord;
596 if(BigEndian)
597 {
598 code.FileIndex = HNC16(code.FileIndex);
599 code.Line = HNC32(code.Line);
600 code.AddrOffset = HNC32(code.AddrOffset);
601 code.CodeWord = HNC32(code.CodeWord);
602 }
603 if( fwrite(&code,1,sizeof(DBGFILE_CODE),Outfile) != sizeof(DBGFILE_CODE) )
604 Report(0,REP_ERROR,"File write error");
605 }
606 fclose( Outfile );
607 }
608 }
609 if( Options & OPTION_SOURCELISTING )
610 {
611 FILE *Outfile;
612
613 strcpy( outfilename, outbase );
614 strcat( outfilename, ".txt" );
615 if (!(Outfile = fopen(outfilename,"wb")))
616 Report(0,REP_ERROR,"Unable to open output file: %s",outfilename);
617 else
618 {
619 char FullPath[SOURCE_BASE_DIR+SOURCE_NAME];
620
621 for( i=0; i<(int)sfIndex; i++ )
622 {
623 fprintf(Outfile, "Source File %d : '%s' ", i+1, sfArray[i].SourceName);
624 strcpy(FullPath,sfArray[i].SourceBaseDir);
625 strcat(FullPath,sfArray[i].SourceName);
626 sfArray[i].FilePtr=fopen(FullPath,"rb");
627 if( sfArray[i].FilePtr!=0 )
628 {
629 sfArray[i].CurrentLine = 1;
630 sfArray[i].CurrentColumn = 1;
631 sfArray[i].LastChar = 0;
632 ListFile(Outfile,&sfArray[i]);
633 fclose(sfArray[i].FilePtr);
634 fprintf(Outfile, "\n\n");
635 }
636 else
637 fprintf(Outfile, "(File Not Found '%s')\n\n",FullPath);
638 }
639
640 fclose(Outfile);
641 }
642 }
643 if( Options & OPTION_BINARY )
644 {
645 FILE *Outfile;
646
647 strcpy( outfilename, outbase );
648 strcat( outfilename, ".bin" );
649 if (!(Outfile = fopen(outfilename,"wb")))
650 Report(0,REP_ERROR,"Unable to open output file: %s",outfilename);
651 else
652 {
653 unsigned char tmp;
654
655 /* Write out as Little Endian */
656 for(i=0;i<CodeOffset;i++)
657 {
658 tmp = (unsigned char)ProgramImage[i].CodeWord;
659 fwrite(&tmp,1,1,Outfile);
660 tmp = (unsigned char)(ProgramImage[i].CodeWord>>8);
661 fwrite(&tmp,1,1,Outfile);
662 tmp = (unsigned char)(ProgramImage[i].CodeWord>>16);
663 fwrite(&tmp,1,1,Outfile);
664 tmp = (unsigned char)(ProgramImage[i].CodeWord>>24);
665 fwrite(&tmp,1,1,Outfile);
666 }
667 fclose( Outfile );
668 }
669 }
670 if( Options & OPTION_BINARYBIG )
671 {
672 FILE *Outfile;
673
674 strcpy( outfilename, outbase );
675 strcat( outfilename, ".bib" );
676 if (!(Outfile = fopen(outfilename,"wb")))
677 Report(0,REP_ERROR,"Unable to open output file: %s",outfilename);
678 else
679 {
680 unsigned char tmp;
681
682 /* Write out as Big Endian */
683 for(i=0;i<CodeOffset;i++)
684 {
685 tmp = (unsigned char)(ProgramImage[i].CodeWord>>24);
686 fwrite(&tmp,1,1,Outfile);
687 tmp = (unsigned char)(ProgramImage[i].CodeWord>>16);
688 fwrite(&tmp,1,1,Outfile);
689 tmp = (unsigned char)(ProgramImage[i].CodeWord>>8);
690 fwrite(&tmp,1,1,Outfile);
691 tmp = (unsigned char)ProgramImage[i].CodeWord;
692 fwrite(&tmp,1,1,Outfile);
693 }
694 fclose( Outfile );
695 }
696 }
697
698 /* Assember label cleanup */
699 while( pLabelList )
700 LabelDestroy( pLabelList );
701
702 if( Errors || CodeOffset<=0 )
703 return(RET_ERROR);
704 return(RET_SUCCESS);
705 }
706
707
708 /*
709 // ProcessSourceFile
710 //
711 // New source file to assemble.
712 //
713 // Returns 1 on success, 0 on error
714 */
715 #define MAX_SOURCE_LINE 256
ProcessSourceFile(SOURCEFILE * ps)716 int ProcessSourceFile( SOURCEFILE *ps )
717 {
718 char src[MAX_SOURCE_LINE];
719 int i;
720
721 for(;;)
722 {
723 /* Abort on a total disaster */
724 if( FatalError || Errors >= 25 )
725 { printf("Aborting...\n"); return(0); }
726
727 /* Get a line of source code */
728 i = GetSourceLine( ps, src, MAX_SOURCE_LINE );
729 if( !i )
730 return(1);
731 if( i<0 )
732 continue;
733
734 if( !ProcessSourceLine(ps, i, src) && Pass==2 )
735 return(0);
736 }
737 }
738
739
740 /*
741 // ProcessSourceLine
742 //
743 // New source line to assemble.
744 //
745 // Returns 1 on success, 0 on error
746 */
ProcessSourceLine(SOURCEFILE * ps,int length,char * src)747 int ProcessSourceLine( SOURCEFILE *ps, int length, char *src )
748 {
749 char *pParams[MAX_TOKENS];
750 SRCLINE sl;
751 int i,rc;
752
753 REPEAT:
754 if( !ParseSourceLine(ps,length,src,&sl) )
755 return(0);
756
757 /* Process Label */
758 if( sl.Flags & SRC_FLG_LABEL )
759 {
760 /* Make sure offset is ready */
761 if( !ValidateOffset(ps) )
762 return(0);
763
764 /* Create Label */
765 if( Pass==1 )
766 {
767 LabelCreate(ps, sl.Label, CodeOffset);
768 }
769
770 /* Note it in listing file */
771 if( Pass==2 && (Options & OPTION_LISTING) )
772 {
773 fprintf(ListingFile,"%s(%5d) : 0x%04x = Label : %s:\n",
774 ps->SourceName,ps->CurrentLine,CodeOffset,sl.Label);
775 }
776 }
777
778 /* Process Command/Opcode */
779 if( sl.Terms )
780 {
781 /* Get the parameters into a collection of string pointers */
782 for(i=0; i<(int)sl.Terms; i++)
783 pParams[i]=sl.Term[i];
784 for( ; i<MAX_TOKENS; i++ )
785 pParams[i]=0;
786
787 /* Perform structure processing */
788 if (!CheckMacro(pParams[0]))
789 for(i=0; i<(int)sl.Terms; i++)
790 if( StructParamProcess(ps, i, pParams[i])<0 )
791 { Report(ps,REP_ERROR,"Error in struct parsing parameter %d",i); return(0); }
792
793 /* Process a dot command */
794 if( sl.Flags & SRC_FLG_DOTCMD1 )
795 {
796 src[0] = 0;
797
798 rc = DotCommand(ps,sl.Terms,pParams,src,MAX_SOURCE_LINE);
799 if( rc<0 )
800 return(0);
801 if( !rc )
802 return(1);
803 /*
804 // The dot command generated new code, process it now
805 */
806 goto REPEAT;
807 }
808 else
809 {
810 /* Process the macro or opcode */
811 if (CheckMacro(pParams[0]))
812 {
813 // Process Macros
814 if ( !ProcessMacro(ps, sl.Terms, pParams) )
815 return (0);
816 }
817 else
818 {
819 // Process Opcodes
820 if( !ProcessOp(ps, sl.Terms, pParams) )
821 {
822 GenOp( ps, sl.Terms, pParams, 0xFFFFFFFF );
823 return (0);
824 }
825 }
826 }
827 }
828 return(1);
829 }
830
831
832 /*
833 // ParseSourceLine
834 //
835 // New source line to parse.
836 //
837 // Returns 1 on success, 0 on error
838 */
ParseSourceLine(SOURCEFILE * ps,int length,char * src,SRCLINE * pa)839 int ParseSourceLine( SOURCEFILE *ps, int length, char *src, SRCLINE *pa )
840 {
841 char c;
842 int srcIdx,wordIdx;
843 int parmCnt;
844
845 srcIdx = 0;
846 pa->Flags = 0;
847 pa->Terms = 0;
848
849 PROCESS_LINE:
850 /* Make sure character 1 is legal */
851 c = src[srcIdx++];
852 if( !LabelChar(c,1) && c!='.' )
853 {
854 Report(ps,REP_ERROR,"Syntax error in Cmd/Opcode");
855 return(0);
856 }
857
858 /* Get the Opcode or Command */
859 wordIdx = 0;
860 while( LabelChar(c,0) || c=='.' )
861 {
862 if( wordIdx>=(TOKEN_MAX_LEN-1) )
863 { Report(ps,REP_ERROR,"Cmd/Opcode too long"); return(0); }
864 pa->Term[0][wordIdx++] = c;
865 c = src[srcIdx++];
866 }
867 pa->Term[0][wordIdx]=0;
868
869 /* See if it is a label */
870 if( c==':' )
871 {
872 if( pa->Flags & SRC_FLG_LABEL )
873 { Report(ps,REP_ERROR,"Two labels found on the same line"); return(0); }
874 pa->Flags |= SRC_FLG_LABEL;
875 strcpy(pa->Label,pa->Term[0]);
876
877 /* Process any assembly after the label */
878 c = src[srcIdx];
879 if( c!=0 )
880 {
881 while( c==' ' || c==0x9 )
882 c = src[++srcIdx];
883 goto PROCESS_LINE;
884 }
885 return(1);
886 }
887
888 if( c!=' ' && c!=0 && c!=0x9 )
889 {
890 Report(ps,REP_ERROR,"Syntax error in Cmd/Opcode");
891 return(0);
892 }
893
894 /* Get up to "MAX_TOKENS-1" parameters (comma delimited) */
895 parmCnt=0;
896 while(c)
897 {
898 wordIdx=0;
899 parmCnt++;
900 if( parmCnt==MAX_TOKENS )
901 { Report(ps,REP_ERROR,"Too many parameters on line"); return(0); }
902
903 /* Trim off leading white space */
904 while( c==' ' || c==0x9 )
905 c = src[srcIdx++];
906
907 if( !LabelChar(c,0) &&
908 c!='.' && c!='#' && c!='-' && c!='(' && c!='"' && c!='&' && c!='*' )
909 { Report(ps,REP_ERROR,"Syntax error in parameter %d",parmCnt); return(0); }
910
911 if( parmCnt==1 && c=='.' )
912 {
913 while( c!=0 && c!=',' && c!=' ' && c!=0x9 )
914 {
915 if( wordIdx>=(TOKEN_MAX_LEN-1) )
916 { Report(ps,REP_ERROR,"Parameter %d too long",parmCnt); return(0); }
917 pa->Term[parmCnt][wordIdx++] = c;
918 c = src[srcIdx++];
919
920 }
921 if(c==' ' || c==0x9)
922 c=',';
923
924 pa->Flags |= SRC_FLG_DOTCMD2;
925 }
926 else
927 {
928 while( c!=0 && c!=',' )
929 {
930 if( wordIdx>=(TOKEN_MAX_LEN-1) )
931 { Report(ps,REP_ERROR,"Parameter %d too long",parmCnt); return(0); }
932 pa->Term[parmCnt][wordIdx++] = c;
933 c = src[srcIdx++];
934 }
935 }
936 pa->Term[parmCnt][wordIdx] = 0;
937
938 /* Trim off trailing white space */
939 while( wordIdx && (pa->Term[parmCnt][wordIdx-1]==0x9 || pa->Term[parmCnt][wordIdx-1]==' ') )
940 pa->Term[parmCnt][--wordIdx]=0;
941
942 /* This character must be a comma or NULL */
943 if( c==',' )
944 c = src[srcIdx++];
945 else if( c )
946 { Report(ps,REP_ERROR,"Syntax error in parameter %d",parmCnt); return(0); }
947 }
948
949 parmCnt++;
950 pa->Terms = parmCnt;
951
952 /* If its a dot command, mark it */
953 if( pa->Term[0][0]=='.' )
954 pa->Flags |= SRC_FLG_DOTCMD1;
955
956 return(1);
957 }
958
959
960 /*
961 // GenOp
962 //
963 // Generate an opcode to the ouput file
964 //
965 // ps - Pointer to source file record
966 // TermCnt - Number of terms (including the command)
967 // pTerms - Pointer to the terms
968 // opcode - Generated Opcode
969 */
GenOp(SOURCEFILE * ps,int TermCnt,char ** pTerms,uint opcode)970 void GenOp( SOURCEFILE *ps, int TermCnt, char **pTerms, uint opcode )
971 {
972 int i;
973
974 if( !ValidateOffset(ps) )
975 return;
976
977 if( (Options & OPTION_LISTING) && Pass==2 )
978 {
979 fprintf(ListingFile,"%s(%5d) : 0x%04x = 0x%08x : ",
980 ps->SourceName,ps->CurrentLine,CodeOffset,opcode);
981 fprintf(ListingFile,"%-8s ",pTerms[0]);
982 for(i=1; i<TermCnt; i++)
983 {
984 if( i>1 )
985 fprintf(ListingFile,", %s",pTerms[i]);
986 else
987 fprintf(ListingFile,"%s",pTerms[i]);
988 }
989 if( opcode==0xFFFFFFFF )
990 fprintf(ListingFile," // *** ERROR ***");
991
992 fprintf(ListingFile,"\n");
993 }
994
995 ProgramImage[CodeOffset].Flags = CODEGEN_FLG_FILEINFO|CODEGEN_FLG_CANMAP;
996 ProgramImage[CodeOffset].FileIndex = ps->FileIndex;
997 ProgramImage[CodeOffset].Line = ps->CurrentLine;
998 ProgramImage[CodeOffset].AddrOffset = CodeOffset;
999 ProgramImage[CodeOffset++].CodeWord = opcode;
1000 }
1001
1002
1003 /*
1004 // Report
1005 //
1006 // Report an abnormal condition
1007 */
Report(SOURCEFILE * ps,int Level,char * fmt,...)1008 void Report( SOURCEFILE *ps, int Level, char *fmt, ... )
1009 {
1010 va_list arg_ptr;
1011
1012 if( Pass==1 && Level==REP_WARN2 )
1013 return;
1014 if( Pass==2 && (Level==REP_INFO || Level==REP_WARN1) )
1015 return;
1016
1017 /* Log to stdout */
1018 if( ps )
1019 printf("%s(%d) ",ps->SourceName,ps->CurrentLine);
1020
1021 if( Level == REP_FATAL )
1022 {
1023 printf("Fatal Error: ");
1024 FatalError=1;
1025 Errors++;
1026 }
1027 else if( Level == REP_ERROR )
1028 {
1029 printf("Error: ");
1030 Errors++;
1031 }
1032 else if( Level==REP_WARN1 || Level==REP_WARN2 )
1033 {
1034 printf("Warning: ");
1035 Warnings++;
1036 }
1037 else
1038 printf("Note: ");
1039
1040 va_start( arg_ptr, fmt );
1041 vprintf( fmt, arg_ptr );
1042 va_end( arg_ptr );
1043
1044 if( !ps )
1045 printf("\n");
1046 printf("\n");
1047 }
1048
1049
1050 /*
1051 // LabelChar
1052 //
1053 // Return whether the character is legal for a label.
1054 // Numbers are not allowed when FlagFirstChar is set.
1055 //
1056 // Returns 1 on success, 0 on error
1057 */
LabelChar(char c,int FlagFirstChar)1058 int LabelChar( char c, int FlagFirstChar )
1059 {
1060 if( FlagFirstChar )
1061 {
1062 if( (c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c=='_') )
1063 return(1);
1064 else
1065 return(0);
1066 }
1067 if( (c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9')||(c=='_'))
1068 return(1);
1069 else
1070 return(0);
1071 }
1072
1073
1074 /*
1075 // LabelCreate
1076 //
1077 // Create a label with the supplied offset value
1078 //
1079 // Returns 1 on success, 0 on error
1080 */
LabelCreate(SOURCEFILE * ps,char * label,int value)1081 int LabelCreate( SOURCEFILE *ps, char *label, int value )
1082 {
1083 LABEL *pl;
1084
1085 if( strlen(label) >= LABEL_NAME_LEN )
1086 { Report(ps,REP_ERROR,"Label too long"); return(0); }
1087
1088 /* Make sure this name is OK to use */
1089 if( !CheckName(ps,label) )
1090 return(0);
1091
1092 /* Allocate a new record */
1093 pl = malloc(sizeof(LABEL));
1094 if( !pl )
1095 { Report(ps,REP_FATAL,"Memory allocation failed"); return(0); }
1096
1097 strcpy( pl->Name, label );
1098 pl->Offset = value;
1099
1100 /* Put this label in the master list */
1101 pl->pPrev = 0;
1102 pl->pNext = pLabelList;
1103 if( pLabelList )
1104 pLabelList->pPrev = pl;
1105 pLabelList = pl;
1106 LabelCount++;
1107
1108 if( (Options & OPTION_DEBUG) )
1109 printf("%s(%5d) : LABEL : '%s' = %05d\n", ps->SourceName,ps->CurrentLine,label,value);
1110
1111 return(1);
1112 }
1113
1114
1115 /*
1116 // LabelFind
1117 //
1118 // Searches for an equate by name. If found, returns the record pointer.
1119 //
1120 // Returns LABEL * on success, 0 on error
1121 */
LabelFind(char * name)1122 LABEL *LabelFind( char *name )
1123 {
1124 LABEL *pl;
1125
1126 pl = pLabelList;
1127 while( pl )
1128 {
1129 if( !strcmp( name, pl->Name ) )
1130 break;
1131 pl = pl->pNext;
1132 }
1133 return(pl);
1134 }
1135
1136
1137 /*
1138 // LabelDestroy
1139 //
1140 // Frees and label record.
1141 //
1142 // void
1143 */
LabelDestroy(LABEL * pl)1144 void LabelDestroy( LABEL *pl )
1145 {
1146 if( !pl->pPrev )
1147 pLabelList = pl->pNext;
1148 else
1149 pl->pPrev->pNext = pl->pNext;
1150
1151 if( pl->pNext )
1152 pl->pNext->pPrev = pl->pPrev;
1153
1154 LabelCount--;
1155
1156 free(pl);
1157 }
1158
1159
1160 /*
1161 // Check Name
1162 //
1163 // Returns 1 if the name is free, or 0 if it is in use
1164 */
CheckName(SOURCEFILE * ps,char * name)1165 int CheckName( SOURCEFILE *ps, char *name )
1166 {
1167 /* Make sure its not a reserved word */
1168 if( CheckTokenType(name)!=TOKENTYPE_UNRESERVED )
1169 { Report(ps,REP_ERROR,"Illegal use of reserved word '%s'",name); return(0); }
1170 if( LabelFind(name) )
1171 { Report(ps,REP_ERROR,"'%s' is already a label",name); return(0); }
1172 if( CheckEquate(name) )
1173 { Report(ps,REP_ERROR,"'%s' is already an equate",name); return(0); }
1174 if( CheckStruct(name) )
1175 { Report(ps,REP_ERROR,"'%s' is already a structure or scope",name); return(0); }
1176 if( CheckMacro(name) )
1177 { Report(ps,REP_ERROR,"'%s' is already a macro",name); return(0); }
1178 return(1);
1179 }
1180
1181
1182 /*===================================================================
1183 //
1184 // Private Functions
1185 //
1186 ====================================================================*/
1187
1188 /*
1189 // ValidateOffset
1190 //
1191 // Validates that the current offset is ready to be used
1192 //
1193 // Returns 1 on success, 0 on error
1194 */
ValidateOffset(SOURCEFILE * ps)1195 static int ValidateOffset( SOURCEFILE *ps )
1196 {
1197 uint opcode;
1198
1199 if( CodeOffset==-1 )
1200 {
1201 CodeOffset = 8;
1202 if( EntryPoint<0 )
1203 EntryPoint = 8;
1204 if( Core != CORE_V0 )
1205 Report(ps,REP_WARN1,"Using default code origin of 8");
1206 else
1207 {
1208 opcode = 0x21000900;
1209
1210 /* Note it in listing file */
1211 if( Pass==2 && (Options & OPTION_LISTING) )
1212 {
1213 fprintf(ListingFile,
1214 "%s(%5d) : 0x%04x = 0x%08x : JMP #0x9 // Legacy Mode\n",
1215 ps->SourceName,ps->CurrentLine,CodeOffset,opcode);
1216 }
1217
1218 ProgramImage[CodeOffset].Flags = CODEGEN_FLG_FILEINFO;
1219 ProgramImage[CodeOffset].FileIndex = ps->FileIndex;
1220 ProgramImage[CodeOffset].Line = ps->CurrentLine;
1221 ProgramImage[CodeOffset].AddrOffset = CodeOffset;
1222 ProgramImage[CodeOffset++].CodeWord = opcode;
1223 }
1224 }
1225
1226 if( CodeOffset >= MAX_PROGRAM )
1227 { Report(ps,REP_FATAL,"Max program size exceeded"); return(0); }
1228
1229 return(1);
1230 }
1231
1232 /*
1233 // PrintLine
1234 //
1235 // Prints out a line of the source file for source listings
1236 //
1237 // Returns 1 on success, 0 on EOF
1238 */
PrintLine(FILE * pfOut,SOURCEFILE * ps)1239 static int PrintLine( FILE *pfOut, SOURCEFILE *ps )
1240 {
1241 int i;
1242 char c;
1243
1244 AGAIN:
1245 i = fread( &c, 1, 1, ps->FilePtr );
1246 if( i != 1 )
1247 return(0);
1248 if( c == 0xd )
1249 goto AGAIN;
1250 if( c == 0xa )
1251 {
1252 ps->CurrentLine++;
1253 fprintf(pfOut,"\n");
1254 return(1);
1255 }
1256 fprintf(pfOut,"%c",c);
1257 goto AGAIN;
1258 }
1259
1260 /*
1261 // GetInfoFromAddr
1262 //
1263 // Returns the SourceFileIndex, Line Number, and CodeWord for a given address offset
1264 //
1265 // Returns 0 on success, -1 on error
1266 */
GetInfoFromAddr(uint address,uint * pIndex,uint * pLineNo,uint * pCodeWord)1267 static int GetInfoFromAddr( uint address, uint *pIndex, uint *pLineNo, uint *pCodeWord )
1268 {
1269 int i;
1270
1271 for(i=0; i<(int)CodeOffset; i++)
1272 {
1273 if( ProgramImage[i].AddrOffset == address )
1274 {
1275 *pIndex = ProgramImage[i].FileIndex;
1276 *pLineNo = ProgramImage[i].Line;
1277 *pCodeWord = ProgramImage[i].CodeWord;
1278 return 0;
1279 }
1280 }
1281 return -1;
1282 }
1283
1284 /*
1285 // ListFile
1286 //
1287 // Prints out an object code annotated listing of an original source file
1288 //
1289 // Returns 1 on success
1290 */
ListFile(FILE * pfOut,SOURCEFILE * ps)1291 static int ListFile( FILE *pfOut, SOURCEFILE *ps )
1292 {
1293 uint addr, index, line, code, count, output, cline;
1294
1295 count = 0;
1296 for( addr=0; addr<(uint)CodeOffset; addr++ )
1297 {
1298 if( GetInfoFromAddr( addr, &index, &line, &code ) >= 0 )
1299 {
1300 if( index == ps->FileIndex )
1301 count++;
1302 }
1303 }
1304
1305 if( !count )
1306 {
1307 // No code section
1308 fprintf(pfOut,"(No Ouput Generated)\n\n");
1309
1310 for(;;)
1311 {
1312 fprintf(pfOut,"%5d : : ",ps->CurrentLine );
1313 if( !PrintLine(pfOut,ps) )
1314 return(1);
1315 }
1316 }
1317 else
1318 {
1319 fprintf(pfOut,"(%d Instructions Generated)\n\n",count);
1320
1321 for(;;)
1322 {
1323 output = 0;
1324 cline = ps->CurrentLine;
1325
1326 for( addr=0; addr<(uint)CodeOffset; addr++ )
1327 {
1328 if( (GetInfoFromAddr( addr, &index, &line, &code ) < 0) || index!=ps->FileIndex || line<cline )
1329 continue;
1330
1331 if( line == cline )
1332 {
1333 if( !output )
1334 {
1335 fprintf(pfOut,"%5d : 0x%04x 0x%08x : ",line,addr,code );
1336 if( !PrintLine(pfOut,ps) )
1337 return(1);
1338 output = 1;
1339 }
1340 else
1341 {
1342 fprintf(pfOut," : 0x%04x 0x%08x : \n",addr,code );
1343 }
1344 }
1345 }
1346
1347 if( !output )
1348 {
1349 fprintf(pfOut,"%5d : : ",ps->CurrentLine );
1350 if( !PrintLine(pfOut,ps) )
1351 return(1);
1352 }
1353 }
1354 }
1355 return(1);
1356 }
1357
1358
1359