#include "cmdlib.h"
#include "mathlib.h"
#include "qfiles.h"
#include "opstrings.h"
Include dependency graph for q3asm.c:

Go to the source code of this file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definition at line 35 of file q3asm.c. 00035 {
00036 OP_UNDEF,
00037
00038 OP_IGNORE,
00039
00040 OP_BREAK,
00041
00042 OP_ENTER,
00043 OP_LEAVE,
00044 OP_CALL,
00045 OP_PUSH,
00046 OP_POP,
00047
00048 OP_CONST,
00049 OP_LOCAL,
00050
00051 OP_JUMP,
00052
00053 //-------------------
00054
00055 OP_EQ,
00056 OP_NE,
00057
00058 OP_LTI,
00059 OP_LEI,
00060 OP_GTI,
00061 OP_GEI,
00062
00063 OP_LTU,
00064 OP_LEU,
00065 OP_GTU,
00066 OP_GEU,
00067
00068 OP_EQF,
00069 OP_NEF,
00070
00071 OP_LTF,
00072 OP_LEF,
00073 OP_GTF,
00074 OP_GEF,
00075
00076 //-------------------
00077
00078 OP_LOAD1,
00079 OP_LOAD2,
00080 OP_LOAD4,
00081 OP_STORE1,
00082 OP_STORE2,
00083 OP_STORE4, // *(stack[top-1]) = stack[yop
00084 OP_ARG,
00085 OP_BLOCK_COPY,
00086
00087 //-------------------
00088
00089 OP_SEX8,
00090 OP_SEX16,
00091
00092 OP_NEGI,
00093 OP_ADD,
00094 OP_SUB,
00095 OP_DIVI,
00096 OP_DIVU,
00097 OP_MODI,
00098 OP_MODU,
00099 OP_MULI,
00100 OP_MULU,
00101
00102 OP_BAND,
00103 OP_BOR,
00104 OP_BXOR,
00105 OP_BCOM,
00106
00107 OP_LSH,
00108 OP_RSHI,
00109 OP_RSHU,
00110
00111 OP_NEGF,
00112 OP_ADDF,
00113 OP_SUBF,
00114 OP_DIVF,
00115 OP_MULF,
00116
00117 OP_CVIF,
00118 OP_CVFI
00119 } opcode_t;
|
|
|
Definition at line 128 of file q3asm.c. 00128 {
00129 CODESEG,
00130 DATASEG, // initialized 32 bit data, will be byte swapped
00131 LITSEG, // strings
00132 BSSSEG, // 0 filled
00133 NUM_SEGMENTS
00134 } segmentName_t;
|
|
|
|
|
|
Definition at line 722 of file q3asm.c. References currentSegment, and segment. 00725 {
00726 currentSegment = &segment[BSSSEG];
00727 return;
00728 }
00729 if ( !strcmp( token, "data" ) ) {
00730 currentSegment = &segment[DATASEG];
00731 return;
00732 }
00733 if ( !strcmp( token, "lit" ) ) {
00734 currentSegment = &segment[LITSEG];
00735 return;
00736 }
00737 if ( !strcmp( token, "line" ) ) {
00738 return;
00739 }
00740 if ( !strcmp( token, "file" ) ) {
00741 return;
00742 }
00743
00744 if ( !strcmp( token, "equ" ) ) {
00745 char name[1024];
00746
00747 Parse();
00748 strcpy( name, token );
00749 Parse();
00750 DefineSymbol( name, atoi(token) );
00751 return;
00752 }
00753
00754 if ( !strcmp( token, "align" ) ) {
00755 v = ParseValue();
00756 currentSegment->imageUsed = (currentSegment->imageUsed + v - 1 ) & ~( v - 1 );
00757 return;
00758 }
00759
00760 if ( !strcmp( token, "skip" ) ) {
00761 v = ParseValue();
00762 currentSegment->imageUsed += v;
00763 return;
00764 }
00765
00766 if ( !strcmp( token, "byte" ) ) {
00767 v = ParseValue();
00768 v2 = ParseValue();
00769
00770 if ( v == 1 ) {
00771 HackToSegment( LITSEG );
00772 } else if ( v == 4 ) {
00773 HackToSegment( DATASEG );
00774 } else if ( v == 2 ) {
00775 CodeError( "16 bit initialized data not supported" );
00776 }
00777
00778 // emit little endien
00779 for ( i = 0 ; i < v ; i++ ) {
00780 EmitByte( currentSegment, v2 );
00781 v2 >>= 8;
00782 }
00783 return;
00784 }
00785
00786 // code labels are emited as instruction counts, not byte offsets,
00787 // because the physical size of the code will change with
00788 // different run time compilers and we want to minimize the
00789 // size of the required translation table
00790 if ( !strncmp( token, "LABEL", 5 ) ) {
00791 Parse();
00792 if ( currentSegment == &segment[CODESEG] ) {
00793 DefineSymbol( token, instructionCount );
00794 } else {
00795 DefineSymbol( token, currentSegment->imageUsed );
00796 }
00797 return;
00798 }
00799
00800 CodeError( "Unknown token: %s\n", token );
00801 }
00802
00803 /*
00804 ==============
00805 InitTables
00806 ==============
00807 */
00808 void InitTables( void ) {
00809 int i;
00810
00811 for ( i = 0 ; i < NUM_SOURCE_OPS ; i++ ) {
00812 opcodesHash[i] = HashString( sourceOps[i].name );
00813 }
00814 }
00815
00816
00817 /*
00818 ==============
00819 WriteMapFile
00820 ==============
00821 */
00822 void WriteMapFile( void ) {
00823 FILE *f;
00824 symbol_t *s;
00825 char imageName[MAX_OS_PATH];
00826 int seg;
00827
00828 strcpy( imageName, outputFilename );
00829 StripExtension( imageName );
00830 strcat( imageName, ".map" );
00831
00832 printf( "Writing %s...\n", imageName );
00833 f = SafeOpenWrite( imageName );
00834 for ( seg = CODESEG ; seg <= BSSSEG ; seg++ ) {
00835 for ( s = symbols ; s ; s = s->next ) {
00836 if ( s->name[0] == '$' ) {
00837 continue; // skip locals
00838 }
00839 if ( &segment[seg] != s->segment ) {
00840 continue;
00841 }
00842 fprintf( f, "%i %8x %s\n", seg, s->value, s->name );
00843 }
00844 }
00845 fclose( f );
00846 }
00847
00848 /*
00849 ===============
00850 WriteVmFile
00851 ===============
00852 */
00853 void WriteVmFile( void ) {
00854 char imageName[MAX_OS_PATH];
00855 vmHeader_t header;
00856 FILE *f;
00857
00858 printf( "%i total errors\n", errorCount );
00859 strcpy( imageName, outputFilename );
00860 StripExtension( imageName );
00861 strcat( imageName, ".qvm" );
00862
00863 remove( imageName );
00864
00865 printf( "code segment: %7i\n", segment[CODESEG].imageUsed );
00866 printf( "data segment: %7i\n", segment[DATASEG].imageUsed );
00867 printf( "lit segment: %7i\n", segment[LITSEG].imageUsed );
00868 printf( "bss segment: %7i\n", segment[BSSSEG].imageUsed );
00869 printf( "instruction count: %i\n", instructionCount );
00870 if ( errorCount != 0 ) {
00871 printf( "Not writing a file due to errors\n" );
00872 return;
00873 }
00874
00875 header.vmMagic = VM_MAGIC;
00876 header.instructionCount = instructionCount;
00877 header.codeOffset = sizeof( header );
00878 header.codeLength = segment[CODESEG].imageUsed;
00879 header.dataOffset = header.codeOffset + segment[CODESEG].imageUsed;
00880 header.dataLength = segment[DATASEG].imageUsed;
00881 header.litLength = segment[LITSEG].imageUsed;
00882 header.bssLength = segment[BSSSEG].imageUsed;
00883
00884 printf( "Writing to %s\n", imageName );
00885
00886 CreatePath( imageName );
00887 f = SafeOpenWrite( imageName );
00888 SafeWrite( f, &header, sizeof( header ) );
00889 SafeWrite( f, &segment[CODESEG].image, segment[CODESEG].imageUsed );
00890 SafeWrite( f, &segment[DATASEG].image, segment[DATASEG].imageUsed );
00891 SafeWrite( f, &segment[LITSEG].image, segment[LITSEG].imageUsed );
00892 fclose( f );
00893 }
00894
00895 /*
00896 ===============
00897 Assemble
00898 ===============
00899 */
00900 void Assemble( void ) {
00901 int i;
00902 char filename[MAX_OS_PATH];
00903 char *ptr;
00904
00905 printf( "outputFilename: %s\n", outputFilename );
00906
00907 for ( i = 0 ; i < numAsmFiles ; i++ ) {
00908 strcpy( filename, asmFileNames[ i ] );
00909 DefaultExtension( filename, ".asm" );
00910 LoadFile( filename, (void **)&asmFiles[i] );
00911 }
00912
00913 // assemble
00914 for ( passNumber = 0 ; passNumber < 2 ; passNumber++ ) {
00915 segment[LITSEG].segmentBase = segment[DATASEG].imageUsed;
00916 segment[BSSSEG].segmentBase = segment[LITSEG].segmentBase + segment[LITSEG].imageUsed;
00917 for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
00918 segment[i].imageUsed = 0;
00919 }
00920 segment[DATASEG].imageUsed = 4; // skip the 0 byte, so NULL pointers are fixed up properly
00921 instructionCount = 0;
00922
00923 for ( i = 0 ; i < numAsmFiles ; i++ ) {
00924 currentFileIndex = i;
00925 currentFileName = asmFileNames[ i ];
00926 currentFileLine = 0;
00927 printf("pass %i: %s\n", passNumber, currentFileName );
00928 ptr = asmFiles[i];
00929 while ( ptr ) {
00930 ptr = ExtractLine( ptr );
00931 AssembleLine();
00932 }
00933 }
00934
00935 // align all segment
00936 for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) {
00937 segment[i].imageUsed = (segment[i].imageUsed + 3) & ~3;
00938 }
00939 }
00940
00941 // reserve the stack in bss
00942 DefineSymbol( "_stackStart", segment[BSSSEG].imageUsed );
00943 segment[BSSSEG].imageUsed += stackSize;
00944 DefineSymbol( "_stackEnd", segment[BSSSEG].imageUsed );
00945
00946 // write the image
00947 WriteVmFile();
00948
00949 // write the map file even if there were errors
00950 WriteMapFile();
00951 }
00952
00953
00954 /*
00955 =============
00956 ParseOptionFile
00957
00958 =============
00959 */
00960 void ParseOptionFile( const char *filename ) {
00961 char expanded[MAX_OS_PATH];
00962 char *text, *text_p;
00963
00964 strcpy( expanded, filename );
00965 DefaultExtension( expanded, ".q3asm" );
00966 LoadFile( expanded, (void **)&text );
00967 if ( !text ) {
00968 return;
00969 }
00970
00971 text_p = text;
00972
00973 while( ( text_p = COM_Parse( text_p ) ) != 0 ) {
00974 if ( !strcmp( com_token, "-o" ) ) {
00975 // allow output override in option file
00976 text_p = COM_Parse( text_p );
00977 if ( text_p ) {
|
|
||||||||||||
|
Definition at line 402 of file q3asm.c. References qboolean, and token. 00411 {
00412 int c;
|
|
||||||||||||
|
Definition at line 450 of file q3asm.c. References atoi, Parse(), and token. 00451 {
00452 Parse();
00453 return atoi( token );
00454 }
00455
00456
00457 /*
00458 ==============
00459 ParseExpression
00460 ==============
00461 */
00462 int ParseExpression(void) {
00463 int i, j;
00464 char sym[MAX_LINE_LENGTH];
00465 int v;
00466
00467 if ( token[0] == '-' ) {
00468 i = 1;
00469 } else {
00470 i = 0;
00471 }
00472
00473 for ( ; i < MAX_LINE_LENGTH ; i++ ) {
00474 if ( token[i] == '+' || token[i] == '-' || token[i] == 0 ) {
00475 break;
00476 }
00477 }
00478
00479 memcpy( sym, token, i );
00480 sym[i] = 0;
00481
00482 if ( ( sym[0] >= '0' && sym[0] <= '9' ) || sym[0] == '-' ) {
00483 v = atoi( sym );
00484 } else {
00485 v = LookupSymbol( sym );
00486 }
00487
00488 // parse add / subtract offsets
00489 while ( token[i] != 0 ) {
00490 for ( j = i + 1 ; j < MAX_LINE_LENGTH ; j++ ) {
00491 if ( token[j] == '+' || token[j] == '-' || token[j] == 0 ) {
00492 break;
00493 }
00494 }
00495
00496 memcpy( sym, token+i+1, j-i-1 );
00497 sym[j-i-1] = 0;
00498
00499 if ( token[i] == '+' ) {
00500 v += atoi( sym );
|
Here is the call graph for this function:

|
||||||||||||
|
Definition at line 419 of file q3asm.c. References lineBuffer, and lineParseOffset. Referenced by Parse(), and ParseExpression(). 00419 {
00420 if ( lineBuffer[ lineParseOffset ] == 0 ) {
00421 return qfalse;
00422 }
00423 lineParseOffset++;
00424 }
00425
|
|
||||||||||||
|
Definition at line 432 of file q3asm.c. References c, lineBuffer, lineParseOffset, and token. Referenced by Parse(). 00434 {
00435 token[len] = c;
00436 len++;
00437 lineParseOffset++;
00438 c = lineBuffer[ lineParseOffset ];
00439 } while (c>32);
00440
00441 token[len] = 0;
|
|
|
Definition at line 549 of file q3asm.c. References token. 00552 {
00553 return;
00554 }
00555
00556 hash = HashString( token );
00557
00558 for ( i = 0 ; i < NUM_SOURCE_OPS ; i++ ) {
00559 if ( hash == opcodesHash[i] && !strcmp( token, sourceOps[i].name ) ) {
00560 int opcode;
00561 int expression;
00562
00563 if ( sourceOps[i].opcode == OP_UNDEF ) {
00564 CodeError( "Undefined opcode: %s\n", token );
00565 }
00566 if ( sourceOps[i].opcode == OP_IGNORE ) {
00567 return; // we ignore most conversions
00568 }
00569
00570 // sign extensions need to check next parm
00571 opcode = sourceOps[i].opcode;
00572 if ( opcode == OP_SEX8 ) {
00573 Parse();
00574 if ( token[0] == '1' ) {
00575 opcode = OP_SEX8;
00576 } else if ( token[0] == '2' ) {
00577 opcode = OP_SEX16;
|
|
|
Definition at line 704 of file q3asm.c. 00707 {
00708 Parse();
00709 v = ParseExpression();
00710
00711 HackToSegment( DATASEG );
00712 EmitInt( currentSegment, v );
00713 return;
00714 }
|
|
|
Definition at line 386 of file q3asm.c. References data. 00386 {
00387 break;
00388 }
00389 }
00390 if ( i == MAX_LINE_LENGTH ) {
00391 CodeError( "MAX_LINE_LENGTH" );
00392 return data;
00393 }
00394 memcpy( lineBuffer, data, i );
|
|
|
Definition at line 984 of file q3asm.c. References numAsmFiles. 00993 {
|
|
|
Definition at line 510 of file q3asm.c. References currentSegment, segment_t::imageUsed, lastSymbol, passNumber, symbol_s::segment, segment, and symbol_s::value. 00516 : I want to put all 32 bit values in the data 00517 segment so they can be byte swapped, and all char data in the lit 00518 segment, but switch jump tables are emited in the lit segment and 00519 initialized strng variables are put in the data segment. 00520 00521 I can change segments here, but I also need to fixup the 00522 label that was just defined 00523 00524 Note that the lit segment is read-write in the VM, so strings 00525 aren't read only as in some architectures. 00526 ============== 00527 */ 00528 void HackToSegment( segmentName_t seg ) { 00529 if ( currentSegment == &segment[seg] ) { 00530 return; 00531 } 00532 00533 currentSegment = &segment[seg]; 00534 if ( passNumber == 0 ) { 00535 lastSymbol->segment = currentSegment; 00536 lastSymbol->value = currentSegment->imageUsed; 00537 }
|
|
||||||||||||
|
|
|
|
Definition at line 587 of file q3asm.c. References CODESEG, EmitByte(), EmitInt(), ParseExpression(), segment, and sourceOps. Referenced by DefineSymbol(). 00587 {
00588 expression = ParseExpression();
00589
00590 // code like this can generate non-dword block copies:
00591 // auto char buf[2] = " ";
00592 // we are just going to round up. This might conceivably
00593 // be incorrect if other initialized chars follow.
00594 if ( opcode == OP_BLOCK_COPY ) {
00595 expression = ( expression + 3 ) & ~3;
00596 }
00597
00598 EmitByte( &segment[CODESEG], opcode );
00599 EmitInt( &segment[CODESEG], expression );
00600 } else {
00601 EmitByte( &segment[CODESEG], opcode );
00602 }
00603
00604 instructionCount++;
00605 return;
00606 }
00607 }
00608
00609 // call instructions reset currentArgOffset
00610 if ( !strncmp( token, "CALL", 4 ) ) {
00611 EmitByte( &segment[CODESEG], OP_CALL );
00612 instructionCount++;
00613 currentArgOffset = 0;
00614 return;
00615 }
00616
00617 // arg is converted to a reversed store
00618 if ( !strncmp( token, "ARG", 3 ) ) {
00619 EmitByte( &segment[CODESEG], OP_ARG );
|
Here is the call graph for this function:

|
|
Definition at line 638 of file q3asm.c. References CODESEG, EmitByte(), instructionCount, OP_POP, and segment. Referenced by Parse(). 00640 {
00641 EmitByte( &segment[CODESEG], OP_POP );
00642 instructionCount++;
00643 return;
00644 }
00645
00646 // address of a parameter is converted to OP_LOCAL
00647 if ( !strncmp( token, "ADDRF", 5 ) ) {
00648 instructionCount++;
00649 Parse();
00650 v = ParseExpression();
00651 v = 16 + currentArgs + currentLocals + v;
00652 EmitByte( &segment[CODESEG], OP_LOCAL );
00653 EmitInt( &segment[CODESEG], v );
00654 return;
00655 }
00656
00657 // address of a local is converted to OP_LOCAL
00658 if ( !strncmp( token, "ADDRL", 5 ) ) {
00659 instructionCount++;
00660 Parse();
00661 v = ParseExpression();
00662 v = 8 + currentArgs + v;
00663 EmitByte( &segment[CODESEG], OP_LOCAL );
00664 EmitInt( &segment[CODESEG], v );
00665 return;
00666 }
00667
00668 if ( !strcmp( token, "proc" ) ) {
00669 char name[1024];
00670
00671 Parse(); // function name
00672 strcpy( name, token );
00673
00674 DefineSymbol( token, instructionCount ); // segment[CODESEG].imageUsed );
00675
00676 currentLocals = ParseValue(); // locals
00677 currentLocals = ( currentLocals + 3 ) & ~3;
00678 currentArgs = ParseValue(); // arg marshalling
00679 currentArgs = ( currentArgs + 3 ) & ~3;
00680
00681 if ( 8 + currentLocals + currentArgs >= 32767 ) {
00682 CodeError( "Locals > 32k in %s\n", name );
00683 }
00684
00685 instructionCount++;
|
Here is the call graph for this function:

|
|
|
|
|
Definition at line 627 of file q3asm.c. 00631 {
|
|
|
Definition at line 998 of file q3asm.c. Referenced by main(). 00999 {
01000 Error( "usage: q3asm [-o output] <files> or q3asm -f <listfile>\n" );
01001 }
01002
01003 start = I_FloatTime ();
01004 InitTables();
01005
01006 // default filename is "q3asm"
01007 strcpy( outputFilename, "q3asm" );
01008 numAsmFiles = 0;
01009
01010 for ( i = 1 ; i < argc ; i++ ) {
01011 if ( argv[i][0] != '-' ) {
01012 break;
01013 }
01014 if ( !strcmp( argv[i], "-o" ) ) {
01015 if ( i == argc - 1 ) {
01016 Error( "-o must preceed a filename" );
01017 }
01018 strcpy( outputFilename, argv[ i+1 ] );
01019 i++;
01020 continue;
01021 }
01022
|
Here is the call graph for this function:

|
|
Definition at line 1029 of file q3asm.c. 01031 : %s", argv[i] ); 01032 } 01033 01034 // the rest of the command line args are asm files 01035 for ( ; i < argc ; i++ ) { 01036 asmFileNames[ numAsmFiles ] = copystring( argv[ i ] ); 01037 numAsmFiles++; 01038 } 01039 01040 Assemble(); 01041 01042 end = I_FloatTime (); 01043 printf ("%5.0f seconds elapsed\n", end-start); 01044 01045 return 0; 01046 } 01047 01048
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definition at line 154 of file q3asm.c. Referenced by AssembleLine(), and LookupSymbol(). |
|
|
Definition at line 159 of file q3asm.c. Referenced by Com_Error(). |
|
|
Definition at line 189 of file q3asm.c. Referenced by ParseExpression(). |
|
|
Definition at line 162 of file q3asm.c. Referenced by LookupSymbol(). |
|
|
Definition at line 185 of file q3asm.c. Referenced by EmitByte(), and EmitInt(). |
|
|
Definition at line 186 of file q3asm.c. Referenced by EmitByte(), and EmitInt(). |
|
|
Definition at line 166 of file q3asm.c. Referenced by InitTables(). |
|
|
|
|
|
|
|
|
Definition at line 30 of file |