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