From 4d0926e3a9868c4fc521f94a07009bb4115cdb41 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 20 Sep 2024 17:19:39 +0200 Subject: [PATCH] pseudo ops can start with dot; db and dm can mix numbers and strings add undoc opcodes "out (c),0" and "in (c)" Signed-off-by: Martin --- z80_assembler.cpp | 5 ++--- z80_assembler.h | 1 + z80_compile.cpp | 46 +++++++++++++++++++++++++--------------------- z80_tokenize.cpp | 36 +++++++++++++++++++++++++++++++++--- 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/z80_assembler.cpp b/z80_assembler.cpp index efcde58..5d8d1ec 100644 --- a/z80_assembler.cpp +++ b/z80_assembler.cpp @@ -82,9 +82,8 @@ int main( int argc, char **argv ) { bool no_outfile = false; - puts( "TurboAss Z80 - a small 1-pass assembler for Z80 code" ); - puts( "(c)1992/3 Sigma-Soft, Markus Fritze" ); - puts( "" ); + fprintf( stderr, "TurboAss Z80 - a small 1-pass assembler for Z80 code\n" ); + fprintf( stderr, "(c)1992/3 Sigma-Soft, Markus Fritze\n\n" ); for ( i = 1, j = 0; i < argc; i++ ) { diff --git a/z80_assembler.h b/z80_assembler.h index 9561c4c..2ff407e 100644 --- a/z80_assembler.h +++ b/z80_assembler.h @@ -51,6 +51,7 @@ extern const uint32_t RAMSIZE; extern uint32_t minPC; extern uint32_t maxPC; extern bool listing; +extern int verboseMode; extern void checkPC( uint32_t pc ); extern RecalcListP LastRecalc; // to patch the type for incomplete formulas diff --git a/z80_compile.cpp b/z80_compile.cpp index 494e9ce..224775e 100644 --- a/z80_compile.cpp +++ b/z80_compile.cpp @@ -23,6 +23,7 @@ int16_t GetOperand( CommandP *c, int32_t *value ) { *value = 0; typ = ( *c )->typ; val = ( *c )++->val; // get value and type + MSG( 2, "GetOperand( %d, %X, %d )\n", typ, val, *value ); if ( typ == OPCODE ) { if ( ( val >= 0x300 ) && ( val <= 0x4FF ) ) { if ( ( val == 0x323 ) && ( ( *c )->typ == OPCODE ) && ( ( *c )->val == '\'' ) ) { // AF'? @@ -87,6 +88,7 @@ int16_t GetOperand( CommandP *c, int32_t *value ) { * test for an opcode ***/ void DoOpcode( CommandP *cp ) { + MSG( 2, "DoOpcode( %X )\n", (*cp)->val ); CommandP c = *cp; uint8_t *iRAM = RAM + PC; uint32_t op0; @@ -144,6 +146,12 @@ void DoOpcode( CommandP *cp ) { op2Recalc = nullptr; // processing done } *iRAM++ = value2; + } else if ( !(Op0_24 & 0x01) && ( op1 == 0x501 ) && ( op2 == 0 ) ) { // undoc: IN (C)) + *iRAM++ = 0xED; + *iRAM++ = 0x70; + } else if ( (Op0_24 & 0x01) && ( op1 == 0x281 ) && ( op2 == 0x501 ) && value1 == 0 ) { // undoc: OUT (C),0 + *iRAM++ = 0xED; + *iRAM++ = 0x71; } else Error( "operands not allowed for IN/OUT" ); break; @@ -859,39 +867,34 @@ void DoOpcode( CommandP *cp ) { bool IgnoreUntilIF = false; // ignore all lines till next "ENDIF" (this could be a stack for nesting support) void DoPseudo( CommandP *cp ) { + MSG( 2, "DoPseudo( %d, %X )\n", (*cp)->typ, (*cp)->val ); CommandP c = *cp; CommandP cptr; uint16_t iPC = PC; switch ( c++->val ) { // all pseudo opcodes case DEFB: + case DEFM: c--; do { - c++; - cptr = c; - checkPC( iPC ); - RAM[ iPC++ ] = CalcTerm( &cptr ); - c = cptr; - if ( LastRecalc ) { // expression undefined? - LastRecalc->typ = 0; // add a single byte - LastRecalc->adr = iPC - 1; - } - } while ( ( c->typ == OPCODE ) && ( c->val == ',' ) ); - break; - case DEFM: - if ( c->typ != STRING ) { - Error( "DEFM requires a string" ); - } else { - char *sp; - c--; - do { - c++; // skip opcode or comma + c++; // skip opcode or comma + if ( c->typ != STRING ) { + cptr = c; + checkPC( iPC ); + RAM[ iPC++ ] = CalcTerm( &cptr ); + c = cptr; + if ( LastRecalc ) { // expression undefined? + LastRecalc->typ = 0; // add a single byte + LastRecalc->adr = iPC - 1; + } + } else { + char *sp; sp = (char *)c++->val; // value = ptr to the string checkPC( iPC + strlen( sp ) - 1 ); // will it overflow? while ( *sp ) RAM[ iPC++ ] = *sp++; // transfer the string - } while ( ( c->typ == OPCODE ) && ( c->val == ',' ) ); - } + } + } while ( ( c->typ == OPCODE ) && ( c->val == ',' ) ); break; case DEFS: cptr = c; @@ -957,6 +960,7 @@ void DoPseudo( CommandP *cp ) { * Compile a single line ***/ void CompileLine( void ) { + MSG( 2, "CompileLine()\n" ); CommandP c = Cmd; CommandP cptr; SymbolP s; diff --git a/z80_tokenize.cpp b/z80_tokenize.cpp index 9ded095..2d3de0c 100644 --- a/z80_tokenize.cpp +++ b/z80_tokenize.cpp @@ -200,6 +200,7 @@ void TokenizeLine( char *sp ) { char maxc; int16_t base; // binary, decimal or hex bool dollar; // token starts with $ + bool dot; Type typ; long val; char AktUpLine[ MAXLINELENGTH ]; @@ -220,8 +221,12 @@ void TokenizeLine( char *sp ) { tp = sp - 1; // pointer to current token typ = ILLEGAL; // default: an illegal type base = 0; - dollar = false; - if ( c == '$' ) { // PC or the beginning of a hex number + dot = false; // pseudo opcodes can start with '.' + dollar = false; // $ = PC + if ( c == '.') { + c = *sp++; + dot = true; + } else if ( c == '$' ) { // PC or the beginning of a hex number if ( isalnum( *sp ) && *sp <= 'F' ) { base = 16; c = *sp++; @@ -278,6 +283,8 @@ void TokenizeLine( char *sp ) { if ( !sym ) break; // error (out of memory) if ( !sym->type ) { // typ = symbol? + if ( dot ) + Error( "symbols can't start with '.'" ); typ = SYMBOL; val = (long)sym; // value = address of the symbol ptr if ( !sym->first ) { // symbol already exists? @@ -287,6 +294,8 @@ void TokenizeLine( char *sp ) { } else { typ = OPCODE; // an opcode val = sym->val; // parameter, ID + if ( dot && ( val < 0x100 || val >= 0x200 ) ) // only pseudo opcodes + Error( "opcodes can't start with '.'" ); } } else Error( "symbols can't start with '$' or digits" ); @@ -343,7 +352,28 @@ void TokenizeLine( char *sp ) { cp->typ = typ; cp->val = val; // copy into the command buffer cp++; - MSG( 2, "type:%2.2X value:%8.8lX\n", typ, val ); + + if ( verboseMode >= 3 ) + switch( typ ) { + case ILLEGAL: + MSG( 3, "ILLEGAL\n" ); + break; + case NUM: + MSG( 3, "NUM: %lX\n", val ); + break; + case OPCODE: + if ( val < 0x100 ) + MSG( 3, "OPCODE: '%c'\n", val ); + else + MSG( 3, "OPCODE: %lX\n", val ); + break; + case SYMBOL: + MSG( 3, "SYMBOL: %s\n", val ); + break; + case STRING: + MSG( 3, "STRING: \"%s\"\n", (char *)val ); + break; + } } cp->typ = ILLEGAL; cp->val = 0; // terminate the command buffer