home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource4
/
219_01
/
a48util.c
< prev
next >
Wrap
Text File
|
1989-01-13
|
14KB
|
529 lines
/*
HEADER: CUG219;
TITLE: 8048 Cross-Assembler (Portable);
FILENAME: A48UTIL.C;
VERSION: 0.2;
DATE: 11/09/1988;
DESCRIPTION: "This program lets you use your computer to assemble
code for the Intel 8048 family of microprocessors.
The program is written in portable C rather than BDS
C. All assembler features are supported except
relocation, linkage, and macros.";
KEYWORDS: Software Development, Assemblers, Cross-Assemblers,
Intel, 8048;
SYSTEM: CP/M-80, CP/M-86, HP-UX, MSDOS, PCDOS, QNIX;
COMPILERS: Aztec C86, Aztec CII, CI-C86, Eco-C, Eco-C88, HP-UX,
Lattice C, Microsoft C, QNIX C;
WARNINGS: "This program has compiled successfully on 2 UNIX
compilers, 5 MSDOS compilers, and 2 CP/M compilers.
A port to Toolworks C is untried."
AUTHORS: William C. Colley III;
*/
/*
8048 Cross-Assembler in Portable C
Copyright (c) 1985,1987 William C. Colley, III
Revision History:
Ver Date Description
0.0 APR 1987 Adapted from version 2.4 of my portable 1805A cross-
assembler. WCC3.
0.1 AUG 1988 Fixed a bug in the command line parser that puts it
into a VERY long loop if the user types a command line
like "A48 FILE.ASM -L". WCC3 per Alex Cameron.
0.2 NOV 1988 Fixed a name conflict between a variable and a goto
label that caused some compilers to choke. WCC3.
This module contains the following utility packages:
1) symbol table building and searching
2) opcode and operator table searching
3) listing file output
4) hex file output
5) error flagging
*/
/* Get global goodies: */
#include "a48.h"
/* Make sure that MSDOS compilers using the large memory model know */
/* that calloc() returns pointer to char as an MSDOS far pointer is */
/* NOT compatible with the int type as is usually the case. */
char *calloc();
/* Get access to global mailboxes defined in A18.C: */
extern char errcode, line[], title[];
extern int eject, listhex;
extern unsigned address, bytes, errors, listleft, obj[], pagelen;
/* The symbol table is a binary tree of variable-length blocks drawn */
/* from the heap with the calloc() function. The root pointer lives */
/* here: */
static SYMBOL *sroot = NULL;
/* Add new symbol to symbol table. Returns pointer to symbol even if */
/* the symbol already exists. If there's not enough memory to store */
/* the new symbol, a fatal error occurs. */
SYMBOL *new_symbol(nam)
char *nam;
{
SCRATCH int i;
SCRATCH SYMBOL **p, *q;
void fatal_error();
for (p = &sroot; (q = *p) && (i = strcmp(nam,q -> sname)); )
p = i < 0 ? &(q -> left) : &(q -> right);
if (!q) {
if (!(*p = q = (SYMBOL *)calloc(1,sizeof(SYMBOL) + strlen(nam))))
fatal_error(SYMBOLS);
strcpy(q -> sname,nam);
}
return q;
}
/* Look up symbol in symbol table. Returns pointer to symbol or NULL */
/* if symbol not found. */
SYMBOL *find_symbol(nam)
char *nam;
{
SCRATCH int i;
SCRATCH SYMBOL *p;
for (p = sroot; p && (i = strcmp(nam,p -> sname));
p = i < 0 ? p -> left : p -> right);
return p;
}
/* Opcode table search routine. This routine pats down the opcode */
/* table for a given opcode and returns either a pointer to it or */
/* NULL if the opcode doesn't exist. */
OPCODE *find_code(nam)
char *nam;
{
OPCODE *bsearch();
static OPCODE opctbl[] = {
{ ADD_OP + (R0 << 4) + 10, 0x60, "ADD" },
{ ADD_OP + (R0 << 4) + 10, 0x70, "ADDC" },
{ LOG_OP + (R0 << 4) + 10, 0x50, "ANL" },
{ OUTPUT + (P4 << 4) + 4, 0x90, "ANLD" },
{ LNG_JMP, 0x14, "CALL" },
{ ONE_ARG + (F0 << 4) + 4, 0x27, "CLR" },
{ ONE_ARG + (F0 << 4) + 4, 0x37, "CPL" },
{ ONE_ARG + (A << 4) + 1, 0x57, "DA" },
{ PSEUDO, DB, "DB" },
{ INC_DEC + (R0 << 4) + 8, 0xc0, "DEC" },
{ ONE_ARG + (TCNTI << 4) + 2, 0x15, "DIS" },
{ REG_CND + (R0 << 4) + 8, 0xe0, "DJNZ" },
{ PSEUDO, DS, "DS" },
{ PSEUDO, DW, "DW" },
{ PSEUDO + ISIF, ELSE, "ELSE" },
{ ONE_ARG + (TCNTI << 4) + 2, 0x05, "EN" },
{ PSEUDO, END, "END" },
{ PSEUDO + ISIF, ENDIF, "ENDIF" },
{ ONE_ARG + (CLK << 4) + 1, 0x75, "ENT0" },
{ PSEUDO, EQU, "EQU" },
{ PSEUDO + ISIF, IF, "IF" },
{ A_REG_1 + (P1 << 4) + 2, 0x00, "IN" },
{ INC_DEC + (R0 << 4) + 10, 0x10, "INC" },
{ PSEUDO, INCL, "INCL" },
{ A_REG_1 + (BUS << 4) + 1, 0x00, "INS" },
{ JMP_CND, 0x12, "JB0" },
{ JMP_CND, 0x32, "JB1" },
{ JMP_CND, 0x52, "JB2" },
{ JMP_CND, 0x72, "JB3" },
{ JMP_CND, 0x92, "JB4" },
{ JMP_CND, 0xb2, "JB5" },
{ JMP_CND, 0xd2, "JB6" },
{ JMP_CND, 0xf2, "JB7" },
{ JMP_CND, 0xf6, "JC" },
{ JMP_CND, 0xb6, "JF0" },
{ JMP_CND, 0x76, "JF1" },
{ LNG_JMP, 0x04, "JMP" },
{ ONE_ARG + (AT_A << 4) + 1, 0xb3, "JMPP" },
{ JMP_CND, 0xe6, "JNC" },
{ JMP_CND, 0x86, "JNI" },
{ JMP_CND, 0x26, "JNT0" },
{ JMP_CND, 0x46, "JNT1" },
{ JMP_CND, 0x96, "JNZ" },
{ JMP_CND, 0x36, "JT0" },
{ JMP_CND, 0x56, "JT1" },
{ JMP_CND, 0x16, "JTF" },
{ JMP_CND, 0xc6, "JZ" },
{ MOV + (R0 << 4) + 10, 0x00, "MOV" },
{ A_REG_2 + (P4 << 4) + 4, 0x00, "MOVD" },
{ A_AT_A + (AT_A << 4) + 1, 0xa3, "MOVP" },
{ A_AT_A + (AT_A << 4) + 1, 0xe3, "MOVP3" },
{ A_REG_2 + (AT_R0 << 4) + 2, 0x80, "MOVX" },
{ NO_ARG, 0x00, "NOP" },
{ PSEUDO, ORG, "ORG" },
{ LOG_OP + (R0 << 4) + 10, 0x40, "ORL" },
{ OUTPUT + (P4 << 4) + 4, 0x80, "ORLD" },
{ OUTPUT + (BUS << 4) + 3, 0x00, "OUTL" },
{ PSEUDO, PAGE, "PAGE" },
{ PSEUDO, REGI, "REG" },
{ NO_ARG, 0x83, "RET" },
{ NO_ARG, 0x93, "RETR" },
{ ONE_ARG + (A << 4) + 1, 0xe7, "RL" },
{ ONE_ARG + (A << 4) + 1, 0xf7, "RLC" },
{ ONE_ARG + (A << 4) + 1, 0x77, "RR" },
{ ONE_ARG + (A << 4) + 1, 0x67, "RRC" },
{ ONE_ARG + (MB0 << 4) + 4, 0xc5, "SEL" },
{ PSEUDO, SET, "SET" },
{ ONE_ARG + (TCNT << 4) + 1, 0x65, "STOP" },
{ ONE_ARG + (CNT << 4) + 2, 0x45, "STRT" },
{ ONE_ARG + (A << 4) + 1, 0x47, "SWAP" },
{ PSEUDO, TITL, "TITL" },
{ A_REG_1 + (R0 << 4) + 10, 0x20, "XCH" },
{ A_REG_1 + (AT_R0 << 4) + 2, 0x30, "XCHD" },
{ ADD_OP + (R0 << 4) + 10, 0xd0, "XRL" }
};
return bsearch(opctbl,opctbl + (sizeof(opctbl) / sizeof(OPCODE)),nam);
}
/* Operator table search routine. This routine pats down the */
/* operator table for a given operator and returns either a pointer */
/* to it or NULL if the opcode doesn't exist. */
OPCODE *find_operator(nam)
char *nam;
{
OPCODE *bsearch();
static OPCODE oprtbl[] = {
{ UNARY + UOP1 + OPR, '$', "$" },
{ REG, A, "A" },
{ BINARY + LOG1 + OPR, AND, "AND" },
{ REG, BUS, "BUS" },
{ REG, C, "C" },
{ REG, CLK, "CLK" },
{ REG, CNT, "CNT" },
{ BINARY + RELAT + OPR, '=', "EQ" },
{ REG, F0, "F0" },
{ REG, F1, "F1" },
{ BINARY + RELAT + OPR, GE, "GE" },
{ BINARY + RELAT + OPR, '>', "GT" },
{ UNARY + UOP3 + OPR, HIGH, "HIGH" },
{ REG, I, "I" },
{ BINARY + RELAT + OPR, LE, "LE" },
{ UNARY + UOP3 + OPR, LOW, "LOW" },
{ BINARY + RELAT + OPR, '<', "LT" },
{ REG, MB0, "MB0" },
{ REG, MB1, "MB1" },
{ BINARY + MULT + OPR, MOD, "MOD" },
{ BINARY + RELAT + OPR, NE, "NE" },
{ UNARY + UOP2 + OPR, NOT, "NOT" },
{ BINARY + LOG2 + OPR, OR, "OR" },
{ REG, P1, "P1" },
{ REG, P2, "P2" },
{ REG, P4, "P4" },
{ REG, P5, "P5" },
{ REG, P6, "P6" },
{ REG, P7, "P7" },
{ REG, PSW, "PSW" },
{ REG, R0, "R0" },
{ REG, R1, "R1" },
{ REG, R2, "R2" },
{ REG, R3, "R3" },
{ REG, R4, "R4" },
{ REG, R5, "R5" },
{ REG, R6, "R6" },
{ REG, R7, "R7" },
{ REG, RB0, "RB0" },
{ REG, RB1, "RB1" },
{ BINARY + MULT + OPR, SHL, "SHL" },
{ BINARY + MULT + OPR, SHR, "SHR" },
{ REG, T, "T" },
{ REG, TCNT, "TCNT" },
{ REG, TCNTI, "TCNTI" },
{ BINARY + LOG2 + OPR, XOR, "XOR" }
};
return bsearch(oprtbl,oprtbl + (sizeof(oprtbl) / sizeof(OPCODE)),nam);
}
s