2021-01-29 15:14:37 -05:00
# include <stdio.h>
/*
Copyright ( c ) 2021 Devine Lu Linvega
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 .
*/
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-02-12 19:18:52 -05:00
typedef signed short Sint16 ;
2021-01-29 15:14:37 -05:00
2021-01-29 16:59:16 -05:00
typedef struct {
2021-02-04 00:53:56 -05:00
int ptr ;
2021-02-04 15:22:08 -05:00
Uint8 data [ 65536 ] ;
2021-01-29 16:59:16 -05:00
} Program ;
2021-01-31 00:31:49 -05:00
typedef struct {
2021-02-14 20:00:17 -05:00
Uint8 len ;
2021-02-04 15:22:08 -05:00
Uint16 addr ;
char name [ 64 ] ;
2021-01-31 00:31:49 -05:00
} Label ;
int labelslen ;
Label labels [ 256 ] ;
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-02-06 13:39:13 -05:00
char ops [ ] [ 4 ] = {
2021-02-14 20:00:17 -05:00
" BRK " , " NOP " , " LIT " , " --- " , " IOR " , " IOW " , " LDR " , " STR " ,
2021-02-14 23:23:00 -05:00
" JMP " , " JSR " , " --- " , " RTS " , " AND " , " ORA " , " ROL " , " ROR " ,
" POP " , " DUP " , " SWP " , " OVR " , " ROT " , " WSR " , " RSW " , " --- " ,
2021-02-07 13:21:41 -05:00
" ADD " , " SUB " , " MUL " , " DIV " , " EQU " , " NEQ " , " GTH " , " LTH "
2021-02-04 15:22:08 -05:00
} ;
2021-02-01 23:21:27 -05:00
2021-02-07 13:21:41 -05:00
int scmp ( char * a , char * b ) { int i = 0 ; while ( a [ i ] = = b [ i ] ) if ( ! a [ i + + ] ) return 1 ; return 0 ; } /* string compare */
int slen ( char * s ) { int i = 0 ; while ( s [ i ] & & s [ + + i ] ) ; return i ; } /* string length */
int sihx ( char * s ) { int i = 0 ; char c ; while ( ( c = s [ i + + ] ) ) if ( ! ( c > = ' 0 ' & & c < = ' 9 ' ) & & ! ( c > = ' a ' & & c < = ' f ' ) & & ! ( c > = ' A ' & & c < = ' F ' ) ) return 0 ; return 1 ; } /* string is hexadecimal */
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 ' ) ; else if ( c > = ' a ' & & c < = ' f ' ) n = n * 16 + 10 + ( c - ' a ' ) ; return n ; } /* string to num */
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-01-29 16:59:16 -05:00
# pragma mark - Helpers
2021-02-07 13:21:41 -05:00
/* clang-format on */
2021-01-30 17:25:48 -05:00
2021-02-04 15:22:08 -05:00
# pragma mark - I / O
2021-02-01 23:21:27 -05:00
void
2021-02-04 15:22:08 -05:00
pushbyte ( Uint8 b , int lit )
2021-02-01 23:21:27 -05:00
{
2021-02-09 23:35:31 -05:00
if ( lit )
pushbyte ( 0x02 , 0 ) ;
2021-02-04 15:22:08 -05:00
p . data [ p . ptr + + ] = b ;
2021-02-01 23:21:27 -05:00
}
void
2021-02-04 15:22:08 -05:00
pushshort ( Uint16 s , int lit )
2021-02-01 23:21:27 -05:00
{
2021-02-13 19:37:03 -05:00
if ( lit )
pushbyte ( 0x22 , 0 ) ;
2021-02-04 15:22:08 -05:00
pushbyte ( ( s > > 8 ) & 0xff , 0 ) ;
pushbyte ( s & 0xff , 0 ) ;
2021-02-01 23:21:27 -05:00
}
2021-01-31 00:31:49 -05:00
Label *
findlabel ( char * s )
{
int i ;
for ( i = 0 ; i < labelslen ; + + i )
if ( scmp ( labels [ i ] . name , s ) )
return & labels [ i ] ;
return NULL ;
}
2021-02-06 13:39:13 -05:00
Uint8
2021-02-13 16:21:05 -05:00
findopcode ( char * s )
2021-02-06 13:39:13 -05:00
{
int i ;
2021-02-07 13:21:41 -05:00
for ( i = 0 ; i < 0x20 ; + + i ) {
2021-02-06 13:39:13 -05:00
int m = 0 ;
2021-02-07 13:21:41 -05:00
char * o = ops [ i ] ;
if ( o [ 0 ] ! = s [ 0 ] | | o [ 1 ] ! = s [ 1 ] | | o [ 2 ] ! = s [ 2 ] )
continue ;
2021-02-06 13:39:13 -05:00
while ( s [ 3 + m ] ) {
2021-02-13 11:38:23 -05:00
if ( s [ 3 + m ] = = ' 2 ' ) i | = ( 1 < < 5 ) ; /* mode: short */
if ( s [ 3 + m ] = = ' S ' ) i | = ( 1 < < 6 ) ; /* mode: signed */
2021-02-07 23:49:00 -05:00
if ( s [ 3 + m ] = = ' ? ' ) i | = ( 1 < < 7 ) ; /* mode: conditional */
2021-02-06 13:39:13 -05:00
m + + ;
}
return i ;
}
return 0 ;
}
2021-02-04 15:22:08 -05:00
# pragma mark - Parser
2021-01-31 00:31:49 -05:00
2021-01-30 17:25:48 -05:00
int
2021-02-04 15:22:08 -05:00
error ( char * name , char * id )
2021-01-30 17:25:48 -05:00
{
2021-02-05 23:18:30 -05:00
printf ( " Error: %s[%s] \n " , name , id ) ;
2021-02-04 16:49:03 -05:00
return 0 ;
}
int
2021-02-14 20:00:17 -05:00
makelabel ( char * name , Uint16 addr , Uint8 len )
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-02-12 19:18:52 -05:00
if ( sihx ( name ) )
return error ( " Label name is hex number " , name ) ;
2021-02-13 16:21:05 -05:00
if ( findopcode ( name ) )
2021-02-13 11:38:23 -05:00
return error ( " Label name is invalid " , name ) ;
2021-02-04 16:49:03 -05:00
l = & labels [ labelslen + + ] ;
l - > addr = addr ;
2021-02-14 20:00:17 -05:00
l - > len = len ;
2021-02-07 13:21:41 -05:00
scpy ( name , l - > name , 64 ) ;
2021-02-14 20:00:17 -05:00
printf ( " New label: %s, at 0x%02x[%d] \n " , l - > name , l - > addr , l - > len ) ;
2021-02-04 16:49:03 -05:00
return 1 ;
}
2021-02-05 13:51:45 -05:00
int
makeconst ( char * id , FILE * f )
{
char wv [ 64 ] ;
fscanf ( f , " %s " , wv ) ;
2021-02-14 20:00:17 -05:00
return makelabel ( id , shex ( wv ) , 1 ) ;
2021-02-05 13:51:45 -05:00
}
2021-02-10 19:41:16 -05:00
int
makevariable ( char * id , Uint16 * addr , FILE * f )
{
char wv [ 64 ] ;
Uint8 origin ;
fscanf ( f , " %s " , wv ) ;
origin = * addr ;
* addr + = shex ( wv ) ;
2021-02-14 20:00:17 -05:00
return makelabel ( id , origin , shex ( wv ) ) ;
2021-02-10 19:41:16 -05:00
}
2021-02-13 19:37:03 -05:00
int
skipcomment ( char * w , int * cap )
{
if ( w [ 0 ] = = ' ) ' ) {
* cap = 0 ;
return 1 ;
}
if ( w [ 0 ] = = ' ( ' ) * cap = 1 ;
if ( * cap ) return 1 ;
return 0 ;
}
int
skipstring ( char * w , int * cap , Uint16 * addr )
{
if ( w [ 0 ] = = ' " ' ) {
if ( * cap )
* addr + = 1 ;
* cap = ! ( * cap ) ;
return 1 ;
}
if ( * cap ) {
* addr + = slen ( w ) + 1 ;
return 1 ;
}
return 0 ;
}
int
capturestring ( char * w , int * cap )
{
if ( w [ 0 ] = = ' " ' ) {
if ( * cap )
pushbyte ( 0x00 , 0 ) ;
* cap = ! ( * cap ) ;
return 1 ;
}
if ( * cap ) {
int i ;
for ( i = 0 ; i < slen ( w ) ; + + i )
pushbyte ( w [ i ] , 0 ) ;
pushbyte ( ' ' , 0 ) ;
return 1 ;
}
return 0 ;
}
2021-02-04 00:53:56 -05:00
int
2021-01-29 15:14:37 -05:00
pass1 ( FILE * f )
{
2021-02-13 19:37:03 -05:00
int ccmnt = 0 , cstrg = 0 ;
2021-02-04 18:23:04 -05:00
Uint16 addr = 0 ;
2021-02-04 15:22:08 -05:00
char w [ 64 ] ;
while ( fscanf ( f , " %s " , w ) = = 1 ) {
2021-02-13 19:37:03 -05:00
if ( skipcomment ( w , & ccmnt ) ) continue ;
if ( skipstring ( w , & cstrg , & addr ) ) continue ;
2021-02-10 19:41:16 -05:00
if ( w [ 0 ] = = ' @ ' ) {
2021-02-14 20:00:17 -05:00
if ( ! makelabel ( w + 1 , addr , 0 ) )
2021-02-10 19:41:16 -05:00
return error ( " Pass1 failed " , w ) ;
} else if ( w [ 0 ] = = ' ; ' ) {
if ( ! makevariable ( w + 1 , & addr , f ) )
return error ( " Pass1 failed " , w ) ;
} else if ( w [ 0 ] = = ' : ' ) {
2021-02-05 13:51:45 -05:00
if ( ! makeconst ( w + 1 , f ) )
return error ( " Pass1 failed " , w ) ;
2021-02-13 16:21:05 -05:00
} else if ( findopcode ( w ) | | scmp ( w , " BRK " ) )
2021-02-04 15:22:08 -05:00
addr + = 1 ;
2021-02-07 13:21:41 -05:00
else {
switch ( w [ 0 ] ) {
case ' | ' : addr = shex ( w + 1 ) ; break ;
2021-02-14 20:00:17 -05:00
case ' = ' : addr + = 4 ; break ; /* STR helper */
case ' ~ ' : addr + = 4 ; break ; /* LDR helper */
2021-02-13 19:37:03 -05:00
case ' , ' : addr + = 3 ; break ;
2021-02-14 13:22:42 -05:00
case ' . ' : addr + = ( slen ( w + 1 ) = = 2 ? 1 : 2 ) ; break ;
2021-02-12 19:18:52 -05:00
case ' + ' : /* signed positive */
case ' - ' : /* signed negative */
2021-02-13 19:37:03 -05:00
case ' # ' : addr + = ( slen ( w + 1 ) = = 2 ? 2 : 3 ) ; break ;
2021-02-13 16:21:05 -05:00
default : return error ( " Unknown label in first pass " , w ) ;
2021-02-07 13:21:41 -05:00
}
}
2021-01-30 17:25:48 -05:00
}
rewind ( f ) ;
2021-02-04 15:22:08 -05:00
return 1 ;
2021-01-30 17:25:48 -05:00
}
2021-02-04 15:22:08 -05:00
int
2021-01-30 17:25:48 -05:00
pass2 ( FILE * f )
{
2021-02-13 19:37:03 -05:00
int ccmnt = 0 , cstrg = 0 ;
2021-02-04 15:22:08 -05:00
char w [ 64 ] ;
while ( fscanf ( f , " %s " , w ) = = 1 ) {
2021-02-01 14:58:47 -05:00
Uint8 op = 0 ;
2021-01-31 00:31:49 -05:00
Label * l ;
2021-02-05 13:51:45 -05:00
if ( w [ 0 ] = = ' @ ' ) continue ;
2021-02-13 19:37:03 -05:00
if ( skipcomment ( w , & ccmnt ) ) continue ;
if ( capturestring ( w , & cstrg ) ) continue ;
2021-02-12 19:18:52 -05:00
/* clang-format off */
if ( w [ 0 ] = = ' | ' ) p . ptr = shex ( w + 1 ) ;
2021-02-13 16:21:05 -05:00
else if ( ( op = findopcode ( w ) ) | | scmp ( w , " BRK " ) ) pushbyte ( op , 0 ) ;
2021-02-12 19:18:52 -05:00
else if ( w [ 0 ] = = ' : ' ) fscanf ( f , " %s " , w ) ;
else if ( w [ 0 ] = = ' ; ' ) fscanf ( f , " %s " , w ) ;
2021-02-14 13:22:42 -05:00
else if ( w [ 0 ] = = ' . ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 2 ) pushbyte ( shex ( w + 1 ) , 0 ) ;
else if ( w [ 0 ] = = ' . ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 4 ) pushshort ( shex ( w + 1 ) , 0 ) ;
else if ( w [ 0 ] = = ' # ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 2 ) pushbyte ( shex ( w + 1 ) , 1 ) ;
else if ( w [ 0 ] = = ' # ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 4 ) pushshort ( shex ( w + 1 ) , 1 ) ;
2021-02-12 19:18:52 -05:00
else if ( w [ 0 ] = = ' + ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 2 ) pushbyte ( ( Sint8 ) shex ( w + 1 ) , 1 ) ;
else if ( w [ 0 ] = = ' + ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 4 ) pushshort ( ( Sint16 ) shex ( w + 1 ) , 1 ) ;
else if ( w [ 0 ] = = ' - ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 2 ) pushbyte ( ( Sint8 ) ( shex ( w + 1 ) * - 1 ) , 1 ) ;
else if ( w [ 0 ] = = ' - ' & & sihx ( w + 1 ) & & slen ( w + 1 ) = = 4 ) pushshort ( ( Sint16 ) ( shex ( w + 1 ) * - 1 ) , 1 ) ;
2021-02-14 20:00:17 -05:00
else if ( w [ 0 ] = = ' = ' & & ( l = findlabel ( w + 1 ) ) & & l - > len ) { pushshort ( l - > addr , 1 ) ; pushbyte ( findopcode ( l - > len = = 2 ? " STR2 " : " STR " ) , 0 ) ; }
else if ( w [ 0 ] = = ' ~ ' & & ( l = findlabel ( w + 1 ) ) & & l - > len ) { pushshort ( l - > addr , 1 ) ; pushbyte ( findopcode ( l - > len = = 2 ? " LDR2 " : " LDR " ) , 0 ) ; }
2021-02-12 19:18:52 -05:00
else if ( ( l = findlabel ( w + 1 ) ) ) pushshort ( l - > addr , w [ 0 ] = = ' , ' ) ;
2021-02-13 16:21:05 -05:00
else return error ( " Unknown label in second pass " , w ) ;
2021-02-12 19:18:52 -05:00
/* clang-format on */
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
}
int
main ( int argc , char * argv [ ] )
{
FILE * f ;
if ( argc < 3 )
2021-02-04 15:22:08 -05:00
return error ( " Input " , " Missing " ) ;
2021-01-29 15:14:37 -05:00
if ( ! ( f = fopen ( argv [ 1 ] , " r " ) ) )
2021-02-04 15:22:08 -05:00
return error ( " Open " , " Failed " ) ;
if ( ! pass1 ( f ) | | ! pass2 ( f ) )
return error ( " Assembly " , " Failed " ) ;
2021-01-29 16:59:16 -05:00
fwrite ( p . data , sizeof ( p . data ) , 1 , fopen ( argv [ 2 ] , " wb " ) ) ;
fclose ( f ) ;
2021-02-08 15:16:39 -05:00
printf ( " Assembled %s. \n \n " , argv [ 2 ] ) ;
2021-01-29 15:14:37 -05:00
return 0 ;
}