2018-06-23 19:57:21 +03:00
//
2021-03-08 00:43:25 +02:00
// RMAC - Renamed Macro Assembler for the Atari Jaguar Console System
2018-06-23 19:57:21 +03:00
// AMODE.C - DSP 56001 Addressing Modes
2021-03-08 00:43:25 +02:00
// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
2018-06-23 19:57:21 +03:00
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
# include "dsp56k_amode.h"
# include "error.h"
# include "token.h"
# include "expr.h"
# include "rmac.h"
# include "procln.h"
# include "sect.h"
# include "math.h"
# define DEF_MN
# include "mntab.h"
2022-03-24 13:28:09 +02:00
# define DEF_REG56
# include "56kregs.h"
2018-06-23 19:57:21 +03:00
// Address-mode information
int dsp_am0 ; // Addressing mode
int dsp_a0reg ; // Register
TOKEN dsp_a0expr [ EXPRSIZE ] ; // Expression
uint64_t dsp_a0exval ; // Expression's value
WORD dsp_a0exattr ; // Expression's attribute
LONG dsp_a0memspace ; // Addressing mode's memory space (P, X, Y)
SYM * dsp_a0esym ; // External symbol involved in expr
int dsp_am1 ; // Addressing mode
int dsp_a1reg ; // Register
TOKEN dsp_a1expr [ EXPRSIZE ] ; // Expression
uint64_t dsp_a1exval ; // Expression's value
WORD dsp_a1exattr ; // Expression's attribute
LONG dsp_a1memspace ; // Addressing mode's memory space (P, X, Y)
SYM * dsp_a1esym ; // External symbol involved in expr
int dsp_am2 ; // Addressing mode
int dsp_a2reg ; // Register
TOKEN dsp_a2expr [ EXPRSIZE ] ; // Expression
uint64_t dsp_a2exval ; // Expression's value
WORD dsp_a2exattr ; // Expression's attribute
SYM * dsp_a2esym ; // External symbol involved in expr
int dsp_am3 ; // Addressing mode
int dsp_a3reg ; // Register
TOKEN dsp_a3expr [ EXPRSIZE ] ; // Expression
uint64_t dsp_a3exval ; // Expression's value
WORD dsp_a3exattr ; // Expression's attribute
SYM * dsp_a3esym ; // External symbol involved in expr
TOKEN dspImmedEXPR [ EXPRSIZE ] ; // Expression
uint64_t dspImmedEXVAL ; // Expression's value
WORD dspImmedEXATTR ; // Expression's attribute
SYM * dspImmedESYM ; // External symbol involved in expr
int deposit_extra_ea ; // Optional effective address extension
TOKEN dspaaEXPR [ EXPRSIZE ] ; // Expression
uint64_t dspaaEXVAL ; // Expression's value
WORD dspaaEXATTR ; // Expression's attribute
SYM * dspaaESYM ; // External symbol involved in expr
2020-08-03 20:16:38 +03:00
LONG dsp_a0perspace ; // Peripheral space (X, Y - used in movep)
LONG dsp_a1perspace ; // Peripheral space (X, Y - used in movep)
2020-06-07 19:24:13 +03:00
2020-08-03 20:16:38 +03:00
int dsp_k ; // Multiplications sign
2018-06-23 19:57:21 +03:00
static inline LONG checkea ( const uint32_t termchar , const int strings ) ;
2020-08-03 20:16:38 +03:00
// ea checking error strings put into a table because I'm not sure there's an
// easy way to do otherwise (the messages start getting differerent in many
// places so it will get awkward to code those in) (I'd rather burn some RAM
// in order to have more helpful error messages than the other way round)
2018-06-23 19:57:21 +03:00
# define X_ERRORS 0
# define Y_ERRORS 1
# define L_ERRORS 2
# define P_ERRORS 3
const char * ea_errors [ ] [ 12 ] = {
2019-08-08 02:24:52 +03:00
// X:
{
" unrecognised X: parallel move syntax: expected '(' after 'X:-' " , // 0
" unrecognised X: parallel move syntax: expected ')' after 'X:-(Rn' " , // 1
" unrecognised X: parallel move syntax: expected R0-R7 after 'X:-(' " , // 2
" unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn+' " , // 3
" unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn+Nn)' " , // 4
" unrecognised X: parallel move syntax: expected ')' after 'X:(Rn+Nn' " , // 5
" unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)+Nn' " , // 6
" unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)+' " , // 7
" unrecognised X: parallel move syntax: expected same register number in Rn and Nn for 'X:(Rn)-Nn' " , // 8
" unrecognised X: parallel move syntax: expected N0-N7 after 'X:(Rn)-' " , // 9
" unrecognised X: parallel move syntax: expected '+', '-' or ',' after 'X:(Rn)' " , // 10
" unrecognised X: parallel move syntax: expected '+' or ')' after 'X:(Rn' " , // 11
} ,
// Y:
{
" unrecognised Y: parallel move syntax: expected '(' after 'Y:-' " , // 0
" unrecognised Y: parallel move syntax: expected ')' after 'Y:-(Rn' " , // 1
" unrecognised Y: parallel move syntax: expected R0-R7 after 'Y:-(' " , // 2
" unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn+' " , // 3
" unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn+Nn)' " , // 4
" unrecognised Y: parallel move syntax: expected ')' after 'Y:(Rn+Nn' " , // 5
" unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)+Nn' " , // 6
" unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)+' " , // 7
" unrecognised Y: parallel move syntax: expected same register number in Rn and Nn for 'Y:(Rn)-Nn' " , // 8
" unrecognised Y: parallel move syntax: expected N0-N7 after 'Y:(Rn)-' " , // 9
" unrecognised Y: parallel move syntax: expected '+', '-' or ',' after 'Y:(Rn)' " , // 10
" unrecognised Y: parallel move syntax: expected '+' or ')' after 'Y:(Rn' " , // 11
} ,
// L:
{
" unrecognised L: parallel move syntax: expected '(' after 'L:-' " , // 0
" unrecognised L: parallel move syntax: expected ')' after 'L:-(Rn' " , // 1
" unrecognised L: parallel move syntax: expected R0-R7 after 'L:-(' " , // 2
" unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn+' " , // 3
" unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn+Nn)' " , // 4
" unrecognised L: parallel move syntax: expected ')' after 'L:(Rn+Nn' " , // 5
" unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)+Nn' " , // 6
" unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)+' " , // 7
" unrecognised L: parallel move syntax: expected same register number in Rn and Nn for 'L:(Rn)-Nn' " , // 8
" unrecognised L: parallel move syntax: expected N0-N7 after 'L:(Rn)-' " , // 9
" unrecognised L: parallel move syntax: expected '+', '-' or ',' after 'L:(Rn)' " , // 10
" unrecognised L: parallel move syntax: expected '+' or ')' after 'L:(Rn' " , // 11
} ,
// P:
{
" unrecognised P: effective address syntax: expected '(' after 'P:-' " , // 0
" unrecognised P: effective address syntax: expected ')' after 'P:-(Rn' " , // 1
" unrecognised P: effective address syntax: expected R0-R7 after 'P:-(' " , // 2
" unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn+' " , // 3
" unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn+Nn)' " , // 4
" unrecognised P: effective address syntax: expected ')' after 'P:(Rn+Nn' " , // 5
" unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)+Nn' " , // 6
" unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)+' " , // 7
" unrecognised P: effective address syntax: expected same register number in Rn and Nn for 'P:(Rn)-Nn' " , // 8
" unrecognised P: effective address syntax: expected N0-N7 after 'P:(Rn)-' " , // 9
" unrecognised P: effective address syntax: expected '+', '-' or ',' after 'P:(Rn)' " , // 10
" unrecognised P: effective address syntax: expected '+' or ')' after 'P:(Rn' " , // 11
}
2018-06-23 19:57:21 +03:00
} ;
enum
{
2019-08-08 02:24:52 +03:00
NUM_NORMAL = 0 ,
NUM_FORCE_LONG = 1 ,
NUM_FORCE_SHORT = 2
2018-06-23 19:57:21 +03:00
} ;
2020-08-03 20:16:38 +03:00
2018-06-23 19:57:21 +03:00
//
// Parse a single addressing mode
//
static inline int dsp_parmode ( int * am , int * areg , TOKEN * AnEXPR , uint64_t * AnEXVAL , WORD * AnEXATTR , SYM * * AnESYM , LONG * memspace , LONG * perspace , const int operand )
{
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_A | | * tok = = REG56_B )
2019-08-08 02:24:52 +03:00
{
* am = M_ACC56 ;
* areg = * tok + + ;
return OK ;
}
else if ( * tok = = ' # ' )
{
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = ' < ' )
{
// Immediate Short Addressing Mode Force Operator
tok + + ;
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0xFFF & & * AnEXVAL < - 4096 )
return error ( " immediate short addressing mode forced but address is bigger than $FFF " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( int32_t ) * AnEXVAL < = 0xFF & & ( int32_t ) * AnEXVAL > - 0x100 )
{
* am = M_DSPIM8 ;
return OK ;
}
* am = M_DSPIM12 ;
return OK ;
}
else if ( * tok = = ' > ' )
{
// Immediate Long Addressing Mode Force Operator
tok + + ;
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
if ( ( int32_t ) * AnEXVAL > 0xFFFFFF | | ( int32_t ) * AnEXVAL < - 0xFFFFFF )
return error ( " long immediate is bigger than $FFFFFF " ) ;
* am = M_DSPIM ;
return OK ;
}
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
if ( * AnEXATTR & DEFINED )
{
2018-06-23 19:57:21 +03:00
if ( ( int32_t ) * AnEXVAL < 0x100 & & ( int32_t ) * AnEXVAL > = - 0x100 )
{
2019-08-08 02:24:52 +03:00
* AnEXVAL & = 0xFF ;
2018-06-23 19:57:21 +03:00
* am = M_DSPIM8 ;
}
2019-08-08 02:24:52 +03:00
else if ( * AnEXVAL < 0x1000 )
* am = M_DSPIM12 ;
else
* am = M_DSPIM ;
}
else
{
// We have no clue what size our immediate will be
// so we have to assume the worst
* am = M_DSPIM ;
}
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_X0 & & * tok < = REG56_Y1 )
2019-08-08 02:24:52 +03:00
{
* am = M_ALU24 ;
* areg = * tok + + ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_X & & * ( tok + 1 ) = = ' : ' )
2019-08-08 02:24:52 +03:00
{
tok = tok + 2 ;
if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
if ( * AnEXATTR & DEFINED )
{
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
2018-06-23 19:57:21 +03:00
* memspace = 0 < < 6 ; // Mark we're on X memory space
2019-08-08 02:24:52 +03:00
// Check if value is between $FFC0 and $FFFF, AKA X:pp
uint32_t temp = ( LONG ) ( ( ( int32_t ) ( ( ( uint32_t ) * AnEXVAL ) < < ( 32 - 6 ) ) ) > > ( 32 - 6 ) ) ; // Sign extend 6 to 32 bits
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( temp > = 0xFFFFFFC0 /* Check for 32bit sign extended number */
& & ( ( int32_t ) * AnEXVAL < 0 ) ) /* Check if 32bit signed number is negative*/
| | ( * AnEXVAL < 0xFFFF & & * AnEXVAL > = 0x8000 ) ) /* Check if 16bit number is negative*/
{
* AnEXVAL = temp ;
* am = M_DSPPP ;
* memspace = 0 < < 6 ; // Mark we're on X memory space
* perspace = 0 < < 16 ; // Mark we're on X peripheral space
* areg = * AnEXVAL & 0x3F ; // Since this is only going to get used in dsp_ea_imm5...
return OK ;
2018-06-23 19:57:21 +03:00
}
// If the symbol/expression is defined then check for valid range.
// Otherwise the value had better fit or Fixups will bark!
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0x3F )
2018-06-23 19:57:21 +03:00
{
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
else
{
* am = M_DSPAA ;
}
}
else
{
// Assume the worst
* memspace = 0 < < 6 ; // Mark we're on X memory space
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
2019-08-08 02:24:52 +03:00
return OK ;
}
else if ( * tok = = ' < ' )
{
// X:aa
// Short Addressing Mode Force Operator in the case of '<'
tok + + ;
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
// If the symbol/expression is defined then check for valid range.
// Otherwise the value had better fit or Fixups will bark!
if ( * AnEXATTR & DEFINED )
{
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0x3F )
return error ( " short addressing mode forced but address is bigger than $3F " ) ;
2018-06-23 19:57:21 +03:00
}
2019-08-08 02:24:52 +03:00
else
{
// Mark it as a fixup
deposit_extra_ea = DEPOSIT_EXTRA_FIXUP ;
}
* am = M_DSPAA ;
* memspace = 0 < < 6 ; // Mark we're on X memory space
* areg = ( int ) * AnEXVAL ; // Since this is only going to get used in dsp_ea_imm5...
return OK ;
}
2018-06-23 19:57:21 +03:00
else if ( * tok = = ' > ' )
{
// Long Addressing Mode Force Operator
tok + + ;
if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2019-08-08 02:24:52 +03:00
2018-06-23 19:57:21 +03:00
if ( * AnEXATTR & DEFINED )
{
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* memspace = 0 < < 6 ; // Mark we're on X memory space
2018-06-23 19:57:21 +03:00
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
else
{
// Assume the worst
* memspace = 0 < < 6 ; // Mark we're on X memory space
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
return OK ;
}
}
2019-08-08 02:24:52 +03:00
else if ( * tok = = SHL ) // '<<'
{
// I/O Short Addressing Mode Force Operator
// X:pp
tok + + ;
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
// If the symbol/expression is defined then check for valid range.
// Otherwise the value had better fit or Fixups will bark!
if ( * AnEXATTR & DEFINED )
{
* AnEXVAL = ( LONG ) ( ( ( int32_t ) ( ( ( uint32_t ) * AnEXVAL ) < < ( 32 - 6 ) ) ) > > ( 32 - 6 ) ) ; // Sign extend 6 to 32 bits
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL < 0xFFFFFFC0 )
return error ( " I/O Short Addressing Mode addresses must be between $FFC0 and $FFFF " ) ;
2018-06-23 19:57:21 +03:00
}
2019-08-08 02:24:52 +03:00
* am = M_DSPPP ;
* memspace = 0 < < 6 ; // Mark we're on X memory space
* perspace = 0 < < 16 ; // Mark we're on X peripheral space
2020-08-03 20:16:38 +03:00
* areg = * AnEXVAL & 0x3F ; // Since this is only going to get used in dsp_ea_imm5...
2019-08-08 02:24:52 +03:00
return OK ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( * areg = checkea ( 0 , X_ERRORS ) ) ! = ERROR )
{
// TODO: what if we need M_DSPAA here????
* memspace = 0 < < 6 ; // Mark we're on X memory space
* am = M_DSPEA ;
return OK ;
}
else
return ERROR ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y & & * ( tok + 1 ) = = ' : ' )
2019-08-08 02:24:52 +03:00
{
tok = tok + 2 ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
* memspace = 1 < < 6 ; // Mark we're on Y memory space
2018-06-23 19:57:21 +03:00
// Check if value is between $ffc0 and $ffff, AKA Y:pp
2019-08-08 02:24:52 +03:00
uint32_t temp = ( LONG ) ( ( ( int32_t ) ( ( ( uint32_t ) * AnEXVAL ) < < ( 32 - 6 ) ) ) > > ( 32 - 6 ) ) ; // Sign extend 6 to 32 bits
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( temp > = 0xFFFFFFC0 /* Check for 32bit sign extended number */
& & ( ( int32_t ) * AnEXVAL < 0 ) ) /* Check if 32bit signed number is negative*/
| | ( * AnEXVAL < 0xFFFF & & * AnEXVAL > = 0x8000 ) ) /* Check if 16bit number is negative*/
{
* AnEXVAL = temp ;
* am = M_DSPPP ;
* perspace = 1 < < 16 ; // Mark we're on X peripheral space
* areg = * AnEXVAL & 0x3F ; // Since this is only going to get used in dsp_ea_imm5...
return OK ;
2018-06-23 19:57:21 +03:00
}
// If the symbol/expression is defined then check for valid range.
// Otherwise the value had better fit or Fixups will bark!
if ( * AnEXATTR & DEFINED )
{
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0x3F )
2018-06-23 19:57:21 +03:00
{
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
else
{
* am = M_DSPAA ;
}
}
else
{
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
2019-08-08 02:24:52 +03:00
return OK ;
}
else if ( * tok = = ' < ' )
{
// Y:aa
// Short Addressing Mode Force Operator in the case of '<'
tok + + ;
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
// If the symbol/expression is defined then check for valid range.
// Otherwise the value had better fit or Fixups will bark!
if ( * AnEXATTR & DEFINED )
{
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0x3F )
2018-06-23 19:57:21 +03:00
{
2021-07-16 15:04:22 +03:00
if ( CHECK_OPTS ( OPT_56K_AUTO_LONG ) )
{
if ( optim_warn_flag )
warn ( " o11: short addressing mode forced but address is bigger than $3F - switching to long " ) ;
2020-08-03 20:16:38 +03:00
2021-07-16 15:04:22 +03:00
* am = M_DSPEA ;
* memspace = 1 < < 6 ; // Mark we're on Y memory space
* areg = DSP_EA_ABS ;
return OK ;
}
else
{
return error ( " short addressing mode forced but address is bigger than $3F - turn opt switch o11 on to bypass " ) ;
}
2018-06-23 19:57:21 +03:00
}
}
2019-08-08 02:24:52 +03:00
else
{
// Mark it as a fixup
deposit_extra_ea = DEPOSIT_EXTRA_FIXUP ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* am = M_DSPAA ;
* memspace = 1 < < 6 ; // Mark we're on Y memory space
* areg = ( int ) * AnEXVAL ; // Since this is only going to get used in dsp_ea_imm5...
return OK ;
}
else if ( * tok = = ' > ' )
{
// Long Addressing Mode Force Operator
2018-06-23 19:57:21 +03:00
tok + + ;
if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2019-08-08 02:24:52 +03:00
2018-06-23 19:57:21 +03:00
if ( * AnEXATTR & DEFINED )
{
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
2018-06-23 19:57:21 +03:00
* memspace = 1 < < 6 ; // Mark we're on Y memory space
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
else
{
// Assume the worst
* memspace = 1 < < 6 ; // Mark we're on Y memory space
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
return OK ;
}
}
2019-08-08 02:24:52 +03:00
else if ( * tok = = SHL ) // '<<'
{
// I/O Short Addressing Mode Force Operator
// Y:pp
tok + + ;
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
// If the symbol/expression is defined then check for valid range.
// Otherwise the value had better fit or Fixups will bark!
if ( * AnEXATTR & DEFINED )
{
* AnEXVAL = ( LONG ) ( ( ( int32_t ) ( ( ( uint32_t ) * AnEXVAL ) < < ( 32 - 6 ) ) ) > > ( 32 - 6 ) ) ; // Sign extend 6 to 32 bits
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL < 0xFFFFFFC0 )
return error ( " I/O Short Addressing Mode addresses must be between $FFE0 and $1F " ) ;
2018-06-23 19:57:21 +03:00
}
2019-08-08 02:24:52 +03:00
* am = M_DSPPP ;
* memspace = 1 < < 6 ; // Mark we're on Y memory space
* perspace = 1 < < 16 ; // Mark we're on Y peripheral space
* areg = * AnEXVAL & 0x3F ; // Since this is only going to get used in dsp_ea_imm5...
return OK ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( * areg = checkea ( 0 , X_ERRORS ) ) ! = ERROR )
{
* memspace = 1 < < 6 ; // Mark we're on Y memory space
* am = M_DSPEA ;
return OK ;
}
else
return ERROR ;
// TODO: add absolute address checks
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok > = REG56_X ) & & ( * tok < = REG56_Y ) )
2019-08-08 02:24:52 +03:00
{
* am = M_INP48 ;
* areg = * tok + + ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok > = REG56_M0 ) & & ( * tok < = REG56_M7 ) )
2019-08-08 02:24:52 +03:00
{
* am = M_DSPM ;
* areg = ( * tok + + ) & 7 ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok > = REG56_R0 ) & & ( * tok < = REG56_R7 ) )
2019-08-08 02:24:52 +03:00
{
* am = M_DSPR ;
2022-03-24 13:28:09 +02:00
* areg = ( * tok + + ) - REG56_R0 ;
2019-08-08 02:24:52 +03:00
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok > = REG56_N0 ) & & ( * tok < = REG56_N7 ) )
2019-08-08 02:24:52 +03:00
{
* am = M_DSPN ;
* areg = ( * tok + + ) & 7 ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok = = REG56_A0 ) | | ( * tok = = REG56_A1 ) | | ( * tok = = REG56_B0 )
| | ( * tok = = REG56_B1 ) )
2019-08-08 02:24:52 +03:00
{
* am = M_ACC24 ;
* areg = * tok + + ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok = = REG56_A2 ) | | ( * tok = = REG56_B2 ) )
2019-08-08 02:24:52 +03:00
{
* am = M_ACC8 ;
* areg = * tok + + ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok = = ' - ' ) & & ( * ( tok + 1 ) = = REG56_X0 | | * ( tok + 1 ) = = REG56_X1 | | * ( tok + 1 ) = = REG56_Y0 | | * ( tok + 1 ) = = REG56_Y1 ) )
2019-08-08 02:24:52 +03:00
{
// '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// Check to see if this is the first operand
if ( operand ! = 0 )
return error ( " -x0/-x1/-y0/-y1 only allowed in the first operand " ) ;
* am = M_ALU24 ;
* areg = * tok + + ;
dsp_k = 1 < < 2 ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = ' + ' & & ( * ( tok + 1 ) = = REG56_X0 | | * ( tok + 1 ) = = REG56_X1 | | * ( tok + 1 ) = = REG56_Y0 | | * ( tok + 1 ) = = REG56_Y1 ) )
2019-08-08 02:24:52 +03:00
{
// '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// Check to see if this is the first operand
if ( operand ! = 0 )
return error ( " +x0/+x1/+y0/+y1 only allowed in the first operand " ) ;
* am = M_ALU24 ;
* areg = * tok + + ;
dsp_k = 0 < < 2 ;
return OK ;
}
else if ( * tok = = ' ( ' | | * tok = = ' - ' )
{
// Could be either an expression or ea mode
if ( * tok + 1 = = SYMBOL )
{
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* am = M_DSPIM ;
return OK ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( * areg = checkea ( 0 , P_ERRORS ) ) ! = ERROR )
{
* am = M_DSPEA ;
return OK ;
}
else
return ERROR ;
// TODO: add absolute address checks
return error ( " internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet! " ) ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_P & & * ( tok + 1 ) = = ' : ' )
2019-08-08 02:24:52 +03:00
{
tok = tok + 2 ;
2018-06-23 19:57:21 +03:00
if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
2019-08-08 02:24:52 +03:00
{
// Address
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0x3F )
{
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
}
else
{
* areg = ( int ) * AnEXVAL ; // Lame, but what the hell
* am = M_DSPAA ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
return OK ;
}
else if ( * tok = = ' < ' )
{
// X:aa
// Short Addressing Mode Force Operator in the case of '<'
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0x3F )
return error ( " short addressing mode forced but address is bigger than $3F " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* am = M_DSPAA ;
* areg = ( int ) * AnEXVAL ; // Since this is only going to get used in dsp_ea_imm5...
return OK ;
}
else if ( * tok = = ' > ' )
{
// Long Addressing Mode Force Operator
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// Immediate Short Addressing Mode Force Operator
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXATTR & DEFINED )
{
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
return OK ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( * areg = checkea ( 0 , P_ERRORS ) ) ! = ERROR )
{
* am = M_DSPEA ;
return OK ;
}
else
return ERROR ;
}
else if ( * tok = = SHL )
{
// I/O Short Addressing Mode Force Operator
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXVAL > 0xFFF )
return error ( " I/O short addressing mode forced but address is bigger than $FFF " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* am = M_DSPABS06 ;
return OK ;
}
else if ( * tok = = ' < ' )
{
// Short Addressing Mode Force Operator
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXATTR & DEFINED )
{
if ( * AnEXVAL > 0xFFF )
return error ( " short addressing mode forced but address is bigger than $FFF " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
* am = M_DSPABS12 ;
return OK ;
}
else if ( * tok = = ' > ' )
{
// Long Addressing Mode Force Operator
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// Immediate Short Addressing Mode Force Operator
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * AnEXATTR & DEFINED )
{
if ( * AnEXVAL > 0xFFFFFF )
return error ( " long address is bigger than $FFFFFF " ) ;
}
* am = M_DSPEA ;
* areg = DSP_EA_ABS ;
return OK ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_PC | | * tok = = REG56_CCR | | * tok = = REG56_SR | | * tok = = REG56_SP | | ( * tok > = REG56_MR & & * tok < = REG56_SS ) )
2019-08-08 02:24:52 +03:00
{
* areg = * tok + + ;
* am = M_DSPPCU ;
return OK ;
}
// expr
else
{
if ( expr ( AnEXPR , AnEXVAL , AnEXATTR , AnESYM ) ! = OK )
return ERROR ;
// We'll store M_DSPEA_ABS in areg and if we have
// any extra info, it'll go in am
if ( * AnEXATTR & DEFINED )
{
* areg = DSP_EA_ABS ;
if ( * AnEXVAL < 0x1000 )
* am = M_DSPABS12 ;
else if ( * AnEXVAL < 0x10000 )
* am = M_DSPABS16 ;
else if ( * AnEXVAL < 0x1000000 )
* am = M_DSPABS24 ;
else
return error ( " address must be smaller than $1000000 " ) ;
return OK ;
}
else
{
// Well, we have no opinion on the expression's size, so let's assume the worst
* areg = DSP_EA_ABS ;
* am = M_DSPABS24 ;
return OK ;
}
}
return error ( " internal assembler error: Please report this error message: 'reached the end of dsp_parmode' with the line of code that caused it. Thanks, and sorry for the inconvenience " ) ; // Something bad happened
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
//
// Parse all addressing modes except parallel moves
//
int dsp_amode ( int maxea )
{
LONG dummy ;
// Initialize global return values
nmodes = dsp_a0reg = dsp_a1reg = 0 ;
dsp_am0 = dsp_am1 = M_AM_NONE ;
dsp_a0expr [ 0 ] = dsp_a1expr [ 0 ] = ENDEXPR ;
dsp_a0exval = 0 ;
dsp_a1exval = 0 ;
dsp_a0exattr = dsp_a1exattr = 0 ;
dsp_a0esym = dsp_a1esym = ( SYM * ) NULL ;
dsp_a0memspace = dsp_a1memspace = - 1 ;
dsp_a0perspace = dsp_a1perspace = - 1 ;
dsp_k = 0 ;
// If at EOL, then no addr modes at all
if ( * tok = = EOL )
return 0 ;
if ( dsp_parmode ( & dsp_am0 , & dsp_a0reg , dsp_a0expr , & dsp_a0exval , & dsp_a0exattr , & dsp_a0esym , & dsp_a0memspace , & dsp_a0perspace , 0 ) = = ERROR )
return ERROR ;
// If caller wants only one mode, return just one (ignore comma);
// If there is no second addressing mode (no comma), then return just one anyway.
nmodes = 1 ;
if ( * tok ! = ' , ' )
{
if ( dsp_k ! = 0 )
return error ( " -x0/-x1/-y0/-y1 only allowed in multiply operations " ) ;
return 1 ;
}
// Eat the comma
tok + + ;
// Parse second addressing mode
if ( dsp_parmode ( & dsp_am1 , & dsp_a1reg , dsp_a1expr , & dsp_a1exval , & dsp_a1exattr , & dsp_a1esym , & dsp_a1memspace , & dsp_a1perspace , 1 ) = = ERROR )
return ERROR ;
if ( maxea = = 2 | | * tok = = EOL )
{
if ( dsp_k ! = 0 )
return error ( " -x0/-x1/-y0/-y1 only allowed in multiply operations " ) ;
nmodes = 2 ;
return 2 ;
}
if ( * tok = = ' , ' )
{
// Only MAC-like or jsset/clr/tst/chg instructions here
tok + + ;
if ( dsp_parmode ( & dsp_am2 , & dsp_a2reg , dsp_a2expr , & dsp_a2exval , & dsp_a2exattr , & dsp_a2esym , & dummy , & dummy , 2 ) = = ERROR )
return ERROR ;
if ( maxea = = 3 )
return 3 ;
if ( * tok ! = EOL )
return error ( extra_stuff ) ;
nmodes = 3 ;
return 3 ;
}
// Only Tcc instructions here, and then only those that accept 4 operands
if ( dsp_parmode ( & dsp_am2 , & dsp_a2reg , dsp_a2expr , & dsp_a2exval , & dsp_a2exattr , & dsp_a2esym , & dummy , & dummy , 2 ) = = ERROR )
return ERROR ;
if ( * tok + + ! = ' , ' )
return error ( " expected 4 parameters " ) ;
if ( dsp_parmode ( & dsp_am3 , & dsp_a3reg , dsp_a3expr , & dsp_a3exval , & dsp_a3exattr , & dsp_a3esym , & dummy , & dummy , 3 ) = = ERROR )
return ERROR ;
if ( * tok = = EOL )
{
if ( dsp_k ! = 0 )
return error ( " -x0/-x1/-y0/-y1 only allowed in multiply operations " ) ;
nmodes = 4 ;
return 4 ;
}
else
{
// Tcc instructions do not support parallel moves, so any remaining tokens are garbage
return error ( extra_stuff ) ;
}
return error ( " internal assembler error: Please report this error message: 'reached the end of dsp_amode' with the line of code that caused it. Thanks, and sorry for the inconvenience " ) ; //Something bad happened
2018-06-23 19:57:21 +03:00
}
//
// Helper function which gives us the encoding of a DSP register
//
static inline int SDreg ( int reg )
{
2022-03-24 13:28:09 +02:00
if ( reg > = REG56_X0 & & reg < = REG56_N7 )
2019-08-08 02:24:52 +03:00
return reg & 0xFF ;
2022-03-24 13:28:09 +02:00
else if ( reg > = REG56_A0 & & reg < = REG56_A2 )
2019-08-08 02:24:52 +03:00
return ( 8 > > ( reg & 7 ) ) | 8 ;
2022-03-24 13:28:09 +02:00
else //if (reg>=REG56_R0&®<=REG56_R7)
return reg - REG56_R0 + 16 ;
2019-08-08 02:24:52 +03:00
// Handy map for the above:
// (values are of course taken from keytab)
// Register | Value | Return value
// x0 | 260 | 4
// x1 | 261 | 5
// y0 | 262 | 6
// y1 | 263 | 7
// b0 | 265 | 8
// b2 | 267 | 9
// b1 | 269 | 10
// a | 270 | 14
// b | 271 | 15
// n0 | 280 | 24
// n1 | 281 | 25
// n2 | 282 | 26
// n3 | 283 | 27
// n4 | 284 | 28
// n5 | 285 | 29
// n6 | 286 | 30
// n7 | 287 | 31
// a0 | 136 | 0
// a1 | 137 | 1
// a2 | 138 | 2
// r0 | 151 | 16
// r1 | 152 | 17
// r2 | 153 | 18
// r3 | 154 | 19
// r4 | 155 | 20
// r5 | 156 | 21
// r6 | 157 | 22
// r7 | 158 | 23
2018-06-23 19:57:21 +03:00
}
//
// Check for X:Y: parallel mode syntax
//
static inline LONG check_x_y ( LONG ea1 , LONG S1 )
{
2019-08-08 02:24:52 +03:00
LONG inst ;
LONG eax_temp , eay_temp ;
LONG D1 , D2 , S2 , ea2 ;
LONG K_D1 , K_D2 ;
LONG w = 1 < < 7 ; // S1=0, D1=1<<14
if ( ( ea1 & 0x38 ) = = DSP_EA_POSTINC | | ( ea1 & 0x38 ) = = DSP_EA_POSTINC1 | |
( ea1 & 0x38 ) = = DSP_EA_POSTDEC1 | | ( ea1 & 0x38 ) = = DSP_EA_NOUPD )
{
switch ( ea1 & 0x38 )
{
case DSP_EA_POSTINC : ea1 = ( ea1 & ( ~ 0x38 ) ) | 0x8 ; break ;
case DSP_EA_POSTINC1 : ea1 = ( ea1 & ( ~ 0x38 ) ) | 0x18 ; break ;
case DSP_EA_POSTDEC1 : ea1 = ( ea1 & ( ~ 0x38 ) ) | 0x10 ; break ;
case DSP_EA_NOUPD : ea1 = ( ea1 & ( ~ 0x38 ) ) | 0x00 ; break ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( S1 = = 0 )
{
// 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
// Check for D1
switch ( K_D1 = * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_X0 : D1 = 0 < < 10 ; break ;
case REG56_X1 : D1 = 1 < < 10 ; break ;
case REG56_A : D1 = 2 < < 10 ; break ;
case REG56_B : D1 = 3 < < 10 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,' " ) ;
}
}
else
{
// 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
w = 0 ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
switch ( S1 )
{
case 4 : D1 = 0 < < 10 ; break ;
case 5 : D1 = 1 < < 10 ; break ;
case 14 : D1 = 2 < < 10 ; break ;
case 15 : D1 = 3 < < 10 ; break ;
default : return error ( " unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax' " ) ;
}
}
2018-06-23 19:57:21 +03:00
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
tok + + ;
// 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
if ( * tok + + ! = ' : ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + = = ' ( ' )
{
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_R0 & & * tok < = REG56_R7 )
2019-08-08 02:24:52 +03:00
{
2022-03-24 13:28:09 +02:00
ea2 = ( * tok + + - REG56_R0 ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( ( ea1 & 7 ) < 4 & & ea2 < 4 ) | | ( ( ea1 & 7 ) > = 4 & & ea2 > 4 ) )
return error ( " unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea Y:eay,D2' " ) ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:(' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// If eax register is r0-r3 then eay register is r4-r7.
// Encode that to 2 bits (i.e. eay value is 0-3)
eax_temp = ( ea2 & 3 ) < < 5 ; // Store register temporarily
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' ) ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ') ' after ' X : ea , D1 / S1 , X : ea Y : ( Rn ' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = ' + ' )
{
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = ' , ' )
{
// (Rn)+
ea2 = 3 < < 12 ;
tok + + ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2019-08-08 02:24:52 +03:00
{
// (Rn)+Nn
if ( ( * tok + + & 7 ) ! = ea2 )
return error ( " unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea Y:(Rn) + Nn , D ' ) " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
ea2 = 1 < < 12 ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn) + Nn ' " ) ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn) + ' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
}
else if ( * tok = = ' - ' )
{
// (Rn)-
ea2 = 2 < < 12 ;
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn) - ' " ) ;
}
else if ( * tok + + = = ' , ' )
{
// (Rn)
ea2 = 0 < < 12 ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
ea2 | = eax_temp ; // OR eay back from temp
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
switch ( K_D2 = * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_Y0 : D2 = 0 < < 8 ; break ;
case REG56_Y1 : D2 = 1 < < 8 ; break ;
case REG56_A : D2 = 2 < < 8 ; break ;
case REG56_B : D2 = 3 < < 8 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,' " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok ! = EOL )
return error ( " unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( S1 = = 0 )
if ( K_D1 = = K_D2 )
return error ( " unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b1100000000000000 | w ;
2019-08-08 02:24:52 +03:00
inst | = ea1 | D1 | ea2 | D2 ;
return inst ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected '(Rn) ' , ' ( Rn ) + ' , ' ( Rn ) - ' , ' ( Rn ) + Nn ' after ' X : ea , D1 / S1 , X : ea Y : ' " ) ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y0 | | * tok = = REG56_Y1 | | * tok = = REG56_A | | * tok = = REG56_B )
2019-08-08 02:24:52 +03:00
{
// 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_Y0 : S2 = 0 < < 8 ; break ;
case REG56_Y1 : S2 = 1 < < 8 ; break ;
case REG56_A : S2 = 2 < < 8 ; break ;
case REG56_B : S2 = 3 < < 8 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,' " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 13:28:09 +02:00
if ( * tok + + = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
// 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
if ( * tok + + ! = ' : ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + = = ' ( ' )
{
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_R0 & & * tok < = REG56_R7 )
2019-08-08 02:24:52 +03:00
{
2022-03-24 13:28:09 +02:00
ea2 = ( * tok + + - REG56_R0 ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ( ( ea1 & 7 ) < 4 & & ea2 < 4 ) | | ( ( ea1 & 7 ) > = 4 & & ea2 > 4 ) )
return error ( " unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea S2,Y:eay' " ) ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:(' " ) ;
// If eax register is r0-r3 then eay register is r4-r7.
// Encode that to 2 bits (i.e. eay value is 0-3)
eay_temp = ( ea2 & 3 ) < < 5 ; //Store register temporarily
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' ) ' )
return error ( " unrecognised X:Y: parallel move syntax: expected ') ' after ' X : ea , D1 / S1 , X : ea S2 , Y : ( Rn ' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = ' + ' )
{
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = EOL )
// (Rn)+
ea2 = 3 < < 12 ;
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2019-08-08 02:24:52 +03:00
{
// (Rn)+Nn
if ( ( * tok + + & 7 ) ! = ea2 )
return error ( " unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea S2,Y:(Rn) + Nn ' ) " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
ea2 = 1 < < 12 ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok ! = EOL )
return error ( " unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn) + Nn ' " ) ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn) + ' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
}
else if ( * tok = = ' - ' )
{
// (Rn)-
ea2 = 2 < < 12 ;
tok + + ;
if ( * tok ! = EOL )
return error ( " unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn) - ' " ) ;
}
else if ( * tok = = EOL )
{
// (Rn)
ea2 = 0 < < 12 ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
ea2 | = eay_temp ; //OR eay back from temp
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b1000000000000000 | w ;
2019-08-08 02:24:52 +03:00
inst | = ( ea1 & 0x1f ) | D1 | S2 | ea2 ;
return inst ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected '(Rn) ' , ' ( Rn ) + ' , ' ( Rn ) - ' , ' ( Rn ) + Nn ' after ' X : ea , D1 / S1 , X : ea Y : ' " ) ;
}
else
return error ( " unrecognised X:Y: parallel move syntax: expected '(Rn) ' , ' ( Rn ) + ' , ' ( Rn ) - ' , ' ( Rn ) + Nn ' in ' X : ea , D1 / S1 , X : ea ' " ) ;
}
else
return error ( " unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,' " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
return error ( " unrecognised X:Y: parallel move syntax: expected '(Rn) ' , ' ( Rn ) + ' , ' ( Rn ) - ' , ' ( Rn ) + Nn ' in ' X : ea , D1 / S1 , X : ea ' " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
//
// Parse X: addressing space parallel moves
//
static inline LONG parse_x ( const int W , LONG inst , const LONG S1 , const int check_for_x_y )
{
int immreg ; // Immediate register destination
LONG S2 , D1 , D2 ; // Source and Destinations
LONG ea1 ; // ea bitfields
uint32_t termchar = ' , ' ; // Termination character for ea checks
int force_imm = NUM_NORMAL ; // Holds forced immediate value (i.e. '<' or '>')
ea1 = - 1 ; // initialise e1 (useful for some code paths)
if ( W = = 0 )
termchar = EOL ;
if ( * tok = = ' - ' )
{
if ( tok [ 1 ] = = CONST | | tok [ 1 ] = = FCONST )
{
tok + + ;
dspImmedEXVAL = * tok + + ;
goto x_check_immed ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// This could be either -(Rn), -aa or -ea. Check for immediate first
if ( tok [ 1 ] = = SYMBOL )
{
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) = = OK )
{
if ( S1 ! = 0 )
{
x_checkea_right :
// 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B', 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_X0 & & tok [ 1 ] = = ' , ' & & tok [ 2 ] = = REG56_A )
2019-08-08 02:24:52 +03:00
{
// 'A,X:ea X0,A'
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( S1 ! = 14 )
return error ( " unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ea1 = = - 1 )
return error ( " unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
if ( ea1 = = 0 b00110100 )
2019-08-08 02:24:52 +03:00
return error ( " unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b0000100000000000 | ea1 | ( 0 < < 8 ) ;
2019-08-08 02:24:52 +03:00
return inst ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_X0 & & tok [ 1 ] = = ' , ' & & tok [ 2 ] = = REG56_B )
2019-08-08 02:24:52 +03:00
{
// 'B,X:ea X0,B'
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( S1 ! = 15 )
return error ( " unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( ea1 = = - 1 )
return error ( " unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
if ( ea1 = = 0 b00110100 )
2019-08-08 02:24:52 +03:00
return error ( " unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b0000100100000000 | ea1 | ( 1 < < 8 ) ;
2019-08-08 02:24:52 +03:00
return inst ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_A | | * tok = = REG56_B )
2019-08-08 02:24:52 +03:00
{
// 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
switch ( S1 )
{
case 4 : D1 = 0 < < 10 ; break ;
case 5 : D1 = 1 < < 10 ; break ;
case 14 : D1 = 2 < < 10 ; break ;
case 15 : D1 = 3 < < 10 ; break ;
default : return error ( " unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2' " ) ;
}
2018-06-23 19:57:21 +03:00
2022-03-24 13:28:09 +02:00
if ( tok [ 1 ] = = ' , ' & & tok [ 2 ] = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
// 'S1,X:eax S2,Y:eay'
return check_x_y ( ea1 , S1 ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// 'S1,X:ea S2,D2'
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_A : S2 = 0 < < 9 ; break ;
case REG56_B : S2 = 1 < < 9 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax' " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_Y0 | | * tok = = REG56_Y1 )
2019-08-08 02:24:52 +03:00
{
2022-03-24 13:28:09 +02:00
if ( * tok + + = = REG56_Y0 )
2019-08-08 02:24:52 +03:00
D2 = 0 < < 8 ;
else
D2 = 1 < < 8 ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok ! = EOL )
return error ( " unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b0001000000000000 | ( 0 < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ea1 | D1 | S2 | D2 ;
return inst ;
}
else
return error ( " unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,' " ) ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
// 'S1,X:eax Y:eay,D2'
return check_x_y ( ea1 , S1 ) ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y0 | | * tok = = REG56_Y1 )
2019-08-08 02:24:52 +03:00
{
// 'S1,X:eax S2,Y:eay'
return check_x_y ( ea1 , S1 ) ;
}
else
return error ( " unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1 " ) ;
}
else
{
// Only check for aa if we have a defined number in our hands or we've
// been asked to use a short number format. The former case we'll just test
// it to see if it's small enough. The later - it's the programmer's call
// so he'd better have a small address or the fixups will bite him/her in the arse!
if ( dspImmedEXATTR & DEFINED | | force_imm = = NUM_FORCE_SHORT )
{
// It's an immediate, so ea or eax is probably an absolute address
// (unless it's aa if the immediate is small enough)
// 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
x_check_immed :
// Check for aa (which is 6 bits zero extended)
if ( dspImmedEXVAL < 0x40 & & force_imm ! = NUM_FORCE_LONG )
{
if ( W = = 1 )
{
// It might be X:aa but we're not 100% sure yet.
// If it is, the only possible syntax here is 'X:aa,D'.
// So check ahead to see if EOL follows D, then we're good to go.
2022-03-24 13:28:09 +02:00
if ( * tok = = ' , ' & & ( ( * ( tok + 1 ) > = REG56_X0 & & * ( tok + 1 ) < = REG56_N7 ) | | ( * ( tok + 1 ) > = REG56_R0 & & * ( tok + 1 ) < = REG56_R7 ) | | ( * ( tok + 1 ) > = REG56_A0 & & * ( tok + 1 ) < = REG56_A2 ) ) & & * ( tok + 2 ) = = EOL )
2019-08-08 02:24:52 +03:00
{
// Yup, we're good to go - 'X:aa,D' it is
tok + + ;
immreg = SDreg ( * tok + + ) ;
inst = inst | ( uint32_t ) dspImmedEXVAL ;
inst | = ( ( immreg & 0x18 ) < < ( 12 - 3 ) ) + ( ( immreg & 7 ) < < 8 ) ;
inst | = 1 < < 7 ; // W
return inst ;
}
}
else
{
if ( * tok = = EOL )
{
// 'S,X:aa'
inst = inst | ( uint32_t ) dspImmedEXVAL ;
inst | = ( ( S1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( S1 & 7 ) < < 8 ) ;
return inst ;
}
else
{
// 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
// 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
ea1 = DSP_EA_ABS ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
goto x_checkea_right ;
}
}
}
}
// Well, that settles it - we do have an ea in our hands
if ( W = = 1 )
{
// 'X:ea,D' [... S2,d2]
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X: parallel move syntax: expected ',' after 'X:ea' " ) ;
2022-03-24 13:28:09 +02:00
if ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) )
2019-08-08 02:24:52 +03:00
{
D1 = SDreg ( * tok + + ) ;
if ( * tok = = EOL )
{
// 'X:ea,D'
2022-03-24 12:29:46 +02:00
inst = inst | 0 b01000000 | ( 1 < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ( ( D1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( D1 & 7 ) < < 8 ) ;
inst | = ea1 ;
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
return inst ;
}
else
{
// 'X:ea,D1 S2,D2'
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_A | | * tok = = REG56_B )
2019-08-08 02:24:52 +03:00
{
S2 = SDreg ( * tok + + ) ;
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2 " ) ;
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_Y0 | | * tok = = REG56_Y1 )
2019-08-08 02:24:52 +03:00
{
D2 = SDreg ( * tok + + ) ;
if ( * tok ! = EOL )
return error ( " unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2 " ) ;
2022-03-24 12:29:46 +02:00
inst = 0 b0001000000000000 | ( 1 < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ( ( D1 & 0x8 ) < < ( 12 - 4 ) ) + ( ( D1 & 1 ) < < 10 ) ;
inst | = ( S2 & 1 ) < < 9 ;
inst | = ( D2 & 1 ) < < 8 ;
inst | = ea1 ;
return inst ;
}
else
return error ( " unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2, " ) ;
}
else
return error ( " unrecognised X:R parallel move syntax: expected a,b after X:ea,D1 " ) ;
}
}
else
return error ( " unrecognised X: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'X:ea,' " ) ;
}
else
{
if ( * tok = = EOL )
{
// 'S,X:ea'
2022-03-24 12:29:46 +02:00
inst = inst | 0 b01000000 | ( 0 < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ( ( S1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( S1 & 7 ) < < 8 ) ;
inst | = ea1 ;
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
return inst ;
}
else
{
// 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
// 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
goto x_checkea_right ;
}
}
}
}
}
else
{
// It's not an immediate, check for '-(Rn)'
ea1 = checkea ( termchar , X_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
goto x_gotea1 ;
}
}
else if ( * tok = = ' # ' )
{
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
// Okay so we have immediate data - mark it down
ea1 = DSP_EA_IMM ;
// Now, proceed to the main code for this branch
goto x_gotea1 ;
}
else if ( * tok = = ' ( ' )
{
// Maybe we got an expression here, check for it
if ( tok [ 1 ] = = CONST | | tok [ 1 ] = = FCONST | | tok [ 1 ] = = SUNARY | | tok [ 1 ] = = SYMBOL | | tok [ 1 ] = = STRING )
{
// Evaluate the expression and go to immediate code path
expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ;
goto x_check_immed ;
}
// Nope, let's check for ea then
ea1 = checkea ( termchar , X_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
x_gotea1 :
if ( W = = 1 )
{
if ( * tok + + ! = ' , ' )
return error ( " Comma expected after 'X:(Rn) ' ) " ) ;
// It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
// If it is, the only possible syntax here is 'X:ea,D'.
// So check ahead to see if EOL follows D, then we're good to go.
2022-03-24 13:28:09 +02:00
if ( ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) ) & & * ( tok + 1 ) = = EOL )
2019-08-08 02:24:52 +03:00
{
//'X:ea,D'
D1 = SDreg ( * tok + + ) ;
2022-03-24 12:29:46 +02:00
inst = inst | 0 b01000000 | ( 1 < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ea1 ;
inst | = ( ( D1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( D1 & 7 ) < < 8 ) ;
return inst ;
}
}
else
{
if ( * tok = = EOL )
{
//'S,X:ea'
2022-03-24 12:29:46 +02:00
inst = inst | 0 b01000000 | ( 0 < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ea1 ;
inst | = ( ( S1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( S1 & 7 ) < < 8 ) ;
return inst ;
}
else
{
goto x_checkea_right ;
}
}
// 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
// Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
2022-03-24 13:28:09 +02:00
if ( ( * tok = = REG56_X0 | | * tok = = REG56_X1 | | * tok = = REG56_A | | * tok = = REG56_B ) & & ( * ( tok + 1 ) = = REG56_A | | * ( tok + 1 ) = = REG56_B ) & & ( * ( tok + 2 ) = = ' , ' ) & & ( * ( tok + 3 ) = = REG56_Y0 | | ( * ( tok + 3 ) = = REG56_Y1 ) ) )
2019-08-08 02:24:52 +03:00
{
// 'X:ea,D1 S2,D2'
// Check if D1 is x0, x1, a or b
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_X0 : D1 = 0 < < 10 ; break ;
case REG56_X1 : D1 = 1 < < 10 ; break ;
case REG56_A : D1 = 2 < < 10 ; break ;
case REG56_B : D1 = 3 < < 10 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,' " ) ;
}
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_A : S2 = 0 < < 9 ; break ;
case REG56_B : S2 = 1 < < 9 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 ' " ) ;
}
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2' " ) ;
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_Y0 | | * tok = = REG56_Y1 )
2019-08-08 02:24:52 +03:00
{
2022-03-24 13:28:09 +02:00
if ( * tok + + = = REG56_Y0 )
2019-08-08 02:24:52 +03:00
D2 = 0 < < 8 ;
else
D2 = 1 < < 8 ;
if ( * tok ! = EOL )
return error ( " unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2' " ) ;
2022-03-24 12:29:46 +02:00
inst = 0 b0001000000000000 | ( W < < 7 ) ;
2019-08-08 02:24:52 +03:00
inst | = ea1 | D1 | S2 | D2 ;
return inst ;
}
else
return error ( " unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,' " ) ;
}
// Check to see if we got eax (which is a subset of ea)
if ( check_for_x_y )
{
if ( ( inst = check_x_y ( ea1 , 0 ) ) ! = 0 )
return inst ;
else
{
// Rewind pointer as it might be an expression and check for it
tok - - ;
if ( expr ( dspaaEXPR , & dspaaEXVAL , & dspaaEXATTR , & dspaaESYM ) ! = OK )
return ERROR ;
// Yes, we have an expression, so we now check for
// 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
goto x_check_immed ;
}
}
}
else if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
// Check for immediate address
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
// We set ea1 here - if it's aa instead of ea
// then it won't be used anyway
ea1 = DSP_EA_ABS ;
if ( ! ( dspImmedEXATTR & DEFINED ) )
{
force_imm = NUM_FORCE_LONG ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
}
goto x_check_immed ;
}
else if ( * tok = = ' > ' )
{
// Check for immediate address forced long
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
2020-08-03 20:16:38 +03:00
if ( ( dspImmedEXATTR & DEFINED ) & & ( dspImmedEXVAL > 0xFFFFFF ) )
return error ( " long address is bigger than $FFFFFF " ) ;
2019-08-08 02:24:52 +03:00
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
force_imm = NUM_FORCE_LONG ;
ea1 = DSP_EA_ABS ;
goto x_check_immed ;
}
else if ( * tok = = ' < ' )
{
// Check for immediate address forced short
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
force_imm = NUM_FORCE_SHORT ;
if ( dspImmedEXATTR & DEFINED )
{
if ( dspImmedEXVAL > 0x3F )
{
2021-07-16 15:04:22 +03:00
if ( CHECK_OPTS ( OPT_56K_AUTO_LONG ) )
{
if ( optim_warn_flag )
warn ( " o11: short addressing mode forced but address is bigger than $3F - switching to long " ) ;
2020-08-03 20:16:38 +03:00
2021-07-16 15:04:22 +03:00
force_imm = NUM_FORCE_LONG ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
ea1 = DSP_EA_ABS ;
}
else
{
return error ( " short addressing mode forced but address is bigger than $3F - turn opt switch o11 on to bypass " ) ;
}
2019-08-08 02:24:52 +03:00
}
}
else
{
// This might end up as something like 'move Y:<adr,register'
// so let's mark it as an extra aa fixup here.
// Note: we are branching to x_check_immed without a
// defined dspImmed so it's going to be 0. It probably
// doesn't harm anything.
deposit_extra_ea = DEPOSIT_EXTRA_FIXUP ;
}
goto x_check_immed ;
}
return error ( " unknown x: addressing mode " ) ;
2018-06-23 19:57:21 +03:00
}
//
// Parse Y: addressing space parallel moves
//
static inline LONG parse_y ( LONG inst , LONG S1 , LONG D1 , LONG S2 )
{
int immreg ; // Immediate register destination
LONG D2 ; // Destination
LONG ea1 ; // ea bitfields
int force_imm = NUM_NORMAL ; // Holds forced immediate value (i.e. '<' or '>')
if ( * tok = = ' - ' )
{
if ( tok [ 1 ] = = CONST | | tok [ 1 ] = = FCONST )
{
tok + + ;
dspImmedEXVAL = * tok + + ;
goto y_check_immed ;
}
// This could be either -(Rn), -aa or -ea. Check for immediate first
if ( * tok = = SYMBOL | | tok [ 1 ] = = SYMBOL )
{
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) = = OK )
{
// Only check for aa if we have a defined number in our hands or we've
// been asked to use a short number format. The former case we'll just test
// it to see if it's small enough. The later - it's the programmer's call
// so he'd better have a small address or the fixups will bite him/her in the arse!
if ( dspImmedEXATTR & DEFINED | | force_imm = = NUM_FORCE_SHORT )
{
// It's an immediate, so ea is probably an absolute address
// (unless it's aa if the immediate is small enough)
// 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
y_check_immed :
// Check for aa (which is 6 bits zero extended)
if ( dspImmedEXVAL < 0x40 & & force_imm ! = NUM_FORCE_LONG )
{
// It might be Y:aa but we're not 100% sure yet.
// If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
// So check ahead to see if EOL follows D, then we're good to go.
if ( * tok = = EOL & & S1 ! = 0 )
{
// 'S,Y:aa'
2022-03-24 12:29:46 +02:00
inst = 0 b0100100000000000 ;
2018-06-23 19:57:21 +03:00
inst | = dspImmedEXVAL ;
inst | = ( ( S1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( S1 & 7 ) < < 8 ) ;
return inst ;
}
2020-08-03 20:16:38 +03:00
2022-03-24 13:28:09 +02:00
if ( * tok = = ' , ' & & ( ( * ( tok + 1 ) > = REG56_X0 & & * ( tok + 1 ) < = REG56_N7 ) | | ( * ( tok + 1 ) > = REG56_R0 & & * ( tok + 1 ) < = REG56_R7 ) | | ( * ( tok + 1 ) > = REG56_A0 & & * ( tok + 1 ) < = REG56_A2 ) ) & & * ( tok + 2 ) = = EOL )
2018-06-23 19:57:21 +03:00
{
// Yup, we're good to go - 'Y:aa,D' it is
tok + + ;
immreg = SDreg ( * tok + + ) ;
inst | = dspImmedEXVAL ;
inst | = ( ( immreg & 0x18 ) < < ( 12 - 3 ) ) + ( ( immreg & 7 ) < < 8 ) ;
return inst ;
}
}
}
// Well, that settles it - we do have a ea in our hands
if ( * tok = = EOL & & S1 ! = 0 )
{
// 'S,Y:ea'
2022-03-24 12:29:46 +02:00
inst = 0 b0100100001110000 ;
2018-06-23 19:57:21 +03:00
inst | = ea1 ;
inst | = ( ( S1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( S1 & 7 ) < < 8 ) ;
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
return inst ;
}
2020-08-03 20:16:38 +03:00
2018-06-23 19:57:21 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised Y: parallel move syntax: expected ',' after 'Y:ea' " ) ;
2020-08-03 20:16:38 +03:00
2018-06-23 19:57:21 +03:00
if ( D1 = = 0 & & S1 = = 0 )
{
// 'Y:ea,D'
2022-03-24 13:28:09 +02:00
if ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) )
2018-06-23 19:57:21 +03:00
{
D1 = SDreg ( * tok + + ) ;
2020-08-03 20:16:38 +03:00
2018-06-23 19:57:21 +03:00
if ( * tok ! = EOL )
return error ( " unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D' " ) ;
2020-08-03 20:16:38 +03:00
2022-03-24 12:29:46 +02:00
inst | = 0 b0000000001110000 ;
2018-06-23 19:57:21 +03:00
inst | = ea1 ;
inst | = ( ( D1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( D1 & 7 ) < < 8 ) ;
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
return inst ;
}
else
return error ( " unrecognised Y: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'Y:ea,' " ) ;
}
else
{
// 'S1,D1 Y:ea,D2'
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_A | | * tok = = REG56_B | | * tok = = REG56_Y0 | | * tok = = REG56_Y1 )
2018-06-23 19:57:21 +03:00
{
D2 = SDreg ( * tok + + ) ;
inst | = ea1 ;
inst | = 1 < < 7 ;
inst | = ( S1 & 1 ) < < 11 ;
inst | = ( D1 & 1 ) < < 10 ;
inst | = ( D2 & 8 ) < < ( 9 - 3 ) ;
inst | = ( D2 & 1 ) < < 8 ;
return inst ;
}
else
return error ( " unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,' " ) ;
}
}
else
return ERROR ;
}
2020-08-03 20:16:38 +03:00
else
{
// It's not an immediate, check for '-(Rn)'
ea1 = checkea ( ' , ' , Y_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
goto y_gotea1 ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
}
}
else if ( * tok = = ' # ' )
{
tok + + ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
// Okay so we have immediate data - mark it down
ea1 = DSP_EA_IMM ;
// Now, proceed to the main code for this branch
goto y_gotea1 ;
}
else if ( * tok = = ' ( ' )
{
// Maybe we got an expression here, check for it
if ( tok [ 1 ] = = CONST | | tok [ 1 ] = = FCONST | | tok [ 1 ] = = SUNARY | | tok [ 1 ] = = SYMBOL | | tok [ 1 ] = = STRING )
{
// Evaluate the expression and go to immediate code path
expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ;
goto y_check_immed ;
}
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
// Nope, let's check for ea then
if ( S1 = = 0 | | ( S1 ! = 0 & & D1 ! = 0 ) )
ea1 = checkea ( ' , ' , Y_ERRORS ) ;
else
ea1 = checkea ( EOL , Y_ERRORS ) ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( ea1 = = ERROR )
return ERROR ;
y_gotea1 :
if ( S1 ! = 0 & & * tok = = EOL )
{
// 'S,Y:ea'
2022-03-24 12:29:46 +02:00
inst = 0 b0100100001000000 ;
2020-08-03 20:16:38 +03:00
inst | = ea1 ;
inst | = ( ( S1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( S1 & 7 ) < < 8 ) ;
return inst ;
}
else if ( S1 ! = 0 & & D1 ! = 0 & & S2 = = 0 )
{
// 'S1,D1 Y:ea,D2'
switch ( S1 )
{
case 14 : S1 = 0 < < 11 ; break ; // A
case 15 : S1 = 1 < < 11 ; break ; // B
default : return error ( " unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2' " ) ; break ;
}
switch ( D1 )
{
case 4 : D1 = 0 < < 10 ; break ; // X0
case 5 : D1 = 1 < < 10 ; break ; // X1
default : return error ( " unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2' " ) ; break ;
}
if ( * tok + + ! = ' , ' )
return error ( " unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea' " ) ;
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_Y0 : D2 = 0 < < 8 ; break ;
case REG56_Y1 : D2 = 1 < < 8 ; break ;
case REG56_A : D2 = 2 < < 8 ; break ;
case REG56_B : D2 = 3 < < 8 ; break ;
2020-08-03 20:16:38 +03:00
default : return error ( " unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea' " ) ;
}
2022-03-24 12:29:46 +02:00
inst = 0 b0001000011000000 ;
2020-08-03 20:16:38 +03:00
inst | = S1 | D1 | D2 ;
inst | = ea1 ;
return inst ;
}
if ( * tok + + ! = ' , ' )
2018-06-23 19:57:21 +03:00
return error ( " Comma expected after 'Y:(Rn) ' ) " ) ;
2020-08-03 20:16:38 +03:00
// It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
// If it is, the only possible syntax here is 'Y:ea,D'.
// So check ahead to see if EOL follows D, then we're good to go.
2022-03-24 13:28:09 +02:00
if ( ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) ) & & * ( tok + 1 ) = = EOL )
2020-08-03 20:16:38 +03:00
{
//'Y:ea,D'
D1 = SDreg ( * tok + + ) ;
2022-03-24 12:29:46 +02:00
inst | = 0 b0000000001000000 ;
2020-08-03 20:16:38 +03:00
inst | = ea1 ;
inst | = ( ( D1 & 0x18 ) < < ( 12 - 3 ) ) + ( ( D1 & 7 ) < < 8 ) ;
return inst ;
}
}
else if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
// Check for immediate address
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
// Yes, we have an expression, so we now check for
// 'Y:ea,D' or 'Y:aa,D'
ea1 = DSP_EA_ABS ; // Reluctant - but it's probably correct
if ( ! ( dspImmedEXATTR & DEFINED ) )
{
force_imm = NUM_FORCE_LONG ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
}
goto y_check_immed ;
}
else if ( * tok = = ' > ' )
{
// Check for immediate address forced long
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
if ( ( dspImmedEXATTR & DEFINED ) & & ( dspImmedEXVAL > 0xFFFFFF ) )
return error ( " long address is bigger than $FFFFFF " ) ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
force_imm = NUM_FORCE_LONG ;
ea1 = DSP_EA_ABS ;
goto y_check_immed ;
}
else if ( * tok = = ' < ' )
{
tok + + ;
if ( S1 ! = 0 & & D1 ! = 0 )
{
// We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
// there's no Y:aa mode here, so we'll force long
2021-07-16 15:04:22 +03:00
if ( CHECK_OPTS ( OPT_56K_AUTO_LONG ) )
{
if ( optim_warn_flag )
warn ( " forced short addressing in R:Y mode is not allowed - switching to long " ) ;
2018-06-23 19:57:21 +03:00
2021-07-16 15:04:22 +03:00
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2021-07-16 15:04:22 +03:00
ea1 = DSP_EA_ABS ;
2018-06-23 19:57:21 +03:00
2021-07-16 15:04:22 +03:00
force_imm = NUM_FORCE_LONG ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
goto y_check_immed ;
}
else
{
return error ( " forced short addressing in R:Y mode is not allowed - turn opt switch o11 on to bypass " ) ;
}
2020-08-03 20:16:38 +03:00
}
else
{
// Check for immediate address forced short
ea1 = DSP_EA_ABS ; // Reluctant - but it's probably correct
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
force_imm = NUM_FORCE_SHORT ;
if ( dspImmedEXATTR & DEFINED )
{
if ( dspImmedEXVAL > 0xFFF )
{
2021-07-16 15:04:22 +03:00
if ( CHECK_OPTS ( OPT_56K_AUTO_LONG ) )
{
if ( optim_warn_flag )
warn ( " short addressing mode forced but address is bigger than $FFF - switching to long " ) ;
2018-06-23 19:57:21 +03:00
2021-07-16 15:04:22 +03:00
ea1 = DSP_EA_ABS ;
force_imm = NUM_FORCE_LONG ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
}
else
{
return error ( " short addressing mode forced but address is bigger than $FFF - turn opt switch o11 on to bypass " ) ;
}
2020-08-03 20:16:38 +03:00
}
}
else
{
// This might end up as something like 'move Y:<adr,register'
// so let's mark it as an extra aa fixup here.
// Note: we are branching to y_check_immed without a
// defined dspImmed so it's going to be 0. It probably
// doesn't harm anything.
deposit_extra_ea = DEPOSIT_EXTRA_FIXUP ;
}
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
goto y_check_immed ;
}
}
return error ( " unrecognised Y: parallel move syntax " ) ;
2018-06-23 19:57:21 +03:00
}
//
// Parse L: addressing space parallel moves
//
static inline LONG parse_l ( const int W , LONG inst , LONG S1 )
{
2020-08-03 20:16:38 +03:00
int immreg ; // Immediate register destination
LONG D1 ; // Source and Destinations
LONG ea1 ; // ea bitfields
int force_imm = NUM_NORMAL ; // Holds forced immediate value (i.e. '<' or '>')
if ( * tok = = ' - ' )
{
if ( * tok = = CONST | | tok [ 1 ] = = FCONST )
{
tok + + ;
dspImmedEXVAL = * tok + + ;
goto l_check_immed ;
}
// This could be either -(Rn), -aa or -ea. Check for immediate first
// Maybe we got an expression here, check for it
if ( * tok = = SYMBOL | | tok [ 1 ] = = SYMBOL )
{
// Evaluate the expression and go to immediate code path
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) = = OK )
{
// Only check for aa if we have a defined number in our hands
// or we've been asked to use a short number format. The
// former case we'll just test it to see if it's small enough.
// The later - it's the programmer's call so he'd better have
// a small address or the fixups will bite him/her in the arse!
if ( dspImmedEXATTR & DEFINED | | force_imm = = NUM_FORCE_SHORT )
{
// It's an immediate, so ea is probably an absolute address
// (unless it's aa if the immediate is small enough)
// 'L:ea,D' or 'L:aa,D'
l_check_immed :
// Check for aa (which is 6 bits zero extended)
if ( * tok = = EOL )
{
// 'S,L:aa'
if ( dspImmedEXVAL < 0x40 & & force_imm ! = NUM_FORCE_LONG )
{
// 'S,L:aa'
2022-03-24 13:28:09 +02:00
if ( S1 = = REG56_A )
2020-08-03 20:16:38 +03:00
S1 = 4 ;
2022-03-24 13:28:09 +02:00
else if ( S1 = = REG56_B )
2020-08-03 20:16:38 +03:00
S1 = 5 ;
else
S1 & = 7 ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b0100000000000000 ;
2020-08-03 20:16:38 +03:00
inst | = dspImmedEXVAL ;
inst | = ( ( S1 & 0x4 ) < < ( 11 - 2 ) ) + ( ( S1 & 3 ) < < 8 ) ;
return inst ;
}
else
{
// 'S,L:ea'
2022-03-24 13:28:09 +02:00
if ( S1 = = REG56_A )
2020-08-03 20:16:38 +03:00
S1 = 4 ;
2022-03-24 13:28:09 +02:00
else if ( S1 = = REG56_B )
2020-08-03 20:16:38 +03:00
S1 = 5 ;
else
S1 & = 7 ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( ea1 = = DSP_EA_ABS )
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst | = 0 b0100000001110000 ;
2020-08-03 20:16:38 +03:00
inst | = ( ( S1 & 0x4 ) < < ( 11 - 2 ) ) + ( ( S1 & 3 ) < < 8 ) ;
inst | = ea1 ;
return inst ;
}
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
}
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa' " ) ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
// Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
2022-03-24 13:28:09 +02:00
if ( ! ( ( * tok > = REG56_A10 & & * ( tok + 1 ) < = REG56_BA ) | | ( * tok > = REG56_A & & * tok < = REG56_B ) ) )
2020-08-03 20:16:38 +03:00
return error ( " unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa' " ) ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( dspImmedEXVAL < ( 1 < < 6 ) & & ( dspImmedEXATTR & DEFINED ) )
{
// 'L:aa,D'
l_aa :
immreg = * tok + + ;
2022-03-24 13:28:09 +02:00
if ( immreg = = REG56_A )
2020-08-03 20:16:38 +03:00
immreg = 4 ;
2022-03-24 13:28:09 +02:00
else if ( immreg = = REG56_B )
2020-08-03 20:16:38 +03:00
immreg = 5 ;
else
immreg & = 7 ;
if ( * tok ! = EOL )
return error ( " unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D " ) ;
2022-03-24 12:29:46 +02:00
inst & = 0 b1111111110111111 ;
2020-08-03 20:16:38 +03:00
inst | = dspImmedEXVAL ;
inst | = ( ( immreg & 0x4 ) < < ( 11 - 2 ) ) + ( ( immreg & 3 ) < < 8 ) ;
return inst ;
}
}
if ( deposit_extra_ea = = DEPOSIT_EXTRA_FIXUP )
{
// Hang on, we've got a L:<aa here, let's do that instead
goto l_aa ;
}
// Well, that settles it - we do have a ea in our hands
// 'L:ea,D'
D1 = * tok + + ;
2022-03-24 13:28:09 +02:00
if ( D1 = = REG56_A )
2020-08-03 20:16:38 +03:00
D1 = 4 ;
2022-03-24 13:28:09 +02:00
else if ( D1 = = REG56_B )
2020-08-03 20:16:38 +03:00
D1 = 5 ;
else
D1 & = 7 ;
if ( * tok ! = EOL )
return error ( " unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D " ) ;
2022-03-24 12:29:46 +02:00
inst | = 0 b0000000000110000 ;
2020-08-03 20:16:38 +03:00
inst | = ( ( D1 & 0x4 ) < < ( 11 - 2 ) ) + ( ( D1 & 3 ) < < 8 ) ;
return inst ;
}
}
else
{
//It's not an immediate, check for '-(Rn)'
ea1 = checkea ( ' , ' , L_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
goto l_gotea1 ;
}
}
else if ( * tok = = ' ( ' )
{
// Maybe we got an expression here, check for it
if ( tok [ 1 ] = = CONST | | tok [ 1 ] = = FCONST | | tok [ 1 ] = = SUNARY | | tok [ 1 ] = = SYMBOL | | tok [ 1 ] = = STRING )
{
// Evaluate the expression and go to immediate code path
expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ;
goto l_check_immed ;
}
//Nope, let's check for ea then
if ( S1 = = 0 )
ea1 = checkea ( ' , ' , L_ERRORS ) ;
else
ea1 = checkea ( EOL , L_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
l_gotea1 :
if ( * tok = = EOL )
{
// 'S,L:ea'
2022-03-24 12:29:46 +02:00
inst = 0 b0100000001000000 ;
2020-08-03 20:16:38 +03:00
2022-03-24 13:28:09 +02:00
if ( S1 = = REG56_A )
2020-08-03 20:16:38 +03:00
S1 = 4 ;
2022-03-24 13:28:09 +02:00
else if ( S1 = = REG56_B )
2020-08-03 20:16:38 +03:00
S1 = 5 ;
else
S1 & = 7 ;
inst | = ea1 ;
inst | = ( ( S1 & 0x4 ) < < ( 11 - 2 ) ) + ( ( S1 & 3 ) < < 8 ) ;
return inst ;
}
else if ( * tok + + ! = ' , ' )
return error ( " Comma expected after 'L:(Rn) ' ) " ) ;
// It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
// If it is, the only possible syntax here is 'L:ea,D'.
// So check ahead to see if EOL follows D, then we're good to go.
2022-03-24 13:28:09 +02:00
if ( ( ( * tok > = REG56_A10 & & * tok < = REG56_BA ) | | ( * tok > = REG56_A & & * tok < = REG56_B ) ) & & * ( tok + 1 ) = = EOL )
2020-08-03 20:16:38 +03:00
{
//'L:ea,D'
D1 = * tok + + ;
2022-03-24 13:28:09 +02:00
if ( D1 = = REG56_A )
2020-08-03 20:16:38 +03:00
D1 = 4 ;
2022-03-24 13:28:09 +02:00
else if ( D1 = = REG56_B )
2020-08-03 20:16:38 +03:00
D1 = 5 ;
else
D1 & = 7 ;
inst | = ea1 ;
inst | = ( ( D1 & 0x4 ) < < ( 11 - 2 ) ) + ( ( D1 & 3 ) < < 8 ) ;
return inst ;
}
}
else if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
// Check for immediate address
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
// We set ea1 here - if it's aa instead of ea
// then it won't be used anyway
ea1 = DSP_EA_ABS ;
if ( ! ( dspImmedEXATTR & DEFINED ) )
{
force_imm = NUM_FORCE_LONG ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
}
2018-06-23 19:57:21 +03:00
else if ( dspImmedEXVAL > 0x3f )
{
// Definitely no aa material, so it's going to be a long
// Mark that we need to deposit an extra word
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
}
2020-08-03 20:16:38 +03:00
// Yes, we have an expression, so we now check for
// 'L:ea,D' or 'L:aa,D'
goto l_check_immed ;
}
else if ( * tok = = ' > ' )
{
// Check for immediate address forced long
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
if ( ( dspImmedEXATTR & DEFINED ) & & ( dspImmedEXVAL > 0xFFFFFF ) )
return error ( " long address is bigger than $FFFFFF " ) ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
force_imm = NUM_FORCE_LONG ;
goto l_check_immed ;
}
else if ( * tok = = ' < ' )
{
// Check for immediate address forced short
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( dspImmedEXATTR & DEFINED )
{
if ( dspImmedEXVAL > 0xFFF )
return error ( " short addressing mode forced but address is bigger than $FFF " ) ;
}
else
{
// This might end up as something like 'move Y:<adr,register'
// so let's mark it as an extra aa fixup here.
// Note: we are branching to l_check_immed without a
// defined dspImmed so it's going to be 0. It probably
// doesn't harm anything.
deposit_extra_ea = DEPOSIT_EXTRA_FIXUP ;
}
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
force_imm = NUM_FORCE_SHORT ;
goto l_check_immed ;
}
return error ( " internal assembler error: Please report this error message: 'reached the end of parse_l' with the line of code that caused it. Thanks, and sorry for the inconvenience " ) ;
2018-06-23 19:57:21 +03:00
}
//
// Checks for all ea cases where indexed addressing is concenred
//
static inline LONG checkea ( const uint32_t termchar , const int strings )
{
2020-08-03 20:16:38 +03:00
LONG ea ;
if ( * tok = = ' - ' )
{
// -(Rn)
tok + + ;
if ( * tok + + ! = ' ( ' )
return error ( ea_errors [ strings ] [ 0 ] ) ;
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_R0 & & * tok < = REG56_R7 )
2020-08-03 20:16:38 +03:00
{
// We got '-(Rn' so mark it down
2022-03-24 13:28:09 +02:00
ea = DSP_EA_PREDEC1 | ( * tok + + - REG56_R0 ) ;
2020-08-03 20:16:38 +03:00
if ( * tok + + ! = ' ) ' )
return error ( ea_errors [ strings ] [ 1 ] ) ;
// Now, proceed to the main code for this branch
return ea ;
}
else
return error ( ea_errors [ strings ] [ 2 ] ) ;
}
else if ( * tok = = ' ( ' )
{
// Checking for ea of type (Rn)
tok + + ;
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_R0 & & * tok < = REG56_R7 )
2020-08-03 20:16:38 +03:00
{
// We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2022-03-24 13:28:09 +02:00
ea = * tok + + - REG56_R0 ;
2020-08-03 20:16:38 +03:00
if ( * tok = = ' + ' )
{
// '(Rn+Nn)'
tok + + ;
2022-03-24 13:28:09 +02:00
if ( * tok < REG56_N0 | | * tok > REG56_N7 )
2020-08-03 20:16:38 +03:00
return error ( ea_errors [ strings ] [ 3 ] ) ;
if ( ( * tok + + & 7 ) ! = ea )
return error ( ea_errors [ strings ] [ 4 ] ) ;
ea | = DSP_EA_INDEX ;
if ( * tok + + ! = ' ) ' )
return error ( ea_errors [ strings ] [ 5 ] ) ;
return ea ;
}
else if ( * tok = = ' ) ' )
{
// Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
tok + + ;
if ( * tok = = ' + ' )
{
tok + + ;
if ( termchar = = ' , ' )
{
if ( * tok = = ' , ' )
{
// (Rn)+
ea | = DSP_EA_POSTINC1 ;
return ea ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2020-08-03 20:16:38 +03:00
{
// (Rn)+Nn
if ( ( * tok + + & 7 ) ! = ea )
return error ( ea_errors [ strings ] [ 6 ] ) ;
ea | = DSP_EA_POSTINC ;
return ea ;
}
else
return error ( ea_errors [ strings ] [ 7 ] ) ;
}
else
{
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2020-08-03 20:16:38 +03:00
{
// (Rn)+Nn
if ( ( * tok + + & 7 ) ! = ea )
return error ( ea_errors [ strings ] [ 6 ] ) ;
ea | = DSP_EA_POSTINC ;
return ea ;
}
else
{
// (Rn)+
ea | = DSP_EA_POSTINC1 ;
return ea ;
}
}
}
else if ( * tok = = ' - ' )
{
tok + + ;
if ( termchar = = ' , ' )
{
if ( * tok = = ' , ' )
{
// (Rn)-
ea | = DSP_EA_POSTDEC1 ;
return ea ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2020-08-03 20:16:38 +03:00
{
// (Rn)-Nn
if ( ( * tok + + & 7 ) ! = ea )
return error ( ea_errors [ strings ] [ 8 ] ) ;
ea | = DSP_EA_POSTDEC ;
return ea ;
}
else
return error ( ea_errors [ strings ] [ 9 ] ) ;
}
else
{
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2020-08-03 20:16:38 +03:00
{
// (Rn)-Nn
if ( ( * tok + + & 7 ) ! = ea )
return error ( ea_errors [ strings ] [ 8 ] ) ;
ea | = DSP_EA_POSTDEC ;
return ea ;
}
else
{
// (Rn)-
ea | = DSP_EA_POSTDEC1 ;
return ea ;
}
}
}
else if ( termchar = = ' , ' )
{
if ( * tok = = ' , ' )
{
// (Rn)
ea | = DSP_EA_NOUPD ;
return ea ;
}
else
return error ( ea_errors [ strings ] [ 10 ] ) ;
}
else
{
// (Rn)
ea | = DSP_EA_NOUPD ;
return ea ;
}
}
else
return error ( ea_errors [ strings ] [ 11 ] ) ;
}
}
return error ( " internal assembler error: Please report this error message: 'reached the end of checkea' with the line of code that caused it. Thanks, and sorry for the inconvenience " ) ;
2018-06-23 19:57:21 +03:00
}
//
// Checks for all ea cases, i.e. all addressing modes that checkea handles
// plus immediate addresses included forced short/long ones.
// In other words this is a superset of checkea (and in fact calls checkea).
//
LONG checkea_full ( const uint32_t termchar , const int strings )
{
2020-08-03 20:16:38 +03:00
LONG ea1 ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
if ( * tok = = CONST | | * tok = = FCONST | | * tok = = SYMBOL )
{
// Check for immediate address
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
2018-06-23 19:57:21 +03:00
2020-08-03 20:16:38 +03:00
// Yes, we have an expression
return DSP_EA_ABS ;
}
else if ( * tok = = ' > ' )
{
// Check for immediate address forced long
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
if ( ( dspImmedEXATTR & DEFINED ) & & ( dspImmedEXVAL > 0xFFFFFF ) )
return error ( " long address is bigger than $FFFFFF " ) ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
// Yes, we have an expression
return DSP_EA_ABS ;
}
else if ( * tok = = ' < ' )
{
// Check for immediate address forced short
tok + + ;
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
if ( ( dspImmedEXATTR & DEFINED ) & & ( dspImmedEXVAL > 0xFFF ) )
return error ( " short addressing mode forced but address is bigger than $FFF " ) ;
// Yes, we have an expression
return DSP_EA_ABS ;
}
else
{
ea1 = checkea ( termchar , strings ) ;
if ( ea1 = = ERROR )
return ERROR ;
else
return ea1 ;
}
2018-06-23 19:57:21 +03:00
}
2019-08-08 02:24:52 +03:00
2018-06-23 19:57:21 +03:00
//
// Main routine to check parallel move modes.
2019-08-08 02:24:52 +03:00
// It's quite complex so it's split into a few procedures (in fact most of the
// above ones). A big effort was made so this can be managable and not too
// hacky, however one look at the 56001 manual regarding parallel moves and
// you'll know that this is not an easy // problem to deal with!
// dest=destination register from the main opcode. This must not be the same
// as D1 or D2 and that even goes for stuff like dest=A, D1=A0/1/2!!!
2018-06-23 19:57:21 +03:00
//
LONG parmoves ( WORD dest )
{
2019-08-08 02:24:52 +03:00
int force_imm ; // Addressing mode force operator
int immreg ; // Immediate register destination
LONG inst ; // 16 bit bitfield that has the parallel move opcode
LONG S1 , S2 , D1 , D2 ; // Source and Destinations
LONG ea1 ; // ea bitfields
if ( * tok = = EOL )
{
// No parallel move
2022-03-24 12:29:46 +02:00
return 0 b0010000000000000 ;
2019-08-08 02:24:52 +03:00
}
if ( * tok = = ' # ' )
{
// '#xxxxxx,D', '#xx,D'
tok + + ;
force_imm = NUM_NORMAL ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = ' > ' )
{
force_imm = NUM_FORCE_LONG ;
tok + + ;
}
else if ( * tok = = ' < ' )
{
force_imm = NUM_FORCE_SHORT ;
tok + + ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( expr ( dspImmedEXPR , & dspImmedEXVAL , & dspImmedEXATTR , & dspImmedESYM ) ! = OK )
return ERROR ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " expected comma " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 13:28:09 +02:00
if ( ! ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) ) )
2019-08-08 02:24:52 +03:00
return error ( " expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
immreg = SDreg ( * tok + + ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok = = EOL )
{
if ( ! ( dspImmedEXATTR & FLOAT ) )
{
if ( dspImmedEXATTR & DEFINED )
{
// From I parallel move:
2020-08-03 20:16:38 +03:00
// "If the destination register D is X0, X1, Y0, Y1, A, or
// B, the 8-bit immediate short operand is interpreted as
// a signed fraction and is stored in the specified
// destination register. That is, the 8 - bit data is
// stored in the eight MS bits of the destination operand,
// and the remaining bits of the destination operand D are
// zeroed."
// The funny bit is that Motorola assembler can parse
// something like 'move #$FF0000,b' into an I (immediate
// short move) - so let's do that as well then...
2019-08-08 02:24:52 +03:00
if ( ( ( immreg > = 4 & & immreg < = 7 ) | | immreg = = 14 | | immreg = = 15 ) & & force_imm ! = NUM_FORCE_LONG )
{
2020-08-03 20:16:38 +03:00
if ( ( dspImmedEXVAL & 0xFFFF ) = = 0 )
2019-08-08 02:24:52 +03:00
{
dspImmedEXVAL > > = 16 ;
}
}
if ( force_imm = = NUM_FORCE_SHORT )
{
if ( dspImmedEXVAL < 0xFF & & ( int32_t ) dspImmedEXVAL > - 0x100 )
{
// '#xx,D'
// value fits in 8 bits - immediate move
2022-03-24 12:29:46 +02:00
inst = 0 b0010000000000000 + ( immreg < < 8 ) + ( uint32_t ) dspImmedEXVAL ;
2019-08-08 02:24:52 +03:00
return inst ;
}
else
{
2021-07-16 15:04:22 +03:00
if ( CHECK_OPTS ( OPT_56K_AUTO_LONG ) )
{
if ( optim_warn_flag )
warn ( " forced short immediate value doesn't fit in 8 bits - switching to long " ) ;
force_imm = NUM_FORCE_LONG ;
}
else
{
return error ( " forced short immediate value doesn't fit in 8 bits - turn opt switch o11 on to bypass " ) ;
}
2019-08-08 02:24:52 +03:00
}
}
if ( force_imm = = NUM_FORCE_LONG )
{
// '#xxxxxx,D'
// it can either be
// X or Y Data move. I don't think it matters much
// which of the two it will be, so let's use X.
deposit_immediate_long_with_register :
2022-03-24 12:29:46 +02:00
inst = 0 b0100000011110100 ;
2019-08-08 02:24:52 +03:00
inst | = ( ( immreg & 0x18 ) < < ( 12 - 3 ) ) + ( ( immreg & 7 ) < < 8 ) ;
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
return inst ;
}
if ( ( ( int32_t ) dspImmedEXVAL < 0x100 ) & & ( ( int32_t ) dspImmedEXVAL > = - 0x100 ) )
{
// value fits in 8 bits - immediate move
deposit_immediate_short_with_register :
2022-03-24 12:29:46 +02:00
inst = 0 b0010000000000000 + ( immreg < < 8 ) + ( uint32_t ) dspImmedEXVAL ;
2019-08-08 02:24:52 +03:00
return inst ;
}
else
{
// value doesn't fit in 8 bits, so it can either be
// X or Y Data move. I don't think it matters much
// which of the two it will be, so let's use X:.
// TODO: if we're just goto'ing perhaps the logic can be simplified
goto deposit_immediate_long_with_register ;
}
}
else
{
if ( force_imm ! = NUM_FORCE_SHORT )
{
// '#xxxxxx,D'
// TODO: if we're just goto'ing perhaps the logic can be simplified
goto deposit_immediate_long_with_register ;
}
else
{
// '#xx,D' - I mode
// No visibility of the number so let's add a fixup for this
AddFixup ( FU_DSPIMM8 , sloc , dspImmedEXPR ) ;
2022-03-24 12:29:46 +02:00
inst = 0 b0010000000000000 ;
2019-08-08 02:24:52 +03:00
inst | = ( ( immreg & 0x18 ) < < ( 11 - 3 ) ) + ( ( immreg & 7 ) < < 8 ) ;
return inst ;
}
}
}
else
{
// Float constant
if ( dspImmedEXATTR & DEFINED )
{
double f = * ( double * ) & dspImmedEXVAL ;
// Check direct.c for ossom comments regarding conversion!
2021-07-16 15:04:22 +03:00
//N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
2019-08-08 02:24:52 +03:00
dspImmedEXVAL = ( ( uint32_t ) ( int32_t ) round ( f * ( 1 < < 23 ) ) ) & 0xFFFFFF ;
double g ;
g = f * ( 1 < < 23 ) ;
g = round ( g ) ;
if ( ( dspImmedEXVAL & 0xFFFF ) = = 0 )
{
2022-04-17 11:40:46 +03:00
if ( CHECK_OPTS ( OPT_56K_SHORT ) )
2021-07-16 15:04:22 +03:00
{
// Value's 16 lower bits are not set so the value can
// fit in a single byte (check parallel I move quoted
// above)
if ( optim_warn_flag )
warn ( " o10: Immediate value fits inside 8 bits, so using instruction short format " ) ;
2020-08-03 20:16:38 +03:00
2021-07-16 15:04:22 +03:00
dspImmedEXVAL > > = 16 ;
goto deposit_immediate_short_with_register ;
}
else
{
2022-04-17 11:40:46 +03:00
return error ( " Immediate value fits inside 8 bits, so using instruction short format - turn opt switch o10 on to bypass " ) ;
2021-07-16 15:04:22 +03:00
}
2019-08-08 02:24:52 +03:00
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( force_imm = = NUM_FORCE_SHORT )
{
if ( ( dspImmedEXVAL & 0xFFFF ) ! = 0 )
{
2021-07-16 15:04:22 +03:00
if ( CHECK_OPTS ( OPT_56K_AUTO_LONG ) )
{
if ( optim_warn_flag )
2022-04-17 11:40:46 +03:00
warn ( " o11: Immediate value short format forced but value does not fit inside 8 bits - switching to long format " ) ;
2020-08-03 20:16:38 +03:00
2021-07-16 15:04:22 +03:00
goto deposit_immediate_long_with_register ;
}
else
{
2022-04-17 11:40:46 +03:00
return error ( " Immediate value short format forced but value does not fit inside 8 bits - turn opt switch o11 on to bypass " ) ;
2021-07-16 15:04:22 +03:00
}
2019-08-08 02:24:52 +03:00
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
return error ( " internal assembler error: we haven't implemented floating point constants in parallel mode parser yet! " ) ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
// If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
goto deposit_immediate_long_with_register ;
}
else
{
if ( force_imm = = NUM_FORCE_SHORT )
{
2018-06-23 19:57:21 +03:00
goto deposit_immediate_short_with_register ;
2019-08-08 02:24:52 +03:00
}
else
{
// Just deposit a float fixup
AddFixup ( FU_DSPIMMFL8 , sloc , dspImmedEXPR ) ;
2022-03-24 12:29:46 +02:00
inst = 0 b0010000000000000 ;
2019-08-08 02:24:52 +03:00
inst | = ( ( immreg & 0x18 ) < < ( 12 - 3 ) ) + ( ( immreg & 7 ) < < 8 ) ;
return inst ;
}
}
}
}
else
{
// At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
switch ( immreg )
{
case 4 : D1 = 0 < < 10 ; break ; // X0
case 5 : D1 = 1 < < 10 ; break ; // X1
case 14 : D1 = 2 < < 10 ; break ; // A
case 15 : D1 = 3 < < 10 ; break ; // B
default : return error ( " unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2' " ) ; break ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_A : S2 = 0 < < 9 ; break ;
case REG56_B : S2 = 1 < < 9 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2' " ) ; break ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2' " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_Y0 : D2 = 0 < < 8 ; break ;
case REG56_Y1 : D2 = 1 < < 8 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2' " ) ; break ;
}
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok ! = EOL )
return error ( " unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
inst = 0 b0001000010110100 | D1 | S2 | D2 ;
2019-08-08 02:24:52 +03:00
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
return inst ;
}
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_X )
2019-08-08 02:24:52 +03:00
{
2018-06-23 19:57:21 +03:00
if ( tok [ 1 ] = = ' , ' )
// Hey look, it's just the register X and not the addressing mode - fall through to general case
goto parse_everything_else ;
tok + + ;
if ( * tok + + ! = ' : ' )
2019-08-08 02:24:52 +03:00
return error ( " expected ':' after 'X' in parallel move (i.e. X:) " ) ;
2018-06-23 19:57:21 +03:00
// 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
2022-03-24 12:29:46 +02:00
return parse_x ( 1 , 0 b0100000000000000 , 0 , 1 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
2018-06-23 19:57:21 +03:00
if ( tok [ 1 ] = = ' , ' )
// Hey look, it's just the register y and not the addressing mode - fall through to general case
goto parse_everything_else ;
tok + + ;
2019-08-08 02:24:52 +03:00
2018-06-23 19:57:21 +03:00
if ( * tok + + ! = ' : ' )
2019-08-08 02:24:52 +03:00
return error ( " expected ':' after 'Y' in parallel move (i.e. Y:) " ) ;
2018-06-23 19:57:21 +03:00
// 'Y:ea,D' or 'Y:aa,D'
2022-03-24 12:29:46 +02:00
return parse_y ( 0 b0100100010000000 , 0 , 0 , 0 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_L )
2019-08-08 02:24:52 +03:00
{
// 'L:ea,D' or 'L:aa,D'
tok + + ;
if ( * tok + + ! = ' : ' )
return error ( " expected ':' after 'L' in parallel move (i.e. L:) " ) ;
2022-03-24 12:29:46 +02:00
return parse_l ( 1 , 0 b0100000011000000 , 0 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) | | ( * tok > = REG56_A10 & & * tok < = REG56_BA ) )
2019-08-08 02:24:52 +03:00
{
// Everything else - brace for impact!
// R: 'S,D'
// X: 'S,X:ea' 'S,X:aa'
// X:R 'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
// Y: 'S,Y:ea' 'S,Y:aa'
// R:Y: 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 #xxxxxx,D2' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
// L: 'S,L:ea' 'S,L:aa'
2018-06-23 19:57:21 +03:00
LONG L_S1 ;
parse_everything_else :
L_S1 = * tok + + ;
S1 = SDreg ( L_S1 ) ;
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' , ' )
return error ( " Comma expected after 'S') " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 13:28:09 +02:00
if ( * tok = = REG56_X )
2019-08-08 02:24:52 +03:00
{
// 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
// 'A,X:ea X0,A' 'B,X:ea X0,B'
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' : ' )
return error ( " unrecognised X: parallel move syntax: expected ':' after 'S,X' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
return parse_x ( 0 , 0 b0100000000000000 , S1 , 1 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
// 'S,Y:ea' 'S,Y:aa'
tok + + ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
if ( * tok + + ! = ' : ' )
return error ( " unrecognised Y: parallel move syntax: expected ':' after 'S,Y' " ) ;
2018-06-23 19:57:21 +03:00
2022-03-24 12:29:46 +02:00
return parse_y ( 0 b000000000000000 , S1 , 0 , 0 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_L )
2019-08-08 02:24:52 +03:00
{
// 'S,L:ea' 'S,L:aa'
tok + + ;
if ( * tok + + ! = ' : ' )
return error ( " unrecognised L: parallel move syntax: expected ':' after 'S,L' " ) ;
2022-03-24 12:29:46 +02:00
return parse_l ( 1 , 0 b0000000000000000 , L_S1 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( ( * tok > = REG56_X0 & & * tok < = REG56_N7 ) | | ( * tok > = REG56_R0 & & * tok < = REG56_R7 ) | | ( * tok > = REG56_A0 & & * tok < = REG56_A2 ) )
2019-08-08 02:24:52 +03:00
{
// 'S,D'
// 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
// 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
D1 = SDreg ( * tok + + ) ;
if ( * tok = = EOL )
{
// R 'S,D'
2022-03-24 12:29:46 +02:00
inst = 0 b0010000000000000 ;
2019-08-08 02:24:52 +03:00
inst | = ( S1 < < 5 ) | ( D1 ) ;
return inst ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_Y )
2019-08-08 02:24:52 +03:00
{
// 'S1,D1 Y:ea,D2'
tok + + ;
if ( * tok + + ! = ' : ' )
return error ( " expected ':' after 'Y' in parallel move (i.e. Y:) " ) ;
2022-03-24 12:29:46 +02:00
return parse_y ( 0 b0001000001000000 , S1 , D1 , 0 ) ;
2019-08-08 02:24:52 +03:00
}
2022-03-24 13:28:09 +02:00
else if ( * tok = = REG56_A | | * tok = = REG56_B | | * tok = = REG56_Y0 | | * tok = = REG56_Y1 )
2019-08-08 02:24:52 +03:00
{
// 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
S2 = SDreg ( * tok + + ) ;
if ( S1 = = 6 & & D1 = = 14 & & S2 = = 14 )
{
// 'Y0,A A,Y:ea'
if ( * tok + + ! = ' , ' )
return error ( " unrecognised Y: parallel move syntax: expected ',' after Y0,A A " ) ;
2022-03-24 13:28:09 +02:00
if ( * tok + + ! = REG56_Y )
2019-08-08 02:24:52 +03:00
return error ( " unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A, " ) ;
if ( * tok + + ! = ' : ' )
return error ( " unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y " ) ;
ea1 = checkea_full ( EOL , Y_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
2022-03-24 12:29:46 +02:00
inst = 0 b0000100010000000 ;
2019-08-08 02:24:52 +03:00
inst | = 0 < < 8 ;
inst | = ea1 ;
return inst ;
}
else if ( S1 = = 6 & & D1 = = 15 & & S2 = = 15 )
{
// 'Y0,B B,Y:ea'
if ( * tok + + ! = ' , ' )
return error ( " unrecognised Y: parallel move syntax: expected ',' after Y0,B B " ) ;
2022-03-24 13:28:09 +02:00
if ( * tok + + ! = REG56_Y )
2019-08-08 02:24:52 +03:00
return error ( " unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B, " ) ;
if ( * tok + + ! = ' : ' )
return error ( " unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y " ) ;
ea1 = checkea_full ( EOL , Y_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
2022-03-24 12:29:46 +02:00
inst = 0 b0000100010000000 ;
2019-08-08 02:24:52 +03:00
inst | = 1 < < 8 ;
inst | = ea1 ;
return inst ;
}
else if ( ( S1 = = 14 | | S1 = = 15 ) & & ( D1 = = 4 | | D1 = = 5 ) & & ( S2 = = 6 | | S2 = = 7 | | S2 = = 14 | | S2 = = 15 ) )
{
//'S1,D1 S2,Y:ea'
if ( * tok + + ! = ' , ' )
return error ( " unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2 " ) ;
2022-03-24 13:28:09 +02:00
if ( * tok + + ! = REG56_Y )
2019-08-08 02:24:52 +03:00
return error ( " unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2, " ) ;
if ( * tok + + ! = ' : ' )
return error ( " unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y " ) ;
ea1 = checkea_full ( EOL , Y_ERRORS ) ;
if ( ea1 = = ERROR )
return ERROR ;
2022-03-24 12:29:46 +02:00
inst = 0 b0001000001000000 ;
2019-08-08 02:24:52 +03:00
inst | = ( S1 & 1 ) < < 11 ;
inst | = ( D1 & 1 ) < < 10 ;
inst | = ( ( S2 & 8 ) < < ( 10 - 4 ) ) | ( ( S2 & 1 ) < < 8 ) ;
inst | = ea1 ;
return inst ;
}
else
return error ( " unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed' " ) ;
// Check for Y:
}
else if ( * tok = = ' # ' )
{
// R:Y: 'S1,D1 #xxxxxx,D2'
tok + + ;
if ( * tok = = ' > ' )
{
// Well, forcing an immediate to be 24 bits is legal here
// but then it's the only available option so my guess is that this
// is simply superfluous. So let's just eat the character
tok + + ;
}
if ( expr ( dspaaEXPR , & dspaaEXVAL , & dspaaEXATTR , & dspaaESYM ) ! = OK )
return ERROR ;
2020-08-03 20:16:38 +03:00
if ( ( dspImmedEXATTR & DEFINED ) & & ( dspImmedEXVAL > 0xFFFFFF ) )
return error ( " immediate is bigger than $FFFFFF " ) ;
2019-08-08 02:24:52 +03:00
deposit_extra_ea = DEPOSIT_EXTRA_WORD ;
if ( * tok + + ! = ' , ' )
return error ( " Comma expected after 'S1,D1 #xxxxxx') " ) ;
// S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
switch ( * tok + + )
{
2022-03-24 13:28:09 +02:00
case REG56_Y0 : D2 = 0 < < 8 ; break ;
case REG56_Y1 : D2 = 1 < < 8 ; break ;
case REG56_A : D2 = 2 < < 8 ; break ;
case REG56_B : D2 = 3 < < 8 ; break ;
2019-08-08 02:24:52 +03:00
default : return error ( " unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2' " ) ;
}
if ( S1 = = 14 | | S1 = = 15 )
{
if ( D1 = = 4 | | D1 = = 5 )
{
2022-03-24 12:29:46 +02:00
inst = 0 b0001000011110100 ;
2019-08-08 02:24:52 +03:00
inst | = ( S1 & 1 ) < < 11 ;
inst | = ( D1 & 1 ) < < 10 ;
inst | = D2 ;
dspImmedEXVAL = dspaaEXVAL ;
return inst ;
}
else
return error ( " unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2' " ) ;
}
else
return error ( " unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2' " ) ;
}
else
return error ( " unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2' " ) ;
}
else
return error ( " unrecognised R:Y: parallel move syntax: Unexpected text after 'S,' " ) ;
}
else if ( * tok = = ' ( ' )
{
// U: 'ea'
// U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
tok + + ;
2022-03-24 13:28:09 +02:00
if ( * tok > = REG56_R0 & & * tok < = REG56_R7 )
2019-08-08 02:24:52 +03:00
{
2022-03-24 13:28:09 +02:00
ea1 = ( * tok + + - REG56_R0 ) ;
2019-08-08 02:24:52 +03:00
}
else
return error ( " unrecognised U parallel move syntax: expected 'Rn' after '(' " ) ;
if ( * tok + + ! = ' ) ' )
return error ( " unrecognised U parallel move syntax: expected ') ' after ' ( Rn ' " ) ;
if ( * tok = = ' + ' )
{
tok + + ;
if ( * tok = = EOL )
// (Rn)+
ea1 | = 3 < < 3 ;
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2019-08-08 02:24:52 +03:00
{
// (Rn)+Nn
if ( ( * tok + + & 7 ) ! = ea1 )
return error ( " unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn) + Nn ' ) " ) ;
ea1 | = 1 < < 3 ;
if ( * tok ! = EOL )
return error ( " unrecognised U parallel move syntax: expected End-Of-Line after '(Rn) + Nn ' " ) ;
}
else
return error ( " unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn) + ' " ) ;
}
else if ( * tok = = ' - ' )
{
tok + + ;
if ( * tok = = EOL )
{
// (Rn)-
ea1 | = 2 < < 3 ;
tok + + ;
}
2022-03-24 13:28:09 +02:00
else if ( * tok > = REG56_N0 & & * tok < = REG56_N7 )
2019-08-08 02:24:52 +03:00
{
// (Rn)-Nn
if ( ( * tok + + & 7 ) ! = ea1 )
return error ( " unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn) - Nn ' ) " ) ;
ea1 | = 0 < < 3 ;
if ( * tok ! = EOL )
return error ( " unrecognised U parallel move syntax: expected End-Of-Line after '(Rn) - Nn ' " ) ;
}
}
2022-03-24 12:29:46 +02:00
inst = 0 b0010000001000000 ;
2019-08-08 02:24:52 +03:00
inst | = ea1 ;
return inst ;
}
else
return error ( " extra (unexpected) text found " ) ;
2018-06-23 19:57:21 +03:00
2019-08-08 02:24:52 +03:00
return OK ;
2018-06-23 19:57:21 +03:00
}