2011-12-27 00:50:27 +02:00
//
2021-03-08 00:43:25 +02:00
// RMAC - Renamed Macro Assembler for all Atari computers
2011-12-27 00:50:27 +02:00
// DIRECT.C - Directive Handling
2021-03-08 00:43:25 +02:00
// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
2011-12-27 00:50:27 +02:00
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
2015-02-19 16:56:14 +02:00
// Source utilised with the kind permission of Landon Dyer
2011-12-27 00:50:27 +02:00
//
# include "direct.h"
2017-04-20 22:29:31 +03:00
# include "6502.h"
2017-05-07 05:07:36 +03:00
# include "amode.h"
2019-08-08 02:24:52 +03:00
# include "dsp56k.h"
2011-12-27 00:50:27 +02:00
# include "error.h"
# include "expr.h"
2018-01-21 16:25:06 +02:00
# include "fltpoint.h"
2011-12-27 00:50:27 +02:00
# include "listing.h"
2017-04-20 22:29:31 +03:00
# include "mach.h"
# include "macro.h"
2011-12-27 00:50:27 +02:00
# include "mark.h"
2017-04-20 22:29:31 +03:00
# include "procln.h"
# include "riscasm.h"
# include "sect.h"
2011-12-27 00:50:27 +02:00
# include "symbol.h"
2017-04-20 22:29:31 +03:00
# include "token.h"
2011-12-27 00:50:27 +02:00
# define DEF_KW
# include "kwtab.h"
2022-03-24 13:28:09 +02:00
# define DEF_REG56
# define DECL_REG56
# include "56kregs.h"
# define DEF_REG68
# define DECL_REG68
# include "68kregs.h"
# define DEF_REGRISC
# define DECL_REGRISC
# include "riscregs.h"
2017-11-29 15:57:58 +02:00
TOKEN exprbuf [ 128 ] ; // Expression buffer
2012-11-24 21:48:52 +02:00
SYM * symbolPtr [ 1000000 ] ; // Symbol pointers table
2013-03-05 19:47:22 +02:00
static long unused ; // For supressing 'write' warnings
2015-02-19 18:04:29 +02:00
char buffer [ 256 ] ; // Scratch buffer for messages
2017-08-29 20:20:17 +03:00
int largestAlign [ 3 ] = { 2 , 2 , 2 } ; // Largest alignment value seen per section
2013-03-05 19:47:22 +02:00
2017-04-20 22:29:31 +03:00
// Function prototypes
int d_unimpl ( void ) ;
int d_68000 ( void ) ;
2017-05-07 05:07:36 +03:00
int d_68020 ( void ) ;
int d_68030 ( void ) ;
int d_68040 ( void ) ;
int d_68060 ( void ) ;
int d_68881 ( void ) ;
int d_68882 ( void ) ;
int d_56001 ( void ) ;
int d_nofpu ( void ) ;
2017-04-20 22:29:31 +03:00
int d_bss ( void ) ;
int d_data ( void ) ;
int d_text ( void ) ;
int d_abs ( void ) ;
int d_comm ( void ) ;
int d_dc ( WORD ) ;
int d_ds ( WORD ) ;
2019-08-29 15:09:37 +03:00
int d_dsm ( WORD ) ;
2017-04-20 22:29:31 +03:00
int d_dcb ( WORD ) ;
int d_globl ( void ) ;
int d_gpu ( void ) ;
int d_dsp ( void ) ;
int d_assert ( void ) ;
int d_include ( void ) ;
int d_list ( void ) ;
int d_nlist ( void ) ;
int d_error ( char * ) ;
int d_warn ( char * ) ;
int d_org ( void ) ;
int d_init ( WORD ) ;
int d_cargs ( void ) ;
int d_undmac ( void ) ;
int d_regbank0 ( void ) ;
int d_regbank1 ( void ) ;
int d_incbin ( void ) ;
int d_noclear ( void ) ;
int d_equrundef ( void ) ;
int d_ccundef ( void ) ;
int d_print ( void ) ;
int d_gpumain ( void ) ;
int d_jpad ( void ) ;
int d_nojpad ( void ) ;
int d_fail ( void ) ;
int d_cstruct ( void ) ;
int d_prgflags ( void ) ;
int d_opt ( void ) ;
2017-05-05 17:51:11 +03:00
int d_dsp ( void ) ;
2018-02-26 05:39:59 +02:00
int d_objproc ( void ) ;
2022-08-16 09:20:04 +03:00
int d_align ( void ) ;
2017-08-29 20:20:17 +03:00
void SetLargestAlignment ( int ) ;
2011-12-27 00:50:27 +02:00
// Directive handler table
int ( * dirtab [ ] ) ( ) = {
2013-03-02 22:22:33 +02:00
d_org , // 0 org
d_even , // 1 even
2017-04-20 22:29:31 +03:00
d_6502 , // 2 .6502
2015-11-01 16:53:46 +02:00
d_68000 , // 3 .68000
2013-03-02 22:22:33 +02:00
d_bss , // 4 bss
2015-11-01 17:14:52 +02:00
d_data , // 5 data
2015-11-01 16:53:46 +02:00
d_text , // 6 text
d_abs , // 7 abs
d_comm , // 8 comm
2015-11-01 17:14:52 +02:00
( void * ) d_init , // 9 init
2015-11-01 16:53:46 +02:00
d_cargs , // 10 cargs
2015-11-01 17:14:52 +02:00
( void * ) d_goto , // 11 goto
( void * ) d_dc , // 12 dc
( void * ) d_ds , // 13 ds
2015-11-01 16:53:46 +02:00
d_undmac , // 14 undefmac
2013-03-02 22:22:33 +02:00
d_gpu , // 15 .gpu
d_dsp , // 16 .dsp
2015-11-01 17:14:52 +02:00
( void * ) d_dcb , // 17 dcb
2015-11-01 16:53:46 +02:00
d_unimpl , // 18* set
d_unimpl , // 19* reg
d_unimpl , // 20 dump
d_incbin , // 21 .incbin //load
d_unimpl , // 22 disable
d_unimpl , // 23 enable
d_globl , // 24 globl
2013-03-02 22:22:33 +02:00
d_regbank0 , // 25 .regbank0
d_regbank1 , // 26 .regbank1
2015-11-01 16:53:46 +02:00
d_unimpl , // 27 xdef
d_assert , // 28 assert
d_unimpl , // 29* if
d_unimpl , // 30* endif
d_unimpl , // 31* endc
d_unimpl , // 32* iif
d_include , // 33 include
fpop , // 34 end
d_unimpl , // 35* macro
ExitMacro , // 36* exitm
d_unimpl , // 37* endm
d_list , // 38 list
d_nlist , // 39 nlist
d_long , // 40* rept
d_phrase , // 41* endr
d_dphrase , // 42 struct
d_qphrase , // 43 ends
d_title , // 44 title
d_subttl , // 45 subttl
eject , // 46 eject
2017-04-14 23:52:31 +03:00
d_error , // 47 error
d_warn , // 48 warn
2013-03-02 22:22:33 +02:00
d_noclear , // 49 .noclear
d_equrundef , // 50 .equrundef/.regundef
d_ccundef , // 51 .ccundef
d_print , // 52 .print
d_cstruct , // 53 .cstruct
2013-03-31 00:42:41 +02:00
d_jpad , // 54 .jpad (deprecated)
d_nojpad , // 55 .nojpad (deprecated)
2014-02-26 16:30:26 +02:00
d_gpumain , // 56 .gpumain (deprecated)
2015-11-14 19:57:21 +02:00
d_prgflags , // 57 .prgflags
2017-05-05 17:51:11 +03:00
d_68020 , // 58 .68020
d_68030 , // 59 .68030
d_68040 , // 60 .68040
d_68060 , // 61 .68060
d_68881 , // 62 .68881
d_68882 , // 63 .68882
d_56001 , // 64 .56001
d_nofpu , // 65 nofpu
2018-02-26 05:39:59 +02:00
d_opt , // 66 .opt
d_objproc , // 67 .objproc
2020-01-09 11:40:02 +02:00
( void * ) d_dsm , // 68 .dsm
2022-08-16 09:20:04 +03:00
d_align // 69 .align
2011-12-27 00:50:27 +02:00
} ;
2012-01-18 04:06:46 +02:00
2017-08-29 20:20:17 +03:00
//
// Set the largest alignment seen in the current section
//
void SetLargestAlignment ( int size )
{
if ( ( scattr & TEXT ) & & ( largestAlign [ 0 ] < size ) )
largestAlign [ 0 ] = size ;
else if ( ( scattr & DATA ) & & ( largestAlign [ 1 ] < size ) )
largestAlign [ 1 ] = size ;
else if ( ( scattr & BSS ) & & ( largestAlign [ 2 ] < size ) )
largestAlign [ 2 ] = size ;
}
2015-11-17 18:59:56 +02:00
//
// .error - Abort compilation, printing an error message
//
int d_error ( char * str )
{
2017-11-29 15:57:58 +02:00
if ( * tok = = EOL )
2015-11-17 18:59:56 +02:00
return error ( " error directive encountered - aborting assembling " ) ;
else
{
2017-11-29 15:57:58 +02:00
switch ( * tok )
2015-11-17 18:59:56 +02:00
{
case STRING :
2017-11-29 15:57:58 +02:00
return error ( string [ tok [ 1 ] ] ) ;
2015-11-17 18:59:56 +02:00
break ;
default :
2017-06-24 03:03:24 +03:00
return error ( " error directive encountered--aborting assembly " ) ;
2015-11-17 18:59:56 +02:00
}
}
}
//
// .warn - Just display a warning on screen
//
int d_warn ( char * str )
{
2017-11-29 15:57:58 +02:00
if ( * tok = = EOL )
2015-11-17 18:59:56 +02:00
return warn ( " WARNING WARNING WARNING " ) ;
else
{
2017-11-29 15:57:58 +02:00
switch ( * tok )
2015-11-17 18:59:56 +02:00
{
case STRING :
2017-11-29 15:57:58 +02:00
return warn ( string [ tok [ 1 ] ] ) ;
2015-11-17 18:59:56 +02:00
break ;
default :
return warn ( " WARNING WARNING WARNING " ) ;
}
}
}
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .org - Set origin
2011-12-27 00:50:27 +02:00
//
2011-12-27 01:54:45 +02:00
int d_org ( void )
{
2017-10-08 16:40:02 +03:00
uint64_t address ;
2017-04-20 22:29:31 +03:00
2020-01-09 11:40:02 +02:00
if ( ! rgpu & & ! rdsp & & ! robjproc & & ! m6502 & & ! dsp56001 & & ! ( obj_format = = RAW ) )
return error ( " .org permitted only in GPU/DSP/OP, 56001, 6502 and 68k (with -fr switch) sections " ) ;
2017-04-20 22:29:31 +03:00
2018-06-23 19:57:21 +03:00
// M56K can leave the expression off the org for some reason :-/
2019-08-08 02:24:52 +03:00
// (It's because the expression is non-standard, and so we have to look at
// it in isolation)
if ( ! dsp56001 & & ( abs_expr ( & address ) = = ERROR ) )
2017-04-20 22:29:31 +03:00
{
error ( " cannot determine org'd address " ) ;
return ERROR ;
}
2018-02-26 05:39:59 +02:00
if ( rgpu | rdsp | robjproc )
2017-04-20 22:29:31 +03:00
{
orgaddr = address ;
orgactive = 1 ;
}
2018-06-23 19:57:21 +03:00
else if ( m6502 )
2017-04-20 22:29:31 +03:00
{
2018-06-23 19:57:21 +03:00
// 6502. We also kludge 'lsloc' so the listing generator doesn't try
2017-04-20 22:29:31 +03:00
// to spew out megabytes.
if ( address > 0xFFFF )
return error ( range_error ) ;
if ( sloc ! = currentorg [ 0 ] )
{
currentorg [ 1 ] = sloc ;
currentorg + = 2 ;
}
currentorg [ 0 ] = address ;
ch_size = 0 ;
lsloc = sloc = address ;
chptr = scode - > chptr + address ;
orgaddr = address ;
orgactive = 1 ;
2018-06-23 19:57:21 +03:00
}
else if ( dsp56001 )
{
2019-08-08 02:24:52 +03:00
// Only mark segments we actually wrote something
if ( chptr ! = dsp_currentorg - > start & & dsp_written_data_in_current_org )
{
dsp_currentorg - > end = chptr ;
dsp_currentorg + + ;
}
// Maybe we switched from a non-DSP section (TEXT, DATA, etc) and
// scode isn't initialised yet. Not that it's going to be a valid
// scenario, but if we try it anyhow it's going to lead to a crash. So
// let's fudge a value of 0 and get on with it.
orgaddr = ( scode ! = NULL ? sloc : 0 ) ;
SaveSection ( ) ;
if ( tok [ 1 ] ! = ' : ' )
return error ( syntax_error ) ;
int sectionToSwitch = 0 ;
switch ( tok [ 0 ] )
{
2022-03-24 13:28:09 +02:00
case REG56_X :
2019-08-08 02:24:52 +03:00
dsp_currentorg - > memtype = ORG_X ;
sectionToSwitch = M56001X ;
break ;
2022-03-24 13:28:09 +02:00
case REG56_Y :
2019-08-08 02:24:52 +03:00
dsp_currentorg - > memtype = ORG_Y ;
sectionToSwitch = M56001Y ;
break ;
2022-03-24 13:28:09 +02:00
case REG56_P :
2019-08-08 02:24:52 +03:00
dsp_currentorg - > memtype = ORG_P ;
sectionToSwitch = M56001P ;
break ;
2022-03-24 13:28:09 +02:00
case REG56_L :
2019-08-08 02:24:52 +03:00
dsp_currentorg - > memtype = ORG_L ;
sectionToSwitch = M56001L ;
break ;
default :
return error ( " unknown type in ORG " ) ;
}
if ( ( obj_format = = LOD ) | | ( obj_format = = P56 ) )
SwitchSection ( sectionToSwitch ) ;
tok + = 2 ;
chcheck ( 3 ) ; // Ensure we got a valid address to write
dsp_currentorg - > chunk = scode ; // Mark down which chunk this org starts from (will be needed when outputting)
if ( * tok = = EOL )
{
// Well, the user didn't specify an address at all so we'll have to
// use the last used address of that section (or 0 if there wasn't one)
address = orgaddr ;
dsp_currentorg - > start = chptr ;
dsp_currentorg - > orgadr = orgaddr ;
}
else
{
if ( abs_expr ( & address ) = = ERROR )
{
error ( " cannot determine org'd address " ) ;
return ERROR ;
}
dsp_currentorg - > start = chptr ;
dsp_currentorg - > orgadr = ( uint32_t ) address ;
sect [ cursect ] . orgaddr = ( uint32_t ) address ;
}
if ( address > DSP_MAX_RAM )
{
return error ( range_error ) ;
}
dsp_written_data_in_current_org = 0 ;
// Copied from 6502 above: kludge `lsloc' so the listing generator
// doesn't try to spew out megabytes.
lsloc = sloc = ( int32_t ) address ;
// N.B.: It seems that by enabling this, even though it works elsewhere, will cause symbols to royally fuck up. Will have to do some digging to figure out why.
// orgactive = 1;
2017-04-20 22:29:31 +03:00
}
2020-01-09 11:40:02 +02:00
else
{
// If we get here we assume it's 68k with RAW output, so this is allowed
if ( orgactive )
{
return error ( " In 68k mode only one .org statement is allowed " ) ;
}
org68k_address = address ;
org68k_active = 1 ;
}
2017-04-20 22:29:31 +03:00
2019-08-08 02:24:52 +03:00
ErrorIfNotAtEOL ( ) ;
2017-04-20 22:29:31 +03:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Print directive
2011-12-27 00:50:27 +02:00
//
2011-12-27 01:54:45 +02:00
int d_print ( void )
{
2015-01-16 16:24:24 +02:00
char prntstr [ LNSIZ ] ; // String for PRINT directive
char format [ LNSIZ ] ; // Format for PRINT directive
int formatting = 0 ; // Formatting on/off
int wordlong = 0 ; // WORD = 0, LONG = 1
int outtype = 0 ; // 0:hex, 1:decimal, 2:unsigned
2017-10-08 16:40:02 +03:00
uint64_t eval ; // Expression value
2015-01-16 16:24:24 +02:00
WORD eattr ; // Expression attributes
SYM * esym ; // External symbol involved in expr.
2012-01-18 04:06:46 +02:00
TOKEN r_expr [ EXPRSIZE ] ;
2017-11-29 15:57:58 +02:00
while ( * tok ! = EOL )
2012-01-18 04:06:46 +02:00
{
2019-08-06 18:16:20 +03:00
switch ( * tok )
2012-01-18 04:06:46 +02:00
{
case STRING :
2017-11-29 15:57:58 +02:00
sprintf ( prntstr , " %s " , string [ tok [ 1 ] ] ) ;
2012-01-18 04:06:46 +02:00
printf ( " %s " , prntstr ) ;
2017-04-14 23:52:31 +03:00
if ( list_fd )
2013-03-05 19:47:22 +02:00
unused = write ( list_fd , prntstr , ( LONG ) strlen ( prntstr ) ) ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
break ;
case ' / ' :
formatting = 1 ;
2018-06-23 19:57:21 +03:00
// "X" & "L" get tokenized now... :-/ Probably should look into preventing this kind of thing from happening (was added with DSP56K code)
2022-03-24 13:28:09 +02:00
// Note (ggn): This is now much less severe as it's localised for 56k only
if ( ( tok [ 1 ] ! = SYMBOL ) & & ( tok [ 1 ] ! = REG56_L ) & & ( tok [ 1 ] ! = REG56_X ) )
2012-01-18 04:06:46 +02:00
goto token_err ;
2022-03-24 13:28:09 +02:00
if ( tok [ 1 ] = = REG56_L )
2012-01-18 04:06:46 +02:00
{
2018-06-23 19:57:21 +03:00
wordlong = 1 ;
tok + = 2 ;
}
2022-03-24 13:28:09 +02:00
else if ( tok [ 1 ] = = REG56_X )
2018-06-23 19:57:21 +03:00
{
outtype = 0 ;
tok + = 2 ;
}
else
{
strcpy ( prntstr , string [ tok [ 2 ] ] ) ;
2019-08-06 18:16:20 +03:00
switch ( prntstr [ 0 ] )
2018-06-23 19:57:21 +03:00
{
case ' l ' : case ' L ' : wordlong = 1 ; break ;
case ' w ' : case ' W ' : wordlong = 0 ; break ;
case ' x ' : case ' X ' : outtype = 0 ; break ;
case ' d ' : case ' D ' : outtype = 1 ; break ;
case ' u ' : case ' U ' : outtype = 2 ; break ;
default :
error ( " unknown print format flag " ) ;
return ERROR ;
}
tok + = 3 ;
2012-01-18 04:06:46 +02:00
}
break ;
case ' , ' :
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
break ;
default :
2017-11-29 15:57:58 +02:00
if ( expr ( r_expr , & eval , & eattr , & esym ) ! = OK )
2012-01-18 04:06:46 +02:00
goto token_err ;
else
{
switch ( outtype )
{
2017-04-14 23:52:31 +03:00
case 0 : strcpy ( format , " %X " ) ; break ;
case 1 : strcpy ( format , " %d " ) ; break ;
case 2 : strcpy ( format , " %u " ) ; break ;
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( wordlong )
sprintf ( prntstr , format , eval ) ;
else
sprintf ( prntstr , format , eval & 0xFFFF ) ;
printf ( " %s " , prntstr ) ;
2017-04-14 23:52:31 +03:00
if ( list_fd )
2013-03-05 19:47:22 +02:00
unused = write ( list_fd , prntstr , ( LONG ) strlen ( prntstr ) ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
formatting = 0 ;
wordlong = 0 ;
outtype = 0 ;
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
break ;
}
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
printf ( " \n " ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return 0 ;
token_err :
2018-06-23 19:57:21 +03:00
error ( " illegal print token [@ '%s'] " , prntstr ) ;
2012-01-18 04:06:46 +02:00
return ERROR ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Undefine an equated condition code
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_ccundef ( void )
{
SYM * ccname ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
// Check that we are in a RISC section
if ( ! rgpu & & ! rdsp )
{
error ( " .ccundef must be defined in .gpu/.dsp section " ) ;
return ERROR ;
}
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok ! = SYMBOL )
2012-01-18 04:06:46 +02:00
{
2013-11-09 17:01:57 +02:00
error ( " syntax error; expected symbol " ) ;
2012-01-18 04:06:46 +02:00
return ERROR ;
}
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
ccname = lookup ( string [ tok [ 1 ] ] , LABEL , 0 ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
// Make sure symbol is a valid ccdef
if ( ! ccname | | ! ( ccname - > sattre & EQUATEDCC ) )
{
error ( " invalid equated condition name specified " ) ;
return ERROR ;
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
ccname - > sattre | = UNDEF_CC ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Undefine an equated register
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_equrundef ( void )
{
SYM * regname ;
// Check that we are in a RISC section
if ( ! rgpu & & ! rdsp )
2014-05-17 23:56:15 +03:00
return error ( " .equrundef/.regundef must be defined in .gpu/.dsp section " ) ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
while ( * tok ! = EOL )
2012-01-18 04:06:46 +02:00
{
2013-03-02 22:22:33 +02:00
// Skip preceeding or seperating commas (if any)
2017-11-29 15:57:58 +02:00
if ( * tok = = ' , ' )
tok + + ;
2012-01-18 04:06:46 +02:00
// Check we are dealing with a symbol
2017-11-29 15:57:58 +02:00
if ( * tok ! = SYMBOL )
2014-05-17 23:56:15 +03:00
return error ( " syntax error; expected symbol " ) ;
2012-01-18 04:06:46 +02:00
// Lookup and undef if equated register
2017-11-29 15:57:58 +02:00
regname = lookup ( string [ tok [ 1 ] ] , LABEL , 0 ) ;
2012-01-18 04:06:46 +02:00
if ( regname & & ( regname - > sattre & EQUATEDREG ) )
2015-01-16 16:24:24 +02:00
{
// Reset the attributes of this symbol...
regname - > sattr = 0 ;
2022-03-07 19:49:09 +02:00
regname - > sattre & = ~ EQUATEDREG ;
2012-01-18 04:06:46 +02:00
regname - > sattre | = UNDEF_EQUR ;
2015-01-16 16:24:24 +02:00
}
2012-01-18 04:06:46 +02:00
// Skip over symbol token and address
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
}
return 0 ;
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
//
2015-01-16 16:24:24 +02:00
// Do not allow use of the CLR.L opcode
2012-01-18 04:06:46 +02:00
//
int d_noclear ( void )
{
2015-10-07 18:21:55 +03:00
warn ( " CLR.L opcode ignored... " ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2017-04-14 23:52:31 +03:00
//
2020-07-04 19:30:11 +03:00
// Include binary file (can add addition size & position params, comma separated)
2012-01-18 04:06:46 +02:00
//
int d_incbin ( void )
{
2013-02-27 16:44:33 +02:00
int fd ;
2012-01-18 04:06:46 +02:00
int bytes = 0 ;
2020-07-04 12:56:21 +03:00
uint64_t pos , size , bytesRead ;
2016-09-13 19:48:44 +03:00
char buf1 [ 256 ] ;
int i ;
2012-01-18 04:06:46 +02:00
2013-02-02 23:04:59 +02:00
// Check to see if we're in BSS, and, if so, throw an error
if ( scattr & SBSS )
{
2017-11-29 15:57:58 +02:00
error ( " cannot include binary file \" %s \" in BSS section " , string [ tok [ 1 ] ] ) ;
2013-02-02 23:04:59 +02:00
return ERROR ;
}
2017-11-29 15:57:58 +02:00
if ( * tok ! = STRING )
2012-01-18 04:06:46 +02:00
{
2018-06-03 18:01:45 +03:00
error ( " syntax error; file to include missing " ) ;
2012-01-18 04:06:46 +02:00
return ERROR ;
}
2016-09-13 19:48:44 +03:00
// Attempt to open the include file in the current directory, then (if that
// failed) try list of include files passed in the enviroment string or by
2020-07-23 16:40:21 +03:00
// the "-i" option.
2020-07-04 12:56:21 +03:00
TOKEN filename = tok [ 1 ] ;
2020-07-04 19:30:11 +03:00
2020-07-04 12:56:21 +03:00
if ( ( fd = open ( string [ filename ] , _OPEN_INC ) ) < 0 )
2013-02-27 16:44:33 +02:00
{
2016-09-27 18:46:14 +03:00
for ( i = 0 ; nthpath ( " RMACPATH " , i , buf1 ) ! = 0 ; i + + )
2016-09-13 19:48:44 +03:00
{
fd = strlen ( buf1 ) ;
2016-09-27 18:46:14 +03:00
// Append path char if necessary
if ( fd > 0 & & buf1 [ fd - 1 ] ! = SLASHCHAR )
2016-09-13 19:48:44 +03:00
strcat ( buf1 , SLASHSTRING ) ;
2020-07-04 12:56:21 +03:00
strcat ( buf1 , string [ filename ] ) ;
2016-09-13 19:48:44 +03:00
if ( ( fd = open ( buf1 , _OPEN_INC ) ) > = 0 )
goto allright ;
}
2020-07-04 12:56:21 +03:00
return error ( " cannot open: \" %s \" " , string [ filename ] ) ;
2013-02-27 16:44:33 +02:00
}
2016-09-13 19:48:44 +03:00
allright :
2020-07-04 12:56:21 +03:00
tok + = 2 ;
2020-07-04 19:30:11 +03:00
2022-12-19 13:09:06 +02:00
size = lseek ( fd , 0L , SEEK_END ) ;
pos = lseek ( fd , 0L , SEEK_SET ) ;
2020-07-04 12:56:21 +03:00
if ( * tok ! = EOL )
{
2022-12-19 13:09:06 +02:00
// Parse size and position parameters
uint64_t requested_size = - 1 ; // -1 means "not set" for these two
2022-12-22 00:37:53 +02:00
2022-12-19 13:09:06 +02:00
if ( * tok + + ! = ' , ' )
{
close ( fd ) ;
return error ( " expected comma after incbin filename " ) ;
}
2022-12-22 00:37:53 +02:00
2023-03-20 20:22:25 +02:00
if ( * tok ! = EOL )
2020-07-04 12:56:21 +03:00
{
if ( * tok ! = ' , ' )
{
2022-12-19 13:09:06 +02:00
if ( abs_expr ( & requested_size ) ! = OK )
2020-07-04 12:56:21 +03:00
{
close ( fd ) ;
return ERROR ;
}
2022-12-22 00:37:53 +02:00
2022-12-19 13:09:06 +02:00
if ( ( int64_t ) requested_size < = 0 | | requested_size > size )
2021-08-14 18:11:17 +03:00
{
2022-12-19 13:09:06 +02:00
close ( fd ) ;
2021-08-14 18:11:17 +03:00
return error ( " invalid incbin size requested " ) ;
}
2020-07-04 12:56:21 +03:00
}
2022-12-22 00:37:53 +02:00
2022-12-19 13:09:06 +02:00
if ( * tok ! = EOL )
2020-07-04 12:56:21 +03:00
{
2022-12-19 13:09:06 +02:00
if ( * tok + + ! = ' , ' )
{
close ( fd ) ;
return error ( " expected comma after size parameter " ) ;
}
2022-12-22 00:37:53 +02:00
2020-07-04 12:56:21 +03:00
if ( * tok ! = EOL )
{
if ( abs_expr ( & pos ) ! = OK )
{
close ( fd ) ;
return ERROR ;
}
2022-12-22 00:37:53 +02:00
2022-12-19 13:09:06 +02:00
if ( ( int64_t ) pos < = 0 | | pos > size )
2021-08-14 18:11:17 +03:00
{
2022-12-19 13:09:06 +02:00
close ( fd ) ;
return error ( " invalid incbin position requested " ) ;
2021-08-14 18:11:17 +03:00
}
2020-07-04 12:56:21 +03:00
}
}
2022-12-19 13:09:06 +02:00
if ( * tok ! = EOL )
{
close ( fd ) ;
return error ( " extra characters following incbin " ) ;
}
2020-07-04 12:56:21 +03:00
}
2022-12-19 13:09:06 +02:00
// Adjust size if the user didn't specify it via the parameter
if ( requested_size = = - 1 )
{
requested_size = size - pos ;
}
2022-12-22 00:37:53 +02:00
2022-12-19 13:09:06 +02:00
// Are we going to read past the end of the file?
if ( pos + requested_size > size )
{
close ( fd ) ;
return error ( " invalid combination of incbin position and size " ) ;
}
size = requested_size ;
// All checks passed, let's seek to where the user requested, otherwise at file start
lseek ( fd , pos , SEEK_SET ) ;
2020-07-04 12:56:21 +03:00
}
2020-07-04 19:30:11 +03:00
2013-02-27 16:44:33 +02:00
chcheck ( size ) ;
2020-07-04 12:56:21 +03:00
DEBUG { printf ( " INCBIN: File '%s' is %li bytes. \n " , string [ filename ] , size ) ; }
2013-02-27 16:44:33 +02:00
char * fileBuffer = ( char * ) malloc ( size ) ;
bytesRead = read ( fd , fileBuffer , size ) ;
if ( bytesRead ! = size )
{
2020-07-04 12:56:21 +03:00
error ( " was only able to read %li bytes from binary file (%s, %li bytes) " , bytesRead , string [ filename ] , size ) ;
2013-02-27 16:44:33 +02:00
return ERROR ;
}
memcpy ( chptr , fileBuffer , size ) ;
chptr + = size ;
sloc + = size ;
ch_size + = size ;
2012-01-18 04:06:46 +02:00
2013-02-27 16:44:33 +02:00
if ( orgactive )
orgaddr + = size ;
free ( fileBuffer ) ;
close ( fd ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2017-04-14 23:52:31 +03:00
//
2015-01-16 16:24:24 +02:00
// Set RISC register banks
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_regbank0 ( void )
{
2022-03-07 19:49:09 +02:00
// Deprecated, it's not as if this did anything useful, ever
warn ( " regbank0 ignored " ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
int d_regbank1 ( void )
{
2022-03-07 19:49:09 +02:00
// Deprecated, it's not as if this did anything useful, ever
warn ( " regbank1 ignored " ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2014-11-14 06:26:00 +02:00
//
// Helper function, to cut down on mistakes & typing
//
static inline void SkipBytes ( unsigned bytesToSkip )
{
if ( ! bytesToSkip )
return ;
if ( ( scattr & SBSS ) = = 0 )
{
chcheck ( bytesToSkip ) ;
D_ZEROFILL ( bytesToSkip ) ;
}
else
{
sloc + = bytesToSkip ;
if ( orgactive )
orgaddr + = bytesToSkip ;
}
}
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Adjust location to an EVEN value
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_even ( void )
{
2017-04-20 22:29:31 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2017-04-19 19:42:26 +03:00
2014-11-14 06:26:00 +02:00
unsigned skip = ( rgpu | | rdsp ? orgaddr : sloc ) & 0x01 ;
2017-04-14 23:52:31 +03:00
2014-11-14 06:26:00 +02:00
if ( skip )
2012-01-18 04:06:46 +02:00
{
if ( ( scattr & SBSS ) = = 0 )
{
chcheck ( 1 ) ;
D_byte ( 0 ) ;
}
else
{
2014-11-14 06:26:00 +02:00
sloc + + ;
if ( orgactive )
orgaddr + + ;
2012-01-18 04:06:46 +02:00
}
}
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Adjust location to a LONG value
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_long ( void )
{
2014-11-14 06:26:00 +02:00
unsigned lower2Bits = ( rgpu | | rdsp ? orgaddr : sloc ) & 0x03 ;
unsigned bytesToSkip = ( 0x04 - lower2Bits ) & 0x03 ;
SkipBytes ( bytesToSkip ) ;
2017-08-29 20:20:17 +03:00
SetLargestAlignment ( 4 ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Adjust location to a PHRASE value
2011-12-27 00:50:27 +02:00
//
2014-11-14 06:26:00 +02:00
// N.B.: We have to handle the GPU/DSP cases separately because you can embed
// RISC code in the middle of a regular 68K section. Also note that all
// of the alignment pseudo-ops will have to be fixed this way.
//
// This *must* behave differently when in a RISC section, as following sloc
// (instead of orgaddr) will fuck things up royally. Note that we do it this
// way because you can embed RISC code in a 68K section, and have the origin
// pointing to a different alignment in the RISC section than the 68K section.
//
2012-01-18 04:06:46 +02:00
int d_phrase ( void )
{
2014-11-14 06:26:00 +02:00
unsigned lower3Bits = ( rgpu | | rdsp ? orgaddr : sloc ) & 0x07 ;
unsigned bytesToSkip = ( 0x08 - lower3Bits ) & 0x07 ;
SkipBytes ( bytesToSkip ) ;
2017-08-29 20:20:17 +03:00
SetLargestAlignment ( 8 ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Adjust location to a DPHRASE value
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_dphrase ( void )
{
2014-11-14 06:26:00 +02:00
unsigned lower4Bits = ( rgpu | | rdsp ? orgaddr : sloc ) & 0x0F ;
unsigned bytesToSkip = ( 0x10 - lower4Bits ) & 0x0F ;
SkipBytes ( bytesToSkip ) ;
2017-08-29 20:20:17 +03:00
SetLargestAlignment ( 16 ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Adjust location to a QPHRASE value
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_qphrase ( void )
{
2014-11-14 06:26:00 +02:00
unsigned lower5Bits = ( rgpu | | rdsp ? orgaddr : sloc ) & 0x1F ;
unsigned bytesToSkip = ( 0x20 - lower5Bits ) & 0x1F ;
SkipBytes ( bytesToSkip ) ;
2017-08-29 20:20:17 +03:00
SetLargestAlignment ( 32 ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2022-08-16 09:20:04 +03:00
//
// Adjust location to <alignment> bytes
//
int d_align ( void )
{
unsigned bytesToSkip ;
uint64_t eval ;
if ( abs_expr ( & eval ) ! = OK )
return 0 ;
if ( eval < 2 )
{
return error ( " Invalid .align value specified " ) ;
}
if ( dsp56001 )
{
bytesToSkip = eval - sloc % eval ;
D_ZEROFILL ( bytesToSkip * 3 ) ;
return 0 ;
}
bytesToSkip = eval - ( rgpu | | rdsp ? orgaddr : sloc ) % eval ;
if ( bytesToSkip ! = eval )
{
if ( ( scattr & SBSS ) = = 0 )
{
D_ZEROFILL ( bytesToSkip ) ;
}
else
{
sloc + = bytesToSkip ;
if ( orgactive )
orgaddr + = bytesToSkip ;
}
}
return 0 ;
}
2011-12-27 00:50:27 +02:00
//
// Do auto-even. This must be called ONLY if 'sloc' is odd.
//
2012-01-18 04:06:46 +02:00
// This is made hairy because, if there was a label on the line, we also have
// to adjust its value. This won't work with more than one label on the line,
// which is OK since multiple labels are only allowed in AS68 kludge mode, and
// the C compiler is VERY paranoid and uses ".even" whenever it can
2011-12-27 00:50:27 +02:00
//
2014-11-14 06:26:00 +02:00
// N.B.: This probably needs the same fixes as above...
//
2012-01-18 04:06:46 +02:00
void auto_even ( void )
{
2017-04-20 22:29:31 +03:00
if ( cursect ! = M6502 )
{
if ( scattr & SBSS )
sloc + + ; // Bump BSS section
else
D_byte ( 0 ) ; // Deposit 0.b in non-BSS
2011-12-27 00:50:27 +02:00
2017-04-20 22:29:31 +03:00
if ( lab_sym ! = NULL ) // Bump label if we have to
lab_sym - > svalue + + ;
}
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Unimplemened directive error
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_unimpl ( void )
{
return error ( " unimplemented directive " ) ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2017-04-14 23:52:31 +03:00
//
2012-01-18 04:06:46 +02:00
// Return absolute (not TDB) and defined expression or return an error
2011-12-27 00:50:27 +02:00
//
2017-10-08 16:40:02 +03:00
int abs_expr ( uint64_t * a_eval )
2012-01-18 04:06:46 +02:00
{
WORD eattr ;
if ( expr ( exprbuf , a_eval , & eattr , NULL ) < 0 )
return ERROR ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( ! ( eattr & DEFINED ) )
return error ( undef_error ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( eattr & TDB )
return error ( rel_error ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// Hand symbols in a symbol-list to a function (kind of like mapcar...)
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int symlist ( int ( * func ) ( ) )
{
2014-05-17 23:56:15 +03:00
const char * em = " symbol list syntax " ;
2012-01-18 04:06:46 +02:00
for ( ; ; )
{
2017-11-29 15:57:58 +02:00
if ( * tok ! = SYMBOL )
2012-01-18 04:06:46 +02:00
return error ( em ) ;
2017-11-29 15:57:58 +02:00
if ( ( * func ) ( string [ tok [ 1 ] ] ) ! = OK )
2012-01-18 04:06:46 +02:00
break ;
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok = = EOL )
2012-01-18 04:06:46 +02:00
break ;
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok ! = ' , ' )
2012-01-18 04:06:46 +02:00
return error ( em ) ;
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
//
// .include "filename"
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_include ( void )
{
int j ;
int i ;
char * fn ;
char buf [ 128 ] ;
char buf1 [ 128 ] ;
2017-11-29 15:57:58 +02:00
if ( * tok = = STRING ) // Leave strings ALONE
fn = string [ * + + tok ] ;
else if ( * tok = = SYMBOL ) // Try to append ".s" to symbols
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
strcpy ( buf , string [ * + + tok ] ) ;
2012-01-18 04:06:46 +02:00
fext ( buf , " .s " , 0 ) ;
fn = & buf [ 0 ] ;
}
2017-04-14 23:52:31 +03:00
else // Punt if no STRING or SYMBOL
2012-01-18 04:06:46 +02:00
return error ( " missing filename " ) ;
// Make sure the user didn't try anything like:
// .include equates.s
2017-11-29 15:57:58 +02:00
if ( * + + tok ! = EOL )
2017-06-24 03:03:24 +03:00
return error ( " extra stuff after filename--enclose it in quotes " ) ;
2012-01-18 04:06:46 +02:00
2012-11-24 21:48:52 +02:00
// Attempt to open the include file in the current directory, then (if that
// failed) try list of include files passed in the enviroment string or by
2017-04-14 23:52:31 +03:00
// the "-i" option.
2012-01-18 04:06:46 +02:00
if ( ( j = open ( fn , 0 ) ) < 0 )
{
2013-02-13 04:14:47 +02:00
for ( i = 0 ; nthpath ( " RMACPATH " , i , buf1 ) ! = 0 ; i + + )
2012-01-18 04:06:46 +02:00
{
j = strlen ( buf1 ) ;
2017-04-14 23:52:31 +03:00
// Append path char if necessary
if ( j > 0 & & buf1 [ j - 1 ] ! = SLASHCHAR )
2012-01-18 04:06:46 +02:00
strcat ( buf1 , SLASHSTRING ) ;
strcat ( buf1 , fn ) ;
if ( ( j = open ( buf1 , 0 ) ) > = 0 )
goto allright ;
}
2017-06-24 03:03:24 +03:00
return error ( " cannot open: \" %s \" " , fn ) ;
2012-01-18 04:06:46 +02:00
}
allright :
include ( j , fn ) ;
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .assert expression [, expression...]
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_assert ( void )
{
WORD eattr ;
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
for ( ; expr ( exprbuf , & eval , & eattr , NULL ) = = OK ; + + tok )
2012-01-18 04:06:46 +02:00
{
if ( ! ( eattr & DEFINED ) )
return error ( " forward or undefined .assert " ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( ! eval )
return error ( " assert failure " ) ;
2017-11-29 15:57:58 +02:00
if ( * tok ! = ' , ' )
2012-01-18 04:06:46 +02:00
break ;
}
2019-08-08 02:24:52 +03:00
ErrorIfNotAtEOL ( ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .globl symbol [, symbol] <<<cannot make local symbols global>>>
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int globl1 ( char * p )
{
2014-05-17 23:56:15 +03:00
SYM * sy ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( * p = = ' . ' )
return error ( " cannot .globl local symbol " ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( ( sy = lookup ( p , LABEL , 0 ) ) = = NULL )
{
2012-11-24 21:48:52 +02:00
sy = NewSymbol ( p , LABEL , 0 ) ;
2012-01-18 04:06:46 +02:00
sy - > svalue = 0 ;
sy - > sattr = GLOBAL ;
2014-05-17 23:56:15 +03:00
//printf("glob1: Making global symbol: attr=%04X, eattr=%08X, %s\n", sy->sattr, sy->sattre, sy->sname);
2012-01-18 04:06:46 +02:00
}
2017-04-14 23:52:31 +03:00
else
2012-01-18 04:06:46 +02:00
sy - > sattr | = GLOBAL ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
int d_globl ( void )
{
2017-04-20 22:29:31 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2017-04-19 19:42:26 +03:00
2012-01-18 04:06:46 +02:00
symlist ( globl1 ) ;
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2015-11-14 19:57:21 +02:00
//
// .prgflags expression
//
int d_prgflags ( void )
{
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2015-11-14 19:57:21 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok = = EOL )
2015-11-14 19:57:21 +02:00
return error ( " PRGFLAGS requires value " ) ;
else if ( abs_expr ( & eval ) = = OK )
{
2017-10-26 15:24:25 +03:00
PRGFLAGS = ( uint32_t ) eval ;
2015-11-14 19:57:21 +02:00
return 0 ;
}
else
{
return error ( " PRGFLAGS requires value " ) ;
}
}
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .abs [expression]
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_abs ( void )
{
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2011-12-27 00:50:27 +02:00
2017-04-20 22:29:31 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2014-05-17 23:56:15 +03:00
SaveSection ( ) ;
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok = = EOL )
2012-01-18 04:06:46 +02:00
eval = 0 ;
else if ( abs_expr ( & eval ) ! = OK )
return 0 ;
2011-12-27 00:50:27 +02:00
2014-05-17 23:56:15 +03:00
SwitchSection ( ABS ) ;
2017-10-26 15:24:25 +03:00
sloc = ( uint32_t ) eval ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// Switch segments
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_text ( void )
{
if ( rgpu | | rdsp )
return error ( " directive forbidden in gpu/dsp mode " ) ;
2017-04-20 22:29:31 +03:00
else if ( m6502 )
return error ( in_6502mode ) ;
2012-01-18 04:06:46 +02:00
if ( cursect ! = TEXT )
{
2014-05-17 23:56:15 +03:00
SaveSection ( ) ;
SwitchSection ( TEXT ) ;
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
int d_data ( void )
{
if ( rgpu | | rdsp )
return error ( " directive forbidden in gpu/dsp mode " ) ;
2017-04-20 22:29:31 +03:00
else if ( m6502 )
return error ( in_6502mode ) ;
2012-01-18 04:06:46 +02:00
if ( cursect ! = DATA )
{
2014-05-17 23:56:15 +03:00
SaveSection ( ) ;
SwitchSection ( DATA ) ;
2012-01-18 04:06:46 +02:00
}
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
int d_bss ( void )
{
if ( rgpu | | rdsp )
return error ( " directive forbidden in gpu/dsp mode " ) ;
2017-04-20 22:29:31 +03:00
else if ( m6502 )
return error ( in_6502mode ) ;
2012-01-18 04:06:46 +02:00
if ( cursect ! = BSS )
{
2014-05-17 23:56:15 +03:00
SaveSection ( ) ;
SwitchSection ( BSS ) ;
2012-01-18 04:06:46 +02:00
}
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .ds[.size] expression
2011-12-27 00:50:27 +02:00
//
2011-12-27 01:54:45 +02:00
int d_ds ( WORD siz )
{
2016-04-15 17:56:45 +03:00
DEBUG { printf ( " Directive: .ds.[size] = %u, sloc = $%X \n " , siz , sloc ) ; }
2013-02-27 16:44:33 +02:00
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2021-03-06 20:18:43 +02:00
WORD eattr ;
2012-01-18 04:06:46 +02:00
2018-06-23 19:57:21 +03:00
if ( ( cursect & ( M6502 | M56KPXYL ) ) = = 0 )
2017-04-20 22:29:31 +03:00
{
if ( ( siz ! = SIZB ) & & ( sloc & 1 ) ) // Automatic .even
auto_even ( ) ;
}
2012-01-18 04:06:46 +02:00
2021-03-06 20:18:43 +02:00
if ( expr ( exprbuf , & eval , & eattr , NULL ) < 0 )
return ERROR ;
2022-12-22 00:37:53 +02:00
2016-09-13 04:58:37 +03:00
// Check to see if the value being passed in is negative (who the hell does
2019-08-09 17:48:31 +03:00
// that?--nobody does; it's the code gremlins, or rum, what does it)
2020-01-03 09:04:32 +02:00
// N.B.: Since 'eval' is of type uint64_t, if it goes negative, it will
2019-08-09 17:48:31 +03:00
// have its high bit set.
2020-01-03 09:04:32 +02:00
if ( eval & 0x8000000000000000 )
2019-08-09 17:48:31 +03:00
return error ( " negative sizes not allowed in DS " ) ;
2016-09-13 04:58:37 +03:00
2012-01-18 04:06:46 +02:00
// In non-TDB section (BSS, ABS and M6502) just advance the location
// counter appropriately. In TDB sections, deposit (possibly large) chunks
2016-09-13 04:58:37 +03:00
// of zeroed memory....
2017-04-19 19:42:26 +03:00
if ( ( scattr & SBSS ) | | cursect = = M6502 )
2012-01-18 04:06:46 +02:00
{
2017-10-26 15:24:25 +03:00
listvalue ( ( uint32_t ) eval ) ;
2012-01-18 04:06:46 +02:00
eval * = siz ;
2017-10-26 15:24:25 +03:00
sloc + = ( uint32_t ) eval ;
2017-04-20 22:29:31 +03:00
if ( cursect = = M6502 )
chptr + = eval ;
2017-04-14 23:52:31 +03:00
just_bss = 1 ; // No data deposited (8-bit CPU mode)
2012-01-18 04:06:46 +02:00
}
2020-01-03 09:04:32 +02:00
else if ( cursect & M56KPXYL )
2019-08-08 23:01:34 +03:00
{
// Change segment instead of marking blanks.
// Only mark segments we actually wrote something
if ( chptr ! = dsp_currentorg - > start & & dsp_written_data_in_current_org )
{
dsp_currentorg - > end = chptr ;
dsp_currentorg + + ;
dsp_currentorg - > memtype = dsp_currentorg [ - 1 ] . memtype ;
}
listvalue ( ( uint32_t ) eval ) ;
sloc + = ( uint32_t ) eval ;
// And now let's create a new segment
dsp_currentorg - > start = chptr ;
dsp_currentorg - > chunk = scode ; // Mark down which chunk this org starts from (will be needed when outputting)
sect [ cursect ] . orgaddr = sloc ;
dsp_currentorg - > orgadr = sloc ;
dsp_written_data_in_current_org = 0 ;
just_bss = 1 ; // No data deposited
}
2012-01-18 04:06:46 +02:00
else
{
2019-08-08 23:01:34 +03:00
dep_block ( eval , siz , 0 , ( DEFINED | ABS ) , NULL ) ;
2012-01-18 04:06:46 +02:00
}
2019-08-08 02:24:52 +03:00
ErrorIfNotAtEOL ( ) ;
2020-01-03 09:04:32 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2019-08-29 15:09:37 +03:00
//
// dsm[.siz] expression
// Define modulo storage
// Quoting the Motorola assembler manual:
// "The DSM directive reserves a block of memory the length of which in words is equal to
// the value of <expression>.If the runtime location counter is not zero, this directive first
// advances the runtime location counter to a base address that is a multiple of 2k, where
// 2k >= <expression>."
// The kicker of course is written a few sentences after:
// "<label>, if present, will be assigned the value of the runtime location counter after a valid
// base address has been established."
//
int d_dsm ( WORD siz )
{
TOKEN * tok_current = tok ; // Keep track of where tok was when we entered this procedure
uint64_t eval ;
if ( abs_expr ( & eval ) ! = OK )
return 0 ;
// Round up to the next highest power of 2
// Nicked from https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
eval - - ;
eval | = eval > > 1 ;
eval | = eval > > 2 ;
eval | = eval > > 4 ;
eval | = eval > > 8 ;
eval | = eval > > 16 ;
int units_to_skip ;
units_to_skip = eval + 1 - sloc ;
sloc + = units_to_skip ; // Bump up sloc - TODO: check if this goes over the RAM limits?
// If a label has been defined in the same line as dsm, its value also needs to be adjusted
if ( label_defined )
{
SYM * label = lookup ( label_defined , LABEL , 0 ) ;
label - > svalue + = units_to_skip ;
}
tok = tok_current ; // Rewind tok back to where it was
return d_ds ( siz ) ; // And let d_ds take over from here
}
2011-12-27 00:50:27 +02:00
//
2019-08-09 17:48:31 +03:00
// dc.b, dc.w / dc, dc.l, dc.i, dc.q, dc.d, dc.s, dc.x
2011-12-27 00:50:27 +02:00
//
2011-12-27 01:54:45 +02:00
int d_dc ( WORD siz )
{
2012-01-18 04:06:46 +02:00
WORD eattr ;
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2017-04-14 23:52:31 +03:00
uint8_t * p ;
2012-01-18 04:06:46 +02:00
if ( ( scattr & SBSS ) ! = 0 )
return error ( " illegal initialization of section " ) ;
2015-10-07 18:21:55 +03:00
// Do an auto_even if it's not BYTE sized (hmm, should we be doing this???)
2019-08-08 02:24:52 +03:00
if ( ( cursect ! = M6502 ) & & ( cursect ! = M56001P ) & & ( cursect ! = M56001X )
& & ( cursect ! = M56001Y ) & & ( cursect ! = M56001L )
& & ( siz ! = SIZB ) & & ( sloc & 1 ) )
2012-01-18 04:06:46 +02:00
auto_even ( ) ;
2015-10-07 18:21:55 +03:00
// Check to see if we're trying to set LONGS on a non 32-bit aligned
// address in a GPU or DSP section, in their local RAM
if ( ( siz = = SIZL ) & & ( orgaddr & 0x03 )
& & ( ( rgpu & & ( orgaddr > = 0xF03000 ) & & ( orgaddr < = 0xF03FFFF ) )
| | ( rdsp & & ( orgaddr > = 0xF1B000 ) & & ( orgaddr < = 0xF1CFFFF ) ) ) )
warn ( " depositing LONGs on a non-long address in local RAM " ) ;
2017-11-29 15:57:58 +02:00
for ( ; ; tok + + )
2012-01-18 04:06:46 +02:00
{
// dc.b 'string' [,] ...
2017-11-29 15:57:58 +02:00
if ( siz = = SIZB & & ( * tok = = STRING | | * tok = = STRINGA8 ) & & ( tok [ 2 ] = = ' , ' | | tok [ 2 ] = = EOL ) )
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
uint32_t i = strlen ( string [ tok [ 1 ] ] ) ;
2012-01-18 04:06:46 +02:00
2017-04-14 23:52:31 +03:00
if ( ( challoc - ch_size ) < i )
2012-01-18 04:06:46 +02:00
chcheck ( i ) ;
2017-11-29 15:57:58 +02:00
if ( * tok = = STRING )
2017-04-21 21:59:50 +03:00
{
2017-11-29 15:57:58 +02:00
for ( p = string [ tok [ 1 ] ] ; * p ! = EOS ; p + + )
2017-04-21 21:59:50 +03:00
D_byte ( * p ) ;
}
2018-06-23 19:57:21 +03:00
else if ( * tok = = STRINGA8 )
2017-04-21 21:59:50 +03:00
{
2017-11-29 15:57:58 +02:00
for ( p = string [ tok [ 1 ] ] ; * p ! = EOS ; p + + )
2017-04-21 21:59:50 +03:00
D_byte ( strtoa8 [ * p ] ) ;
}
else
{
error ( " String format not supported... yet " ) ;
}
2017-04-21 14:49:33 +03:00
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
goto comma ;
}
2017-04-14 23:52:31 +03:00
int movei = 0 ; // MOVEI flag for dc.i
2017-11-29 15:57:58 +02:00
if ( * tok = = DOTI )
2012-01-18 04:06:46 +02:00
{
movei = 1 ;
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
siz = SIZL ;
}
// dc.x <expression>
2017-04-14 23:52:31 +03:00
SYM * esym = 0 ;
if ( expr ( exprbuf , & eval , & eattr , & esym ) ! = OK )
2012-01-18 04:06:46 +02:00
return 0 ;
2017-10-26 15:24:25 +03:00
2017-11-21 15:54:55 +02:00
uint16_t tdb = eattr & TDB ;
uint16_t defined = eattr & DEFINED ;
2012-01-18 04:06:46 +02:00
2019-08-08 02:24:52 +03:00
// N.B.: This is awful. This needs better handling, rather than just bodging something in that, while works, is basically an ugly wart on the assembler. !!! FIX !!!
if ( dsp56001 )
{
if ( cursect ! = M56001L )
{
if ( ! defined )
{
AddFixup ( FU_DSPIMM24 | FU_SEXT , sloc , exprbuf ) ;
D_dsp ( 0 ) ;
}
else
{
if ( eattr & FLOAT )
{
double fval = * ( double * ) & eval ;
2019-08-08 05:15:19 +03:00
eval = DoubleToDSPFloat ( fval ) ;
2019-08-08 02:24:52 +03:00
}
else
{
if ( ( uint32_t ) eval + 0x1000000 > = 0x2000000 )
return error ( range_error ) ;
}
// Deposit DSP word (24-bit)
D_dsp ( eval ) ;
}
}
else
{
// In L: we deposit stuff to both X: and Y: instead
2019-08-08 05:15:19 +03:00
// We will be a bit lazy and require that there is a 2nd value
// in the same source line. (Motorola's assembler can parse
// 12-digit hex values, which we can't do at the moment) This
// of course requires to parse 2 values in one pass. If there
// isn't another value in this line, assume X: value is 0.
2019-08-08 02:24:52 +03:00
int secondword = 0 ;
uint32_t evaly ;
l_parse_loop :
if ( ! defined )
{
AddFixup ( FU_DSPIMM24 | FU_SEXT , sloc , exprbuf ) ;
D_dsp ( 0 ) ;
}
else
{
if ( eattr & FLOAT )
{
float fval = * ( float * ) & eval ;
2019-08-08 05:15:19 +03:00
eval = DoubleToDSPFloat ( fval ) ;
2019-08-08 02:24:52 +03:00
}
else
{
if ( eval + 0x1000000 > = 0x2000000 )
return error ( range_error ) ;
}
// Parse 2nd value if we didn't do this yet
if ( secondword = = 0 )
{
evaly = ( uint32_t ) eval ;
secondword = 1 ;
if ( * tok ! = ' : ' )
{
// If we don't have a : then we're probably at EOL,
// which means the X: value will be 0
eval = 0 ;
ErrorIfNotAtEOL ( ) ;
}
else
{
tok + + ; // Eat the comma;
if ( expr ( exprbuf , & eval , & eattr , NULL ) ! = OK )
return 0 ;
defined = ( WORD ) ( eattr & DEFINED ) ;
goto l_parse_loop ;
}
}
// Deposit DSP words (24-bit)
D_dsp ( eval ) ;
D_dsp ( evaly ) ;
sloc - - ; // We do write 2 DSP words but as far as L: space is concerned we actually advance our counter by one
}
}
2019-08-08 05:15:19 +03:00
2019-08-08 02:24:52 +03:00
goto comma ;
}
2012-01-18 04:06:46 +02:00
switch ( siz )
{
case SIZB :
if ( ! defined )
2011-12-27 01:54:45 +02:00
{
2014-05-17 23:56:15 +03:00
AddFixup ( FU_BYTE | FU_SEXT , sloc , exprbuf ) ;
2012-01-18 04:06:46 +02:00
D_byte ( 0 ) ;
}
else
2011-12-27 01:54:45 +02:00
{
2017-05-05 17:51:11 +03:00
if ( tdb )
return error ( " non-absolute byte value " ) ;
2012-01-18 04:06:46 +02:00
if ( eval + 0x100 > = 0x200 )
2017-06-24 03:03:24 +03:00
return error ( " %s (value = $%X) " , range_error, eval) ;
2012-01-18 04:06:46 +02:00
D_byte ( eval ) ;
}
break ;
2019-08-09 17:48:31 +03:00
2012-01-18 04:06:46 +02:00
case SIZW :
case SIZN :
if ( ! defined )
2011-12-27 01:54:45 +02:00
{
2014-05-17 23:56:15 +03:00
AddFixup ( FU_WORD | FU_SEXT , sloc , exprbuf ) ;
2012-01-18 04:06:46 +02:00
D_word ( 0 ) ;
}
else
2011-12-27 01:54:45 +02:00
{
2012-01-18 04:06:46 +02:00
if ( eval + 0x10000 > = 0x20000 )
return error ( range_error ) ;
2011-12-27 01:54:45 +02:00
2017-04-14 23:52:31 +03:00
if ( tdb )
MarkRelocatable ( cursect , sloc , tdb , MWORD , NULL ) ;
// Deposit 68000 or 6502 (byte-reversed) word
2017-04-20 22:29:31 +03:00
if ( cursect ! = M6502 )
D_word ( eval )
else
D_rword ( eval )
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
break ;
2019-08-09 17:48:31 +03:00
2012-01-18 04:06:46 +02:00
case SIZL :
2017-10-08 16:40:02 +03:00
// Shamus: Why can't we do longs in 6502 mode?
2017-04-20 22:29:31 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2017-04-19 19:42:26 +03:00
2012-01-18 04:06:46 +02:00
if ( ! defined )
{
2019-08-09 17:48:31 +03:00
AddFixup ( FU_LONG | ( movei ? FU_MOVEI : 0 ) , sloc , exprbuf ) ;
2012-01-18 04:06:46 +02:00
D_long ( 0 ) ;
}
else
{
if ( tdb )
2017-04-14 23:52:31 +03:00
MarkRelocatable ( cursect , sloc , tdb , MLONG , NULL ) ;
2012-01-18 04:06:46 +02:00
2017-04-14 23:52:31 +03:00
if ( movei )
eval = WORDSWAP32 ( eval ) ;
2012-01-18 04:06:46 +02:00
D_long ( eval ) ;
}
2018-02-26 05:39:59 +02:00
2012-01-18 04:06:46 +02:00
break ;
2019-08-09 17:48:31 +03:00
2017-11-21 15:54:55 +02:00
case SIZQ :
// 64-bit size
if ( m6502 )
return error ( in_6502mode ) ;
2018-02-26 05:39:59 +02:00
// DEFINITELY NEED FIXUPS HERE!
if ( ! defined )
{
AddFixup ( FU_QUAD , sloc , exprbuf ) ;
2019-08-09 17:48:31 +03:00
eval = 0 ;
2018-02-26 05:39:59 +02:00
}
2019-08-09 17:48:31 +03:00
D_quad ( eval ) ;
2017-11-21 15:54:55 +02:00
break ;
2019-08-09 17:48:31 +03:00
2017-10-26 15:24:25 +03:00
case SIZS :
2018-01-21 16:25:06 +02:00
// 32-bit float size
2017-10-26 15:24:25 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2019-08-09 17:48:31 +03:00
/* Seems to me that if something is undefined here, then that should be an error. Likewise for the D & X variants. */
2017-10-26 15:24:25 +03:00
if ( ! defined )
{
2019-08-09 17:48:31 +03:00
// AddFixup(FU_FLOATSING, sloc, exprbuf);
// D_long(0);
return error ( " labels not allowed in floating point expressions " ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-02-26 05:39:59 +02:00
//Would this *ever* happen?
// if (tdb)
// MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
PTR ptr ;
ptr . u64 = & eval ;
uint32_t ieee754 = FloatToIEEE754 ( ( float ) * ptr . dp ) ;
D_long ( ieee754 ) ;
2017-10-26 15:24:25 +03:00
}
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
break ;
2019-08-09 17:48:31 +03:00
2017-10-08 16:40:02 +03:00
case SIZD :
2018-01-21 16:25:06 +02:00
// 64-bit double size
2017-10-26 15:24:25 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
if ( ! defined )
{
2019-08-09 17:48:31 +03:00
// AddFixup(FU_FLOATDOUB, sloc, exprbuf);
// D_quad(0LL);
return error ( " labels not allowed in floating point expressions " ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-02-26 05:39:59 +02:00
//Would this *ever* happen?
// if (tdb)
// MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
PTR ptr ;
ptr . u64 = & eval ;
uint64_t ieee754 = DoubleToIEEE754 ( * ptr . dp ) ;
D_quad ( ieee754 ) ;
2017-10-26 15:24:25 +03:00
}
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
break ;
2019-08-09 17:48:31 +03:00
2017-10-26 15:24:25 +03:00
case SIZX :
if ( m6502 )
return error ( in_6502mode ) ;
2018-01-21 16:25:06 +02:00
uint8_t extDbl [ 12 ] ;
memset ( extDbl , 0 , 12 ) ;
2017-10-26 15:24:25 +03:00
if ( ! defined )
{
2019-08-09 17:48:31 +03:00
// AddFixup(FU_FLOATEXT, sloc, exprbuf);
// D_extend(extDbl);
return error ( " labels not allowed in floating point expressions " ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-02-26 05:39:59 +02:00
//Would this *ever* happen?
// if (tdb)
// MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
PTR ptr ;
ptr . u64 = & eval ;
DoubleToExtended ( * ptr . dp , extDbl ) ;
D_extend ( extDbl ) ;
2017-10-26 15:24:25 +03:00
}
2017-11-21 15:54:55 +02:00
2017-10-08 16:40:02 +03:00
break ;
2012-01-18 04:06:46 +02:00
}
2017-04-14 23:52:31 +03:00
2012-01-18 04:06:46 +02:00
comma :
2017-11-29 15:57:58 +02:00
if ( * tok ! = ' , ' )
2012-01-18 04:06:46 +02:00
break ;
}
2019-08-08 02:24:52 +03:00
ErrorIfNotAtEOL ( ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2'
2011-12-27 00:50:27 +02:00
//
2011-12-27 01:54:45 +02:00
int d_dcb ( WORD siz )
{
2017-10-08 16:40:02 +03:00
uint64_t evalc , eval ;
2012-01-18 04:06:46 +02:00
WORD eattr ;
2011-12-27 00:50:27 +02:00
2016-04-15 17:56:45 +03:00
DEBUG { printf ( " dcb: section is %s%s%s (scattr=$%X) \n " , ( cursect & TEXT ? " TEXT " : " " ) , ( cursect & DATA ? " DATA " : " " ) , ( cursect & BSS ? " BSS " : " " ) , scattr ) ; }
2012-01-18 04:06:46 +02:00
if ( ( scattr & SBSS ) ! = 0 )
return error ( " illegal initialization of section " ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( abs_expr ( & evalc ) ! = OK )
return 0 ;
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = ' , ' )
2012-01-18 04:06:46 +02:00
return error ( " missing comma " ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( expr ( exprbuf , & eval , & eattr , NULL ) < 0 )
return 0 ;
2011-12-27 00:50:27 +02:00
2017-04-19 19:42:26 +03:00
if ( cursect ! = M6502 & & ( siz ! = SIZB ) & & ( sloc & 1 ) )
2012-01-18 04:06:46 +02:00
auto_even ( ) ;
2011-12-27 00:50:27 +02:00
2017-10-26 15:24:25 +03:00
dep_block ( ( uint32_t ) evalc , siz , ( uint32_t ) eval , eattr , exprbuf ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
// Generalized initialization directive
2017-04-14 23:52:31 +03:00
//
2011-12-27 00:50:27 +02:00
// .init[.siz] [#count,] expression [.size] , ...
2017-04-14 23:52:31 +03:00
//
2012-01-18 04:06:46 +02:00
// The size suffix on the ".init" directive becomes the default size of the
// objects to deposit. If an item is preceeded with a sharp (immediate) sign
// and an expression, it specifies a repeat count. The value to be deposited
// may be followed by a size suffix, which overrides the default size.
2011-12-27 00:50:27 +02:00
//
2011-12-27 01:54:45 +02:00
int d_init ( WORD def_siz )
{
2017-10-08 16:40:02 +03:00
uint64_t count ;
uint64_t eval ;
2012-01-18 04:06:46 +02:00
WORD eattr ;
WORD siz ;
if ( ( scattr & SBSS ) ! = 0 )
return error ( " .init not permitted in BSS or ABS " ) ;
if ( rgpu | | rdsp )
return error ( " directive forbidden in gpu/dsp mode " ) ;
for ( ; ; )
{
// Get repeat count (defaults to 1)
2017-11-29 15:57:58 +02:00
if ( * tok = = ' # ' )
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
if ( abs_expr ( & count ) ! = OK )
return 0 ;
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = ' , ' )
2012-01-18 04:06:46 +02:00
return error ( comma_error ) ;
}
else
count = 1 ;
// Evaluate expression to deposit
if ( expr ( exprbuf , & eval , & eattr , NULL ) < 0 )
return 0 ;
2017-11-29 15:57:58 +02:00
switch ( * tok + + )
2012-01-18 04:06:46 +02:00
{ // Determine size of object to deposit
case DOTB : siz = SIZB ; break ;
case DOTW : siz = SIZB ; break ;
case DOTL : siz = SIZL ; break ;
2017-04-14 23:52:31 +03:00
default :
2012-01-18 04:06:46 +02:00
siz = def_siz ;
2017-11-29 15:57:58 +02:00
tok - - ;
2012-01-18 04:06:46 +02:00
break ;
}
2017-10-26 15:24:25 +03:00
dep_block ( ( uint32_t ) count , siz , ( uint32_t ) eval , eattr , exprbuf ) ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
switch ( * tok )
2012-01-18 04:06:46 +02:00
{
case EOL :
return 0 ;
case ' , ' :
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
continue ;
default :
return error ( comma_error ) ;
}
}
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
//
// Deposit 'count' values of size 'siz' in the current (non-BSS) segment
2011-12-27 00:50:27 +02:00
//
2017-11-29 15:57:58 +02:00
int dep_block ( uint32_t count , WORD siz , uint32_t eval , WORD eattr , TOKEN * exprbuf )
2012-01-18 04:06:46 +02:00
{
2019-08-08 23:01:34 +03:00
WORD tdb = eattr & TDB ;
WORD defined = eattr & DEFINED ;
2012-01-18 04:06:46 +02:00
while ( count - - )
{
if ( ( challoc - ch_size ) < 4 )
chcheck ( 4L ) ;
switch ( siz )
{
case SIZB :
if ( ! defined )
{
2014-05-17 23:56:15 +03:00
AddFixup ( FU_BYTE | FU_SEXT , sloc , exprbuf ) ;
2012-01-18 04:06:46 +02:00
D_byte ( 0 ) ;
}
else
{
if ( tdb )
return error ( " non-absolute byte value " ) ;
if ( eval + 0x100 > = 0x200 )
return error ( range_error ) ;
D_byte ( eval ) ;
}
break ;
case SIZW :
case SIZN :
if ( ! defined )
{
2014-05-17 23:56:15 +03:00
AddFixup ( FU_WORD | FU_SEXT , sloc , exprbuf ) ;
2012-01-18 04:06:46 +02:00
D_word ( 0 ) ;
}
else
{
if ( tdb )
2017-04-14 23:52:31 +03:00
MarkRelocatable ( cursect , sloc , tdb , MWORD , NULL ) ;
2012-01-18 04:06:46 +02:00
if ( eval + 0x10000 > = 0x20000 )
return error ( range_error ) ;
// Deposit 68000 or 6502 (byte-reversed) word
2017-04-19 19:42:26 +03:00
if ( cursect ! = M6502 )
2017-04-20 22:29:31 +03:00
D_word ( eval )
2017-04-19 19:42:26 +03:00
else
2017-04-20 22:29:31 +03:00
D_rword ( eval )
2017-04-19 19:42:26 +03:00
2012-01-18 04:06:46 +02:00
}
break ;
case SIZL :
2017-04-19 19:42:26 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2017-04-20 22:29:31 +03:00
2012-01-18 04:06:46 +02:00
if ( ! defined )
{
2014-05-17 23:56:15 +03:00
AddFixup ( FU_LONG , sloc , exprbuf ) ;
2012-01-18 04:06:46 +02:00
D_long ( 0 ) ;
}
else
{
if ( tdb )
2017-04-14 23:52:31 +03:00
MarkRelocatable ( cursect , sloc , tdb , MLONG , NULL ) ;
2012-01-18 04:06:46 +02:00
D_long ( eval ) ;
}
break ;
}
}
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .comm symbol, size
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_comm ( void )
{
SYM * sym ;
char * p ;
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2012-01-18 04:06:46 +02:00
2017-04-19 19:42:26 +03:00
if ( m6502 )
return error ( in_6502mode ) ;
2017-11-29 15:57:58 +02:00
if ( * tok ! = SYMBOL )
2012-01-18 04:06:46 +02:00
return error ( " missing symbol " ) ;
2017-11-29 15:57:58 +02:00
p = string [ tok [ 1 ] ] ;
tok + = 2 ;
2011-12-27 00:50:27 +02:00
2018-02-10 07:08:47 +02:00
if ( * p = = ' . ' ) // Cannot .comm a local symbol
2012-01-18 04:06:46 +02:00
return error ( locgl_error ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
if ( ( sym = lookup ( p , LABEL , 0 ) ) = = NULL )
2012-11-24 21:48:52 +02:00
sym = NewSymbol ( p , LABEL , 0 ) ;
2012-01-18 04:06:46 +02:00
else
{
if ( sym - > sattr & DEFINED )
return error ( " .comm symbol already defined " ) ;
}
2011-12-27 00:50:27 +02:00
2012-11-24 21:48:52 +02:00
sym - > sattr = GLOBAL | COMMON | BSS ;
2011-12-27 00:50:27 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = ' , ' )
2012-01-18 04:06:46 +02:00
return error ( comma_error ) ;
2011-12-27 00:50:27 +02:00
2018-02-10 07:08:47 +02:00
if ( abs_expr ( & eval ) ! = OK ) // Parse size of common region
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
2018-02-10 07:08:47 +02:00
sym - > svalue = eval ; // Install common symbol's size
2019-08-08 02:24:52 +03:00
ErrorIfNotAtEOL ( ) ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .list - Turn listing on
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_list ( void )
{
if ( list_flag )
2013-02-13 04:14:47 +02:00
listing + + ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .nlist - Turn listing off
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_nlist ( void )
{
if ( list_flag )
2013-02-13 04:14:47 +02:00
listing - - ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// .68000 - Back to 68000 TEXT segment
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_68000 ( void )
{
2018-06-23 19:57:21 +03:00
rgpu = rdsp = robjproc = dsp56001 = 0 ;
2012-01-18 04:06:46 +02:00
// Switching from gpu/dsp sections should reset any ORG'd Address
2017-04-14 23:52:31 +03:00
orgactive = 0 ;
2012-01-18 04:06:46 +02:00
orgwarning = 0 ;
2014-05-17 23:56:15 +03:00
SaveSection ( ) ;
SwitchSection ( TEXT ) ;
2017-05-07 05:07:36 +03:00
activecpu = CPU_68000 ;
2022-03-24 13:28:09 +02:00
regbase = reg68base ; // Update register DFA tables
regtab = reg68tab ;
regcheck = reg68check ;
regaccept = reg68accept ;
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
// .68020 - Back to 68000 TEXT segment and select 68020
//
int d_68020 ( void )
{
d_68000 ( ) ;
2017-05-07 05:07:36 +03:00
activecpu = CPU_68020 ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
// .68030 - Back to 68000 TEXT segment and select 68030
//
int d_68030 ( void )
{
d_68000 ( ) ;
2017-05-07 05:07:36 +03:00
activecpu = CPU_68030 ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
// .68040 - Back to 68000 TEXT segment and select 68040
//
int d_68040 ( void )
{
d_68000 ( ) ;
2017-05-07 05:07:36 +03:00
activecpu = CPU_68040 ;
activefpu = FPU_68040 ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
// .68060 - Back to 68000 TEXT segment and select 68060
//
int d_68060 ( void )
{
d_68000 ( ) ;
2017-05-07 05:07:36 +03:00
activecpu = CPU_68060 ;
2018-01-23 14:07:23 +02:00
activefpu = FPU_68060 ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
2018-01-23 14:07:23 +02:00
// .68881 - Back to 680x0 TEXT segment and select 68881 FPU
2017-05-05 17:51:11 +03:00
//
int d_68881 ( void )
{
2017-05-07 05:07:36 +03:00
activefpu = FPU_68881 ;
2022-03-24 13:28:09 +02:00
regbase = reg68base ; // Update register DFA tables
regtab = reg68tab ;
regcheck = reg68check ;
regaccept = reg68accept ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
2018-01-23 14:07:23 +02:00
// .68882 - Back to 680x0 TEXT segment and select 68882 FPU
2017-05-05 17:51:11 +03:00
//
int d_68882 ( void )
{
2018-01-23 14:07:23 +02:00
activefpu = FPU_68882 ;
2022-03-24 13:28:09 +02:00
regbase = reg68base ; // Update register DFA tables
regtab = reg68tab ;
regcheck = reg68check ;
regaccept = reg68accept ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
// nofpu - Deselect FPUs.
//
int d_nofpu ( void )
{
2017-05-07 05:07:36 +03:00
activefpu = FPU_NONE ;
2017-05-05 17:51:11 +03:00
return 0 ;
}
2017-05-07 05:07:36 +03:00
2017-05-05 17:51:11 +03:00
//
2018-06-23 19:57:21 +03:00
// .56001 - Switch to DSP56001 assembler
2017-05-05 17:51:11 +03:00
//
int d_56001 ( void )
{
2018-06-23 19:57:21 +03:00
dsp56001 = 1 ;
rgpu = rdsp = robjproc = 0 ;
SaveSection ( ) ;
2019-08-08 02:24:52 +03:00
if ( ( obj_format = = LOD ) | | ( obj_format = = P56 ) )
2018-06-23 19:57:21 +03:00
SwitchSection ( M56001P ) ;
2022-03-24 13:28:09 +02:00
regbase = reg56base ; // Update register DFA tables
regtab = reg56tab ;
regcheck = reg56check ;
regaccept = reg56accept ;
2022-10-26 21:30:21 +03:00
used_architectures | = M56001P | M56001X | M56001Y | M56001L ;
2018-06-23 19:57:21 +03:00
return 0 ;
2017-05-05 17:51:11 +03:00
}
2012-01-18 04:06:46 +02:00
2017-05-07 05:07:36 +03:00
2011-12-27 00:50:27 +02:00
//
2015-01-16 16:24:24 +02:00
// .gpu - Switch to GPU assembler
2012-01-18 04:06:46 +02:00
//
int d_gpu ( void )
{
if ( ( cursect ! = TEXT ) & & ( cursect ! = DATA ) )
{
error ( " .gpu can only be used in the TEXT or DATA segments " ) ;
return ERROR ;
}
2017-11-21 15:54:55 +02:00
// If previous section was DSP or 68000 then we need to reset ORG'd Addresses
2012-01-18 04:06:46 +02:00
if ( ! rgpu )
{
orgactive = 0 ;
orgwarning = 0 ;
}
2013-02-13 04:14:47 +02:00
rgpu = 1 ; // Set GPU assembly
rdsp = 0 ; // Unset DSP assembly
2018-02-26 05:39:59 +02:00
robjproc = 0 ; // Unset OP assembly
2018-06-23 19:57:21 +03:00
dsp56001 = 0 ; // Unset 56001 assembly
2022-03-24 13:28:09 +02:00
regbase = regriscbase ; // Update register DFA tables
regtab = regrisctab ;
regcheck = regrisccheck ;
regaccept = regriscaccept ;
2022-10-26 21:30:21 +03:00
//used_architectures |= MGPU; // TODO: Should GPU/DSP have their own dedicated sections in the long run?
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
//
2015-01-16 16:24:24 +02:00
// .dsp - Switch to DSP assembler
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int d_dsp ( void )
{
if ( ( cursect ! = TEXT ) & & ( cursect ! = DATA ) )
{
error ( " .dsp can only be used in the TEXT or DATA segments " ) ;
return ERROR ;
}
// If previous section was gpu or 68000 then we need to reset ORG'd Addresses
if ( ! rdsp )
{
orgactive = 0 ;
orgwarning = 0 ;
}
2013-02-13 04:14:47 +02:00
rdsp = 1 ; // Set DSP assembly
rgpu = 0 ; // Unset GPU assembly
2018-02-26 05:39:59 +02:00
robjproc = 0 ; // Unset OP assembly
2018-06-23 19:57:21 +03:00
dsp56001 = 0 ; // Unset 56001 assembly
2022-03-24 13:28:09 +02:00
regbase = regriscbase ; // Update register DFA tables
regtab = regrisctab ;
regcheck = regrisccheck ;
regaccept = regriscaccept ;
2022-10-26 21:30:21 +03:00
//used_architectures |= MDSP; // TODO: Should GPU/DSP have their own dedicated sections in the long run?
2012-01-18 04:06:46 +02:00
return 0 ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
// .cargs [#offset], symbol[.size], ...
2017-04-14 23:52:31 +03:00
//
2012-01-18 04:06:46 +02:00
// Lists of registers may also be mentioned; they just take up space. Good for
2013-02-13 04:14:47 +02:00
// "documentation" purposes:
2017-04-14 23:52:31 +03:00
//
2013-02-13 04:14:47 +02:00
// .cargs a6, .arg1, .arg2, .arg3...
2017-04-14 23:52:31 +03:00
//
2013-02-13 04:14:47 +02:00
// Symbols thus created are ABS and EQUATED.
2012-01-18 04:06:46 +02:00
//
int d_cargs ( void )
{
2017-10-08 16:40:02 +03:00
uint64_t eval = 4 ; // Default to 4 if no offset specified (to account for
2013-02-13 20:51:43 +02:00
// return address)
2012-01-18 04:06:46 +02:00
WORD rlist ;
2013-02-13 04:14:47 +02:00
SYM * symbol ;
2012-01-18 04:06:46 +02:00
char * p ;
int env ;
int i ;
if ( rgpu | | rdsp )
return error ( " directive forbidden in gpu/dsp mode " ) ;
2017-11-29 15:57:58 +02:00
if ( * tok = = ' # ' )
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
if ( abs_expr ( & eval ) ! = OK )
return 0 ;
2013-02-13 04:14:47 +02:00
// Eat the comma, if it's there
2017-11-29 15:57:58 +02:00
if ( * tok = = ' , ' )
tok + + ;
2012-01-18 04:06:46 +02:00
}
for ( ; ; )
{
2017-11-29 15:57:58 +02:00
if ( * tok = = SYMBOL )
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
p = string [ tok [ 1 ] ] ;
2012-01-18 04:06:46 +02:00
2013-02-13 04:14:47 +02:00
// Set env to either local (dot prefixed) or global scope
env = ( * p = = ' . ' ? curenv : 0 ) ;
symbol = lookup ( p , LABEL , env ) ;
2012-01-18 04:06:46 +02:00
2013-02-13 04:14:47 +02:00
if ( symbol = = NULL )
2012-01-18 04:06:46 +02:00
{
2013-02-13 04:14:47 +02:00
symbol = NewSymbol ( p , LABEL , env ) ;
symbol - > sattr = 0 ;
2012-01-18 04:06:46 +02:00
}
2013-02-13 04:14:47 +02:00
else if ( symbol - > sattr & DEFINED )
2017-06-24 03:03:24 +03:00
return error ( " multiply-defined label '%s' " , p ) ;
2012-01-18 04:06:46 +02:00
// Put symbol in "order of definition" list
2015-02-01 04:49:38 +02:00
AddToSymbolDeclarationList ( symbol ) ;
2012-01-18 04:06:46 +02:00
2013-02-13 04:14:47 +02:00
symbol - > sattr | = ( ABS | DEFINED | EQUATED ) ;
2018-02-10 07:08:47 +02:00
symbol - > svalue = eval ;
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
2013-02-13 04:14:47 +02:00
// What this does is eat any dot suffixes attached to a symbol. If
// it's a .L, it adds 4 to eval; if it's .W or .B, it adds 2. If
// there is no dot suffix, it assumes a size of 2.
2017-11-29 15:57:58 +02:00
switch ( ( int ) * tok )
2012-01-18 04:06:46 +02:00
{
case DOTL :
eval + = 2 ;
case DOTB :
case DOTW :
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
}
eval + = 2 ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG68_D0 & & * tok < = REG68_A7 )
2012-01-18 04:06:46 +02:00
{
2013-02-13 04:14:47 +02:00
if ( reglist ( & rlist ) < 0 )
return 0 ;
2012-01-18 04:06:46 +02:00
2013-02-13 04:14:47 +02:00
for ( i = 0 ; i < 16 ; i + + , rlist > > = 1 )
{
if ( rlist & 1 )
eval + = 4 ;
2012-01-18 04:06:46 +02:00
}
2013-02-13 04:14:47 +02:00
}
else
{
2017-11-29 15:57:58 +02:00
switch ( ( int ) * tok )
2012-01-18 04:06:46 +02:00
{
2022-03-24 13:28:09 +02:00
case REG68_USP :
case REG68_SSP :
case REG68_PC :
2013-02-13 04:14:47 +02:00
eval + = 2 ;
// FALLTHROUGH
2022-03-24 13:28:09 +02:00
case REG68_SR :
case REG68_CCR :
2013-02-13 04:14:47 +02:00
eval + = 2 ;
2017-11-29 15:57:58 +02:00
tok + + ;
2013-02-13 04:14:47 +02:00
break ;
case EOL :
return 0 ;
default :
return error ( " .cargs syntax " ) ;
2012-01-18 04:06:46 +02:00
}
}
2013-02-13 04:14:47 +02:00
// Eat commas in between each argument, if they exist
2017-11-29 15:57:58 +02:00
if ( * tok = = ' , ' )
tok + + ;
2012-01-18 04:06:46 +02:00
}
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
2013-02-13 20:51:43 +02:00
//
// .cstruct [#offset], symbol[.size], ...
2017-04-14 23:52:31 +03:00
//
2013-02-13 20:51:43 +02:00
// Lists of registers may also be mentioned; they just take up space. Good for
// "documentation" purposes:
2017-04-14 23:52:31 +03:00
//
2013-02-13 20:51:43 +02:00
// .cstruct a6, .arg1, .arg2, .arg3...
2017-04-14 23:52:31 +03:00
//
2013-02-13 20:51:43 +02:00
// Symbols thus created are ABS and EQUATED. Note that this is for
// compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
// the suggestion.
//
int d_cstruct ( void )
{
2017-10-08 16:40:02 +03:00
uint64_t eval = 0 ; // Default, if no offset specified, is zero
2013-02-13 20:51:43 +02:00
WORD rlist ;
SYM * symbol ;
char * symbolName ;
int env ;
int i ;
if ( rgpu | | rdsp )
return error ( " directive forbidden in gpu/dsp mode " ) ;
2017-11-29 15:57:58 +02:00
if ( * tok = = ' # ' )
2013-02-13 20:51:43 +02:00
{
2017-11-29 15:57:58 +02:00
tok + + ;
2013-02-13 20:51:43 +02:00
if ( abs_expr ( & eval ) ! = OK )
return 0 ;
// Eat the comma, if it's there
2017-11-29 15:57:58 +02:00
if ( * tok = = ' , ' )
tok + + ;
2013-02-13 20:51:43 +02:00
}
for ( ; ; )
{
2017-11-29 15:57:58 +02:00
if ( * tok = = SYMBOL )
2013-02-13 20:51:43 +02:00
{
2017-11-29 15:57:58 +02:00
symbolName = string [ tok [ 1 ] ] ;
2013-02-13 20:51:43 +02:00
// Set env to either local (dot prefixed) or global scope
env = ( symbolName [ 0 ] = = ' . ' ? curenv : 0 ) ;
symbol = lookup ( symbolName , LABEL , env ) ;
// If the symbol wasn't found, then define it. Otherwise, throw an
// error.
if ( symbol = = NULL )
{
symbol = NewSymbol ( symbolName , LABEL , env ) ;
symbol - > sattr = 0 ;
}
else if ( symbol - > sattr & DEFINED )
2017-06-24 03:03:24 +03:00
return error ( " multiply-defined label '%s' " , symbolName ) ;
2013-02-13 20:51:43 +02:00
// Put symbol in "order of definition" list
2015-02-01 04:49:38 +02:00
AddToSymbolDeclarationList ( symbol ) ;
2013-02-13 20:51:43 +02:00
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2013-02-13 20:51:43 +02:00
// Adjust label start address if it's a word or a long, as a byte
// label might have left us on an odd address.
2017-11-29 15:57:58 +02:00
switch ( ( int ) * tok )
2013-02-13 20:51:43 +02:00
{
case DOTW :
case DOTL :
eval + = eval & 0x01 ;
}
symbol - > sattr | = ( ABS | DEFINED | EQUATED ) ;
2018-02-10 07:08:47 +02:00
symbol - > svalue = eval ;
2013-02-13 20:51:43 +02:00
// Check for dot suffixes and adjust space accordingly (longs and
// words on an odd boundary get bumped to the next word aligned
// address). If no suffix, then throw an error.
2017-11-29 15:57:58 +02:00
switch ( ( int ) * tok )
2013-02-13 20:51:43 +02:00
{
case DOTL :
eval + = 4 ;
break ;
case DOTW :
eval + = 2 ;
break ;
case DOTB :
eval + = 1 ;
break ;
default :
return error ( " Symbol missing dot suffix in .cstruct construct " ) ;
}
2017-11-29 15:57:58 +02:00
tok + + ;
2013-02-13 20:51:43 +02:00
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG68_D0 & & * tok < = REG68_A7 )
2013-02-13 20:51:43 +02:00
{
if ( reglist ( & rlist ) < 0 )
return 0 ;
for ( i = 0 ; i < 16 ; i + + , rlist > > = 1 )
{
if ( rlist & 1 )
eval + = 4 ;
}
}
else
{
2017-11-29 15:57:58 +02:00
switch ( ( int ) * tok )
2013-02-13 20:51:43 +02:00
{
2022-03-24 13:28:09 +02:00
case REG68_USP :
case REG68_SSP :
case REG68_PC :
2013-02-13 20:51:43 +02:00
eval + = 2 ;
// FALLTHROUGH
2022-03-24 13:28:09 +02:00
case REG68_SR :
case REG68_CCR :
2013-02-13 20:51:43 +02:00
eval + = 2 ;
2017-11-29 15:57:58 +02:00
tok + + ;
2013-02-13 20:51:43 +02:00
break ;
case EOL :
return 0 ;
default :
return error ( " .cstruct syntax " ) ;
}
}
// Eat commas in between each argument, if they exist
2017-11-29 15:57:58 +02:00
if ( * tok = = ' , ' )
tok + + ;
2013-02-13 20:51:43 +02:00
}
}
2018-02-26 05:39:59 +02:00
//
// Define start of OP object list (allows the use of ORG)
//
int d_objproc ( void )
{
if ( ( cursect ! = TEXT ) & & ( cursect ! = DATA ) )
{
error ( " .objproc can only be used in the TEXT or DATA segments " ) ;
return ERROR ;
}
// If previous section was DSP or 68000 then we need to reset ORG'd
// Addresses
if ( ! robjproc )
{
orgactive = 0 ;
orgwarning = 0 ;
}
robjproc = 1 ; // Set OP assembly
rgpu = 0 ; // Unset GPU assembly
rdsp = 0 ; // Unset DSP assembly
2018-06-23 19:57:21 +03:00
dsp56001 = 0 ; // Unset 56001 assembly
2022-10-26 21:30:21 +03:00
//used_architectures |= MOP; // TODO: Should OP have its own dedicated section in the long run?
2018-02-26 05:39:59 +02:00
return OK ;
}
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
// Undefine a macro - .undefmac macname [, macname...]
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int undmac1 ( char * p )
{
2013-02-13 04:14:47 +02:00
SYM * symbol = lookup ( p , MACRO , 0 ) ;
2011-12-27 00:50:27 +02:00
2013-02-13 04:14:47 +02:00
// If the macro symbol exists, cause it to disappear
if ( symbol ! = NULL )
symbol - > stype = ( BYTE ) SY_UNDEF ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
2012-01-18 04:06:46 +02:00
int d_undmac ( void )
{
symlist ( undmac1 ) ;
return 0 ;
2011-12-27 00:50:27 +02:00
}
2013-02-13 04:14:47 +02:00
2013-03-31 00:42:41 +02:00
int d_jpad ( void )
{
warn ( " JPAD directive is deprecated/non-functional " ) ;
return OK ;
}
int d_nojpad ( void )
{
warn ( " NOJPAD directive is deprecated/non-functional " ) ;
return OK ;
}
2014-02-26 16:30:26 +02:00
int d_gpumain ( void )
{
return error ( " What the hell? Do you think we adhere to the Goof standard? " ) ;
}
2016-09-13 06:27:30 +03:00
2016-09-07 14:18:24 +03:00
//
// .opt - turn a specific (or all) optimisation on or off
//
int d_opt ( void )
{
2017-11-29 15:57:58 +02:00
while ( * tok ! = EOL )
2016-09-07 14:18:24 +03:00
{
2017-11-29 15:57:58 +02:00
if ( * tok = = STRING )
2016-09-07 14:18:24 +03:00
{
2017-11-29 15:57:58 +02:00
tok + + ;
char * tmpstr = string [ * tok + + ] ;
2016-09-07 14:18:24 +03:00
if ( ParseOptimization ( tmpstr ) ! = OK )
2017-06-24 03:03:24 +03:00
return error ( " unknown optimization flag '%s' " , tmpstr ) ;
2016-09-07 14:18:24 +03:00
}
else
2016-09-13 06:27:30 +03:00
return error ( " .opt directive needs every switch enclosed inside quotation marks " ) ;
2016-09-07 14:18:24 +03:00
}
2016-09-22 18:44:16 +03:00
return OK ;
2016-09-13 06:27:30 +03:00
}
2017-07-19 23:27:06 +03:00
//
// .if, Start conditional assembly
//
int d_if ( void )
{
WORD eattr ;
2017-10-08 16:40:02 +03:00
uint64_t eval ;
2017-07-19 23:27:06 +03:00
SYM * esym ;
IFENT * rif = f_ifent ;
// Alloc an IFENTRY
if ( rif = = NULL )
rif = ( IFENT * ) malloc ( sizeof ( IFENT ) ) ;
else
f_ifent = rif - > if_prev ;
rif - > if_prev = ifent ;
ifent = rif ;
if ( ! disabled )
{
if ( expr ( exprbuf , & eval , & eattr , & esym ) ! = OK )
return 0 ;
if ( ( eattr & DEFINED ) = = 0 )
return error ( undef_error ) ;
disabled = ! eval ;
}
rif - > if_state = ( WORD ) disabled ;
return 0 ;
}
//
// .else, Do alternate case for .if
//
int d_else ( void )
{
IFENT * rif = ifent ;
if ( rif - > if_prev = = NULL )
return error ( " mismatched .else " ) ;
if ( disabled )
disabled = rif - > if_prev - > if_state ;
else
disabled = 1 ;
rif - > if_state = ( WORD ) disabled ;
return 0 ;
}
//
// .endif, End of conditional assembly block
// This is also called by fpop() to pop levels of IFENTs in case a macro or
// include file exits early with `exitm' or `end'.
//
int d_endif ( void )
{
IFENT * rif = ifent ;
if ( rif - > if_prev = = NULL )
return error ( " mismatched .endif " ) ;
ifent = rif - > if_prev ;
disabled = rif - > if_prev - > if_state ;
rif - > if_prev = f_ifent ;
f_ifent = rif ;
return 0 ;
}