Skip to content

Commit

Permalink
Revert "Merge pull request #18 from sarnau/revert-17-fixes"
Browse files Browse the repository at this point in the history
This reverts commit e0272e2, reversing
changes made to 3963126.
  • Loading branch information
sarnau committed Sep 13, 2024
1 parent e0272e2 commit af6291a
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 67 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ DEPS = z80_assembler.h
%.o: %.cp $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

all: z80assembler z80disassembler

z80assembler: z80_assembler.o z80_tokenize.o z80_compile.o z80_calc.o
z80assembler: z80_assembler.o z80_tokenize.o z80_compile.o z80_calc.o kk_ihex_write.o
$(CC) -o $@ $^ $(CFLAGS)

z80disassembler: z80_disassembler.o
Expand Down
325 changes: 263 additions & 62 deletions z80_assembler.cp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,29 @@
* Z80 Assembler
***/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <cctype>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include "kk_ihex_write.h"
#include "z80_assembler.h"

uint32_t PC; // current address
uint32_t nextPC; // remember address
uint8_t *RAM; // RAM of the Z80
const uint32_t RAMSIZE = 0x10000;
uint32_t minPC = RAMSIZE;
uint32_t maxPC = 0;
bool listing = false;

static FILE *infile;
static FILE *outbin;
static FILE *outhex;

int verboseMode = 0;

long LineNo; // current line number
char LineBuf[MAXLINELENGTH]; // buffer for the current line

Expand All @@ -20,95 +35,281 @@ void Error(const char* s)
{
const char *p;

printf("Fehler in Zeile %ld: %s\n",LineNo,s);
printf("Error in line %ld: %s\n",LineNo,s);
for(p = LineBuf;isspace(*p);p++)
;
puts(p);
exit(1);
}


void usage( const char *fullpath ) {
const char *progname = nullptr;
char c;
while ( ( c = *fullpath++ ) )
if ( c == '/' || c == '\\' )
progname = fullpath;
printf( "Usage: %s [-l] [-n] [-v] INFILE\n"
" -c CP/M com file format for binary\n"
" -fXX fill ram with byte XX (default: 00)\n"
" -l show listing\n"
" -n no output files\n"
" -oXXXX offset address = 0x0000 .. 0xFFFF\n"
" -v increase verbosity\n",
progname );
}


static void listOneLine( uint32_t firstPC, uint32_t lastPC, const char *oneLine );


/***
* …
***/
int main(void)
int main( int argc, char **argv )
{
FILE *f;
char* s;
int32_t i;
char *filename = nullptr;

LineNo = 1;
InitSymTab(); // init symbol table
char *oneLine;
int i, j;

int com = 0;
int offset = 0;
// int start = 0;
int fill = 0;
int result;
bool no_outfile = false;

RAM = (uint8_t*)malloc(65536);
memset(RAM,0xFF,65536); // erase 64K RAM
PC = 0x0000; // default start address of the code

puts("TurboAss Z80 - a small 1-pass assembler for Z80 code");
puts("(c)1992/3 Sigma-Soft, Markus Fritze");
puts("");

f = fopen("FuturaFirmware.asm","r");
if(!f) {
Error("File 'FuturaFirmware.asm' not found");

for ( i = 1, j = 0; i < argc; i++ ) {
if ( '-' == argv[ i ][ 0 ] ) {
switch ( argv[ i ][ ++j ] ) {
case 'c': // create cp/m com file
com = 0x100;
break;
case 'f': // fill
if ( argv[ i ][ ++j ] ) // "-fXX"
result = sscanf( argv[ i ] + j, "%x", &fill );
else if ( i < argc - 1 ) // "-f XX"
result = sscanf( argv[ ++i ], "%x", &fill );
if ( result )
fill &= 0x00FF; // limit to byte size
else {
fprintf( stderr, "Error: option -f needs a hexadecimal argument\n" );
return 1;
}
j = 0; // end of this arg group
break;
case 'l': // parse program flow
listing = true;
break;
case 'n': // parse program flow
no_outfile = true;
break;
case 'o': // program offset
if ( argv[ i ][ ++j ] ) // "-oXXXX"
result = sscanf( argv[ i ] + j, "%x", &offset );
else if ( i < argc - 1 ) // "-o XXXX"
result = sscanf( argv[ ++i ], "%x", &offset );
if ( result )
offset &= 0xFFFF; // limit to 64K
else {
fprintf( stderr, "Error: option -o needs a hexadecimal argument\n" );
return 1;
}
j = 0; // end of this arg group
break;
case 'v':
++verboseMode;
break;
default:
usage( argv[ 0 ] );
return 1;
}

if ( j && argv[ i ][ j + 1 ] ) { // one more arg char
--i; // keep this arg group
continue;
}
j = 0; // start from the beginning in next arg group
} else {
if ( !filename )
filename = argv[ i ];
else {
usage( argv[ 0 ] );
return 1;
} // check next arg string
}
}
if ( !filename ) {
usage( argv[ 0 ] );
return 1;
}

infile = fopen( filename, "r" );
if ( !infile ) {
fprintf( stderr, "Error: cannot open infile %s\n", filename );
return 1;
}
while(1) {
s = fgets(LineBuf,sizeof(LineBuf),f); // read a single line
if(!s) break; // end of the code => exit
*(s + strlen(s) - 1) = 0; // remove end of line marker
TokenizeLine(s); // tokenize line
MSG( 1, "Processing infile \"%s\"\n", filename );

LineNo = 1;
InitSymTab(); // init symbol table

RAM = (uint8_t*)malloc(RAMSIZE+256);// guard against overflow at ram top
memset(RAM, fill, RAMSIZE); // erase 64K RAM
PC = 0x0000; // default start address of the code

while( true ) {
uint32_t prevPC = PC;
oneLine = fgets(LineBuf,sizeof(LineBuf),infile); // read a single line
if(!oneLine) break; // end of the code => exit
*(oneLine + strlen(oneLine) - 1) = 0; // remove end of line marker
TokenizeLine( oneLine ); // tokenize line
CompileLine(); // generate machine code for the line
listOneLine( prevPC, PC, oneLine ); // create listing if enabled
LineNo++; // next line
}
fclose(f);
list( "\n" );
fclose( infile );

// puts("undefined symbols:");
// cross reference
for(i=0;i<256;i++) { // iterate over symbol table
SymbolP s;
for(s = SymTab[i];s;s = s->next)
if(s->recalc) // depend expressions on a symbol?
printf("symbol \"%s\" undefined!\n",s->name);
printf("---- %s is undefined!\n",s->name);
else if ( !s->type )
list("%04X%*s\n", s->val, 20 + int( strlen( s->name ) ), s->name );
}

#if 0
puts("Read original EPROM");
f = fopen("EPROM","rb");
if(!f) exit(1);
uint8_t EPROM[0x2000];
fread(EPROM,sizeof(uint8_t),0x2000,f);// read 8K EPROM
fclose(f);

puts("Compare code with the original EPROM");
int32_t j = 0; // and compare
for(i=0;(i<0x2000)&&(j < 10);i++)
if(RAM[i] != EPROM[i]) {
printf("%4.4X : %2.2X != %2.2X\n",(uint16_t)i,RAM[i],EPROM[i]);
j++;
if ( minPC < 0x100 || maxPC <= 0x100 ) // cannot be a CP/M com file
com = 0;

if ( listing || verboseMode ) {
if ( minPC <= maxPC )
printf( "\nUsing RAM range [0x%04X...0x%04X]\n", minPC, maxPC );
else {
printf( "\nNo data created\n" );
exit( 1 );
}
if(!j)
puts("Code is identical to the original EPROM");
else
{
puts("Calculate new 16-bit checksum");
j = 0;
for(i=0;i<0x1FF0;i++)
j += (uint8_t)RAM[i];
{
SymbolP FindSymbol(const char* name);
SymbolP s = FindSymbol("ROMCHECKSUM");
if(s) {
RAM[s->val] = j;
RAM[s->val+1] = j >> 8;
puts("ROMChecksum adjusted.");
} else
puts("ROMChecksum not found");
}

if ( !no_outfile && strlen( filename ) > 4 && !strcmp( filename + strlen( filename ) - 4, ".asm" ) ) {
// create out file name(s) from in file name
sprintf( filename + strlen( filename ) - 3, com ? "com" : "bin" );
MSG( 1, "Creating output file %s\n", filename );
outbin = fopen( filename, "wb" );
if ( !outbin ) {
fprintf( stderr, "Error: Can't open output file \"%s\".\n", filename );
return 1;
}

sprintf( filename + strlen( filename ) - 3, "hex" );
MSG( 1, "Creating output file %s\n", filename );
outhex = fopen( filename, "wb" );
if ( !outhex ) {
fprintf( stderr, "Error: Can't open output file \"%s\".\n", filename );
return 1;
}
} else {
MSG( 1, "No output files created\n" );
exit( 0 );
}
if ( outbin ) {
if ( com )
fwrite( RAM + 0x100, sizeof( uint8_t ), maxPC + 1 - 0x100, outbin );
else
fwrite( RAM + offset, sizeof( uint8_t ), maxPC + 1 - offset, outbin );
fclose( outbin );
}
#endif
if ( outhex ) {
// write the data as intel hex
struct ihex_state ihex;
ihex_init( &ihex );

ihex_write_at_address( &ihex, minPC );
ihex_write_bytes( &ihex, RAM + minPC, maxPC + 1 - minPC );
ihex_end_write( &ihex );
fclose( outhex );
}
return 0;
}


void checkPC( uint32_t pc ) {
MSG( 3, "checkPC( %04X )", pc );
if ( pc >= RAMSIZE ) {
Error("Address overflow -> exit");
exit(0);
}
if ( pc < minPC )
minPC = pc;
if ( pc > maxPC )
maxPC = pc;
MSG( 3, "[%04X..%04X]\n", minPC, maxPC );
}


void MSG( int mode, const char *format, ... ) {
if ( verboseMode >= mode ) {
while ( mode-- )
fprintf( stderr, " " );
va_list argptr;
va_start( argptr, format );
vfprintf( stderr, format, argptr );
va_end( argptr );
}
}


void list( const char *format, ... ) {
if ( listing ) {
va_list argptr;
va_start( argptr, format );
vprintf( format, argptr );
va_end( argptr );
}
}

// create listing for one sorce code line
// address data bytes source code
// break long data block (e.g. defm) into lines of 4 data bytes
static void listOneLine( uint32_t firstPC, uint32_t lastPC, const char *oneLine ) {
if ( !listing )
return;
if ( firstPC == lastPC ) {
printf( "%*s\n", 24 + int(strlen( oneLine ) ), oneLine );
} else {
printf( "%4.4X ", firstPC );
uint32_t adr = firstPC;
int i = 0;
while ( adr < lastPC ) {
printf( " %2.2X", RAM[ adr++ ] );
if ( i == 3 )
printf( " %s", oneLine );
if ( (i & 3) == 3 ) {
printf( "\n" );
if ( adr < lastPC )
printf( "%4.4X ", adr );
}
++i;
}
if ( i < 4 )
printf( "%*s\n", 5+3*(4-i)+int(strlen( oneLine ) ), oneLine );
else if ( (i & 3) )
printf( "\n" );
}
}

f = fopen("Z80.code","wb");
if(!f) exit(1);
fwrite(RAM,sizeof(uint8_t),0x2000,f); // write code to disk
fclose(f);

return 0;
void ihex_flush_buffer( struct ihex_state *ihex, char *buffer, char *eptr ) {
(void)ihex;
*eptr = '\0';
(void)fputs( buffer, outhex );
}
Loading

0 comments on commit af6291a

Please sign in to comment.