2021-01-29 15:14:37 -05:00
# include <stdio.h>
/*
2023-01-02 09:40:23 -05:00
Copyright ( c ) 2021 - 2023 Devine Lu Linvega , Andrew Alderwick
2021-01-29 15:14:37 -05:00
Permission to use , copy , modify , and distribute this software for any
purpose with or without fee is hereby granted , provided that the above
copyright notice and this permission notice appear in all copies .
THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE .
*/
2021-04-20 17:30:26 -04:00
# define TRIM 0x0100
2021-10-23 18:15:07 -04:00
# define LENGTH 0x10000
2021-03-28 14:06:36 -04:00
2021-01-29 15:14:37 -05:00
typedef unsigned char Uint8 ;
2021-02-12 19:18:52 -05:00
typedef signed char Sint8 ;
2021-02-04 15:22:08 -05:00
typedef unsigned short Uint16 ;
2021-01-29 15:14:37 -05:00
2021-03-14 16:30:17 -04:00
typedef struct {
2022-04-11 18:34:53 -04:00
char name [ 0x40 ] , items [ 0x40 ] [ 0x40 ] ;
2021-06-18 00:20:19 -04:00
Uint8 len ;
2021-03-14 16:30:17 -04:00
} Macro ;
2021-03-13 23:51:43 -05:00
typedef struct {
2022-04-11 18:34:53 -04:00
char name [ 0x40 ] ;
2021-06-18 00:20:19 -04:00
Uint16 addr , refs ;
2021-01-31 00:31:49 -05:00
} Label ;
2021-11-27 14:33:22 -05:00
typedef struct {
2022-04-11 18:34:53 -04:00
char name [ 0x40 ] , rune ;
2021-11-27 14:33:22 -05:00
Uint16 addr ;
} Reference ;
2021-03-13 17:55:29 -05:00
typedef struct {
2021-10-26 11:59:58 -04:00
Uint8 data [ LENGTH ] ;
2022-02-18 19:28:03 -05:00
unsigned int ptr , length ;
Uint16 llen , mlen , rlen ;
2022-04-11 18:34:53 -04:00
Label labels [ 0x400 ] ;
Macro macros [ 0x100 ] ;
2023-03-01 00:47:45 -05:00
Reference refs [ 0x400 ] ;
2022-04-11 18:34:53 -04:00
char scope [ 0x40 ] ;
2021-03-13 17:55:29 -05:00
} Program ;
2021-02-23 01:15:02 -05:00
2021-02-07 13:21:41 -05:00
Program p ;
2021-01-30 17:25:48 -05:00
2021-02-01 23:21:27 -05:00
/* clang-format off */
2021-06-28 17:42:36 -04:00
static char ops [ ] [ 4 ] = {
2022-04-18 04:45:33 -04:00
" LIT " , " INC " , " POP " , " NIP " , " SWP " , " ROT " , " DUP " , " OVR " ,
2021-05-11 14:12:07 -04:00
" EQU " , " NEQ " , " GTH " , " LTH " , " JMP " , " JCN " , " JSR " , " STH " ,
2021-05-11 14:14:52 -04:00
" LDZ " , " STZ " , " LDR " , " STR " , " LDA " , " STA " , " DEI " , " DEO " ,
2021-03-21 13:24:44 -04:00
" ADD " , " SUB " , " MUL " , " DIV " , " AND " , " ORA " , " EOR " , " SFT "
2021-02-04 15:22:08 -05:00
} ;
2021-02-01 23:21:27 -05:00
2021-08-29 14:43:00 -04:00
static int scmp ( char * a , char * b , int len ) { int i = 0 ; while ( a [ i ] = = b [ i ] ) if ( ! a [ i ] | | + + i > = len ) return 1 ; return 0 ; } /* string compare */
2021-06-28 17:42:36 -04:00
static int sihx ( char * s ) { int i = 0 ; char c ; while ( ( c = s [ i + + ] ) ) if ( ! ( c > = ' 0 ' & & c < = ' 9 ' ) & & ! ( c > = ' a ' & & c < = ' f ' ) ) return 0 ; return i > 1 ; } /* string is hexadecimal */
static int shex ( char * s ) { int n = 0 , i = 0 ; char c ; while ( ( c = s [ i + + ] ) ) if ( c > = ' 0 ' & & c < = ' 9 ' ) n = n * 16 + ( c - ' 0 ' ) ; else if ( c > = ' a ' & & c < = ' f ' ) n = n * 16 + 10 + ( c - ' a ' ) ; return n ; } /* string to num */
2022-01-03 21:04:09 -05:00
static int slen ( char * s ) { int i = 0 ; while ( s [ i ] ) i + + ; return i ; } /* string length */
2022-06-06 12:42:26 -04:00
static int spos ( char * s , char c ) { Uint8 i = 0 , j ; while ( ( j = s [ i + + ] ) ) if ( j = = c ) return i ; return - 1 ; } /* character position */
2022-01-03 21:04:09 -05:00
static char * scpy ( char * src , char * dst , int len ) { int i = 0 ; while ( ( dst [ i ] = src [ i ] ) & & i < len - 2 ) i + + ; dst [ i + 1 ] = ' \0 ' ; return dst ; } /* string copy */
2021-06-28 17:42:36 -04:00
static char * scat ( char * dst , const char * src ) { char * ptr = dst + slen ( dst ) ; while ( * src ) * ptr + + = * src + + ; * ptr = ' \0 ' ; return dst ; } /* string cat */
2021-01-29 16:59:16 -05:00
2021-02-07 13:21:41 -05:00
/* clang-format on */
2021-01-30 17:25:48 -05:00
2021-11-29 19:19:47 -05:00
static int parse ( char * w , FILE * f ) ;
2021-11-27 14:33:22 -05:00
static int
error ( const char * name , const char * msg )
{
fprintf ( stderr , " %s: %s \n " , name , msg ) ;
return 0 ;
}
2021-02-04 15:22:08 -05:00
2021-11-27 17:44:28 -05:00
static char *
sublabel ( char * src , char * scope , char * name )
{
2023-01-14 18:08:40 -05:00
if ( slen ( scope ) + slen ( name ) > = 0x3f ) {
error ( " Sublabel length too long " , name ) ;
return NULL ;
}
2022-04-11 18:34:53 -04:00
return scat ( scat ( scpy ( scope , src , 0x40 ) , " / " ) , name ) ;
2021-11-27 17:44:28 -05:00
}
2021-06-28 17:42:36 -04:00
static Macro *
2021-03-14 16:30:17 -04:00
findmacro ( char * name )
{
int i ;
2022-01-03 21:04:09 -05:00
for ( i = 0 ; i < p . mlen ; i + + )
2022-04-11 18:34:53 -04:00
if ( scmp ( p . macros [ i ] . name , name , 0x40 ) )
2021-03-14 16:30:17 -04:00
return & p . macros [ i ] ;
return NULL ;
}
2021-06-28 17:42:36 -04:00
static Label *
2021-04-20 00:00:14 -04:00
findlabel ( char * name )
2021-01-31 00:31:49 -05:00
{
2021-04-20 00:00:14 -04:00
int i ;
2022-01-03 21:04:09 -05:00
for ( i = 0 ; i < p . llen ; i + + )
2022-04-11 18:34:53 -04:00
if ( scmp ( p . labels [ i ] . name , name , 0x40 ) )
2021-03-13 17:55:29 -05:00
return & p . labels [ i ] ;
2021-01-31 00:31:49 -05:00
return NULL ;
}
2021-06-28 17:42:36 -04:00
static Uint8
2021-02-13 16:21:05 -05:00
findopcode ( char * s )
2021-02-06 13:39:13 -05:00
{
int i ;
2022-01-03 21:04:09 -05:00
for ( i = 0 ; i < 0x20 ; i + + ) {
2022-04-14 13:24:48 -04:00
int m = 0 ;
2021-08-29 14:43:00 -04:00
if ( ! scmp ( ops [ i ] , s , 3 ) )
2021-02-07 13:21:41 -05:00
continue ;
2021-10-29 19:28:33 -04:00
if ( ! i ) i | = ( 1 < < 7 ) ; /* force keep for LIT */
2022-04-14 13:24:48 -04:00
while ( s [ 3 + m ] ) {
if ( s [ 3 + m ] = = ' 2 ' )
i | = ( 1 < < 5 ) ; /* mode: short */
else if ( s [ 3 + m ] = = ' r ' )
i | = ( 1 < < 6 ) ; /* mode: return */
else if ( s [ 3 + m ] = = ' k ' )
i | = ( 1 < < 7 ) ; /* mode: keep */
else
return 0 ; /* failed to match */
m + + ;
}
return i ;
2022-04-11 19:07:15 -04:00
}
2021-02-06 13:39:13 -05:00
return 0 ;
}
2021-06-28 17:42:36 -04:00
static int
2021-03-14 16:30:17 -04:00
makemacro ( char * name , FILE * f )
{
Macro * m ;
2022-04-11 18:34:53 -04:00
char word [ 0x40 ] ;
2021-03-14 16:30:17 -04:00
if ( findmacro ( name ) )
return error ( " Macro duplicate " , name ) ;
if ( sihx ( name ) & & slen ( name ) % 2 = = 0 )
return error ( " Macro name is hex number " , name ) ;
2021-11-17 18:14:05 -05:00
if ( findopcode ( name ) | | scmp ( name , " BRK " , 4 ) | | ! slen ( name ) )
2021-03-14 16:30:17 -04:00
return error ( " Macro name is invalid " , name ) ;
2022-04-11 18:34:53 -04:00
if ( p . mlen = = 0x100 )
2021-11-29 11:48:12 -05:00
return error ( " Macros limit exceeded " , name ) ;
2021-03-14 16:30:17 -04:00
m = & p . macros [ p . mlen + + ] ;
2022-04-11 18:34:53 -04:00
scpy ( name , m - > name , 0x40 ) ;
2021-08-27 18:47:05 -04:00
while ( fscanf ( f , " %63s " , word ) = = 1 ) {
2021-03-14 16:30:17 -04:00
if ( word [ 0 ] = = ' { ' ) continue ;
if ( word [ 0 ] = = ' } ' ) break ;
2021-11-29 11:48:12 -05:00
if ( word [ 0 ] = = ' % ' )
return error ( " Macro error " , name ) ;
2022-04-11 18:34:53 -04:00
if ( m - > len > = 0x40 )
2021-11-29 11:48:12 -05:00
return error ( " Macro size exceeded " , name ) ;
2022-04-11 18:34:53 -04:00
scpy ( word , m - > items [ m - > len + + ] , 0x40 ) ;
2021-03-14 16:30:17 -04:00
}
return 1 ;
}
2021-06-28 17:42:36 -04:00
static int
2021-08-28 02:51:48 -04:00
makelabel ( char * name )
2021-02-04 16:49:03 -05:00
{
Label * l ;
2021-02-07 13:21:41 -05:00
if ( findlabel ( name ) )
return error ( " Label duplicate " , name ) ;
2021-12-06 12:01:48 -05:00
if ( sihx ( name ) & & ( slen ( name ) = = 2 | | slen ( name ) = = 4 ) )
2021-02-12 19:18:52 -05:00
return error ( " Label name is hex number " , name ) ;
2021-08-17 17:48:48 -04:00
if ( findopcode ( name ) | | scmp ( name , " BRK " , 4 ) | | ! slen ( name ) )
2021-02-13 11:38:23 -05:00
return error ( " Label name is invalid " , name ) ;
2022-04-11 18:34:53 -04:00
if ( p . llen = = 0x400 )
2021-11-29 11:48:12 -05:00
return error ( " Labels limit exceeded " , name ) ;
2021-03-13 17:55:29 -05:00
l = & p . labels [ p . llen + + ] ;
2021-11-27 14:33:22 -05:00
l - > addr = p . ptr ;
2021-03-01 12:16:40 -05:00
l - > refs = 0 ;
2022-04-11 18:34:53 -04:00
scpy ( name , l - > name , 0x40 ) ;
2021-02-04 16:49:03 -05:00
return 1 ;
}
2021-11-27 17:44:28 -05:00
static int
2023-03-01 00:47:45 -05:00
makereference ( char * scope , char * label , char rune , Uint16 addr )
2021-11-27 17:44:28 -05:00
{
2022-06-06 12:42:26 -04:00
char subw [ 0x40 ] , parent [ 0x40 ] ;
2021-11-27 17:44:28 -05:00
Reference * r ;
2023-01-21 21:24:11 -05:00
if ( p . rlen = = 0x1000 )
2021-11-29 11:48:12 -05:00
return error ( " References limit exceeded " , label ) ;
2021-11-27 17:44:28 -05:00
r = & p . refs [ p . rlen + + ] ;
2023-03-01 00:47:45 -05:00
if ( label [ 0 ] = = ' & ' ) {
if ( ! sublabel ( subw , scope , label + 1 ) )
2023-01-14 18:08:40 -05:00
return error ( " Invalid sublabel " , label ) ;
scpy ( subw , r - > name , 0x40 ) ;
} else {
2023-03-01 00:47:45 -05:00
int pos = spos ( label , ' / ' ) ;
2022-06-07 14:39:43 -04:00
if ( pos > 0 ) {
2022-06-06 12:42:26 -04:00
Label * l ;
2023-03-01 00:47:45 -05:00
if ( ( l = findlabel ( scpy ( label , parent , pos ) ) ) )
2022-06-06 12:42:26 -04:00
l - > refs + + ;
}
2023-03-01 00:47:45 -05:00
scpy ( label , r - > name , 0x40 ) ;
2022-06-06 12:42:26 -04:00
}
2023-03-01 00:47:45 -05:00
r - > rune = rune ;
2021-11-27 17:44:28 -05:00
r - > addr = addr ;
return 1 ;
}
2022-02-18 19:26:55 -05:00
static int
2021-11-27 17:20:56 -05:00
writebyte ( Uint8 b )
2021-02-15 17:04:58 -05:00
{
2022-04-11 18:34:53 -04:00
if ( p . ptr < TRIM )
return error ( " Writing in zero-page " , " " ) ;
else if ( p . ptr > 0xffff )
return error ( " Writing after the end of RAM " , " " ) ;
else if ( p . ptr < p . length )
return error ( " Memory overwrite " , " " ) ;
2021-11-27 14:33:22 -05:00
p . data [ p . ptr + + ] = b ;
p . length = p . ptr ;
2022-02-18 19:26:55 -05:00
return 1 ;
2021-02-15 17:04:58 -05:00
}
2022-05-26 23:26:21 -04:00
static int
writeopcode ( char * w )
{
2023-01-02 20:45:06 -05:00
return writebyte ( findopcode ( w ) ) ;
2022-05-26 23:26:21 -04:00
}
2022-02-18 19:26:55 -05:00
static int
2021-11-27 14:33:22 -05:00
writeshort ( Uint16 s , int lit )
2021-03-14 16:30:17 -04:00
{
2021-11-27 17:20:56 -05:00
if ( lit )
2022-02-18 19:26:55 -05:00
if ( ! writebyte ( findopcode ( " LIT2 " ) ) ) return 0 ;
return writebyte ( s > > 8 ) & & writebyte ( s & 0xff ) ;
2021-03-14 16:30:17 -04:00
}
2022-02-18 19:26:55 -05:00
static int
2021-11-27 16:55:33 -05:00
writelitbyte ( Uint8 b )
{
2023-01-02 20:45:06 -05:00
return writebyte ( findopcode ( " LIT " ) ) & & writebyte ( b ) ;
2021-11-27 16:55:33 -05:00
}
2021-11-27 17:07:25 -05:00
static int
doinclude ( const char * filename )
{
FILE * f ;
2022-04-11 18:34:53 -04:00
char w [ 0x40 ] ;
2021-11-27 17:07:25 -05:00
if ( ! ( f = fopen ( filename , " r " ) ) )
2021-11-29 11:48:12 -05:00
return error ( " Include missing " , filename ) ;
2021-11-27 17:07:25 -05:00
while ( fscanf ( f , " %63s " , w ) = = 1 )
2021-11-29 19:19:47 -05:00
if ( ! parse ( w , f ) )
2021-11-27 17:07:25 -05:00
return error ( " Unknown token " , w ) ;
fclose ( f ) ;
return 1 ;
}
2021-06-28 17:42:36 -04:00
static int
2021-11-29 19:19:47 -05:00
parse ( char * w , FILE * f )
2021-01-29 15:14:37 -05:00
{
2021-12-29 12:33:23 -05:00
int i ;
2022-04-11 18:34:53 -04:00
char word [ 0x40 ] , subw [ 0x40 ] , c ;
2021-11-27 16:55:33 -05:00
Macro * m ;
2021-11-27 14:33:22 -05:00
if ( slen ( w ) > = 63 )
return error ( " Invalid token " , w ) ;
switch ( w [ 0 ] ) {
case ' ( ' : /* comment */
2021-12-28 21:38:05 -05:00
if ( slen ( w ) ! = 1 ) fprintf ( stderr , " -- Malformed comment: %s \n " , w ) ;
i = 1 ; /* track nested comment depth */
while ( fscanf ( f , " %63s " , word ) = = 1 ) {
2021-12-29 12:11:03 -05:00
if ( slen ( word ) ! = 1 )
continue ;
else if ( word [ 0 ] = = ' ( ' )
i + + ;
else if ( word [ 0 ] = = ' ) ' & & - - i < 1 )
break ;
2021-12-28 21:38:05 -05:00
}
2021-11-27 14:33:22 -05:00
break ;
case ' ~ ' : /* include */
if ( ! doinclude ( w + 1 ) )
return error ( " Invalid include " , w ) ;
break ;
case ' % ' : /* macro */
if ( ! makemacro ( w + 1 , f ) )
return error ( " Invalid macro " , w ) ;
break ;
case ' | ' : /* pad-absolute */
if ( ! sihx ( w + 1 ) )
return error ( " Invalid padding " , w ) ;
p . ptr = shex ( w + 1 ) ;
break ;
case ' $ ' : /* pad-relative */
if ( ! sihx ( w + 1 ) )
return error ( " Invalid padding " , w ) ;
p . ptr + = shex ( w + 1 ) ;
break ;
case ' @ ' : /* label */
if ( ! makelabel ( w + 1 ) )
return error ( " Invalid label " , w ) ;
2022-04-11 18:34:53 -04:00
scpy ( w + 1 , p . scope , 0x40 ) ;
2021-11-27 14:33:22 -05:00
break ;
case ' & ' : /* sublabel */
2023-01-14 18:08:40 -05:00
if ( ! sublabel ( subw , p . scope , w + 1 ) | | ! makelabel ( subw ) )
2021-11-27 14:33:22 -05:00
return error ( " Invalid sublabel " , w ) ;
break ;
case ' # ' : /* literals hex */
2023-01-02 20:45:06 -05:00
if ( sihx ( w + 1 ) & & slen ( w ) = = 3 )
return writelitbyte ( shex ( w + 1 ) ) ;
else if ( sihx ( w + 1 ) & & slen ( w ) = = 5 )
return writeshort ( shex ( w + 1 ) , 1 ) ;
else
2021-11-27 14:33:22 -05:00
return error ( " Invalid hex literal " , w ) ;
break ;
2022-11-10 23:54:53 -05:00
case ' _ ' : /* raw byte relative */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr ) ;
2023-01-02 20:45:06 -05:00
return writebyte ( 0xff ) ;
2021-11-27 14:33:22 -05:00
case ' , ' : /* literal byte relative */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr + 1 ) ;
2023-01-02 20:45:06 -05:00
return writelitbyte ( 0xff ) ;
2022-11-10 23:54:53 -05:00
case ' - ' : /* raw byte absolute */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr ) ;
2023-01-02 20:45:06 -05:00
return writebyte ( 0xff ) ;
2022-11-10 23:54:53 -05:00
case ' . ' : /* literal byte zero-page */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr + 1 ) ;
2023-01-02 20:45:06 -05:00
return writelitbyte ( 0xff ) ;
2023-03-01 00:47:45 -05:00
case ' : ' :
case ' = ' : /* raw short absolute */
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr ) ;
2023-01-02 20:45:06 -05:00
return writeshort ( 0xffff , 0 ) ;
2022-11-10 23:54:53 -05:00
case ' ; ' : /* literal short absolute */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr + 1 ) ;
2023-01-02 20:45:06 -05:00
return writeshort ( 0xffff , 1 ) ;
2023-01-12 12:44:27 -05:00
case ' ? ' : /* JCI */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr + 1 ) ;
2023-01-02 20:45:06 -05:00
return writebyte ( 0x20 ) & & writeshort ( 0xffff , 0 ) ;
2023-01-12 12:44:27 -05:00
case ' ! ' : /* JMI */
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w + 1 , w [ 0 ] , p . ptr + 1 ) ;
2023-01-02 20:45:06 -05:00
return writebyte ( 0x40 ) & & writeshort ( 0xffff , 0 ) ;
2021-11-27 14:33:22 -05:00
case ' " ' : /* raw string */
i = 0 ;
while ( ( c = w [ + + i ] ) )
2022-02-18 19:26:55 -05:00
if ( ! writebyte ( c ) ) return 0 ;
2021-11-27 14:33:22 -05:00
break ;
2022-06-06 10:57:29 -04:00
case ' [ ' :
case ' ] ' :
2022-06-07 14:39:43 -04:00
if ( slen ( w ) = = 1 ) break ; /* else fallthrough */
2021-11-27 14:33:22 -05:00
default :
/* opcode */
2023-01-02 20:45:06 -05:00
if ( findopcode ( w ) | | scmp ( w , " BRK " , 4 ) )
return writeopcode ( w ) ;
2021-11-27 14:33:22 -05:00
/* raw byte */
2023-01-02 20:45:06 -05:00
else if ( sihx ( w ) & & slen ( w ) = = 2 )
return writebyte ( shex ( w ) ) ;
2021-11-27 14:33:22 -05:00
/* raw short */
2023-01-02 20:45:06 -05:00
else if ( sihx ( w ) & & slen ( w ) = = 4 )
return writeshort ( shex ( w ) , 0 ) ;
2021-11-27 14:33:22 -05:00
/* macro */
else if ( ( m = findmacro ( w ) ) ) {
2022-01-03 21:04:09 -05:00
for ( i = 0 ; i < m - > len ; i + + )
2021-11-29 19:19:47 -05:00
if ( ! parse ( m - > items [ i ] , f ) )
2021-11-27 14:33:22 -05:00
return 0 ;
return 1 ;
2023-01-02 20:45:06 -05:00
} else {
2023-03-01 00:47:45 -05:00
makereference ( p . scope , w , ' ' , p . ptr + 1 ) ;
2023-01-02 20:45:06 -05:00
return writebyte ( 0x60 ) & & writeshort ( 0xffff , 0 ) ;
}
2021-01-30 17:25:48 -05:00
}
2021-02-04 15:22:08 -05:00
return 1 ;
2021-01-30 17:25:48 -05:00
}
2021-06-28 17:42:36 -04:00
static int
2021-11-27 14:33:22 -05:00
resolve ( void )
2021-01-30 17:25:48 -05:00
{
2021-11-27 14:33:22 -05:00
Label * l ;
int i ;
2023-01-12 08:22:21 -05:00
Uint16 a ;
2022-01-03 21:04:09 -05:00
for ( i = 0 ; i < p . rlen ; i + + ) {
2021-11-27 14:33:22 -05:00
Reference * r = & p . refs [ i ] ;
switch ( r - > rune ) {
2022-11-10 23:54:53 -05:00
case ' _ ' :
2023-01-12 08:15:07 -05:00
case ' , ' :
2021-11-27 14:33:22 -05:00
if ( ! ( l = findlabel ( r - > name ) ) )
2022-11-10 23:54:53 -05:00
return error ( " Unknown relative reference " , r - > name ) ;
p . data [ r - > addr ] = ( Sint8 ) ( l - > addr - r - > addr - 2 ) ;
if ( ( Sint8 ) p . data [ r - > addr ] ! = ( l - > addr - r - > addr - 2 ) )
return error ( " Relative reference is too far " , r - > name ) ;
2021-11-27 14:33:22 -05:00
l - > refs + + ;
break ;
2022-11-10 23:54:53 -05:00
case ' - ' :
case ' . ' :
if ( ! ( l = findlabel ( r - > name ) ) )
return error ( " Unknown zero-page reference " , r - > name ) ;
2023-01-12 08:15:07 -05:00
p . data [ r - > addr ] = l - > addr & 0xff ;
2021-11-27 14:33:22 -05:00
l - > refs + + ;
break ;
case ' : ' :
2022-11-09 19:40:07 -05:00
case ' = ' :
2023-01-12 08:15:07 -05:00
case ' ; ' :
2023-01-12 08:22:21 -05:00
if ( ! ( l = findlabel ( r - > name ) ) )
return error ( " Unknown absolute reference " , r - > name ) ;
p . data [ r - > addr ] = l - > addr > > 0x8 ;
p . data [ r - > addr + 1 ] = l - > addr & 0xff ;
l - > refs + + ;
break ;
2023-01-12 08:15:07 -05:00
case ' ? ' :
case ' ! ' :
default :
2021-11-27 14:33:22 -05:00
if ( ! ( l = findlabel ( r - > name ) ) )
return error ( " Unknown absolute reference " , r - > name ) ;
2023-01-12 08:22:21 -05:00
a = l - > addr - r - > addr - 2 ;
p . data [ r - > addr ] = a > > 0x8 ;
p . data [ r - > addr + 1 ] = a & 0xff ;
2021-11-27 14:33:22 -05:00
l - > refs + + ;
break ;
2021-03-11 18:47:28 -05:00
}
2021-01-29 15:14:37 -05:00
}
2021-02-04 15:22:08 -05:00
return 1 ;
2021-01-29 15:14:37 -05:00
}
2021-11-27 14:33:22 -05:00
static int
assemble ( FILE * f )
{
2022-04-11 18:34:53 -04:00
char w [ 0x40 ] ;
2023-01-13 13:14:20 -05:00
p . ptr = 0x100 ;
2022-04-11 18:34:53 -04:00
scpy ( " on-reset " , p . scope , 0x40 ) ;
2023-01-07 14:59:00 -05:00
while ( fscanf ( f , " %62s " , w ) = = 1 )
if ( slen ( w ) > 0x3d | | ! parse ( w , f ) )
return error ( " Invalid token " , w ) ;
2021-11-30 13:27:35 -05:00
return resolve ( ) ;
2021-11-27 14:33:22 -05:00
}
2021-11-27 17:07:25 -05:00
static void
review ( char * filename )
{
int i ;
2022-01-03 21:04:09 -05:00
for ( i = 0 ; i < p . llen ; i + + )
2021-11-27 17:07:25 -05:00
if ( p . labels [ i ] . name [ 0 ] > = ' A ' & & p . labels [ i ] . name [ 0 ] < = ' Z ' )
continue ; /* Ignore capitalized labels(devices) */
else if ( ! p . labels [ i ] . refs )
2021-11-29 11:48:12 -05:00
fprintf ( stderr , " -- Unused label: %s \n " , p . labels [ i ] . name ) ;
fprintf ( stderr ,
" Assembled %s in %d bytes(%.2f%% used), %d labels, %d macros. \n " ,
filename ,
p . length - TRIM ,
2022-02-18 18:01:46 -05:00
( p . length - TRIM ) / 652.80 ,
2021-11-29 11:48:12 -05:00
p . llen ,
p . mlen ) ;
2021-11-27 17:07:25 -05:00
}
2022-12-09 15:30:04 -05:00
static void
writesym ( char * filename )
{
2023-01-01 16:40:58 -05:00
int i ;
2022-12-10 14:07:45 -05:00
char symdst [ 0x60 ] ;
2022-12-10 22:54:58 -05:00
FILE * fp ;
2022-12-10 14:07:45 -05:00
if ( slen ( filename ) > 0x60 - 5 )
return ;
fp = fopen ( scat ( scpy ( filename , symdst , slen ( filename ) + 1 ) , " .sym " ) , " w " ) ;
2022-12-09 15:30:04 -05:00
if ( fp ! = NULL ) {
for ( i = 0 ; i < p . llen ; i + + ) {
2023-01-12 11:40:33 -05:00
Uint8 hb = p . labels [ i ] . addr > > 8 , lb = p . labels [ i ] . addr & 0xff ;
fwrite ( & hb , 1 , 1 , fp ) ;
fwrite ( & lb , 1 , 1 , fp ) ;
2022-12-09 15:30:04 -05:00
fwrite ( p . labels [ i ] . name , slen ( p . labels [ i ] . name ) + 1 , 1 , fp ) ;
}
}
fclose ( fp ) ;
}
2021-01-29 15:14:37 -05:00
int
main ( int argc , char * argv [ ] )
{
2021-10-29 12:29:23 -04:00
FILE * src , * dst ;
2021-04-19 12:29:39 -04:00
if ( argc < 3 )
2021-07-24 20:09:46 -04:00
return ! error ( " usage " , " input.tal output.rom " ) ;
2021-10-29 12:29:23 -04:00
if ( ! ( src = fopen ( argv [ 1 ] , " r " ) ) )
2021-11-29 11:48:12 -05:00
return ! error ( " Invalid input " , argv [ 1 ] ) ;
2021-11-27 14:33:22 -05:00
if ( ! assemble ( src ) )
2021-07-24 20:09:46 -04:00
return ! error ( " Assembly " , " Failed to assemble rom. " ) ;
2021-10-29 12:29:23 -04:00
if ( ! ( dst = fopen ( argv [ 2 ] , " wb " ) ) )
return ! error ( " Invalid Output " , argv [ 2 ] ) ;
2022-05-09 16:13:28 -04:00
if ( p . length < = TRIM )
return ! error ( " Assembly " , " Output rom is empty. " ) ;
2021-10-29 12:29:23 -04:00
fwrite ( p . data + TRIM , p . length - TRIM , 1 , dst ) ;
2021-11-27 14:33:22 -05:00
review ( argv [ 2 ] ) ;
2022-12-09 15:30:04 -05:00
writesym ( argv [ 2 ] ) ;
2021-01-29 15:14:37 -05:00
return 0 ;
}