Initial commit of z80as (and hex2bin) source.
This commit is contained in:
parent
fb8cfb89f0
commit
109a8caafa
|
@ -0,0 +1,27 @@
|
|||
Copyright © 1977-1995 by Robert Swartz. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is"
|
||||
and any express or implied warranties, including, but not limited to, the
|
||||
implied warranties of merchantability and fitness for a particular purpose
|
||||
are disclaimed. In no event shall the copyright holder or contributors be
|
||||
liable for any direct, indirect, incidental, special, exemplary, or
|
||||
consequential damages (including, but not limited to, procurement of
|
||||
substitute goods or services; loss of use, data, or profits; or business
|
||||
interruption) however caused and on any theory of liability, whether in
|
||||
contract, strict liability, or tort (including negligence or otherwise)
|
||||
arising in any way out of the use of this software, even if advised of the
|
||||
possibility of such damage.
|
|
@ -0,0 +1,16 @@
|
|||
CC = cc
|
||||
CFLAGS = -O2 -Wall
|
||||
|
||||
all: z80as hex2bin
|
||||
|
||||
z80as: as0.o as1.o as2.o as3.o as4.o as5.o as6.o
|
||||
$(CC) -o z80as.x86 as0.o as1.o as2.o as3.o as4.o as5.o as6.o
|
||||
|
||||
hex2bin: hex2bin.c
|
||||
$(CC) -o hex2bin hex2bin.c
|
||||
|
||||
install:
|
||||
su root cp z80as.x86 /usr/local/bin/z80as
|
||||
|
||||
clean:
|
||||
rm -f z80as.x86 hex2bin *.o
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Header file, used by all
|
||||
* parts of the assembler.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#ifdef vax
|
||||
#include stsdef
|
||||
#include ssdef
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Table sizes, etc.
|
||||
*/
|
||||
#define NCPS 8 /* # of characters in symbol */
|
||||
#define NHASH 64 /* # of hash buckets */
|
||||
#define HMASK 077 /* Mask for above */
|
||||
#define NFNAME 32 /* # of characters in filename */
|
||||
#define NERR 10 /* Size of error buffer */
|
||||
#define NCODE 128 /* # of characters in code buffer */
|
||||
#define NINPUT 128 /* # of characters in input line */
|
||||
#define NLPP 60 /* # of lines on a page */
|
||||
#define XXXX 0 /* Unused value */
|
||||
|
||||
/*
|
||||
* Exit codes.
|
||||
*/
|
||||
#ifdef vax
|
||||
#define GOOD (SS$_NORMAL)
|
||||
#define BAD (STS$M_INHIB_MSG|SS$_ABORT)
|
||||
#else
|
||||
#define GOOD 0
|
||||
#define BAD 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Listing modes.
|
||||
*/
|
||||
#define NLIST 0 /* No list */
|
||||
#define ALIST 1 /* Address only */
|
||||
#define BLIST 2 /* Byte format */
|
||||
#define WLIST 3 /* Word format */
|
||||
#define SLIST 4 /* Source text only */
|
||||
|
||||
/*
|
||||
* Types. These are used
|
||||
* in both symbols and in address
|
||||
* descriptions. Observe the way the
|
||||
* symbol flags hide in the register
|
||||
* field of the address.
|
||||
*/
|
||||
#define TMREG 0x00FF /* Register code */
|
||||
#define TMMDF 0x0001 /* Multidef */
|
||||
#define TMASG 0x0002 /* Defined by "=" */
|
||||
#define TMMODE 0xFF00 /* Mode */
|
||||
#define TMINDIR 0x8000 /* Indirect flag in mode */
|
||||
|
||||
#define TNEW 0x0000 /* Virgin */
|
||||
#define TUSER 0x0100 /* User name */
|
||||
#define TBR 0x0200 /* Byte register */
|
||||
#define TWR 0x0300 /* Word register */
|
||||
#define TSR 0x0400 /* Special register (I, R) */
|
||||
#define TDEFB 0x0500 /* defb */
|
||||
#define TDEFW 0x0600 /* defw */
|
||||
#define TDEFS 0x0700 /* defs */
|
||||
#define TDEFM 0x0800 /* defm */
|
||||
#define TORG 0x0900 /* org */
|
||||
#define TEQU 0x0A00 /* equ */
|
||||
#define TCOND 0x0B00 /* conditional */
|
||||
#define TENDC 0x0C00 /* end conditional */
|
||||
#define TNOP 0x0F00 /* nop */
|
||||
#define TRST 0x1000 /* restarts */
|
||||
#define TREL 0x1100 /* djnz, jr */
|
||||
#define TRET 0x1200 /* ret */
|
||||
#define TJMP 0x1300 /* call, jp */
|
||||
#define TPUSH 0x1400 /* push, pop */
|
||||
#define TIM 0x1500 /* im */
|
||||
#define TIO 0x1600 /* in, out */
|
||||
#define TBIT 0x1700 /* set, res, bit */
|
||||
#define TSHR 0x1800 /* sl, sr et al */
|
||||
#define TINC 0x1900 /* inc, dec */
|
||||
#define TEX 0x1A00 /* ex */
|
||||
#define TADD 0x1B00 /* add, adc, sbc */
|
||||
#define TLD 0x1C00 /* ld */
|
||||
#define TCC 0x1D00 /* condition code */
|
||||
#define TSUB 0x1E00 /* sub et al */
|
||||
|
||||
/*
|
||||
* Registers.
|
||||
*/
|
||||
#define B 0
|
||||
#define C 1
|
||||
#define D 2
|
||||
#define E 3
|
||||
#define H 4
|
||||
#define L 5
|
||||
#define M 6
|
||||
#define A 7
|
||||
#define IX 8
|
||||
#define IY 9
|
||||
|
||||
#define BC 0
|
||||
#define DE 1
|
||||
#define HL 2
|
||||
#define SP 3
|
||||
#define AF 4
|
||||
#define AFPRIME 5
|
||||
|
||||
#define I 0
|
||||
#define R 1
|
||||
|
||||
/*
|
||||
* Condition codes.
|
||||
*/
|
||||
#define CNZ 0
|
||||
#define CZ 1
|
||||
#define CNC 2
|
||||
#define CC 3
|
||||
#define CPO 4
|
||||
#define CPE 5
|
||||
#define CP 6
|
||||
#define CM 7
|
||||
|
||||
typedef unsigned int VALUE; /* For symbol values */
|
||||
|
||||
/*
|
||||
* Address description.
|
||||
*/
|
||||
typedef struct ADDR {
|
||||
int a_type; /* Type */
|
||||
VALUE a_value; /* Index offset, etc */
|
||||
} ADDR;
|
||||
|
||||
/*
|
||||
* Symbol.
|
||||
*/
|
||||
typedef struct SYM {
|
||||
struct SYM *s_fp; /* Link in hash */
|
||||
char s_id[NCPS]; /* Name */
|
||||
int s_type; /* Type */
|
||||
VALUE s_value; /* Value */
|
||||
} SYM;
|
||||
|
||||
/*
|
||||
* External variables.
|
||||
*/
|
||||
extern char *cp;
|
||||
extern char *ep;
|
||||
extern char *ip;
|
||||
extern char cb[];
|
||||
extern char eb[];
|
||||
extern char ib[];
|
||||
extern FILE *ifp;
|
||||
extern FILE *ofp;
|
||||
extern FILE *lfp;
|
||||
extern int line;
|
||||
extern int lmode;
|
||||
extern VALUE laddr;
|
||||
extern SYM sym[];
|
||||
extern int pass;
|
||||
extern SYM *phash[];
|
||||
extern SYM *uhash[];
|
||||
extern int lflag;
|
||||
extern jmp_buf env;
|
||||
extern VALUE dot;
|
||||
extern SYM *lookup();
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Command line processing
|
||||
* and main driver.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
FILE *ifp;
|
||||
FILE *ofp;
|
||||
FILE *lfp;
|
||||
char cb[NCODE];
|
||||
char eb[NERR];
|
||||
char ib[NINPUT];
|
||||
char *cp;
|
||||
char *ep;
|
||||
char *ip;
|
||||
int lflag;
|
||||
VALUE laddr;
|
||||
int lmode;
|
||||
VALUE dot;
|
||||
SYM *phash[NHASH];
|
||||
SYM *uhash[NHASH];
|
||||
int pass;
|
||||
int line;
|
||||
jmp_buf env;
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
register char *ifn;
|
||||
register char *p;
|
||||
register int i;
|
||||
register int c;
|
||||
char fn[NFNAME];
|
||||
|
||||
ifn = NULL;
|
||||
for (i=1; i<argc; ++i) {
|
||||
p = argv[i];
|
||||
if (*p == '-') {
|
||||
while ((c = *++p) != 0) {
|
||||
switch (c) {
|
||||
case 'l':
|
||||
++lflag;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Bad option %c\n", c);
|
||||
exit(BAD);
|
||||
}
|
||||
}
|
||||
} else if (ifn == NULL)
|
||||
ifn = p;
|
||||
else {
|
||||
fprintf(stderr, "Too many source files\n");
|
||||
exit(BAD);
|
||||
}
|
||||
}
|
||||
if (ifn == NULL) {
|
||||
fprintf(stderr, "No source file\n");
|
||||
exit(BAD);
|
||||
}
|
||||
if ((ifp=fopen(ifn, "r")) == NULL) {
|
||||
fprintf(stderr, "%s: cannot open\n", ifn);
|
||||
exit(BAD);
|
||||
}
|
||||
mkname(fn, ifn, "hex");
|
||||
if ((ofp=fopen(fn, "w")) == NULL) {
|
||||
fprintf(stderr, "%s: cannot create\n", fn);
|
||||
exit(BAD);
|
||||
}
|
||||
if (lflag != 0) {
|
||||
mkname(fn, ifn, "lis");
|
||||
if ((lfp=fopen(fn, "w")) == NULL) {
|
||||
fprintf(stderr, "%s: cannot create\n", fn);
|
||||
exit(BAD);
|
||||
}
|
||||
}
|
||||
syminit();
|
||||
for (pass=0; pass<2; ++pass) {
|
||||
line = 0;
|
||||
dot = 0;
|
||||
fseek(ifp, 0L, 0);
|
||||
while (fgets(ib, NINPUT, ifp) != NULL) {
|
||||
++line;
|
||||
cp = &cb[0];
|
||||
ep = &eb[0];
|
||||
ip = &ib[0];
|
||||
if (setjmp(env) == 0)
|
||||
asmline();
|
||||
if (pass != 0)
|
||||
list();
|
||||
}
|
||||
}
|
||||
outeof();
|
||||
exit(GOOD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make up a file name.
|
||||
* The "sfn" is the source file
|
||||
* name and "dft" is the desired file
|
||||
* type. The finished name is copied
|
||||
* into the "dfn" buffer.
|
||||
*/
|
||||
mkname(dfn, sfn, dft)
|
||||
char *dfn;
|
||||
char *sfn;
|
||||
char *dft;
|
||||
{
|
||||
register char *p1;
|
||||
register char *p2;
|
||||
register int c;
|
||||
|
||||
p1 = sfn;
|
||||
while (*p1 != 0)
|
||||
++p1;
|
||||
#ifdef vax
|
||||
while (p1!=sfn && p1[-1]!=':' && p1[-1]!=']')
|
||||
--p1;
|
||||
#else
|
||||
while (p1!=sfn && p1[-1]!='/')
|
||||
--p1;
|
||||
#endif
|
||||
p2 = dfn;
|
||||
while ((c = *p1++)!=0 && c!='.')
|
||||
*p2++ = c;
|
||||
*p2++ = '.';
|
||||
p1 = dft;
|
||||
while (*p2++ = *p1++)
|
||||
;
|
||||
}
|
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Assemble one line of input.
|
||||
* Knows all the dirt.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
#define OPDJNZ 0x10 /* Opcode: djnz */
|
||||
#define OPADD 0x80 /* Opcode: add */
|
||||
#define OPDAD 0x09 /* Opcode: dad */
|
||||
#define OPADC 0x88 /* Opcode: adc */
|
||||
#define OPADCW 0x4A /* Opcode: adc hl */
|
||||
#define OPSBCW 0x42 /* Opcode: sbc hl */
|
||||
#define OPSUBI 0xC6 /* Opcode: make immediate */
|
||||
#define OPXCHG 0xEB /* Opcode: xchg */
|
||||
#define OPXTHL 0xE3 /* Opcode: xthl */
|
||||
#define OPEXAF 0x08 /* Opcode: ex af,af' */
|
||||
#define OPRST 0xC7 /* Opcode: rst 0 */
|
||||
#define OPINCRP 0x03 /* Opcode: inc rp */
|
||||
#define OPDECRP 0x0B /* Opcode: dec rp */
|
||||
#define OPINC 0x04 /* Opcode: inc */
|
||||
#define OPIIN 0x40 /* Opcode: indirect in */
|
||||
#define OPIOUT 0x41 /* Opcode: indirect out */
|
||||
#define OPIN 0xDB /* Opcode: in */
|
||||
#define OPIM 0x46 /* Opcode: im */
|
||||
#define OPPCHL 0xE9 /* Opcode: jp (hl) */
|
||||
#define OPJP 0xC3 /* Opcode: jp cc base */
|
||||
#define OPJR 0x20 /* Opcode: jr cc base */
|
||||
#define OPRET 0xC0 /* Opcode: ret cc base */
|
||||
|
||||
/*
|
||||
* Assemble one line.
|
||||
* The line in in "ib", the "ip"
|
||||
* scans along it. The code is written
|
||||
* right out, and also stashed in the
|
||||
* "cb" for the listing.
|
||||
*/
|
||||
asmline()
|
||||
{
|
||||
register SYM *sp;
|
||||
register int c;
|
||||
register int opcode;
|
||||
register int disp;
|
||||
register int reg;
|
||||
register int srcreg;
|
||||
register int cc;
|
||||
register VALUE value;
|
||||
register int delim;
|
||||
register SYM *sp1;
|
||||
char id[NCPS];
|
||||
char id1[NCPS];
|
||||
ADDR a1;
|
||||
ADDR a2;
|
||||
|
||||
laddr = dot;
|
||||
lmode = SLIST;
|
||||
loop:
|
||||
if ((c=getnb())=='\n' || c==';')
|
||||
return;
|
||||
if (isalpha(c) == 0)
|
||||
qerr();
|
||||
getid(id, c);
|
||||
if ((c=getnb()) == ':') {
|
||||
sp = lookup(id, uhash, 1);
|
||||
if (pass == 0) {
|
||||
if ((sp->s_type&TMMODE) != TNEW
|
||||
&& (sp->s_type&TMASG) == 0)
|
||||
sp->s_type |= TMMDF;
|
||||
sp->s_type &= ~TMMODE;
|
||||
sp->s_type |= TUSER;
|
||||
sp->s_value = dot;
|
||||
} else {
|
||||
if ((sp->s_type&TMMDF) != 0)
|
||||
err('m');
|
||||
if (sp->s_value != dot)
|
||||
err('p');
|
||||
}
|
||||
lmode = ALIST;
|
||||
goto loop;
|
||||
}
|
||||
/*
|
||||
* If the first token is an
|
||||
* id and not an operation code,
|
||||
* assume that it is the name in front
|
||||
* of an "equ" assembler directive.
|
||||
*/
|
||||
if ((sp=lookup(id, phash, 0)) == NULL) {
|
||||
getid(id1, c);
|
||||
if ((sp1=lookup(id1, phash, 0)) == NULL
|
||||
|| (sp1->s_type&TMMODE) != TEQU) {
|
||||
err('o');
|
||||
return;
|
||||
}
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
sp = lookup(id, uhash, 1);
|
||||
if ((sp->s_type&TMMODE) != TNEW
|
||||
&& (sp->s_type&TMASG) == 0)
|
||||
err('m');
|
||||
sp->s_type &= ~TMMODE;
|
||||
sp->s_type |= TUSER|TMASG;
|
||||
sp->s_value = a1.a_value;
|
||||
laddr = a1.a_value;
|
||||
lmode = ALIST;
|
||||
goto loop;
|
||||
}
|
||||
unget(c);
|
||||
lmode = BLIST;
|
||||
opcode = sp->s_value;
|
||||
switch (sp->s_type&TMMODE) {
|
||||
case TORG:
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
lmode = ALIST;
|
||||
laddr = dot = a1.a_value;
|
||||
break;
|
||||
|
||||
case TDEFB:
|
||||
do {
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
outab(a1.a_value);
|
||||
} while ((c=getnb()) == ',');
|
||||
unget(c);
|
||||
break;
|
||||
|
||||
case TDEFW:
|
||||
lmode = WLIST;
|
||||
do {
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
outaw(a1.a_value);
|
||||
} while ((c=getnb()) == ',');
|
||||
unget(c);
|
||||
break;
|
||||
|
||||
case TDEFM:
|
||||
if ((delim=getnb()) == '\n')
|
||||
qerr();
|
||||
while ((c=get()) != delim) {
|
||||
if (c == '\n')
|
||||
qerr();
|
||||
outab(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case TDEFS:
|
||||
laddr = dot;
|
||||
lmode = ALIST;
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
dot += a1.a_value;
|
||||
break;
|
||||
|
||||
case TNOP:
|
||||
if ((opcode&0xFF00) != 0)
|
||||
outab(opcode >> 8);
|
||||
outab(opcode);
|
||||
break;
|
||||
|
||||
case TRST:
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
if (a1.a_value < 8) {
|
||||
outab(OPRST|(a1.a_value<<3));
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TREL:
|
||||
getaddr(&a1);
|
||||
if ((cc=ccfetch(&a1)) >= 0) {
|
||||
if (opcode==OPDJNZ || cc>=CPO)
|
||||
aerr();
|
||||
opcode = OPJR | (cc<<3);
|
||||
comma();
|
||||
getaddr(&a1);
|
||||
}
|
||||
istuser(&a1);
|
||||
disp = a1.a_value-dot-2;
|
||||
if (disp<-128 || disp>127)
|
||||
aerr();
|
||||
outab(opcode);
|
||||
outab(disp);
|
||||
break;
|
||||
|
||||
case TRET:
|
||||
unget(c = getnb());
|
||||
if (c!='\n' && c!=';') {
|
||||
getaddr(&a1);
|
||||
if ((cc=ccfetch(&a1)) < 0)
|
||||
aerr();
|
||||
opcode = OPRET | (cc<<3);
|
||||
}
|
||||
outab(opcode);
|
||||
break;
|
||||
|
||||
case TJMP:
|
||||
getaddr(&a1);
|
||||
if ((cc=ccfetch(&a1)) >= 0) {
|
||||
opcode = (opcode&0x00C6) | (cc<<3);
|
||||
comma();
|
||||
getaddr(&a1);
|
||||
}
|
||||
if ((a1.a_type&TMMODE) == TBR) {
|
||||
reg = a1.a_type&TMREG;
|
||||
if (reg==M || reg==IX || reg==IY) {
|
||||
if (opcode != OPJP)
|
||||
aerr();
|
||||
outop(OPPCHL, &a1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
istuser(&a1);
|
||||
outab(opcode);
|
||||
outaw(a1.a_value);
|
||||
break;
|
||||
|
||||
case TPUSH:
|
||||
getaddr(&a1);
|
||||
if ((a1.a_type&TMMODE) == TWR) {
|
||||
reg = a1.a_type&TMREG;
|
||||
switch (reg) {
|
||||
case IX:
|
||||
outab(0xDD);
|
||||
reg = HL;
|
||||
break;
|
||||
case IY:
|
||||
outab(0xFD);
|
||||
reg = HL;
|
||||
break;
|
||||
case AF:
|
||||
reg = SP;
|
||||
break;
|
||||
case SP:
|
||||
case AFPRIME:
|
||||
aerr();
|
||||
}
|
||||
outab(opcode|(reg<<4));
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TIM:
|
||||
getaddr(&a1);
|
||||
istuser(&a1);
|
||||
if ((value=a1.a_value) > 2)
|
||||
aerr();
|
||||
else if (value != 0)
|
||||
++value;
|
||||
outab(0xED);
|
||||
outab(OPIM|(value<<3));
|
||||
break;
|
||||
|
||||
case TIO:
|
||||
getaddr(opcode==OPIN ? &a1 : &a2);
|
||||
comma();
|
||||
getaddr(opcode==OPIN ? &a2 : &a1);
|
||||
if (a1.a_type==(TBR|A) && a2.a_type==(TUSER|TMINDIR)) {
|
||||
outab(opcode);
|
||||
outab(a2.a_value);
|
||||
break;
|
||||
}
|
||||
if ((a1.a_type&TMMODE)==TBR && a2.a_type==(TBR|TMINDIR|C)) {
|
||||
reg = a1.a_type&TMREG;
|
||||
if (reg==M || reg==IX || reg==IY)
|
||||
aerr();
|
||||
outab(0xED);
|
||||
if (opcode == OPIN)
|
||||
opcode = OPIIN; else
|
||||
opcode = OPIOUT;
|
||||
outab(opcode|(reg<<3));
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TBIT:
|
||||
getaddr(&a1);
|
||||
comma();
|
||||
getaddr(&a2);
|
||||
if ((a1.a_type&TMMODE) == TUSER
|
||||
&& a1.a_value < 8
|
||||
&& (a2.a_type&TMMODE) == TBR) {
|
||||
if ((reg=a2.a_type&TMREG)==IX || reg==IY)
|
||||
reg = M;
|
||||
outop(opcode|(a1.a_value<<3)|reg, &a2);
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TSHR:
|
||||
getaddr(&a1);
|
||||
if ((a1.a_type&TMMODE) == TBR) {
|
||||
if ((reg=a1.a_type&TMREG)==IX || reg==IY)
|
||||
reg = M;
|
||||
outop(opcode|reg, &a1);
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
|
||||
case TINC:
|
||||
getaddr(&a1);
|
||||
if ((a1.a_type&TMMODE) == TWR) {
|
||||
reg = a1.a_type&TMREG;
|
||||
switch (reg) {
|
||||
case IX:
|
||||
outab(0xDD);
|
||||
reg = HL;
|
||||
break;
|
||||
case IY:
|
||||
outab(0xFD);
|
||||
reg = HL;
|
||||
break;
|
||||
case AF:
|
||||
case AFPRIME:
|
||||
aerr();
|
||||
}
|
||||
if (opcode == OPINC)
|
||||
opcode = OPINCRP; else
|
||||
opcode = OPDECRP;
|
||||
outab(opcode|(reg<<4));
|
||||
break;
|
||||
}
|
||||
if ((a1.a_type&TMMODE) == TBR) {
|
||||
if ((reg=a1.a_type&TMREG)==IX || reg==IY)
|
||||
reg = M;
|
||||
outop(opcode|(reg<<3), &a1);
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TEX:
|
||||
getaddr(&a1);
|
||||
comma();
|
||||
getaddr(&a2);
|
||||
if (a1.a_type==(TWR|AF) && a2.a_type==(TWR|AFPRIME)) {
|
||||
outab(OPEXAF);
|
||||
break;
|
||||
}
|
||||
if (a1.a_type == (TWR|DE))
|
||||
opcode = OPXCHG;
|
||||
else if (a1.a_type == (TWR|TMINDIR|SP))
|
||||
opcode = OPXTHL;
|
||||
else
|
||||
aerr();
|
||||
if (a2.a_type == (TWR|HL))
|
||||
outab(opcode);
|
||||
else if (a2.a_type == (TWR|IX)) {
|
||||
outab(0xDD);
|
||||
outab(opcode);
|
||||
} else if (a2.a_type == (TWR|IY)) {
|
||||
outab(0xFD);
|
||||
outab(opcode);
|
||||
} else
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TSUB:
|
||||
getaddr(&a1);
|
||||
if (a1.a_type == TUSER) {
|
||||
outab(opcode | OPSUBI);
|
||||
outab(a1.a_value);
|
||||
break;
|
||||
}
|
||||
if ((a1.a_type&TMMODE) == TBR) {
|
||||
if ((reg=a1.a_type&TMREG)==IX || reg==IY)
|
||||
reg = M;
|
||||
outop(opcode|reg, &a1);
|
||||
break;
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TADD:
|
||||
getaddr(&a1);
|
||||
comma();
|
||||
getaddr(&a2);
|
||||
if (a1.a_type == (TBR|A)) {
|
||||
if (a2.a_type == TUSER) {
|
||||
outab(opcode | OPSUBI);
|
||||
outab(a2.a_value);
|
||||
break;
|
||||
}
|
||||
if ((a2.a_type&TMMODE) == TBR) {
|
||||
if ((reg=a2.a_type&TMREG)==IX || reg==IY)
|
||||
reg = M;
|
||||
outop(opcode|reg, &a1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((a1.a_type&TMMODE) == TWR) {
|
||||
switch(reg = a1.a_type&TMREG) {
|
||||
case IX:
|
||||
if (opcode != OPADD)
|
||||
aerr();
|
||||
outab(0xDD);
|
||||
opcode = OPDAD;
|
||||
srcreg = IX;
|
||||
break;
|
||||
case IY:
|
||||
if (opcode != OPADD)
|
||||
aerr();
|
||||
outab(0xFD);
|
||||
opcode = OPDAD;
|
||||
srcreg = IY;
|
||||
break;
|
||||
case HL:
|
||||
if (opcode == OPADD)
|
||||
opcode = OPDAD;
|
||||
else {
|
||||
outab(0xED);
|
||||
if (opcode == OPADC)
|
||||
opcode = OPADCW;
|
||||
else
|
||||
opcode = OPSBCW;
|
||||
}
|
||||
srcreg = HL;
|
||||
break;
|
||||
default:
|
||||
aerr();
|
||||
}
|
||||
if ((a2.a_type&TMMODE) == TWR) {
|
||||
reg = a2.a_type&TMREG;
|
||||
if (reg==BC || reg==DE || reg==SP) {
|
||||
outab(opcode|(reg<<4));
|
||||
break;
|
||||
}
|
||||
if (reg == srcreg) {
|
||||
outab(opcode|(HL<<4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
aerr();
|
||||
break;
|
||||
|
||||
case TLD:
|
||||
asmld();
|
||||
break;
|
||||
|
||||
default:
|
||||
err('o');
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the dreaded "ld" instruction,
|
||||
* with its dozens of forms, formats and special
|
||||
* encodings. The "getldaddr" routine performs most
|
||||
* of the special stuff for index registers and for
|
||||
* indexing. This layer just screens out the many
|
||||
* cases, and emits the correct bytes.
|
||||
*/
|
||||
asmld()
|
||||
{
|
||||
int mdst;
|
||||
int rdst;
|
||||
int msrc;
|
||||
int rsrc;
|
||||
ADDR *indexap;
|
||||
ADDR dst;
|
||||
ADDR src;
|
||||
ADDR *getldaddr();
|
||||
|
||||
indexap = NULL;
|
||||
indexap = getldaddr(&dst, &mdst, &rdst, indexap);
|
||||
comma();
|
||||
indexap = getldaddr(&src, &msrc, &rsrc, indexap);
|
||||
if (dst.a_type == (TBR|A)) {
|
||||
if (msrc == TSR) {
|
||||
if (rsrc == I)
|
||||
outaw(0x57ED); /* ld a,i */
|
||||
else
|
||||
outaw(0x5FED); /* ld a,r */
|
||||
return;
|
||||
}
|
||||
if (msrc == (TMINDIR|TUSER)) {
|
||||
outab(0x3A); /* lda */
|
||||
outaw(src.a_value);
|
||||
return;
|
||||
}
|
||||
if (msrc == (TMINDIR|TWR)) {
|
||||
if (rsrc==BC || rsrc==DE) {
|
||||
outab(0x0A|(rsrc<<4)); /* ldax */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src.a_type == (TBR|A)) {
|
||||
if (mdst == TSR) {
|
||||
if (rdst == I)
|
||||
outaw(0x47ED); /* ld i,a */
|
||||
else
|
||||
outaw(0x4FED); /* ld r,a */
|
||||
return;
|
||||
}
|
||||
if (mdst == (TMINDIR|TUSER)) {
|
||||
outab(0x32); /* sta */
|
||||
outaw(dst.a_value);
|
||||
return;
|
||||
}
|
||||
if (mdst == (TMINDIR|TWR)) {
|
||||
if (rdst==BC || rdst==DE) {
|
||||
outab(0x02|(rdst<<4)); /* stax */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dst.a_type==(TWR|SP) && msrc==TWR) {
|
||||
if (rsrc == HL) {
|
||||
outab(0xF9); /* sphl */
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (msrc == TUSER) {
|
||||
if (mdst == TBR) {
|
||||
outab(0x06|(rdst<<3)); /* mvi */
|
||||
if (indexap != NULL)
|
||||
outab(indexap->a_value);
|
||||
outab(src.a_value);
|
||||
return;
|
||||
}
|
||||
if (mdst == TWR) {
|
||||
outab(0x01|(rdst<<4)); /* lxi */
|
||||
outaw(src.a_value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mdst==TWR && msrc==(TMINDIR|TUSER)) {
|
||||
if (rdst == HL)
|
||||
outab(0x2A); /* lhld */
|
||||
else
|
||||
outaw(0x4BED|(rdst<<12)); /* ld rp,(ppqq) */
|
||||
outaw(src.a_value);
|
||||
return;
|
||||
}
|
||||
if (mdst==(TMINDIR|TUSER) && msrc==TWR) {
|
||||
if (rsrc == HL)
|
||||
outab(0x22); /* shld */
|
||||
else
|
||||
outaw(0x43ED|(rsrc<<12)); /* ld (ppqq),rp */
|
||||
outaw(dst.a_value);
|
||||
return;
|
||||
}
|
||||
if (mdst==TBR && msrc==TBR && (rdst!=M || rsrc!=M)) {
|
||||
outab(0x40|(rdst<<3)|rsrc);
|
||||
if (indexap != NULL)
|
||||
outab(indexap->a_value);
|
||||
return;
|
||||
}
|
||||
aerr();
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in addresses for "ld"
|
||||
* instructions. Split off the mode
|
||||
* and the register name. Adjust the register
|
||||
* name to correctly deal with the index registers
|
||||
* and for indexed addressing modes. Return the address
|
||||
* pointer "ap" if indexing is required, otherwise just
|
||||
* pass the "iap" through.
|
||||
*/
|
||||
ADDR *
|
||||
getldaddr(ap, modep, regp, iap)
|
||||
ADDR *ap;
|
||||
int *modep;
|
||||
int *regp;
|
||||
ADDR *iap;
|
||||
{
|
||||
register int mode;
|
||||
register int reg;
|
||||
|
||||
getaddr(ap);
|
||||
mode = ap->a_type&TMMODE;
|
||||
reg = ap->a_type&TMREG;
|
||||
switch (ap->a_type) {
|
||||
case TBR|IX:
|
||||
outab(0xDD);
|
||||
reg = M;
|
||||
iap = ap;
|
||||
break;
|
||||
|
||||
case TBR|IY:
|
||||
outab(0xFD);
|
||||
reg = M;
|
||||
iap = ap;
|
||||
break;
|
||||
|
||||
case TWR|IX:
|
||||
outab(0xDD);
|
||||
reg = HL;
|
||||
break;
|
||||
|
||||
case TWR|IY:
|
||||
outab(0xFD);
|
||||
reg == HL;
|
||||
break;
|
||||
|
||||
case TWR|AF:
|
||||
case TWR|AFPRIME:
|
||||
aerr();
|
||||
reg = HL;
|
||||
}
|
||||
*modep = mode;
|
||||
*regp = reg;
|
||||
return (iap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output an opcode, surrounded
|
||||
* by the index prefix bytes and the
|
||||
* index displacement byte. Look at
|
||||
* the address mode to see if the bytes
|
||||
* are needed.
|
||||
*/
|
||||
outop(op, ap)
|
||||
register int op;
|
||||
register ADDR *ap;
|
||||
{
|
||||
register int needisp;
|
||||
|
||||
needisp = 0;
|
||||
if (ap->a_type == (TBR|IX)) {
|
||||
outab(0xDD);
|
||||
needisp = 1;
|
||||
} else if (ap->a_type == (TBR|IY)) {
|
||||
outab(0xFD);
|
||||
needisp = 1;
|
||||
}
|
||||
if ((op&0xFF00) != 0) {
|
||||
outab(op>>8);
|
||||
if (needisp != 0) {
|
||||
outab(ap->a_value);
|
||||
needisp = 0;
|
||||
}
|
||||
}
|
||||
outab(op);
|
||||
if (needisp != 0)
|
||||
outab(ap->a_value);
|
||||
}
|
||||
|
||||
/*
|
||||
* The next character
|
||||
* in the input must be a comma
|
||||
* or it is a fatal error.
|
||||
*/
|
||||
comma()
|
||||
{
|
||||
if (getnb() != ',')
|
||||
qerr();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the mode of
|
||||
* an ADDR is TUSER. If not, give
|
||||
* an error.
|
||||
*/
|
||||
istuser(ap)
|
||||
register ADDR *ap;
|
||||
{
|
||||
if ((ap->a_type&TMMODE) != TUSER)
|
||||
aerr();
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to interpret an "ADDR"
|
||||
* as a condition code name. Return
|
||||
* the condition, or "-1" if it cannot
|
||||
* be interpreted as a condition. The
|
||||
* "c" condition is a pain.
|
||||
*/
|
||||
ccfetch(ap)
|
||||
register ADDR *ap;
|
||||
{
|
||||
if (ap->a_type == (TBR|C))
|
||||
return (CC);
|
||||
if ((ap->a_type&TMMODE) == TCC)
|
||||
return (ap->a_type&TMREG);
|
||||
return (-1);
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Symbol table routines
|
||||
* and error handling.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
/*
|
||||
* Given a pointer to a
|
||||
* sumbol, compute the hash bucket
|
||||
* number. The "add all the characters
|
||||
* and take the result modulo the table
|
||||
* size" algorithm is used.
|
||||
*/
|
||||
symhash(id)
|
||||
register char *id;
|
||||
{
|
||||
register int hash;
|
||||
register int n;
|
||||
|
||||
hash = 0;
|
||||
n = NCPS;
|
||||
do {
|
||||
hash += *id++;
|
||||
} while (--n);
|
||||
return (hash&HMASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle an error.
|
||||
* If no listing file, write out
|
||||
* the error directly. Otherwise save
|
||||
* the error in the error buffer.
|
||||
*/
|
||||
err(c)
|
||||
{
|
||||
if (pass != 0) {
|
||||
if (lflag != 0)
|
||||
storerror(c);
|
||||
else
|
||||
printf("%04d %c\n", line, c);
|
||||
}
|
||||
if (c == 'q')
|
||||
longjmp(env, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is like
|
||||
* "err", but it has the "u"
|
||||
* code screwed into it, and it
|
||||
* prints the name of the identifier
|
||||
* "id" in the message.
|
||||
*/
|
||||
uerr(id)
|
||||
char *id;
|
||||
{
|
||||
if (pass != 0) {
|
||||
if (lflag != 0)
|
||||
storerror('u');
|
||||
else
|
||||
printf("%04d u %.*s\n", line, NCPS, id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "a" error is common.
|
||||
*/
|
||||
aerr()
|
||||
{
|
||||
err('a');
|
||||
}
|
||||
|
||||
/*
|
||||
* Ditto the "q" error.
|
||||
*/
|
||||
qerr()
|
||||
{
|
||||
err('q');
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the error code
|
||||
* "c" into the error buffer.
|
||||
* Check that it is not already
|
||||
* there.
|
||||
*/
|
||||
storerror(c)
|
||||
register int c;
|
||||
{
|
||||
register char *p;
|
||||
|
||||
p = &eb[0];
|
||||
while (p < ep)
|
||||
if (*p++ == c)
|
||||
return;
|
||||
if (p < &eb[NERR]) {
|
||||
*p++ = c;
|
||||
ep = p;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read identifier.
|
||||
* The character "c" is the first
|
||||
* character of the name.
|
||||
*/
|
||||
getid(id, c)
|
||||
register int c;
|
||||
char *id;
|
||||
{
|
||||
register char *p;
|
||||
|
||||
if (c < 0) {
|
||||
c = getnb();
|
||||
if (isalpha(c) == 0)
|
||||
qerr();
|
||||
}
|
||||
p = &id[0];
|
||||
do {
|
||||
if (p < &id[NCPS]) {
|
||||
if (isupper(c))
|
||||
c = tolower(c);
|
||||
*p++ = c;
|
||||
}
|
||||
if ((c = *ip) != '\n')
|
||||
++ip;
|
||||
} while (c=='\'' || isalnum(c)!=0);
|
||||
if (c != '\n')
|
||||
--ip;
|
||||
while (p < &id[NCPS])
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup symbol in
|
||||
* hash table "htable".
|
||||
* If not there, and "cf" is
|
||||
* true, create it.
|
||||
*/
|
||||
SYM *
|
||||
lookup(id, htable, cf)
|
||||
char *id;
|
||||
SYM *htable[];
|
||||
{
|
||||
register SYM *sp;
|
||||
register int hash;
|
||||
|
||||
hash = symhash(id);
|
||||
sp = htable[hash];
|
||||
while (sp != NULL) {
|
||||
if (symeq(id, sp->s_id))
|
||||
return (sp);
|
||||
sp = sp->s_fp;
|
||||
}
|
||||
if (cf != 0) {
|
||||
if ((sp=(SYM *)malloc(sizeof(SYM))) == NULL) {
|
||||
fprintf(stderr, "No memory\n");
|
||||
exit(BAD);
|
||||
}
|
||||
sp->s_fp = htable[hash];
|
||||
htable[hash] = sp;
|
||||
sp->s_type = TNEW;
|
||||
sp->s_value = 0;
|
||||
symcopy(sp->s_id, id);
|
||||
}
|
||||
return (sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two names.
|
||||
* Each are blocks of "NCPS"
|
||||
* bytes. True return if the names
|
||||
* are exactly equal.
|
||||
*/
|
||||
symeq(p1, p2)
|
||||
register char *p1;
|
||||
register char *p2;
|
||||
{
|
||||
register int n;
|
||||
|
||||
n = NCPS;
|
||||
do {
|
||||
if (*p1++ != *p2++)
|
||||
return (0);
|
||||
} while (--n);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the characters
|
||||
* that make up the name of a
|
||||
* symbol.
|
||||
*/
|
||||
symcopy(p1, p2)
|
||||
register char *p1;
|
||||
register char *p2;
|
||||
{
|
||||
register int n;
|
||||
|
||||
n = NCPS;
|
||||
do {
|
||||
*p1++ = *p2++;
|
||||
} while (--n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next character
|
||||
* from the input buffer. Do not
|
||||
* step past the newline.
|
||||
*/
|
||||
get()
|
||||
{
|
||||
register int c;
|
||||
|
||||
if ((c = *ip) != '\n')
|
||||
++ip;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next non
|
||||
* whitespace character from
|
||||
* the input buffer. Do not step
|
||||
* past the newline.
|
||||
*/
|
||||
getnb()
|
||||
{
|
||||
register int c;
|
||||
|
||||
while ((c = *ip)==' ' || c=='\t')
|
||||
++ip;
|
||||
if (c != '\n')
|
||||
++ip;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a character back.
|
||||
*/
|
||||
unget(c)
|
||||
{
|
||||
if (c != '\n')
|
||||
--ip;
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Read in expressions in
|
||||
* address fields.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
#define LOPRI 0
|
||||
#define ADDPRI 1
|
||||
#define MULPRI 2
|
||||
#define HIPRI 3
|
||||
|
||||
/*
|
||||
* Read in an address
|
||||
* descriptor, and fill in
|
||||
* the supplied "ADDR" structure
|
||||
* with the mode and value.
|
||||
* Exits directly to "qerr" if
|
||||
* there is no address field or
|
||||
* if the syntax is bad.
|
||||
*/
|
||||
getaddr(ap)
|
||||
register ADDR *ap;
|
||||
{
|
||||
register int reg;
|
||||
register int c;
|
||||
|
||||
if ((c=getnb()) != '(') {
|
||||
unget(c);
|
||||
expr1(ap, LOPRI, 0);
|
||||
return;
|
||||
}
|
||||
expr1(ap, LOPRI, 1);
|
||||
if (getnb() != ')')
|
||||
qerr();
|
||||
reg = ap->a_type&TMREG;
|
||||
switch (ap->a_type&TMMODE) {
|
||||
case TBR:
|
||||
if (reg != C)
|
||||
aerr();
|
||||
ap->a_type |= TMINDIR;
|
||||
break;
|
||||
case TSR:
|
||||
case TCC:
|
||||
aerr();
|
||||
break;
|
||||
case TUSER:
|
||||
ap->a_type |= TMINDIR;
|
||||
break;
|
||||
case TWR:
|
||||
if (reg == HL)
|
||||
ap->a_type = TBR|M;
|
||||
else if (reg==IX || reg==IY)
|
||||
ap->a_type = TBR|reg;
|
||||
else if (reg==AF || reg==AFPRIME)
|
||||
aerr();
|
||||
else
|
||||
ap->a_type |= TMINDIR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Expression reader,
|
||||
* real work, part I. Read
|
||||
* operators and resolve types.
|
||||
* The "lpri" is the firewall operator
|
||||
* priority, which stops the scan.
|
||||
* The "paren" argument is true if
|
||||
* the expression is in parentheses.
|
||||
*/
|
||||
expr1(ap, lpri, paren)
|
||||
register ADDR *ap;
|
||||
{
|
||||
register int c;
|
||||
register int opri;
|
||||
ADDR right;
|
||||
|
||||
expr2(ap);
|
||||
while ((c=getnb())=='+' || c=='-' || c=='*' || c=='/') {
|
||||
opri = ADDPRI;
|
||||
if (c=='*' || c=='/')
|
||||
opri = MULPRI;
|
||||
if (opri <= lpri)
|
||||
break;
|
||||
expr1(&right, opri, paren);
|
||||
switch (c) {
|
||||
case '+':
|
||||
if ((ap->a_type&TMMODE) != TUSER)
|
||||
istuser(&right);
|
||||
else
|
||||
ap->a_type = right.a_type;
|
||||
isokaors(ap, paren);
|
||||
ap->a_value += right.a_value;
|
||||
break;
|
||||
case '-':
|
||||
istuser(&right);
|
||||
isokaors(ap, paren);
|
||||
ap->a_value -= right.a_value;
|
||||
break;
|
||||
case '*':
|
||||
istuser(ap);
|
||||
istuser(&right);
|
||||
ap->a_value *= right.a_value;
|
||||
break;
|
||||
case '/':
|
||||
istuser(ap);
|
||||
istuser(&right);
|
||||
ap->a_value /= right.a_value;
|
||||
}
|
||||
}
|
||||
unget(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expression reader,
|
||||
* real work, part II. Read
|
||||
* in terminals.
|
||||
*/
|
||||
expr2(ap)
|
||||
register ADDR *ap;
|
||||
{
|
||||
register int c;
|
||||
register SYM *sp;
|
||||
register int mode;
|
||||
char id[NCPS];
|
||||
|
||||
c = getnb();
|
||||
if (c == '[') {
|
||||
expr1(ap, LOPRI);
|
||||
if (getnb() != ']')
|
||||
qerr();
|
||||
return;
|
||||
}
|
||||
if (c == '-') {
|
||||
expr1(ap, HIPRI);
|
||||
istuser(ap);
|
||||
ap->a_value = -ap->a_value;
|
||||
return;
|
||||
}
|
||||
if (c == '~') {
|
||||
expr1(ap, HIPRI);
|
||||
istuser(ap);
|
||||
ap->a_value = ~ap->a_value;
|
||||
return;
|
||||
}
|
||||
if (c == '\'') {
|
||||
ap->a_type = TUSER;
|
||||
ap->a_value = get();
|
||||
while ((c=get()) != '\'') {
|
||||
if (c == '\n')
|
||||
qerr();
|
||||
ap->a_value = (ap->a_value<<8) + c;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (c>='0' && c<='9') {
|
||||
expr3(ap, c);
|
||||
return;
|
||||
}
|
||||
if (isalpha(c)) {
|
||||
getid(id, c);
|
||||
if ((sp=lookup(id, uhash, 0)) == NULL
|
||||
&& (sp=lookup(id, phash, 0)) == NULL)
|
||||
sp = lookup(id, uhash, 1);
|
||||
mode = sp->s_type&TMMODE;
|
||||
if (mode==TBR || mode==TWR || mode==TSR || mode==TCC) {
|
||||
ap->a_type = mode|sp->s_value;
|
||||
ap->a_value = 0;
|
||||
return;
|
||||
}
|
||||
if (mode == TNEW)
|
||||
uerr(id);
|
||||
ap->a_type = TUSER;
|
||||
ap->a_value = sp->s_value;
|
||||
return;
|
||||
}
|
||||
qerr();
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in a constant. The argument
|
||||
* "c" is the first character of the constant,
|
||||
* and has already been validated. The number is
|
||||
* gathered up (stopping on non alphanumeric).
|
||||
* The radix is determined, and the number is
|
||||
* converted to binary.
|
||||
*/
|
||||
expr3(ap, c)
|
||||
register ADDR *ap;
|
||||
register int c;
|
||||
{
|
||||
register char *np1;
|
||||
register char *np2;
|
||||
register int radix;
|
||||
register VALUE value;
|
||||
char num[40];
|
||||
|
||||
np1 = &num[0];
|
||||
do {
|
||||
if (isupper(c))
|
||||
c = tolower(c);
|
||||
*np1++ = c;
|
||||
c = *ip++;
|
||||
} while (isalnum(c));
|
||||
--ip;
|
||||
switch (*--np1) {
|
||||
case 'h':
|
||||
radix = 16;
|
||||
break;
|
||||
case 'o':
|
||||
case 'q':
|
||||
radix = 8;
|
||||
break;
|
||||
case 'b':
|
||||
radix = 2;
|
||||
break;
|
||||
default:
|
||||
radix = 10;
|
||||
++np1;
|
||||
}
|
||||
np2 = &num[0];
|
||||
value = 0;
|
||||
while (np2 < np1) {
|
||||
if ((c = *np2++)>='0' && c<='9')
|
||||
c -= '0';
|
||||
else if (c>='a' && c<='f')
|
||||
c -= 'a'-10;
|
||||
else
|
||||
err('n');
|
||||
if (c >= radix)
|
||||
err('n');
|
||||
value = radix*value + c;
|
||||
}
|
||||
ap->a_type = TUSER;
|
||||
ap->a_value = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the
|
||||
* mode and register fields of
|
||||
* the type of the "ADDR" pointed to
|
||||
* by "ap" can participate in an addition
|
||||
* or a subtraction.
|
||||
*/
|
||||
isokaors(ap, paren)
|
||||
register ADDR *ap;
|
||||
{
|
||||
register int mode;
|
||||
register int reg;
|
||||
|
||||
mode = ap->a_type&TMMODE;
|
||||
if (mode == TUSER)
|
||||
return;
|
||||
if (mode==TWR && paren!=0) {
|
||||
reg = ap->a_type&TMREG;
|
||||
if (reg==IX || reg==IY)
|
||||
return;
|
||||
}
|
||||
aerr();
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Output Intel compatable
|
||||
* hex files.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
#define NHEX 32 /* Longest record */
|
||||
|
||||
VALUE hexla;
|
||||
VALUE hexpc;
|
||||
char hexb[NHEX];
|
||||
char *hexp = &hexb[0];
|
||||
|
||||
/*
|
||||
* Output a word. Use the
|
||||
* standard Z-80 ordering (low
|
||||
* byte then high byte).
|
||||
*/
|
||||
outaw(w)
|
||||
{
|
||||
outab(w);
|
||||
outab(w >> 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output an absolute
|
||||
* byte to the code and listing
|
||||
* streams.
|
||||
*/
|
||||
outab(b)
|
||||
{
|
||||
if (pass != 0) {
|
||||
if (cp < &cb[NCODE])
|
||||
*cp++ = b;
|
||||
outbyte(b);
|
||||
}
|
||||
++dot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put out the end of file
|
||||
* hex item at the very end of
|
||||
* the object file.
|
||||
*/
|
||||
outeof()
|
||||
{
|
||||
outflush();
|
||||
fprintf(ofp, ":00000001FF\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a hex byte. Flush
|
||||
* the buffer if no room. Store the
|
||||
* byte in the buffer, for future
|
||||
* checksumming. Remember the load
|
||||
* address for flushing.
|
||||
*/
|
||||
outbyte(b)
|
||||
{
|
||||
if (hexp>=&hexb[NHEX] || hexpc!=dot) {
|
||||
outflush();
|
||||
hexp = &hexb[0];
|
||||
}
|
||||
if (hexp == &hexb[0]) {
|
||||
hexla = dot;
|
||||
hexpc = dot;
|
||||
}
|
||||
*hexp++ = b;
|
||||
++hexpc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush out a block of
|
||||
* code to the hex file. Figure
|
||||
* out the length word and the
|
||||
* checksum byte.
|
||||
*/
|
||||
outflush()
|
||||
{
|
||||
register char *p;
|
||||
register int b;
|
||||
register int c;
|
||||
|
||||
if ((b = hexp-&hexb[0]) != 0) {
|
||||
putc(':', ofp);
|
||||
outhex(b);
|
||||
outhex(hexla >> 8);
|
||||
outhex(hexla);
|
||||
outhex(0);
|
||||
c = b + (hexla>>8) + hexla;
|
||||
p = &hexb[0];
|
||||
while (p < hexp) {
|
||||
b = *p++;
|
||||
outhex(b);
|
||||
c += b;
|
||||
}
|
||||
outhex(-c);
|
||||
putc('\n', ofp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put out "b", as a
|
||||
* two character hex value.
|
||||
* We cannot use printf because
|
||||
* of case problems on VMS.
|
||||
* Upper case ascii.
|
||||
*/
|
||||
outhex(b)
|
||||
{
|
||||
static char hex[] = {
|
||||
'0', '1', '2', '3',
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
putc(hex[(b>>4)&0x0F], ofp);
|
||||
putc(hex[b&0x0F], ofp);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Build up lines for the
|
||||
* listing file.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
/*
|
||||
* Copy the data in the listing
|
||||
* code buffer to the listing file.
|
||||
* Produce no file if "lfp" is NULL.
|
||||
* Honour the listing mode stored
|
||||
* in the "lmode".
|
||||
*/
|
||||
list()
|
||||
{
|
||||
register char *wp;
|
||||
register int nb;
|
||||
|
||||
if (lfp==NULL || lmode==NLIST)
|
||||
return;
|
||||
while (ep < &eb[NERR])
|
||||
*ep++ = ' ';
|
||||
fprintf(lfp, "%.10s", eb);
|
||||
if (lmode == SLIST) {
|
||||
fprintf(lfp, "%31s %5d %s", "", line, ib);
|
||||
return;
|
||||
}
|
||||
fprintf(lfp, " %04x", laddr);
|
||||
if (lmode == ALIST) {
|
||||
fprintf(lfp, "%24s %5d %s", "", line, ib);
|
||||
return;
|
||||
}
|
||||
wp = cb;
|
||||
nb = cp - cb;
|
||||
list1(wp, nb, 1);
|
||||
fprintf(lfp, " %5d %s", line, ib);
|
||||
while ((nb -= 8) > 0) {
|
||||
wp += 8;
|
||||
fprintf(lfp, "%17s", "");
|
||||
list1(wp, nb, 0);
|
||||
fprintf(lfp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy out a partial line
|
||||
* to the listing. Used for the first
|
||||
* and the extra lines in BLIST and
|
||||
* WLIST mode.
|
||||
*/
|
||||
list1(wp, nb, f)
|
||||
register char *wp;
|
||||
register int nb;
|
||||
{
|
||||
register int d;
|
||||
register int i;
|
||||
|
||||
if (nb > 8)
|
||||
nb = 8;
|
||||
for (i=0; i<nb; ++i) {
|
||||
d = (*wp++) & 0xFF;
|
||||
if (lmode == BLIST)
|
||||
fprintf(lfp, " %02x", d);
|
||||
else {
|
||||
d |= *wp++ << 8;
|
||||
fprintf(lfp, " %04x", d);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (f != 0) {
|
||||
while (i < 8) {
|
||||
fprintf(lfp, " ");
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Z-80 assembler.
|
||||
* Basic symbol tables.
|
||||
* Contain all of the instructions
|
||||
* and register names.
|
||||
*/
|
||||
#include "as.h"
|
||||
|
||||
/*
|
||||
* This array of symbol nodes
|
||||
* make up the basic symbol table.
|
||||
* The "syminit" routine links these
|
||||
* nodes into the builtin symbol hash
|
||||
* table at start-up time.
|
||||
*/
|
||||
SYM sym[] = {
|
||||
0, "b", TBR, B,
|
||||
0, "c", TBR, C,
|
||||
0, "d", TBR, D,
|
||||
0, "e", TBR, E,
|
||||
0, "h", TBR, H,
|
||||
0, "l", TBR, L,
|
||||
0, "a", TBR, A,
|
||||
0, "bc", TWR, BC,
|
||||
0, "de", TWR, DE,
|
||||
0, "hl", TWR, HL,
|
||||
0, "sp", TWR, SP,
|
||||
0, "af", TWR, AF,
|
||||
0, "af'", TWR, AFPRIME,
|
||||
0, "ix", TWR, IX,
|
||||
0, "iy", TWR, IY,
|
||||
0, "i", TSR, I,
|
||||
0, "r", TSR, R,
|
||||
0, "nz", TCC, CNZ,
|
||||
0, "z", TCC, CZ,
|
||||
0, "nc", TCC, CNC,
|
||||
0, "po", TCC, CPO,
|
||||
0, "pe", TCC, CPE,
|
||||
0, "p", TCC, CP,
|
||||
0, "m", TCC, CM,
|
||||
0, "defb", TDEFB, XXXX,
|
||||
0, "defw", TDEFW, XXXX,
|
||||
0, "defs", TDEFS, XXXX,
|
||||
0, "defm", TDEFM, XXXX,
|
||||
0, "org", TORG, XXXX,
|
||||
0, "equ", TEQU, XXXX,
|
||||
0, "cond", TCOND, XXXX,
|
||||
0, "endc", TENDC, XXXX,
|
||||
0, "nop", TNOP, 0x0000,
|
||||
0, "rlca", TNOP, 0x0007,
|
||||
0, "rrca", TNOP, 0x000F,
|
||||
0, "rla", TNOP, 0x0017,
|
||||
0, "rra", TNOP, 0x001F,
|
||||
0, "daa", TNOP, 0x0027,
|
||||
0, "cpl", TNOP, 0x002F,
|
||||
0, "scf", TNOP, 0x0037,
|
||||
0, "ccf", TNOP, 0x003F,
|
||||
0, "halt", TNOP, 0x0076,
|
||||
0, "exx", TNOP, 0x00D9,
|
||||
0, "di", TNOP, 0x00F3,
|
||||
0, "ei", TNOP, 0x00FB,
|
||||
0, "neg", TNOP, 0xED44,
|
||||
0, "retn", TNOP, 0xED45,
|
||||
0, "reti", TNOP, 0xED4D,
|
||||
0, "rrd", TNOP, 0xED67,
|
||||
0, "rld", TNOP, 0xED6F,
|
||||
0, "ldi", TNOP, 0xEDA0,
|
||||
0, "cpi", TNOP, 0xEDA1,
|
||||
0, "ini", TNOP, 0xEDA2,
|
||||
0, "outi", TNOP, 0xEDA3,
|
||||
0, "ldd", TNOP, 0xEDA8,
|
||||
0, "cpd", TNOP, 0xEDA9,
|
||||
0, "ind", TNOP, 0xEDAA,
|
||||
0, "outd", TNOP, 0xEDAB,
|
||||
0, "ldir", TNOP, 0xEDB0,
|
||||
0, "cpir", TNOP, 0xEDB1,
|
||||
0, "inir", TNOP, 0xEDB2,
|
||||
0, "otir", TNOP, 0xEDB3,
|
||||
0, "lddr", TNOP, 0xEDB8,
|
||||
0, "cpdr", TNOP, 0xEDB9,
|
||||
0, "indr", TNOP, 0xEDBA,
|
||||
0, "otdr", TNOP, 0xEDBB,
|
||||
0, "rst", TRST, XXXX,
|
||||
0, "djnz", TREL, 0x0010,
|
||||
0, "jr", TREL, 0x0018,
|
||||
0, "ret", TRET, 0x00C9,
|
||||
0, "call", TJMP, 0x00CD,
|
||||
0, "jp", TJMP, 0x00C3,
|
||||
0, "push", TPUSH, 0x00C5,
|
||||
0, "pop", TPUSH, 0x00C1,
|
||||
0, "im", TIM, XXXX,
|
||||
0, "in", TIO, 0x00DB,
|
||||
0, "out", TIO, 0x00D3,
|
||||
0, "bit", TBIT, 0xCB40,
|
||||
0, "res", TBIT, 0xCB80,
|
||||
0, "set", TBIT, 0xCBC0,
|
||||
0, "rlc", TSHR, 0xCB00,
|
||||
0, "rrc", TSHR, 0xCB08,
|
||||
0, "rl", TSHR, 0xCB10,
|
||||
0, "rr", TSHR, 0xCB18,
|
||||
0, "sla", TSHR, 0xCB20,
|
||||
0, "sra", TSHR, 0xCB28,
|
||||
0, "srl", TSHR, 0xCB38,
|
||||
0, "inc", TINC, 0x0004,
|
||||
0, "dec", TINC, 0x0005,
|
||||
0, "ex", TEX, XXXX,
|
||||
0, "add", TADD, 0x0080,
|
||||
0, "adc", TADD, 0x0088,
|
||||
0, "sbc", TADD, 0x0098,
|
||||
0, "sub", TSUB, 0x0090,
|
||||
0, "and", TSUB, 0x00A0,
|
||||
0, "xor", TSUB, 0x00A8,
|
||||
0, "or", TSUB, 0x00B0,
|
||||
0, "cp", TSUB, 0x00B8,
|
||||
0, "ld", TLD, XXXX
|
||||
};
|
||||
|
||||
/*
|
||||
* Set up the symbol table.
|
||||
* Sweep through the initializations
|
||||
* of the "phash", and link them into the
|
||||
* buckets. Because it is here, a
|
||||
* "sizeof" works.
|
||||
*/
|
||||
syminit()
|
||||
{
|
||||
register SYM *sp;
|
||||
register int hash;
|
||||
|
||||
sp = &sym[0];
|
||||
while (sp < &sym[sizeof(sym)/sizeof(SYM)]) {
|
||||
hash = symhash(sp->s_id);
|
||||
sp->s_fp = phash[hash];
|
||||
phash[hash] = sp;
|
||||
++sp;
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,174 @@
|
|||
:20010000312017AF32221721DE1822DA182A06002B22DC18213108CD010ECD330F3A6318C7
|
||||
:20012000FE4ECA4201FE59C214012ADA187EFE01CA3901CDAF02C32D0122D818CDCD02C3BB
|
||||
:200140004501CDC5023E0C32CA18115F18218808CD7A0DCDAF0F212B08CD010E3E0132248A
|
||||
:2001600017312017CDB20FCD330FCD8D07DA7601CDFE01C36701CD7C01C35C012163182292
|
||||
:200180002517CDE00DE6A0FEA011A908CA7C03CD6D03CDE80DFE0DC8015342C3B301014119
|
||||
:2001A00042C3B301015343C3B30101424FC3B301014D44C5CDB20FC1CD770F41CD770F21C1
|
||||
:2001C0004208CD010E3A2417B7C25301214908CD010E2ADA18444D5E160019EB212517CD1A
|
||||
:2001E000130EEBDAD501030A6F030A67116318CDD80E3E0D12216318CDFC0DC353012ADA2A
|
||||
:20020000187E3DCA1D02EB132A6118EBCD130E2BDA3202CA32027ECDAF02C301023A6018FD
|
||||
:20022000FE04C8CDB4022AD818CD8602360122D818C94622CD183A6018DA4A02D604CA43E4
|
||||
:2002400002C60490CA7D02DA6902473A6018FE04C878CDB4022ACD18CDA3022AD818EB224E
|
||||
:20026000D81803CD9802C37D022F3CCDAF02CDA302EB2ACD18C48D02360122D8182ACD18E2
|
||||
:200280003A6018FE04C81160181A4F06001A7713230B78B1C28D02C91A772B1B0B78B1C208
|
||||
:2002A0009802C93AD818954F3AD9189C47B1C9856FD024C92AD818CDAF02EB21DC18CD131C
|
||||
:2002C0000ED2D20DC92ADA18360122D8182AD8182322AE18EB21DC18AF12CD130E13C2D8B0
|
||||
:2002E000022ADC18224318218A17360022451821451822AC18C9CDBE0EDA9E017D322217C3
|
||||
:20030000C35301CDE00DFE0D110000CA1103CDBE0E2ADA187E3DC823CD130E2BDA2903CACE
|
||||
:2003200029037ECDAF02C31403D5116318CDF70723E5216318CDFC0DCDBC0FCDB20FE1D13D
|
||||
:20034000C31403CDCD022ADA187E3DCA5301232323222517224118AF322417CDB20FCDBCBD
|
||||
:200360000FCD6D03CD0C0DD25E03C35301CDE00DB7F28A03FE91D2980111B708CDE80DE69F
|
||||
:200380001F076F260019CD1E0EE9CDC80CDA9801E506F5CDD80DCDC506D1CD9C0DC9CD414B
|
||||
:2003A0000ECDC80CDA9801E506F5CDD80DCDC506D1D5CD9C0D069ECDD80DCDC506CDE00D2D
|
||||
:2003C000FE9FCACE03115E08CD860DC3D403CDE80DCDC50611FEFFCDAB0DEBCD0C0DDAA438
|
||||
:2003E00001EB722B7311FBFFCDAB0DE511FBFFCDAB0DCD9B0DD1CD9C0D11FDFFCDAB0DD1DD
|
||||
:20040000722B732B3601C36A04CD410E2A45187E3DC2A40123E5CDC80CDA2504EBE1E5CD4A
|
||||
:20042000130EC2A401E1E5E511060019E3CD1E0E444DD1D5CD5813E12B7E11060019EBE188
|
||||
:20044000CD1E0ED5B7CA4904EB444DCD3B0AD1FA5D04CA5D0421030019224518C913EBCDCB
|
||||
:200460001E0EEBCD0C0DEB222517215E03E3C90601CDC7062AAC1834F5CD9B0DF1C2F6042E
|
||||
:20048000069DCDD80DCDBE0EDA6D03C39804AF322417CDBE0EDA9801EBCD4C0E232323C35F
|
||||
:2004A0006204CD410E11FDFFCDAB0DE5CDBE0EDA9801EBCD0C0D444DE1702B712B3602CDB8
|
||||
:2004C0004C0E232323C36704CD410E3224172A45187EB7CAA401FE02CAE204110F0019C3CB
|
||||
:2004E000D104235E235623224518EB7E3DC26204C35301CD410ECDE80DFE0DC2F6042B22B4
|
||||
:200500002517C9CD270DDA980179F6804FCD360DD2B001E506E0CDD80DCDC5060629CDD8A8
|
||||
:200520000DCD680E218308CD130ED2B001E1CDA40CCDE00DFE2CC0CDE80DC30305CD410EA3
|
||||
:20054000CDAF0F32CF18215308C3C201CD410E2A2517E52A4118222517CDE80DFE2CCA797E
|
||||
:2005600005FE87CA79053DCAA605CDF604237E3DCAA605232323C35605CDC506CDE00DFE06
|
||||
:200580002CCA8705CD0C0D2A2517224118E1222517CDC80CDA9801CD9B0DCDE00DFE2CC0A6
|
||||
:2005A000CDE80DC34C05E1222517014452C3B3012ADA18232323224118C9CDE00DFE0DCAC0
|
||||
:2005C000B20FFE22CA0406FE9CCA4606FE25CA1106FE0DC8FE3BC8CDC506114B18CD9C0D5C
|
||||
:2005E0003A2017FE38D4B20F214B18CD03100620CD770FCDE00DFE2CC2B20FCDE80DCDE00C
|
||||
:200600000DC3C205CDE80DCD010E23222517C3F3053E0C32CA18CDE80DCDE80D21CA18FE86
|
||||
:2006200025CAF3050680FE5ACA40060601FE45CA4006CD8A12D29801D63007477EE6C177C7
|
||||
:200640007EB077C31906CDE80D06E0CDD80DCDC5060629CDD80DCD680E3A2017BBD2F30507
|
||||
:200660000620CD770FC35906CDE00DFE2CCAB906CDB20F063FCD770FCD330F116318D5CD0F
|
||||
:20068000C80CDA9801D106001AFE2BCA9506FE2DC29606060113C5E5CDE711DABF06E12BD7
|
||||
:2006A000F177CDE00DFE2CC0CDE80D78FE2CCA7E06063FCD770FC37306CDE80DC3780601A4
|
||||
:2006C0004E49C3B301060021C509AF322117C5E5AF3223173A2317B7C2F506CDC80CD48557
|
||||
:2006E0000DD2F506CD250ED2F506CDE00DFEE021AD09CA7107CDE00DFEE0D21307FEC0D28E
|
||||
:200700006207E13A2317B7CA9801F1212117BEC8C39801E61F2A23172DCA2E07FE05CA2C47
|
||||
:2007200007FE03C29801CDE80DC3D4063E09CD8307D11ABED20A07D5E5CDE80DE1E5060085
|
||||
:20074000CDCE06E1E57E2AAC18444DE601C259071105001922AC18545D21D406E323CD1E7A
|
||||
:200760000EE9CDE80DE63F2A23172DCA9801CD8307E506E0CDD80DCDC5060629CDD80DE179
|
||||
:20078000C344074F060021AD09090909C9216318222517CDBE0E226118F52A25170E04118F
|
||||
:2007A0006318D511D908E51A47131ABEC2B30723C3A907B7FAE507131AB7F2B707E1EEFFB5
|
||||
:2007C000C2A607D17EFE0DCAEE0712130C23FE22C2A2077EFE0DCAEE0712130C23FE22CA2C
|
||||
:2007E000A207C3D307F1D17812130CC3A2073E0D1221601871F1C923E5CD1E0ECDD80E3EC9
|
||||
:20080000201213E123237EB7FA130812FE0DC813C30508E521D908BE23C217087EB7FA275B
|
||||
:2008200008121323C31C08E1C3050852454144592250524F4752414D204C4F414445443F19
|
||||
:200840002022204552524F522220494E204C494E45202253544F5022FF001000000081163B
|
||||
:2008600066670180833333007E198413017D275573007B2505210179FF0010000000815086
|
||||
:2008800000000180416667007F138889017E248016007C275573017A200000008115708061
|
||||
:2008A00000816366200080271743030303F602C5020001000000008A0309046F048E04A2C3
|
||||
:2008C00004C8044C05F3049E03BA05680603053D055301B005F604CD02804C4554814E459D
|
||||
:2008E000585482494683474F544F84474F5355428552455455524E86524541448744415414
|
||||
:200900004188464F52895052494E54893A8A494E5055548B44494D8C53544F508D454E4499
|
||||
:200920008E524553544F52458F52454D90434C4541529F535445509E544F9D5448454E9C17
|
||||
:20094000544142A052554EA14C495354A24E554C4CA3534352A44D454DA554534156A65486
|
||||
:200960004C4F4144E028E22AE32BE52DE72FEF3E3DF03C3DF13C3EEA3D3EEB3D3CF43CF5E1
|
||||
:200980003DF63EC1414253C6494E54CC415247CD43414C4CCE524E44D253474ED353494EE6
|
||||
:2009A000C4535152D754414ED8434F53FF0F930A0FA30A0A740A06600A0F2E0B066A0A0FD6
|
||||
:2009C000810C0A7E0A0100000D940A04230A042F0A0F500C0F5D0C0F840B04230A042F0AEF
|
||||
:2009E000041A0A0FA90A0FC40A04040A04110A04F8090F130B0F070BCD3B0ACA010AFA0DBE
|
||||
:200A00000AAF12C9CD3B0ACA010AFA010A3EFF12C9CD3B0ACA0D0AC3010ACD3B0ACA010A96
|
||||
:200A2000C30D0ACD3B0ACA0D0AFA0D0AC3010ACD3B0ACA0D0AFA010AC30D0AD50B1B606974
|
||||
:200A40001A962313C2590A014B18CDAF133A4B18B7CA590A3A4A18073D3E01322117D1C9F4
|
||||
:200A60006069424BCD5813C3850A6069424BCDAF13C3850A6069424BCD2814C3850A6069E5
|
||||
:200A8000424BCD3115AF3221173AB316B7C82AAC183600C90AB7CA9E0A0B0AEE0102AF3214
|
||||
:200AA0002117C90BAF02C39E0ACD9E0A50590AB7C2B50A12C90B0AB7215E08CA7A0D2157B7
|
||||
:200AC00013C37A0DCD080C2AAC18545D015018CD780AF1F51FDAFE0A1155182AAC18CD7AE7
|
||||
:200AE0000D017708CDDA0BCD010C215518CD780AF147F107A82AAC182BD602F834C90197AA
|
||||
:200B000008CDDA0BC3F00ACD010C21A108CD640AC3C40A2AAC18CD850DCD070B115A18CD72
|
||||
:200B20009C0DCDC40ACD010C215A18C3820A2AAC18115018CD7A0D2AAC187EB7C8D680FABF
|
||||
:200B4000480B0FE67FC34F0B2F3C0FE67F2F3CC680772B7E01414EB7C2B3013E06F50155B5
|
||||
:200B6000181150182AAC18CD820A1155182AAC18444DCD640ACD010C219C08CD820AF13D3F
|
||||
:200B8000C25D0BC9CD010C115F18215F18CD780A2AAC18368001FCFF09462323CDD50BCD6A
|
||||
:200BA000D50BCDD50B2AAC1801FCFF097EE6F0C2CB0B2AAC187E3D32B916CD14160604CD51
|
||||
:200BC0005E16CD010CCD2A16C3A50B115F182AAC18CD7A0DC97E70472BC92AAC18EB6069E9
|
||||
:200BE000CD7A0DE5CD010C215018CD780ACD010CE1E5CD640AE101FAFF097E23B7F2E30B13
|
||||
:200C0000C92AAC18EB424BC92AAC182B46AF7760E3E52AAC18CD850DCD010C21A608CD78F4
|
||||
:200C20000ACD010CCD810C2AAC18CD850DCD680E7BF5CD010C21A108CD780A115018CD9CA1
|
||||
:200C40000DCD010C215018CD6E0AF1E603E1F5E9CD680EEB22D618114B18C3860DCD680EFB
|
||||
:200C60002AD618EB01690CC5E911D018CDD80E3E0D1211D018214B18CDE711114B18C38645
|
||||
:200C80000D0AD681F2910CAF1605020B15C28A0CC9D605D0570B0B0AE6F00214C8AF0214AF
|
||||
:200CA000C2960CC9E513D52100000E05CDF60DEB2AAE18E519CDC00D22AE18C1D1E1E57211
|
||||
:200CC0002B732B702B71E1C9CD5E0DD8CD2B0DCDE00DFEE0CADC0CCD360DB7C9CDE80D3EA6
|
||||
:200CE00080B14FCD360DE5110A00DCA40CCDC506CD680E0629CDD80DE12BCD130ED2AA01A5
|
||||
:200D00002B2BCD1E0E0E0513CDF60DC9CDE80DFE3BC8FE0DC298017E3DCA230D232323225C
|
||||
:200D20002517C937C31F0DCD5E0DD8470E00CD6B0D3FD04FB7C92ADC1811F9FF7EB7CA508A
|
||||
:200D40000DB8C24C0D2B7EB92BC8232319C33C0D702B7123EB192243181B1BEB37C9CDE075
|
||||
:200D60000DFE41D8FE5B3FD8C3750DCDE00DFE30D8FE3A3FD823222517C90E057E122B1B58
|
||||
:200D80000DC27C0DC9EB2AAC1801FBFF0922AC18EBCD7A0D3E01322317B7C9EB2AAC18E547
|
||||
:200DA0000105000922AC18E1C37A0D2A4518E519224518EB21A708CD130EDAA401E12BC912
|
||||
:200DC000EB21AE18CD130EDAD20D214318CD130EEBD8014F53C3B301CDE80DB8C8C39801B5
|
||||
:200DE000CDE80D2B222517C92A25177E23FE20CAEB0D222517C9190DC2F60DC90E0DC3033C
|
||||
:200E00000E0E227E47B9C8FE0DCA9801CD770F23C3030E7B96237A9E2BC07B96B7C9F57E5B
|
||||
:200E200023666FF1C92A2517EB214B18CDE711D81BEB222517114B18CD860DAF3C322317FF
|
||||
:200E4000C93A2417B7C8014944C3B3012ADA1806004E79FE01CA620E23CD130E2BC809C3DE
|
||||
:200E6000510E014E4CC3B3012AAC18444DE5CD810C214B18CD9B0DE14E2B7EB7C2AA01113D
|
||||
:200E8000FCFF1911000079B7C80D237E0F0F0F0FCDA40EDAAA010DF07ECDA40EDAAA010DBB
|
||||
:200EA000FA8A0EC9E53333626B29D829D819D829D8EB3B3BE1E60F835F7ACE0057C9CD6B12
|
||||
:200EC0000DD8110000C3CF0ECD6B0D626B3FD0D630CDA40ED2C80EC9AF01F0D8CDFD0E0114
|
||||
:200EE00018FCCDFD0E019CFFCDFD0E01F6FFCDFD0E01FFFFCDFD0EC03E301213C9D516FFE7
|
||||
:200F0000E533331409DA000F3B3BE142D1B0C83E30801213C9C5D5E50E01CD0500E67FFEFF
|
||||
:200F200061DA2B0FFE7BD22B0FD620E1D1C147C9CDB20F2163180E49CD150FFE7FCA580F1E
|
||||
:200F4000FE15CA300F77060AFE0DCA770F230DC2380F014C4CC3B301790607FE49CA630F41
|
||||
:200F60002B460CCD770FC3380FC5D5E50E0BCD0500E1D1C1E601C9C5D5E50E0258CD050051
|
||||
:200F8000E1D1C178FE0DC28D0FAFC3990FFE0ACA9D0FFE20D83A20173C322017C93A22171D
|
||||
:200FA000B7C8C54F0600CD770F0DC2A60FC1C9CDB20F060DCD770F060AC3770FCD690FC8DD
|
||||
:200FC000CD150FFE03CA4005C9E5EB3A2017B7C4B20FCD010ECD330F216318222517CDBE5A
|
||||
:200FE0000EDA0001FE0DC20001D1226318216318CD130ED200012A63187E2F77BEC2000125
|
||||
:201000002F77C901FCFF09444D21BF183ACA1832C9181E033600230A571F1F1F1FE60F77E1
|
||||
:20102000237AE60F7723031DC217100A32B918AF7721C71877030AB7CAD811D680C24110F1
|
||||
:2010400034F247102F343C21C818775FFE0621C918DA58103E01B6777E1FD26B10E60FFE0C
|
||||
:2010600006DA66103E05573CC3B110E60F5783FE0747DA7B107EE640C254103AC718B7C2E4
|
||||
:20108000861078C3B1107A93D2A2103ACA18B7F2D811E60ECAD8110F5F1D0E0121BE18C384
|
||||
:2010A0001311CA8B10C3B110061FA0FE07D83E07C9CDA8104F060021C0180922B2187EFE2F
|
||||
:2010C00005DAD8102B347EB7CAD910FE0AC2D5103600C3C4102AB2182B3AC91817DAED105E
|
||||
:2010E0007EB7C2ED102B0DFAD811C3E01021BF187EB7CA131106013AC718B7CA001106FF5C
|
||||
:201100003AC818B7C20C1132C71806018032C8181C0C2B2379FE07C21B110D3AB9181FD28A
|
||||
:201120002811CDD311C32B11CDDD113AC9181FDA66113AC718B7CA581179B7C24211CDD893
|
||||
:2011400011C9CDE211AFB3CA5111CDD8111DC24511CDC911C25111C9CDC9111DC258117980
|
||||
:20116000B7C8F8C34211CDC911CA7511CDE211CDC911C26F110645CD770F3AC718B7CA8B7F
|
||||
:2011800011CDD3113AC8183CC39411062BCD770F3AC8183D0E641600CDBE11FE30CAA41123
|
||||
:2011A00014CD770F7B0E0ACDBE11FE30C2B31115C2B611CD770F7BC63047CD770FC9062FEB
|
||||
:2011C0000491D2C011815F78C97EC63047CD770F230DC9062DC3770F0630C3770F0620C3CB
|
||||
:2011E000770F062EC3770FE5D5EB2B22B01821B6180E09CDAB1211000021BA1822B418218F
|
||||
:20120000FF11E5AF32C718CD7D12DA3412FE2ECA2512FE45CAB312473AB618E610C29112F4
|
||||
:20122000E1D1E137C9AFB2C22F12C6C0B35FC93E80B35FC9E60F4721B6183E30B677AFB098
|
||||
:20124000C24C12B2C24C12B35FC81CC97B17DA52121C7B32B818147AE67FFE07D0AFB2FA51
|
||||
:201260006F12F68057782AB4180707070777C9E67F57782AB418B67723C1C3FC112AB01859
|
||||
:20128000237EFE20CA801222B018FE3AD0FE303FC9110000C5CD0E13C1D1D1D10E0521BE21
|
||||
:2012A00018CD7A0D2AB018EB13B7C9AF77230DC2AC12C9CD7D12DAD812FEE3CAD212FE2BDB
|
||||
:2012C000CAD212FE2DCACD12FEE5C20A133E0132C718CD7D12D20A13CDDE12C39412EB21FD
|
||||
:2012E00000001ACD8A12D2F912D630444D292909294F06000913C3E212EB4722B0187AB7FE
|
||||
:20130000C20A137B17DA0A131FC9C1C32012EB3ABA18B7CA1B13CD1F13C68032BE18C93AD1
|
||||
:20132000B8185FE63F473AC718B7CA4113243E40A3CA3C137D68CD4D132F3CC97D2F3C8018
|
||||
:20134000C93E40A3CA4C137845C33D137885F0E1C30A131000000181C5CDD2150E001BEBDD
|
||||
:201360003AB816AE47EB1A1BA932B81621BA167EB7237ECA7A1307070707C6B0781FDABEC8
|
||||
:201380001317CD9D13D294130604CD381621B91634CA8416C1CD2A16C9E1C3941321B716B0
|
||||
:2013A00006031A8E27772B1B05C2A213D034C9C5CDD2153AB816EE0132B816C35E13173F55
|
||||
:2013C000CD121421B816DADD137EEE01772B06033E9A9EC60027772B053FC2D01321B5166F
|
||||
:2013E0000103007EB7C2F6132304040DC2E313AF32B916C39413FE10D2FC130421B9167E7E
|
||||
:2014000090CA8A16DA8A167778070747CD5E16C3941321B71606033E99CE0096EB8627EBB4
|
||||
:20142000772B1B05C21714C9C57EB7CA42141AB7CA421486DA3D14F28A16C34014FA84163B
|
||||
:20144000D68032B9161B2B1AAE2B1BE521B816772BAF0605772B05C254143AB916B7CA99BD
|
||||
:20146000130E032195161A772B1B0DC26614712B06FA1104004B19EB1904F2AE141A8F27BB
|
||||
:20148000771B2B0DC27D1404C272142311A2160E04417E1223130DC292142199161B1A8ED6
|
||||
:2014A00027121B2B05C29E1406F9EBC37214EB233604C121B21635CAE4140A0BC52BEB87A1
|
||||
:2014C000DACE14CADC1421FCFF19EBC3BF144FB7CD9D131A862777791BC3BF140608CD38E2
|
||||
:2014E00016C3B2143AB516E6F0CAF5147AE6F021B716C30615060421B91635CA8A16CD5EBF
|
||||
:20150000167A0F0F0F0FFE50DA2A153CE60F0E038E27773E002B0DC21015D29413233610EB
|
||||
:2015200021B91634C29413C38416E60F8677C39413C57EB7CA84161AB7CA8F1696DA4615FC
|
||||
:20154000FA8416C34915F28A16C681329616EBD5CD1416D1EB3AB8162BAE329516EB1B01E7
|
||||
:2015600092162E06C5E50E003721B71606033E99CE00EB96EB8627772B1B05C26E157E3F27
|
||||
:20158000DE00771F21030019EB0C17D26815B7CD9D1321030019EBC50604CD5E16C10DE122
|
||||
:2015A00061C17DC2B515FE06C2B51521961635CC8A16C362151F7CD2C5150A0707070784D7
|
||||
:2015C0000203C3C615022DC26415219616C1CD2D16C91A960E00D2DD150CEB2F3C471A3220
|
||||
:2015E000B91678FE06DAEA153E06070747E60432BA16C5D5CD14163E2890FE28CA0E16E6C1
|
||||
:20160000F81F1F1F835F7ACE00571A32BB16CD3816D1C1C911B8160E042B7E122B1B0DC2A0
|
||||
:201620001A16AF121B1232BB16C921B9161E057E020B2B1DC22F16C90E0421B41678D608B7
|
||||
:20164000D2511605F8B77E1F77230DC24616C3381647AF56777A230DC25316C338160E046F
|
||||
:2016600021B71678D608D2771605F8B77E17772B0DC26C16C35E1647AF56777A2B0DC279A4
|
||||
:1216800016C35E16015046C3B3013EFF32B3163333C996
|
||||
:00000001FF
|
|
@ -0,0 +1,218 @@
|
|||
/*************************************************************
|
||||
* Convert Intel HEX file to BIN format
|
||||
* Bobbi
|
||||
* Oct 8 2019
|
||||
*************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#undef DEBUG
|
||||
#define FNAMELEN 15
|
||||
|
||||
/* Convert hex character to value
|
||||
* Returns value or 127 on error */
|
||||
char hexchar(char c) {
|
||||
c = toupper(c);
|
||||
if ((c >= '0') && (c <= '9')) return c - '0';
|
||||
if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
|
||||
return 127;
|
||||
}
|
||||
|
||||
/* Do the actual work of converting a HEX file to a BIN file
|
||||
* Returns 0 on success, 1 on error, 2 on EOF */
|
||||
char hextobin(FILE *in, FILE *out) {
|
||||
int c, datalen, addr, rectype, i;
|
||||
char byte;
|
||||
static int endaddr = -1;
|
||||
|
||||
/* Each line starts with a colon */
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
if (c != ':') {
|
||||
puts("Expected :");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Then two hex digits representing the data length */
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
datalen = c * 16;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
datalen += c;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("datalen=%d\n", datalen);
|
||||
#endif
|
||||
|
||||
/* Then four hex digits representing the address */
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
addr = c * 16 * 16 * 16;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
addr += c * 16 * 16;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
addr += c * 16;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
addr += c;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("addr=%d\n", addr);
|
||||
#endif
|
||||
|
||||
/* Then two more hex digits representing the record type */
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
rectype = c * 16;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
rectype += c;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("rectype=%d\n", rectype);
|
||||
#endif
|
||||
|
||||
/* We only support record type 0 (data) and 1 (EOF) */
|
||||
if ((rectype != 0) && (rectype != 1)) {
|
||||
printf("Unsupported record type %d\n", rectype);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle EOF record */
|
||||
if (rectype == 1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Initialize endaddr on first call */
|
||||
if (endaddr == -1) endaddr = addr;
|
||||
|
||||
/* Check for overlapping addresses */
|
||||
if (addr < endaddr) {
|
||||
puts("Overlap in data!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Zero fill gaps */
|
||||
if (addr > endaddr) {
|
||||
for (i = 0; i < addr - endaddr; ++i) {
|
||||
puts("FILL");
|
||||
fputc(0, out);
|
||||
}
|
||||
}
|
||||
|
||||
endaddr = addr + datalen;
|
||||
|
||||
/* Now datalen bytes stored as 2*datalen hex digits */
|
||||
for (i = 0; i < datalen; ++i) {
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
byte = c * 16;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
byte += c;
|
||||
fputc(byte, out);
|
||||
}
|
||||
|
||||
/* Finally two checksum hex digits (ignored) */
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
c = fgetc(in);
|
||||
if (c == -1) return 1;
|
||||
c = hexchar(c);
|
||||
if (c == 127) return 1;
|
||||
|
||||
/* Now eat the newline */
|
||||
c = fgetc(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char len, ret;
|
||||
char inname[FNAMELEN+1], outname[FNAMELEN+1];
|
||||
FILE *in, *out;
|
||||
|
||||
if (argc != 2) {
|
||||
puts("usage: hex2bin hexfile");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Strip off .HEX extension, if provided */
|
||||
len = strlen(argv[1]);
|
||||
if (len > 4) {
|
||||
if (((argv[1][len-1] == 'x') && (argv[1][len-2] == 'e') &&
|
||||
(argv[1][len-3] == 'h') && (argv[1][len-4] == '.')) ||
|
||||
((argv[1][len-1] == 'X') && (argv[1][len-2] == 'E') &&
|
||||
(argv[1][len-3] == 'H') && (argv[1][len-4] == '.')))
|
||||
argv[1][len-4] = '\0';
|
||||
}
|
||||
|
||||
strcpy(inname, argv[1]);
|
||||
strcat(inname, ".hex");
|
||||
strcpy(outname, argv[1]);
|
||||
strcat(outname, ".bin");
|
||||
printf("%s -> %s\n", inname, outname);
|
||||
|
||||
in = fopen(inname, "r");
|
||||
if (!in) {
|
||||
printf("Can't open %s for reading\n", inname);
|
||||
goto done;
|
||||
}
|
||||
|
||||
out = fopen(outname, "w");
|
||||
if (!out) {
|
||||
printf("Can't open %s for writing\n", outname);
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (!feof(in)) {
|
||||
ret = hextobin(in, out);
|
||||
putchar('.');
|
||||
if (ret == 1) {
|
||||
printf("Error parsing %s\n", inname);
|
||||
goto done;
|
||||
}
|
||||
if (ret == 2) {
|
||||
puts("Done.");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
done:
|
||||
if (in) fclose(in);
|
||||
if (out) fclose(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue