From decwrl!elroy.jpl.nasa.gov!jarthur!uunet!allbery Sun Feb 18 00:49:13 PST 1990 Article 1331 of comp.sources.misc: Path: decwrl!elroy.jpl.nasa.gov!jarthur!uunet!allbery From: stauffer@cpsc.ucalgary.ca (Kenneth Stauffer) Newsgroups: comp.sources.misc Subject: v10i060: An 8031/8051 Assembler Message-ID: <78919@uunet.UU.NET> Date: 14 Feb 90 01:57:59 GMT Sender: allbery@uunet.UU.NET Lines: 3702 Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) Posting-number: Volume 10, Issue 60 Submitted-by: stauffer@cpsc.ucalgary.ca (Kenneth Stauffer) Archive-name: asm.8051 This is an 8031/8051 Assembler, which generates many different output formats including S-records. Ken Stauffer. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'README' <<'END_OF_FILE' X X X as31 - An 8031/8051 assembler. X X Written by: X K e n S t a u f f e r X X Xas31, is an 8031/8051 assembler. The program consists of the Xfollowing files: X X makefile - Makefile. X as31.h - Package header file. X as31.y - Parser / code generator. X lexer.c - Scanner. X symbol.c - Symbol table / opcode table. X emitter.c - Object code generation routines. X main.c - Command line / calls yyparse(). X X as31.man - Assembler manual. X X new.asm - Sample 8031 code. This is a working X debugger written by Theo Deraadt. X XOVERVIEW OF AS31: X as31 is a full featured assembler but it does lack X facilities for linking several modules together. X as31 can be configured to produced a wide variety of X object output formats. X One of the supported output formats is S-records. X (Written by: Theo Deraadt) X X Standard assembler syntax is accepted. X XMAKING AS31: X On most unix systems, running make should be sufficient X to produce a working assembler. X X Also typing: X X % make man X X Will produces a text file from as31.man (called as31.cat). X This is the users manual. X X This package does work on the following systems: X SUN 3 / SUN 4 (SunOS 4.0), Tandy 6000 (Xenix) X X Non-unix systems may require some porting for the FILE I/O X stuff but most reasonable implementations of stdio.h X should work. X XSOURCE CODE: X This code is public domain. X XREPORTING BUGS: X If any bugs are detected in this program, I would X like to know about them so that I could fix them. I can X be reached via E-mail at: X X stauffer@cpsc.ucalgary.ca X XJanuary 26, 1990 X END_OF_FILE if test 1528 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'as31.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'as31.h'\" else echo shar: Extracting \"'as31.h'\" \(3549 characters\) sed "s/^X//" >'as31.h' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X * FILE: as31.h X * PACKAGE: as31 - 8031/8051 Assembler. X * X * DESCRIPTION: X * The sole header file for the 8031/8051 assembler package. X * It defines several structures used by the yacc stack. X * It defines several macros for testing the bitsize of numeric X * quantities. X * X * Some macros to extract information from the mode structure. X * X * REVISION HISTORY: X * Jan. 19, 1990 - Created. (Ken Stauffer) X * X * AUTHOR: X * All code in this file written by Ken Stauffer (University of Calgary). X * January, 1990. X * X */ X X/* ---------------------------------------------------------------------- X * user / keyword symbol structures: X */ X Xstruct opcode { X char *name; X int type; X unsigned char *bytes; X}; X Xstruct symbol { X char *name; X int type; X long value; X struct symbol *next; X}; X X#define UNDEF 0 X#define LABEL 1 X X/* ---------------------------------------------------------------------- X * addressing mode stuff: X */ X Xstruct mode { X unsigned char mode; /* value to index with */ X unsigned char size; /* # of bytes used */ X unsigned char orval; /* value OR'd to obcode */ X unsigned char byte1; /* extra byte 1 */ X unsigned char byte2; /* extra byte 2 */ X}; X X#define set_md(m,a) ((m).mode=(a)) X#define set_sz(m,a) ((m).size=(a)) X#define set_ov(m,a) ((m).orval=(a)) X#define set_b1(m,a) ((m).byte1=(a)) X#define set_b2(m,a) ((m).byte2=(a)) X X#define get_md(m) ((m).mode) X#define get_sz(m) ((m).size) X#define get_ov(m) ((m).orval) X#define get_b1(m) ((m).byte1) X#define get_b2(m) ((m).byte2) X X/* ---------------------------------------------------------------------- X * yacc stack stuff: X */ X Xstruct value { X long v; X unsigned char d; /* expression defined flag */ X}; X Xunion ystack { X long value; X struct value val; X struct opcode *op; X struct symbol *sym; X struct mode mode; X char *str; X}; X X/* ---------------------------------------------------------------------- X * IS_BIT_MAPPED_RAM: X * True is the byte 'a' is the byte address of a bit mapped X * RAM location. X */ X#define isbmram(a) (((a)&0xf0)==0x20) X X/* ---------------------------------------------------------------------- X * IS_BIT_MAPPED_SFR: X * True is the byte 'a' is the byte address of a bit mapped X * SPECIAL FUCTION REGISTER. X */ X#define isbmsfr(a) (((a)&0x80) && !((a) & 0x07)) X X/* ---------------------------------------------------------------------- X * isbit8, ... X * Macros to check the sizes of values and to convert X * a value to a certain, size. X * X */ X#define size8 (~0x00ff) X#define size11 (~0x07ff) X#define size13 (~0x1fff) X#define size16 (~0xffff) X X#define size10 (~0x03ff) X#define size12 (~0x0fff) X#define size15 (~0x7fff) X X#define isbit8(v) ( !( ((v)>=0) ? (v)&size8 : -(v)>=128) ) X#define isbit11(v) ( !( ((v)>=0) ? (v)&size11 : (-(v))&size10 ) ) X#define isbit13(v) ( !( ((v)>=0) ? (v)&size13 : (-(v))&size12 ) ) X#define isbit16(v) ( !( ((v)>=0) ? (v)&size16 : (-(v))&size15 ) ) X X/* ---------------------------------------------------------------------- X * Size of user hash table. X */ X#define HASHTABSIZE 1000 X X/* ---------------------------------------------------------------------- X * Macros to nicely test which pass we are in. X */ X#define pass1 (!pass) X#define pass2 (pass) X X/* -------- TOKENS ------------------------------------------------------ X * X * This includes the header file generated by yacc -d. X * NOPE is defined inside of as31.y, which does not X * need to re-include the tokens twice, thus NOPE prevents this. X * X */ X#ifdef NOPE X#else X#include "y.tab.h" X#endif X END_OF_FILE if test 3549 -ne `wc -c <'as31.h'`; then echo shar: \"'as31.h'\" unpacked with wrong size! fi # end of 'as31.h' fi if test -f 'as31.y' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'as31.y'\" else echo shar: Extracting \"'as31.y'\" \(22290 characters\) sed "s/^X//" >'as31.y' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X * FILE: as31.y X * PACKAGE: as31 - 8031/8051 Assembler. X * X * DESCRIPTION: X * This file contains the yacc parser for the assembler. X * Related to this are the following: X * error(), warning(), yyerror() X * genbyte(), genword(), genstr(), makeop() X * X * X * REVISION HISTORY: X * Jan. 19, 1990 - Created. (Ken Stauffer) X * X * AUTHOR: X * All code in this file written by Ken Stauffer (University of Calgary). X * January 1990. X * X */ X X%{ X X#include X#include X#define NOPE X#include "as31.h" X#undef NOPE X X#define YYSTYPE union ystack X Xextern int lineno; Xextern int dashl; Xextern char *asmfile; Xextern jmp_buf main_env; Xextern FILE *listing; X Xint pass,fatal; Xunsigned long lc; X Xstatic unsigned char bytebuf[1024]; /* used by dumplist() */ Xstatic int bytecount; X X/* ------------------------ G R A M M E R ----------------------------- */ X X%} X X%token STRING X%token D_ORG X%token D_BYTE X%token D_WORD X%token D_SKIP X%token D_EQU X%token D_FLAG X%token D_END X%token ACALL X%token ADD X%token ADDC X%token AJMP X%token ANL X%token CJNE X%token CLR X%token CPL X%token DA X%token DEC X%token DIV X%token DJNZ X%token INC X%token JB X%token JBC X%token JC X%token JMP X%token JNB X%token JNC X%token JNZ X%token JZ X%token LCALL X%token LJMP X%token MOV X%token MOVC X%token MOVX X%token NOP X%token MUL X%token ORL X%token POP X%token PUSH X%token RET X%token RETI X%token RL X%token RLC X%token RR X%token RRC X%token SETB X%token SJMP X%token SUBB X%token SWAP X%token XCH X%token XCHD X%token XRL X%token AB X%token A X%token C X%token PC X%token DPTR X%token BITPOS X%token R0 X%token R1 X%token R2 X%token R3 X%token R4 X%token R5 X%token R6 X%token R7 X%token VALUE X%token SYMBOL X X%left '+' '-' X%left '*' '/' '%' X%left '|' '&' X X%start program X X%% Xprogram : linelist X{ X} X ; X Xlinelist : linelist line X | line X ; X Xline : undefsym ':' linerest X{ X if( pass1 ) { X $1.sym->type = LABEL; X $1.sym->value = lc; X } X inclc($3.value); X bytecount = 0; X} X | linerest { inclc($1.value); bytecount = 0; } X ; X Xlinerest : directive '\n' { X $$.value = $1.value; X if( dashl && pass2 ) X dumplist($2.str,1); X } X | instr '\n' { X $$.value = $1.value; X if( dashl && pass2 ) X dumplist($2.str,1); X X } X | '\n' { X $$.value = 0; X if( dashl && pass2 ) X dumplist($1.str,0); X } X ; X X X X X X/* -------------------- X * DIRECTIVES: X * X */ X Xdirective : '.' D_ORG defexpr X{ X lc = $3.val.v; X if( pass2 ) emitaddr(lc); X bytecount = 0; X $$.value = 0; X} X | '.' D_BYTE blist { $$.value = $3.value; } X | '.' D_WORD wlist { $$.value = $3.value; } X | '.' D_SKIP defexpr { $$.value = $3.val.v; X if( pass2 ) X emitaddr(lc+$$.value); } X | '.' D_EQU undefsym ',' expr X{ X if( $5.val.d == 0 ) X error("Expression is undefined in pass 1"); X $3.sym->type = LABEL; X $3.sym->value = $5.val.v; X $$.value = 0; X} X X | '.' D_FLAG SYMBOL ',' flag X{ X $3.sym->type = LABEL; X $3.sym->value = $5.value; X $$.value = 0; X} X | '.' D_END { $$.value = 0; } X ; X Xdefexpr : expr X{ X if( $1.val.d == 0 ) X error("Expression is undefined in pass 1"); X if( !(isbit16($1.val.v)) ) X error("Value greater than 16-bits"); X $$.value = $1.val.v; X} X ; X Xflag : flagv BITPOS X{ X if( !isbit8($1.value) ) X warning("Bit address exceeds 8-bits"); X if( isbmram($1.value) ) X $$.value = ($1.value-0x20)*8+ $2.value; X else if( isbmsfr($1.value) ) X $$.value = $1.value + $2.value; X else X warning("Invalid bit addressable RAM location"); X} X ; X Xflagv : SYMBOL X{ X if( $1.sym->type == UNDEF ) X error("Symbol %s must be defined in pass 1",$1.sym->name); X $$.value = $1.sym->value; X} X | VALUE { $$.value = $1.value; } X ; X X Xundefsym : SYMBOL X{ X if( $1.sym->type != UNDEF && pass1) X error("Attempt to redefine symbol: %s",$1.sym->name); X $$.sym = $1.sym; X} X ; X Xblist : blist ',' data8 X{ X if( pass2 ) genbyte($3.value); X $$.value = $1.value + 1; X} X | blist ',' STRING X{ X if( pass1 ) X $$.value = $1.value + $3.value; X else { X $$.value = $1.value + strlen($3.str); X genstr($3.str); X X free($3.str); X } X} X | data8 X{ X if( pass2 ) genbyte($1.value); X $$.value = 1; X} X | STRING X{ X if( pass1 ) X $$.value = $1.value; X else { X $$.value = strlen($1.str); X genstr($1.str); X free($1.str); X } X} X ; X Xwlist : wlist ',' data16 X{ X if( pass2 ) genword($3.value); X $$.value = $1.value + 2; X} X | data16 X{ X if( pass2 ) genword($1.value); X $$.value = 2; X} X ; X X X X/* -------------------- X * EXPRESSIONS: X * X */ X Xexpr : '*' { $$.val.v = lc; X $$.val.d = 1; } X X | '(' expr ')' { $$.val.v = $2.val.v; X $$.val.d = $2.val.d; } X X | '-' expr %prec '*' { $$.val.v = -$2.val.v; X $$.val.d = $2.val.d; } X X | expr '|' expr { $$.val.v = $1.val.v | $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X X | expr '&' expr { $$.val.v = $1.val.v & $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X X | expr '*' expr { $$.val.v = $1.val.v * $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X X | expr '/' expr { $$.val.v = $1.val.v / $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X X | expr '%' expr { $$.val.v = $1.val.v % $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X X | expr '-' expr { $$.val.v = $1.val.v - $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X X | expr '+' expr { $$.val.v = $1.val.v + $3.val.v; X $$.val.d = $1.val.d && $3.val.d; } X | SYMBOL X{ X if( pass1 ) { X $$.val.v = $1.sym->value; X $$.val.d = ($1.sym->type != UNDEF); X } X else { X if( $1.sym->type == UNDEF ) X error("Undefined symbol %s",$1.sym->name); X $$.val.v = $1.sym->value; X $$.val.d = 1; X } X} X | VALUE { $$.val.v = $1.val.v; $$.val.d=1; } X ; X X X X X X/* -------------------- X * INSTRUCTIONS: X * X */ X Xinstr : NOP X { $$.value = makeop($1.op,NULL,0); } X | ACALL addr11 X { $$.value = makeop($1.op,&$2.mode,0); } X | AJMP addr11 X { $$.value = makeop($1.op,&$2.mode,0); } X | ADD two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | ADDC two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | SUBB two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | XRL two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | XRL two_op2 X { $$.value = makeop($1.op,&$2.mode,4); } X | ANL two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | ANL two_op2 X { $$.value = makeop($1.op,&$2.mode,4); } X | ANL two_op3 X { $$.value = makeop($1.op,&$2.mode,6); } X | ORL two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | ORL two_op2 X { $$.value = makeop($1.op,&$2.mode,4); } X | ORL two_op3 X { $$.value = makeop($1.op,&$2.mode,6); } X | XCH two_op1 X { if( get_md($2.mode) == 3 ) X error("Immediate mode is illegal"); X $$.value = makeop($1.op,&$2.mode,0); X } X | INC single_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | INC DPTR X { $$.value = makeop($1.op,NULL,4); } X | DEC single_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | DA A X { $$.value = makeop($1.op,NULL,0); } X | DIV AB X { $$.value = makeop($1.op,NULL,0); } X | JMP '@' A '+' DPTR X { $$.value = makeop($1.op,NULL,0); } X | JMP '@' DPTR '+' A X { $$.value = makeop($1.op,NULL,0); } X | MUL AB X { $$.value = makeop($1.op,NULL,0); } X | RET X { $$.value = makeop($1.op,NULL,0); } X | RETI X { $$.value = makeop($1.op,NULL,0); } X | RL A X { $$.value = makeop($1.op,NULL,0); } X | RLC A X { $$.value = makeop($1.op,NULL,0); } X | RR A X { $$.value = makeop($1.op,NULL,0); } X | RRC A X { $$.value = makeop($1.op,NULL,0); } X | SWAP A X { $$.value = makeop($1.op,NULL,0); } X | XCHD two_op1 X { if( get_md($2.mode) != 2 ) X error("Invalid addressing mode"); X $$.value = makeop($1.op,&$2.mode,-2); } X | CLR single_op2 X { $$.value = makeop($1.op,&$2.mode,0); } X | CPL single_op2 X { $$.value = makeop($1.op,&$2.mode,0); } X | SETB single_op2 X { if( get_md($2.mode) == 0 ) X error("Invalid addressing mode"); X $$.value = makeop($1.op,&$2.mode,-1); } X | PUSH data8 X { X struct mode tmp; X set_md(tmp,0); X set_ov(tmp,0); X set_sz(tmp,1); X set_b1(tmp,$2.value); X $$.value = makeop($1.op,&tmp,0); X } X | POP data8 X { X struct mode tmp; X set_md(tmp,0); X set_ov(tmp,0); X set_sz(tmp,1); X set_b1(tmp,$2.value); X $$.value = makeop($1.op,&tmp,0); X } X | LJMP addr16 X { $$.value = makeop($1.op,&$2.mode,0); } X | LCALL addr16 X { $$.value = makeop($1.op,&$2.mode,0); } X | JC relative X { $$.value = makeop($1.op,&$2.mode,0); } X | JNC relative X { $$.value = makeop($1.op,&$2.mode,0); } X | JNZ relative X { $$.value = makeop($1.op,&$2.mode,0); } X | JZ relative X { $$.value = makeop($1.op,&$2.mode,0); } X | SJMP relative X { $$.value = makeop($1.op,&$2.mode,0); } X | CJNE three_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | JB two_op4 X { $$.value = makeop($1.op,&$2.mode,0); } X | JNB two_op4 X { $$.value = makeop($1.op,&$2.mode,0); } X | JBC two_op4 X { $$.value = makeop($1.op,&$2.mode,0); } X | DJNZ two_op5 X { $$.value = makeop($1.op,&$2.mode,0); } X | MOV two_op1 X { $$.value = makeop($1.op,&$2.mode,0); } X | MOV two_op2 X { $$.value = makeop($1.op,&$2.mode,4); } X | MOV two_op6 X { $$.value = makeop($1.op,&$2.mode,6); } X X X | MOVC A ',' '@' A '+' DPTR X { $$.value = makeop($1.op,NULL,0); } X | MOVC A ',' '@' DPTR '+' A X { $$.value = makeop($1.op,NULL,0); } X | MOVC A ',' '@' A '+' PC X { $$.value = makeop($1.op,NULL,1); } X | MOVC A ',' '@' PC '+' A X { $$.value = makeop($1.op,NULL,1); } X X | MOVX A ',' '@' regi X { $$.value = makeop($1.op,NULL,$5.value); } X | MOVX A ',' '@' DPTR X { $$.value = makeop($1.op,NULL,2); } X | MOVX '@' regi ',' A X { $$.value = makeop($1.op,NULL,$3.value+3); } X | MOVX '@' DPTR ',' A X { $$.value = makeop($1.op,NULL,5); } X ; X X X X X/* -------------------- X * ADDRESSING MODES: X * X */ X Xtwo_op1 : A ',' reg X { X set_md($$.mode,0); X set_ov($$.mode, $3.value); X set_sz($$.mode, 0); X } X | A ',' data8 X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$3.value); X } X | A ',' '@' regi X { X set_md($$.mode,2); X set_ov($$.mode,$4.value); X set_sz($$.mode,0); X } X | A ',' '#' data8 X { X set_md($$.mode,3); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$4.value); X } X ; X Xtwo_op2 : data8 ',' A X { X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$1.value); X } X | data8 ',' '#' data8 X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode,$1.value); X set_b2($$.mode,$4.value); X } X ; X Xtwo_op3 : C ',' bit X { X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$3.value); X } X | C ',' '/' bit X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$4.value); X } X | C ',' '!' bit X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$4.value); X } X ; X Xtwo_op4 : bit ',' rel X { X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode,$1.value); X set_b2($$.mode,$3.value); X } X ; X Xtwo_op5 : reg ',' rel2 X { X set_md($$.mode,0); X set_ov($$.mode,$1.value); X set_sz($$.mode,1); X set_b1($$.mode,$3.value); X } X | data8 ',' rel X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode,$1.value); X set_b2($$.mode,$3.value); X } X ; X Xtwo_op6 : reg ',' A X { X set_md($$.mode,0); X set_ov($$.mode,$1.value); X set_sz($$.mode,0); X } X | reg ',' data8 X { X set_md($$.mode,1); X set_ov($$.mode,$1.value); X set_sz($$.mode,1); X set_b1($$.mode,$3.value); X } X | reg ',' '#' data8 X { X set_md($$.mode,2); X set_ov($$.mode,$1.value); X set_sz($$.mode,1); X set_b1($$.mode,$4.value); X } X | data8 ',' reg X { X set_md($$.mode,3); X set_ov($$.mode,$3.value); X set_sz($$.mode,1); X set_b1($$.mode,$1.value); X } X | data8 ',' data8 X { X set_md($$.mode,4); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode,$3.value); X set_b2($$.mode,$1.value); X } X | data8 ',' '@' regi X { X set_md($$.mode,5); X set_ov($$.mode,$4.value); X set_sz($$.mode,1); X set_b1($$.mode,$1.value); X } X | '@' regi ',' A X { X set_md($$.mode,6); X set_ov($$.mode,$2.value); X set_sz($$.mode,0); X } X | '@' regi ',' data8 X { X set_md($$.mode,7); X set_ov($$.mode,$2.value); X set_sz($$.mode,1); X set_b1($$.mode,$4.value); X } X | '@' regi ',' '#' data8 X { X set_md($$.mode,8); X set_ov($$.mode,$2.value); X set_sz($$.mode,1); X set_b1($$.mode,$5.value); X } X | DPTR ',' '#' data16 X { X set_md($$.mode,9); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode, ($4.value & 0xff00) >> 8 ); X set_b2($$.mode, ($4.value & 0x00ff) ); X } X | C ',' bit X { X set_md($$.mode,10); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$3.value); X } X /* X * Following two productions cannot be represented by: X * X * bit ',' C X * X * Because yacc gives tons of reduce/reduce errors if X * that is attempted. X * X */ X | data8 ',' C X { X set_md($$.mode,11); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$1.value); X } X | data8 BITPOS ',' C X{ X if( pass2 ) { X if( !isbit8($1.value) ) X warning("Bit address exceeds 8-bits"); X if( isbmram($1.value) ) X set_b1($$.mode, ($1.value-0x20)*8+ $2.value ); X else if( isbmsfr($1.value) ) X set_b1($$.mode, $1.value + $2.value ); X else X warning("Invalid bit addressable RAM location"); X } X set_md($$.mode,11); X set_ov($$.mode,0); X set_sz($$.mode,1); X} X ; X X Xsingle_op1 : A X { X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,0); X } X X | reg X { X set_md($$.mode,1); X set_ov($$.mode,$1.value); X set_sz($$.mode,0); X } X | data8 X { X set_md($$.mode,2); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$1.value); X } X | '@' regi X { X set_md($$.mode,3); X set_ov($$.mode,$2.value); X set_sz($$.mode,0); X } X ; X Xsingle_op2 : A X { X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,0); X } X | C X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,0); X } X | bit X { X set_md($$.mode,2); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,$1.value); X } X ; X Xthree_op1 : A ',' data8 ',' rel X { X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode,$3.value); X set_b2($$.mode,$5.value); X } X | A ',' '#' data8 ',' rel X { X set_md($$.mode,1); X set_ov($$.mode,0); X set_sz($$.mode,2); X set_b1($$.mode,$4.value); X set_b2($$.mode,$6.value); X } X | reg ',' '#' data8 ',' rel X { X set_md($$.mode,2); X set_ov($$.mode,$1.value); X set_sz($$.mode,2); X set_b1($$.mode,$4.value); X set_b2($$.mode,$6.value); X } X | '@' regi ',' '#' data8 ',' rel X { X set_md($$.mode,3); X set_ov($$.mode,$2.value); X set_sz($$.mode,2); X set_b1($$.mode,$5.value); X set_b2($$.mode,$7.value); X } X ; X Xrel : expr X{ X long offset; X if( pass2 ) { X offset = $1.val.v - (lc+3); X if( offset > 127 || offset < -128 ) X warning("Relative offset exceeds -128 / +127"); X $$.value = offset; X } X} X ; X X/* X * This production differs from the above, by 1 number! X * X */ X Xrel2 : expr X{ X long offset; X if( pass2 ) { X offset = $1.val.v - (lc+2); /* different! */ X if( offset > 127 || offset < -128 ) X warning("Relative offset exceeds -128 / +127"); X $$.value = offset; X } X} X ; X X Xbit : bitv BITPOS X{ X if( pass2 ) { X if( !isbit8($1.value) ) X warning("Bit address exceeds 8-bits"); X if( isbmram($1.value) ) X $$.value = ($1.value-0x20)*8+$2.value; X else if( isbmsfr($1.value) ) X $$.value = $1.value + $2.value; X else X warning("Invalid bit addressable RAM location"); X } X} X | bitv X{ X if( pass2 ) { X if( !isbit8($1.value) ) X warning("Bit address exceeds 8-bits"); X $$.value = $1.value; X } X} X ; X Xbitv : SYMBOL X{ X if( $1.sym->type == UNDEF && pass2 ) X error("Symbol %s undefined",$1.sym->name); X $$.value = $1.sym->value; X} X | VALUE { $$.value = $1.value; } X ; X Xreg : R0 { $$.value = 0; } X | R1 { $$.value = 1; } X | R2 { $$.value = 2; } X | R3 { $$.value = 3; } X | R4 { $$.value = 4; } X | R5 { $$.value = 5; } X | R6 { $$.value = 6; } X | R7 { $$.value = 7; } X ; X Xregi : R0 { $$.value = 0; } X | R1 { $$.value = 1; } X | R2 X { $$.value = 0; X warning("Illegal indirect register: @r2"); } X | R3 X { $$.value = 0; X warning("Illegal indirect register: @r3"); } X | R4 X { $$.value = 0; X warning("Illegal indirect register: @r4"); } X | R5 X { $$.value = 0; X warning("Illegal indirect register: @r5"); } X | R6 X { $$.value = 0; X warning("Illegal indirect register: @r6"); } X | R7 X { $$.value = 0; X warning("Illegal indirect register: @r7"); } X ; X Xdata8 : expr X{ X if( pass2 ) { X if( !isbit8($1.val.v) ) X warning("Expression greater than 8-bits"); X } X $$.value = $1.val.v; X} X ; X Xdata16 : expr X{ X if( pass2 ) { X if( !isbit16($1.val.v) ) X warning("Expression greater than 16-bits"); X } X $$.value = $1.val.v; X} X ; X Xaddr11 : expr X{ X if( pass2 ) { X if( !isbit16($1.val.v) ) X warning("Address greater than 16-bits"); X if( ($1.val.v & size11) != ((lc+2) & size11) ) X warning("Address outside current 2K page"); X } X set_md($$.mode,0); X set_ov($$.mode, ($1.val.v&0x0700)>>3 ); X set_sz($$.mode,1); X set_b1($$.mode,$1.val.v&0x00ff); X} X ; X Xaddr16 : expr X{ X if( pass2 ) { X if( !isbit16($1.val.v) ) X warning("Address greater than 16-bits"); X } X set_md($$.mode,0); X set_ov($$.mode, 0 ); X set_sz($$.mode,2); X set_b1($$.mode, ($1.val.v & 0xff00 ) >> 8 ); X set_b2($$.mode, ($1.val.v & 0x00ff ) ); X} X ; X Xrelative : expr X{ X long offset; X if( pass2 ) { X offset = $1.val.v - (lc+2); X if( offset>127 || offset<-128 ) X warning("Relative offset exceeds -128 / +127"); X } X set_md($$.mode,0); X set_ov($$.mode,0); X set_sz($$.mode,1); X set_b1($$.mode,offset); X X} X ; X X%% X X/* ---------------------------------------------------------------------- */ X Xyyerror(s) Xchar *s; X{ X error(s); X} X X X/* ---------------------------------------------------------------------- X * error: X * Uses semi-variable arguments. This causes immediate assembler X * termination. X */ X Xerror(cs,a1,a2,a3,a4,a5,a6) Xchar *cs,*a1,*a2,*a3,*a4,*a5,*a6; X{ X fprintf(stderr,"File: %s, line: %d, ",asmfile,lineno); X fprintf(stderr,cs,a1,a2,a3,a4,a5,a6); X fprintf(stderr,".\n"); X longjmp(main_env,1); X} X X/* ---------------------------------------------------------------------- X * warning: X * Produce error message. This will abort assembly at X * the end of the current pass. X * X */ X Xwarning(cs,a1,a2,a3,a4,a5,a6) Xchar *cs,*a1,*a2,*a3,*a4,*a5,*a6; X{ X fatal++; X fprintf(stderr,"File: %s, line: %d, ",asmfile,lineno); X fprintf(stderr,cs,a1,a2,a3,a4,a5,a6); X fprintf(stderr,".\n"); X} X X X/* ---------------------------------------------------------------------- X * makeop: X * This function makes an opcode based on the instruction symbol table X * entry, and an addressing mode structure. X * This function is called from both passes, but X * only generates code in pass 2. X * X * Resultant opcode bytes are passed to genbyte(). X * X * Returns the nuumber of bytes that the instruction X * occupies. X * X */ X Xmakeop(op,m,add) Xstruct opcode *op; Xstruct mode *m; X{ X register unsigned int newop; X X if( m == NULL ) { X if(pass2) genbyte(op->bytes[0+add]); X return(1); X } X X if( pass2 ) { X newop = op->bytes[ get_md(*m)+add ] | get_ov(*m); X genbyte(newop); X if( get_sz(*m) > 0 ) genbyte( get_b1(*m) ); X if( get_sz(*m) > 1 ) genbyte( get_b2(*m) ); X } X return( get_sz(*m)+1 ); X} X X X/* ---------------------------------------------------------------------- X * inclc: X * Increments the Location Counter by 'i' amount. X * Check to see if 'i' overflows 64K. X * Checks to see if assembler is overlapping previous sections X * of code. (using a large bit field). X * X */ X X#define indx(a) ( (a)/(sizeof(long)*8) ) X#define bit(a) ( 1 << ((a)%(sizeof(long)*8)) ) X X#define getloc(a) (regions[indx(a)] & bit(a)) X#define setloc(a) (regions[indx(a)] |= bit(a)) X Xinclc(i) X{ X static unsigned long regions[ 0x10000/(sizeof(long)*8) ]; X X while(i-- > 0) { X if( pass2 && getloc(lc) ) X error("Location counter overlaps"); X if( pass2 ) setloc(lc); X lc += 1; X } X X if( lc > 0xffff ) X error("Location counter has exceeded 16-bits"); X} X X/* ---------------------------------------------------------------------- X * padline: X * This routine returns a new string, which is equivilant to X * 'line' except that all tabs have been expanded to spaces, and X * the total length has been truncated to 60 chars. X */ X Xchar *padline(line) Xchar *line; X{ X static char newline[61]; X char *p1; X int pos=0,nxtpos; X X for(p1=line; pos= 4 ) { X j = 0; X fprintf(listing,"\n "); X } X } X while(++j <= 4) X fprintf(listing," "); X X fprintf(listing," %s\n",padline(txt)); X} X X/* ---------------------------------------------------------------------- X * gen* routines: X * Place information into the bytebuf[] array, and also X * call emitbyte with the byte. X * X */ X Xgenbyte(b) Xint b; X{ X if( bytecount < sizeof(bytebuf) ) X bytebuf[bytecount++] = b; X emitbyte(b); X} X Xgenstr(s) Xchar *s; X{ X while( *s ) X genbyte(*s++); X} X Xgenword(w) Xunsigned long w; X{ X genbyte( (w & 0xff00) >> 8 ); X genbyte( (w & 0x00ff) ); X} X END_OF_FILE if test 22290 -ne `wc -c <'as31.y'`; then echo shar: \"'as31.y'\" unpacked with wrong size! fi # end of 'as31.y' fi if test -f 'as31.man' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'as31.man'\" else echo shar: Extracting \"'as31.man'\" \(9374 characters\) sed "s/^X//" >'as31.man' <<'END_OF_FILE' X.TH AS31 1L X.SH NAME Xas31 - An Intel 8031/8051 assembler X.SH SYNOPSIS X.B as31 X[ X.B \-Fformat X] [ X.B \-Aarg X] [ X.B \-l X] X.BR infile.asm X.SH DESCRIPTION X.I As31 Xassembles X.IR infile.asm Xinto one of several different output formats. The output Xwill be in a file called infile.obj. The .asm extenstion Xis required. X X.SH OPTIONS XThe options must appear before the input file name. Both Xoptions are optional. The text of each flag must appear Xon the same argument as the flag. For example, "-Fod" is a Xvalid argument, but "-F od" is not. X.TP X.I \-Fformat XThis options specifies the output format that is to be used. X.IP XCurrently the only options available for this are: X.RS X.IP "tdr" XThis format generates an asci file of hex digits formatted in such a Xway, so that they can be read by tdr's debugger. An argument can be Xspecified (See -A option) which will pass a format specific string to Xthe format generator. In this case, the argument string represents Xan offset to add to the location counter. This offset is Xspecified in decimal and defaults to 64*1024 (0x10000). To specify Xand offset of 100, you would need "-Ftdr -A100" when invoking the Xassembler. X X.IP "byte" XThis format is simply an address and a byte on each line, in ascii. XNo -A option is used. X X.IP "od" XThis format is similar to the output from od(1). The format Xconsists of an address followed by sixteen hexadecimal bytes, followed Xby the equivilant ASCII. No -A option is used. X X.IP "srec2, srec3, srec4" XThe srecord generator is capable of generating output with any one Xof 2, 3, or 4 byte addresses. The -A option can be used to set the Xbase address offset, the default here is 0x0000 (unlike \fBtdr\fP). X.RE X.IP XNOTE: This assembler allows for the output formats to be expanded to Xinclude many different output formats. X.IP \-Aarg XThis option specifies a format specific string which is Xpassed to the format generator. Both format "tdr" and the srecord Xformats use this option. X.IP \-l XThis option tells the assembler to also generate a listing file. XA listing will be placed in the file infile.lst. Where 'infile' is Xthe file that is being assembled. This option may appear Xanywhere before infile.asm. The option must occur isolated on Xthe command line. X.IP XThe listing file shows the assembler generated code in hex, and up to X60 characters are retained from the source file. X.DE X X.SH "ASSEMBLER INSTRUCTIONS" XThis assembler accepts standard 8031/8051 instruction formats. XBelow is a list of instructions Xand addressing modes. X.IP X.RS X.nf X.ta +1i +2i +1i +1i XINSTRUCTION BYTES CYCLES X----------- ----- ------ XACALL addr11 2 24 XADD A, #data8 2 12 XADD A, @Ri 1 12 XADD A, Rn 1 12 XADD A, direct 2 12 XADDC A, #data8 2 12 XADDC A, @Ri 1 12 XADDC A, Rn 1 12 XADDC A, direct 2 12 XAJMP addr11 2 24 XANL A, #data8 2 12 XANL A, @Ri 1 12 XANL A, Rn 1 12 XANL A, direct 2 12 XANL C, /bit 2 24 XANL C, !bit 2 24 XANL C, bit 2 24 XANL direct, #data8 3 24 XANL direct, A 2 12 XCJNE @Ri, #data8, rel 3 24 XCJNE A, #data8, rel 3 24 XCJNE A, direct, rel 3 24 XCJNE Rn, #data8, rel 3 24 XCLR A 1 12 XCLR C 1 12 XCLR bit 2 12 XCPL A 1 12 XCPL C 1 12 XCPL bit 2 12 XDA A 1 12 XDEC @Ri 1 12 XDEC A 1 12 XDEC DPTR 1 12 XDEC Rn 1 12 XDEC direct 2 12 XDIV AB 1 48 XDJNZ Rn, rel 2 24 XDJNZ direct, rel 3 24 XINC @Ri 1 12 XINC A 1 12 XINC DPTR 1 24 XINC Rn 1 12 XINC direct 2 12 XJB bit, rel 3 24 XJBC bit, rel 3 24 XJC relative 2 24 XJMP @A + DPTR 1 24 XJMP @DPTR + A 1 24 XJNB bit, rel 3 24 XJNC relative 2 24 XJNZ relative 2 24 XJZ relative 2 24 XLCALL addr16 3 24 XLJMP addr16 3 24 XMOV @Ri, #data8 2 12 XMOV @Ri, A 1 12 XMOV @Ri, direct 2 24 XMOV A, #data8 2 12 XMOV A, @Ri 1 12 XMOV A, Rn 1 12 XMOV A, direct 2 12 XMOV C, bit 2 12 XMOV DPTR, #data16 3 24 XMOV Rn, #data8 2 12 XMOV Rn, A 1 12 XMOV Rn, direct 2 24 XMOV bit, C 2 24 XMOV direct, #data8 3 24 XMOV direct, @Ri 2 24 XMOV direct, A 2 12 XMOV direct, Rn 2 24 XMOV direct, direct 3 24 XMOVC A, @A + DPTR 1 24 XMOVC A, @A + PC 1 24 XMOVC A, @DPTR + A 1 24 XMOVC A, @PC + A 1 24 XMOVX @DPTR, A 1 12 XMOVX @Ri, A 1 24 XMOVX A, @DPTR 1 24 XMOVX A, @Ri 1 24 XMUL AB 1 48 XNOP 1 12 XORL A, #data8 2 12 XORL A, @Ri 1 12 XORL A, Rn 1 12 XORL A, direct 2 12 XORL C, /bit 2 24 XORL C, !bit 2 24 XORL C, bit 2 24 XORL direct, #data8 3 24 XORL direct, A 2 12 XPOP direct 2 24 XPUSH direct 2 24 XRET 1 24 XRETI 1 24 XRL A 1 12 XRLC A 1 12 XRR A 1 12 XRRC A 1 12 XSETB A 1 12 XSETB bit 2 12 XSJMP relative 2 24 XSUBB A, #data8 2 12 XSUBB A, @Ri 1 12 XSUBB A, Rn 1 12 XSUBB A, direct 2 12 XSWAP A 1 12 XXCH A, #data8 2 12 XXCH A, @Ri 1 12 XXCH A, Rn 1 12 XXCH A, direct 2 12 XXCHD A, #data8 2 12 XXCHD A, @Ri 1 12 XXCHD A, Rn 1 12 XXCHD A, direct 2 12 XXRL A, #data8 2 12 XXRL A, @Ri 1 12 XXRL A, Rn 1 12 XXRL A, direct 2 12 XXRL direct, #data8 3 12 XXRL direct, A 2 12 X.fi X.RE X X.SH "ASSEMBLER DIRECTIVES" XAs31 includes the following assembler directives: X.IP ".ORG expr" XStart assembling at the address specified by the expression expr. XAn error occurs if the assembler starts assembling over an address Xspace that has previously been assembled into. X X.IP ".EQU symbol, expr" XSet symbol to the value of expr. The value for expr must be Xknown during the first pass, when the line containing the .EQU Xis encountered. X X.IP ".BYTE expr, expr, ..." XAssemble the bytes specified by the expression into memory. A Xstring may also be specified with this directive. X X.IP ".WORD expr, expr, ..." XAssemble the words specified by the expression into memory. XThe byte ordering used, is that used by the 8031. X X.IP ".FLAG symbol1, symbol.[0-7]" XSets symbol1 to the bit address specified by the symbol.[0-7] Xexpression. Where [0-7] denotes a character between 0 and 7. XThe resulting bit address is checked to see if it is a valid bit Xaddress. X X.IP ".END" XThis directive is ignored. X X.IP ".SKIP expr" XAdds the value of expr to the location counter. Used Xto reserve a block of uninitialized data. Expr should Xbe in bytes. X X.SH "LEXICAL CONVENTIONS" X.IP "-" XAll characters following a semi-colon are ignored until a newline Xis encountered. X X.IP "-" XAll numbers default to decimal, unless the number starts with Xone of the following: X.RS X.IP "0x or 0X" XThis indicates a hexadecimal number. ie. 0x00ff X.IP "0b or 0B" XThis indicates a binary number. (1's and 0's). ie. 0b1100110010 X.IP "0" XThis indicates an octal number. ie. 0377 X.RE X.IP "-" XAll numbers default to decimal, unless the number ends with Xone of the following characters: X.RS X.IP "b or B" XThis indicates a binary number. Unless 0x was used above. Xie. 1010101b X.IP "h or H" XThis always indicates a hex number, However the if the first Xcharacter is non-numerical, then either 0x or 0 must be specified. XThis avoids confusing the assembler into thinking a hex number is Xa symbol. XFor example: 0ffh, 0xffh, 0XffH, 20h, 0x20 and 020h are means Xto specify a valid hexdigit. But the following are not: Xffh, 0ff. X.IP "d or D" XThis forces a number to decimal. Unless 0X was used. ie. 129d X.IP "o or O" XThis causes the number to be interpreted as octal. ie. 377o X.RE X X.IP "-" XA character constant can be entered as 'c' where c is some Xcharacter. \\b, \\n, \\r, \\t, \\' \\0 are also valid. A character Xconstant can be used anywhere that an integer value can. X X.IP "-" XA string is entered as a set of characters enclosed in double quotes "". XA string is only valid with the .BYTE directive. \\b, \\n, \\r, \\t, \\" Xare also valid escapes. However \\0 is not. X X.IP "-" XInstructions, directives, and the symbols: R0, R1, R2, R3, R4, R5, XR6, R7, A, AB, and C can be entered in upper or lower case without Xassembler confusion. These words however cannot be defined as a user symbol. XAny user symbol may be used, and case will be preserved. So the Xuser symbols "foo" and "Foo" are different, but "addc" is the same Xas "aDdC". X X.IP "-" XA symbol can be any alpha numerical character plus the underscore ('_'). X X.IP "-" XExpressions are accepted in most places where a value or a symbol is Xneeded. An expression consists of the following operators. All Xoperators evaulate to integer objects (higher precedence opertors listed Xfirst): X.RS X.IP "-" XUnary minus X.IP "&" XBit-wise AND. X.IP "|" XBit-Wise OR. X.IP "*" XInteger multiplication. X.IP X\\ Integer division X.IP "%" XIntieger modulus X.IP "+" XInteger addition. X.IP "-" XInteger subtraction. X.RE X.IP "-" XIn addition to these operators, a special symbol '*' may be used Xto represent the current location counter. X X.SH EXAMPLES X.IP XBelow is a sample assembly program. X.RS X.nf X X .org 0 Xstart: mov P3, #0xff ; use alternate fns on P3 X ; leds on P1 are inverted. X setb F0 ; climbing up X mov A, #0x01 ; initial bit X Xwrite: cpl A ; write it X mov P1, A X cpl A X acall delay X jb F0, climbup ; climbing which way? X Xclimbdn: rr A ; down - shift right X jnb ACC.0, write ; back for more X setb F0 X ajmp write X Xclimbup: rl A ; up - shift left X jnb ACC.7, write ; back for more X clr F0 X ajmp write X .end ; this directive ignored. X.fi X X X.SH AUTHOR XKen Stauffer (University of Calgary) X.br Xstauffer@cpsc.ucalgary.ca END_OF_FILE if test 9374 -ne `wc -c <'as31.man'`; then echo shar: \"'as31.man'\" unpacked with wrong size! fi # end of 'as31.man' fi if test -f 'emitter.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'emitter.c'\" else echo shar: Extracting \"'emitter.c'\" \(8382 characters\) sed "s/^X//" >'emitter.c' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X * FILE: emitter.c X * PACKAGE: as31 - 8031/8051 Assembler. X * X * DESCRIPTION: X * This file contains the code to generate various X * object code formats. Provisions exist to X * support many types of output formats within the X * same executable. X * X * REVISION HISTORY: X * Jan. 19, 1990 - Created. (Ken Stauffer) X * Jan. 29, 1990 - Added S-records (Theo Deraadt) X * X * X * AUTHOR: X * All code in this file written by Ken Stauffer (University of Calgary). X * January, 1990. X */ X X#include X X/* ---------------------------------------------------------------------- X * DECLARE your own open(), close(), addr(), and byte() routines here. X * X */ X Xstatic int open1(), close1(), addr1(), byte1(); Xstatic int open2(), close2(), addr2(), byte2(); Xstatic int open3(), close3(), addr3(), byte3(); Xstatic int open4(), close4(), addr4(), byte4(); X X/* ---------------------------------------------------------------------- X * ADD an entry to this table to register your X * output format routines. Give your object format X * a name to be specified with the -F option. X * X */ X Xstatic int format; Xstatic struct { X char *name; X int (*e_open)(); X int (*e_close)(); X int (*e_addr)(); X int (*e_byte)(); X} formtab[] = { X { "tdr", open1, close1, addr1, byte1 }, X { "byte", open2, close2, addr2, byte2 }, X { "od", open3, close3, addr3, byte3 }, X { "srec2", open4, close4, addr4, byte4 }, X { "srec3", open4, close4, addr4, byte4 }, X { "srec4", open4, close4, addr4, byte4 } X}; X X#define FORMTABSIZE (sizeof(formtab)/sizeof(formtab[0])) X Xemitusage() X{ X int i; X fprintf(stderr, "\tfmt is one of:"); X for(i=0; i=' ' && b[i]<='~') ? b[i] : '.' ); X else X break; X } X fprintf(fout,"\n"); X} X X/* ---------------------------------------------------------------------- X * srecord format. This is called with "-Fsrec2", "-Fsrec3", or X * "-Fsrec4"... X * X * arg: This is a number in decimal which specifies X * the offset, -Fsrec3 -A0000 X * X * These options specifies the tdr format, with an argument X * of 0. This becomes the offset used in generating the X * script file. The default if no A is present is 0x0000. X * X */ X#define SREC_BYTESPERLINE 32 X Xstatic char format4; Xstatic int check4, index4; Xstatic char buf4[SREC_BYTESPERLINE]; Xstatic long address4; X Xstatic open4(file,ftype,arg) Xchar *file, *ftype, *arg; X{ X format4 = ftype[4]; /* will be '2' -- '4' */ X X fout = fopen(file,"w"); X if( fout == NULL ) { X fprintf(stderr,"Cannot open %s for writing.\n",file); X exit(1); X } X X if(arg) offset = atoi(arg); X else offset = 0; X X fprintf(fout, "S0030000%02X\n", (~3 & 0xff) ); X X} X Xstatic close4() X{ X if(index4) X finishline(); X switch(format4) { X case '2': X fprintf(fout, "S9030000%02X\n", ~3 & 0xff); X break; X case '3': X fprintf(fout, "S804000000%02X\n", ~4 & 0xff); X break; X case '4': X fprintf(fout, "S70500000000%02X\n", ~5 & 0xff); X break; X } X fclose(fout); X} X X Xstatic addr4(a) Xunsigned long int a; X{ X if(index4>0) X finishline(); X address4 = a + offset; X} X Xstatic byte4(b) X{ X buf4[index4++] = b; X if(index4==SREC_BYTESPERLINE) { X finishline(); X address4 += SREC_BYTESPERLINE; X } X} X Xfinishline() X{ X int i; X X check4 = index4 + (address4 & 0xff) + ((address4>>8) & 0xff) + 4; X X switch(format4) { X case '2': X fprintf(fout, "S1%02X%04X", index4 + 4, address4 & 0xffff); X break; X case '3': X fprintf(fout, "S2%02X%06X", index4 + 6, address4 & 0xffffff); X check4 += ((address4>>16) & 0xff) + 2; X break; X case '4': X fprintf(fout, "S3%02X%08X", index4 + 8, address4); X check4 += ((address4>>16) & 0xff) +((address4>>24) & 0xff) + 4; X break; X } X X for(i=0; i'lexer.c' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X * FILE: lexer.c X * PACKAGE: as31 - 8031/8051 Assembler. X * X * DESCRIPTION: X * This file contains the lexical tokenizer for the assembler. X * Since yacc is being used the lexer is called yylex(). X * X * In order to produce a listing, some record of the users X * source line must be kept. This is done by adding X * get_ch(), and unget_ch() routine which returns/ungets a character X * but also places information into a secret array. X * X * When a newline is encountered the text line is returned as X * an attribute on the '\n' character. X * X * REVISION HISTORY: X * Jan. 19, 1990 - Created. (Ken Stauffer) X * X * AUTHOR: X * All code in this file written by Ken Stauffer (University of Calgary). X * January, 1990. X * X */ X X#include X#include X#include "as31.h" X Xextern union ystack yylval; Xextern int pass; X Xstruct symbol *looksym(); Xstruct opcode *lookop(); Xchar *malloc(); Xint lineno; X Xstatic char line[100],*lineptr=line; X X/* ---------------------------------------------------------------------- X * get_ch: X * Get a character from stdin, place char in line[] X */ X Xget_ch() X{ X register int c; X X c = getchar(); X if( c != EOF && lineptr - line < sizeof(line) ) X *lineptr++ = c; X return(c); X} X X/* ---------------------------------------------------------------------- X * unget_ch: X * Unget a character and move lineptr back by one. X */ X Xunget_ch(c) Xint c; X{ X ungetc(c,stdin); X if( lineptr > line ) X lineptr--; X} X X/* ---------------------------------------------------------------------- X * yylex: X * The tokens themselves are returned via return(token) X * X * Some tokens have attributes. These attributes are returned X * by setting a global variable yylval: X * X * yylval.value X * numbers (any base) X * strings (in pass 1). X * bit positions .0, .1, .2, ... X * X * yylval.str X * strings (in pass 2). X * '\n' (both passes). X * X * yylval.sym X * User defined symbols. X * X * yylval.op X * Reserved keyword (opcode/directive/misc.) X * X * No other fields in yylval are used by yylex(). X * X * Characters that do not have an attribute do X * not set anything in the yylval variable. X * X */ X Xyylex() X{ X static nl_flag=0; /* sync. error messages and the cur. line */ X register int c; X char buf[120]; /* temporary buffer */ X char *p; /* general pointer */ X struct symbol *sym; X struct opcode *op; X X int octal=0,hex=0,decimal=0,binary=0; X register long value = 0; X X if( nl_flag ) { X nl_flag = 0; X lineno++; X } X Xfor(;;) { X c = get_ch(); X switch(c) { X case EOF: return(EOF); X case ' ': X case '\t': X break; X X case '\n': X nl_flag = 1; X yylval.str = line; X *lineptr = '\0'; X lineptr = line; X return('\n'); X X case ';': X while((c=get_ch()) != EOF && c!='\n'); X nl_flag= 1; X yylval.str = line; X *lineptr = '\0'; X lineptr = line; X return(c); X X case '"': X p = buf; X while((c=get_ch()) != EOF && c!='"' && c!='\n') { X if( c == '\\' ) { X switch(c=get_ch()) { X case 'n': c = '\n'; break; X case 'r': c = '\r'; break; X case 't': c = '\t'; break; X case 'b': c = '\b'; break; X case '"': c = '"'; break; X case '\\': c = '\\'; break; X default: X error("Invalid escape character: \\%c",c); X break; X } X } X if( p-buf='0' && c<='7' ) { X yylval.value = c-'0'; X return(BITPOS); X } X unget_ch(c); X return('.'); X X case '\'': X c = get_ch(); X if( c=='\\' ) { X switch(c=get_ch()) { X case 'n': c = '\n'; break; X case 'r': c = '\r'; break; X case 't': c = '\t'; break; X case 'b': c = '\b'; break; X case '\\': c = '\\'; break; X case '\'': c = '\''; break; X default: X error("Invalid escape character: \\%c",c); X } X } X if( get_ch() != '\'' ) X error("Missing quote in character constant"); X yylval.value = c; X return(VALUE); X X case '0': /* parse a number */ X case '1': /* could be followed by a: */ X case '2': /* 'b','B' - Binary */ X case '3': /* 'h','H' - Hex */ X case '4': /* 'd','D' - Decimal */ X case '5': /* 'o','O' - Octal */ X case '6': /* *** Numbers must start with a digit */ X case '7': /* Numbers could be also preceeded by: */ X case '8': /* 0x - Hex, 0b - binary */ X case '9': /* 0 - Octal */ X X p = buf; X do { X if( p-buf='a' && *p<='f' ) X value += *p-'a'+ 10; X else if( *p>='A' && *p<='F' ) X value += *p-'A'+ 10; X else X error("Invalid hex digit: %c",*p); X } X yylval.value = value; X return(VALUE); X } X X if( decimal ) { X for(p=buf; *p; p++ ) { X if( isdigit(*p) ) X value = value*10 + *p-'0'; X else X error("Invalid decimal digit: %c",*p); X } X yylval.value = value; X return(VALUE); X } X X if( octal ) { X for(p=buf; *p; p++ ) { X if( *p>='0' && *p<='7' ) X value = value<<3 + *p-'0'; X else X error("Invalid octal digit: %c",*p); X } X yylval.value = value; X return(VALUE); X } X X default: X if( isalpha(c) || c=='_' ) { X p = buf; X do { X if( p-buftype); X } X sym = looksym(buf); X yylval.sym = sym; X return(SYMBOL); X } else X return(c); X } /* switch */ X} /* for */ X X} /* yylex */ END_OF_FILE if test 6816 -ne `wc -c <'lexer.c'`; then echo shar: \"'lexer.c'\" unpacked with wrong size! fi # end of 'lexer.c' fi if test -f 'main.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'main.c'\" else echo shar: Extracting \"'main.c'\" \(2745 characters\) sed "s/^X//" >'main.c' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X * FILE: main.c X * PACKAGE: as31 - 8031/8051 Assembler. X * X * DESCRIPTION: X * The file contains main(). It handles the arguments and makes X * sure that pass 1 is done before pass 2 etc... X * X * REVISION HISTORY: X * Jan. 19, 1990 - Created. (Ken Stauffer) X * X * AUTHOR: X * All code in this file written by Ken Stauffer (University of Calgary). X * January, 1990. */ static char X * id_id= "Written by: Ken Stauffer";/* X * X */ X X#include X#include X Xextern int lineno; Xextern int pass,fatal; Xextern unsigned long lc; X Xjmp_buf main_env; Xchar *asmfile; Xint dashl=0; XFILE *listing; X X/* ---------------------------------------------------------------------- X * checkext: X * Check the string s, for the presence of an extenstion e. X * Return the position of the start of e in s. X * or return NULL. X */ X Xchar *checkext(s,e) Xchar *s,*e; X{ X register char *ps = s, *pe = e; X X while( *ps ) ps++; X while( *pe ) pe++; X X for( ; ps>=s && pe>=e && *ps == *pe; ps--, pe-- ) X if( pe == e ) return(ps); X return(NULL); X} X Xmain(argc,argv) Xchar *argv[]; X{ X FILE *fin; X char *p,*dashF=NULL, *dashA=NULL; X char objfile[100]; X char lstfile[100]; X int i; X X if( argc < 2 ) { X fprintf(stderr,"Usage: %s [-l] [-Ffmt] [-Aarg] infile.asm\n", X argv[0]); X emitusage(); X exit(1); X } X X for(i=1; i'makefile' <<'END_OF_FILE' X# FILE: makefile X# PACKAGE: as31 - 8031/8051 Assembler. X# X# DESCRIPTION: X# X# X# REVISION HISTORY: X# Jan. 19, 1990 - Created. (Ken Stauffer). X# Jan. 30, 1990 - Theo played here. X XCFLAGS=-O XYACCFLAGS=-d XOBJ=as31.o symbol.o lexer.o emitter.o main.o XSHARFILES=README as31.h as31.y as31.man emitter.c lexer.c main.c makefile \ X symbol.c new.asm X Xas31: $(OBJ) X $(CC) $(CFLAGS) -o as31 $(OBJ) X chmod a+rx as31 X Xmain.o: main.c as31.h Xemitter.o: emitter.c as31.h Xsymbol.o: symbol.c as31.h Xlexer.o: lexer.c as31.h Xas31.o: as31.c Xas31.c: as31.y as31.h X yacc $(YACCFLAGS) as31.y X /bin/mv y.tab.c as31.c X Xman: as31.cat X Xas31.cat: as31.man X nroff -man as31.man > as31.cat X chmod a+r as31.cat as31.man X Xasm: new.obj ram.obj X Xnew.obj: new.asm X ./as31 -Ftdr -l new.asm X Xclean: X $(RM) *~ *.o as31.c y.tab.h as31.shar X Xshar: X shar $(SHARFILES) > as31.shar END_OF_FILE if test 856 -ne `wc -c <'makefile'`; then echo shar: \"'makefile'\" unpacked with wrong size! fi # end of 'makefile' fi if test -f 'symbol.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'symbol.c'\" else echo shar: Extracting \"'symbol.c'\" \(10609 characters\) sed "s/^X//" >'symbol.c' <<'END_OF_FILE' X/* ---------------------------------------------------------------------- X * FILE: symbol.c X * PACKAGE: as31 - 8031/8051 Assembler. X * X * DESCRIPTION: X * This file contains the symbol table search/insertion routines X * associated with user defined symbols. X * X * The reserved keyword (instructions/directives) look up routine X * is defined here. X * X * The opcode table for all of the instructions is located in this X * file. X * X * REVISION HISTORY: X * Jan. 19, 1990 - Created. (Ken Stauffer) X * X * AUTHOR: X * All code in this file written by Ken Stauffer (University of Calgary) X * January, 1990. X * X */ X X#include "as31.h" X#define NULL (0) X X#define B(a) (0xF0+(a)) X#define ACC(a) (0xE0+(a)) X#define PSW(a) (0xD0+(a)) X#define T2CON(a) (0xC8+(a)) X#define IP(a) (0xB8+(a)) X#define P3(a) (0xB0+(a)) X#define IE(a) (0xA8+(a)) X#define P2(a) (0xA0+(a)) X#define SCON(a) (0x98+(a)) X#define P1(a) (0x90+(a)) X#define TCON(a) (0x88+(a)) X#define P0(a) (0x80+(a)) X X/* ---------------------------------------------------------------------- X * sinit[] X * These symbols are not reserved keywords. X * This array contains the initial symbol table entries X * for the user symbol table. The symbols are X * basically convienient names that make writting X * in 8031/8051 bearable. X * X * The function syminit() inserts these entries into the X * symbol table. X * X */ X Xstatic struct symbol sinit[] = { X { "AC", LABEL, PSW(6), NULL }, X { "ACC", LABEL, ACC(0), NULL }, X { "B", LABEL, B(0), NULL }, X { "CY", LABEL, PSW(7), NULL }, X { "DPH", LABEL, 0x83, NULL }, X { "DPL", LABEL, 0x82, NULL }, X { "EA", LABEL, IE(7), NULL }, X { "ES", LABEL, IE(4), NULL }, X { "ET0", LABEL, IE(1), NULL }, X { "ET1", LABEL, IE(3), NULL }, X { "ET2", LABEL, IE(5), NULL }, X { "EX0", LABEL, IE(0), NULL }, X { "EX1", LABEL, IE(2), NULL }, X { "EXEN2", LABEL, T2CON(3),NULL }, X { "EXF2", LABEL, T2CON(6),NULL }, X { "F0", LABEL, PSW(5), NULL }, X { "IE", LABEL, IE(0), NULL }, X { "IE0", LABEL, TCON(1),NULL }, X { "IE1", LABEL, TCON(3),NULL }, X { "IP", LABEL, IP(0), NULL }, X { "IT0", LABEL, TCON(0),NULL }, X { "IT1", LABEL, TCON(2),NULL }, X { "OV", LABEL, PSW(2), NULL }, X { "P", LABEL, PSW(0), NULL }, X { "P0", LABEL, P0(0), NULL }, X { "P1", LABEL, P1(0), NULL }, X { "P2", LABEL, P2(0), NULL }, X { "P3", LABEL, P3(0), NULL }, X { "PCON", LABEL, 0x87, NULL }, X { "PS", LABEL, IP(4), NULL }, X { "PSW", LABEL, PSW(0), NULL }, X { "PT0", LABEL, IP(1), NULL }, X { "PT1", LABEL, IP(3), NULL }, X { "PT2", LABEL, IP(5), NULL }, X { "PX0", LABEL, IP(0), NULL }, X { "PX1", LABEL, IP(2), NULL }, X { "RB8", LABEL, SCON(2),NULL }, X { "RCAP2H", LABEL, 0xCB, NULL }, X { "RCAP2L", LABEL, 0xCA, NULL }, X { "RCLK", LABEL, T2CON(5),NULL }, X { "REN", LABEL, SCON(4),NULL }, X { "RI", LABEL, SCON(0),NULL }, X { "RL2", LABEL, T2CON(0),NULL }, X { "RS0", LABEL, PSW(3), NULL }, X { "RS1", LABEL, PSW(4), NULL }, X { "SBUF", LABEL, 0x99, NULL }, X { "SCON", LABEL, SCON(0),NULL }, X { "SM0", LABEL, SCON(7),NULL }, X { "SM1", LABEL, SCON(6),NULL }, X { "SM2", LABEL, SCON(5),NULL }, X { "SP", LABEL, 0x81, NULL }, X { "T2CON", LABEL, T2CON(0),NULL }, X { "TB8", LABEL, SCON(3),NULL }, X { "TCLK", LABEL, T2CON(4),NULL }, X { "TCON", LABEL, TCON(0),NULL }, X { "TF0", LABEL, TCON(5),NULL }, X { "TF1", LABEL, TCON(7),NULL }, X { "TF2", LABEL, T2CON(7),NULL }, X { "TH0", LABEL, 0x8C, NULL }, X { "TH1", LABEL, 0x8D, NULL }, X { "TH2", LABEL, 0xCD, NULL }, X { "TI", LABEL, SCON(1),NULL }, X { "TL0", LABEL, 0x8A, NULL }, X { "TL1", LABEL, 0x8B, NULL }, X { "TL2", LABEL, 0xCC, NULL }, X { "TMOD", LABEL, 0x89, NULL }, X { "TR0", LABEL, TCON(4),NULL }, X { "TR1", LABEL, TCON(6),NULL }, X { "TR2", LABEL, T2CON(2),NULL } X}; X X#define SINITSIZE (sizeof(sinit)/sizeof(sinit[0])) X X/* ---------------------------------------------------------------------- X * opcode vectors: X * These arrays contain the various opcodes for the X * various forms an instruction may take. X * X * The ordering of these opcodes is very critical to the X * proper fuctioning of the assembler. X * X * When a given form of an instruction is parsed, the parser X * indexes one of these arrays by the correct amount and thus X * obtains the correct opcode for the particular form. X * X */ X Xstatic unsigned char acall[]= { 0x11 }; Xstatic unsigned char add[]= { 0x28, 0x25, 0x26, 0x24 }; Xstatic unsigned char addc[]= { 0x38, 0x35, 0x36, 0x34 }; Xstatic unsigned char ajmp[]= { 0x01 }; Xstatic unsigned char anl[]= { 0x58, 0x55, 0x56, 0x54, 0x52, 0x53, 0x82, X 0xb0 }; Xstatic unsigned char cjne[]= { 0xb5, 0xb4, 0xb8, 0xb6 }; Xstatic unsigned char clr[]= { 0xe4, 0xc3, 0xc2 }; Xstatic unsigned char cpl[]= { 0xf4, 0xb3, 0xb2 }; Xstatic unsigned char da[]= { 0xd4 }; Xstatic unsigned char dec[]= { 0x14, 0x18, 0x15, 0x16 }; Xstatic unsigned char div[]= { 0x84 }; Xstatic unsigned char djnz[]= { 0xd8, 0xd5 }; Xstatic unsigned char inc[]= { 0x04, 0x08, 0x05, 0x06, 0xa3 }; Xstatic unsigned char jb[]= { 0x20 }; Xstatic unsigned char jbc[]= { 0x10 }; Xstatic unsigned char jc[]= { 0x40 }; Xstatic unsigned char jmp[]= { 0x73 }; Xstatic unsigned char jnb[]= { 0x30 }; Xstatic unsigned char jnc[]= { 0x50 }; Xstatic unsigned char jnz[]= { 0x70 }; Xstatic unsigned char jz[]= { 0x60 }; Xstatic unsigned char lcall[]= { 0x12 }; Xstatic unsigned char ljmp[]= { 0x02 }; Xstatic unsigned char mov[]= { 0xe8, 0xe5, 0xe6, 0x74, 0xf5, 0x75, 0xf8, X 0xa8, 0x78, 0x88, 0x85, 0x86, 0xf6, 0xa6, X 0x76, 0x90, 0xa2, 0x92 }; Xstatic unsigned char movc[]= { 0x93, 0x83 }; Xstatic unsigned char movx[]= { 0xe2, 0xe3, 0xe0, 0xf2, 0xf3, 0xf0 }; Xstatic unsigned char mul[]= { 0xa4 }; Xstatic unsigned char nop[]= { 0x00 }; Xstatic unsigned char orl[]= { 0x48, 0x45, 0x46, 0x44, 0x42, 0x43, 0x72, X 0xa0 }; Xstatic unsigned char pop[]= { 0xd0 }; Xstatic unsigned char push[]= { 0xc0 }; Xstatic unsigned char ret[]= { 0x22 }; Xstatic unsigned char reti[]= { 0x32 }; Xstatic unsigned char rl[]= { 0x23 }; Xstatic unsigned char rlc[]= { 0x33 }; Xstatic unsigned char rr[]= { 0x03 }; Xstatic unsigned char rrc[]= { 0x13 }; Xstatic unsigned char setb[]= { 0xd3, 0xd2 }; Xstatic unsigned char sjmp[]= { 0x80 }; Xstatic unsigned char subb[]= { 0x98, 0x95, 0x96, 0x94 }; Xstatic unsigned char swap[]= { 0xc4 }; Xstatic unsigned char xch[]= { 0xc8, 0xc5, 0xc6 }; Xstatic unsigned char xchd[]= { 0xd6 }; Xstatic unsigned char xrl[]= { 0x68, 0x65, 0x66, 0x64, 0x62, 0x63 }; X X/* ---------------------------------------------------------------------- X * optable[] X * This table contains opcodes, directives and a few reserved X * symbols. X * X * The second field is the keywords token value. X * X * Unless the symbol is an opcode, the third field will X * be NULL. X * X * The third field is a pointer to an array of opcode bytes. X * X */ X Xstatic struct opcode optable[] = { X {"a", A, NULL }, X {"ab", AB, NULL }, X {"acall", ACALL, acall }, X {"add", ADD, add }, X {"addc", ADDC, addc }, X {"ajmp", AJMP, ajmp }, X {"anl", ANL, anl }, X {"byte", D_BYTE, NULL }, X {"c", C, NULL }, X {"cjne", CJNE, cjne }, X {"clr", CLR, clr }, X {"cpl", CPL, cpl }, X {"da", DA, da }, X {"dec", DEC, dec }, X {"div", DIV, div }, X {"djnz", DJNZ, djnz }, X {"dptr", DPTR, NULL }, X {"end", D_END, NULL }, X {"equ", D_EQU, NULL }, X {"flag", D_FLAG, NULL }, X {"inc", INC, inc }, X {"jb", JB, jb }, X {"jbc", JBC, jbc }, X {"jc", JC, jc }, X {"jmp", JMP, jmp }, X {"jnb", JNB, jnb }, X {"jnc", JNC, jnc }, X {"jnz", JNZ, jnz }, X {"jz", JZ, jz }, X {"lcall", LCALL, lcall }, X {"ljmp", LJMP, ljmp }, X {"mov", MOV, mov }, X {"movc", MOVC, movc }, X {"movx", MOVX, movx }, X {"mul", MUL, mul }, X {"nop", NOP, nop }, X {"org", D_ORG, NULL }, X {"orl", ORL, orl }, X {"pc", PC, NULL }, X {"pop", POP, pop }, X {"push", PUSH, push }, X {"r0", R0, NULL }, X {"r1", R1, NULL }, X {"r2", R2, NULL }, X {"r3", R3, NULL }, X {"r4", R4, NULL }, X {"r5", R5, NULL }, X {"r6", R6, NULL }, X {"r7", R7, NULL }, X {"ret", RET, ret }, X {"reti", RETI, reti }, X {"rl", RL, rl }, X {"rlc", RLC, rlc }, X {"rr", RR, rr }, X {"rrc", RRC, rrc }, X {"setb", SETB, setb }, X {"sjmp", SJMP, sjmp }, X {"skip", D_SKIP, NULL }, X {"subb", SUBB, subb }, X {"swap", SWAP, swap }, X {"word", D_WORD, NULL }, X {"xch", XCH, xch }, X {"xchd", XCHD, xchd }, X {"xrl", XRL, xrl } X}; X X#define OPTABSIZE (sizeof(optable)/sizeof(struct opcode)) X X/* ---------------------------------------------------------------------- X * strcase: X * A case IN-sensitive string compare. X * X */ X Xstrcase(s,t) Xchar *s,*t; X{ X for( ; (*s|040) == (*t|040); s++, t++) X if( *s == '\0') return(0); X return( (*s|040) - (*t|040) ); X} X X/* ---------------------------------------------------------------------- X * lookop: X * Do a binary search through optable[], for a matching X * symbol. Return the symbol found or NULL. X * X */ X Xstruct opcode *lookop(s) Xchar *s; X{ X register int low,high,mid,cond; X X low = 0; X high = OPTABSIZE-1; X while( low<=high ) { X mid = (low+high)/2; X if( (cond = strcase(s,optable[mid].name)) < 0 ) X high = mid-1; X else if(cond > 0 ) X low = mid+1; X else X return(&optable[mid]); X } X return(NULL); X} X X/* ---------------------------------------------------------------------- X * symtab, hash, looksym: X * User symbol table routines. X * symtab is the hash table for the user symbols. X * (chaining is used for collision resolution). X * X */ X Xstatic struct symbol *symtab[HASHTABSIZE]; X Xstatic hash(s) Xchar *s; X{ X register char *p; X register unsigned h=0,g; X for(p=s; *p; p++) { X h = (h<<4) + *p; X if( g = h&0xf0000000 ) { X h = h ^ (g >> 24); X h = h ^ g; X } X } X return( h % HASHTABSIZE ); X} X Xstruct symbol *looksym(s) Xchar *s; X{ X register struct symbol *ptr,*prev; X char *malloc(),*p; X register int hv; X X hv = hash(s); X X prev = NULL; X for(ptr=symtab[hv]; ptr; ptr = ptr->next) { X if( !strcmp(ptr->name,s) ) { X if( prev != NULL ) { X prev->next = ptr->next; X ptr->next = symtab[hv]; X symtab[hv] = ptr; X } X return(ptr); X } X prev = ptr; X } X X if( p = malloc(strlen(s)+1) ) X strcpy(p,s); X else X error("Cannot allocate %d bytes",strlen(s)+1); X X ptr = (struct symbol *) malloc( sizeof(struct symbol) ); X if( ptr == NULL ) X error("Cannot allocate %d bytes",sizeof(struct symbol)); X ptr->name = p; X ptr->type = UNDEF; X ptr->next = symtab[hv]; X symtab[hv] = ptr; X return(ptr); X} X X/* ---------------------------------------------------------------------- X * syminit: X * Initializes the hash table, with the initial symbols from X * sinit[] X * X */ X Xsyminit() X{ X register int i,hv; X X for(i=0; i'new.asm' <<'END_OF_FILE' X; ----------------------------------------------------------------------- X; - debugger v2.0 theo de raadt 21/1/90 - X; NOTE: Hardware has to be specially built to handle this monitor. X; The CODE address space and the DATA address space have to be mapped X; on top of each other. ie. CHIP_READ* = 8031RD* AND 8031PSEN* and X; CHIP_WRITE* = 8031WR*. X; Within this (combined) address space, you can now use either MOVX X; or MOVC for the same effect. X; In this address space, I have placed the rom this debugger is in X; at 0x0000 and ram at 0x8000. (additional IO would go in between.) X; (actually, I used a battery backed up static ram at 0x000.) X; Some of the commands in the help are actually unimplimented. It X; suited my purposes. The 'g' command could be much improved, to have X; a seperate register set for the called routine. X; ----------------------------------------------------------------------- X X .org 0 Xstart: nop ; for accidental overwrite if ram X ; at 0 -- bug in my decode logic? X mov P3, #0xff ; use alternate fns on P3 X ajmp main X X; ----------------------------------------------------------------------- X; SERINIT() nothing hurt Xserinit: mov TMOD, #0x20 ; timer 1 mode 2 X ; mov TH1, #230 ; 1200 baud X mov TH1,#243 ; 4800 baud X mov TCON, #0x40 ; turn timer 1 on X mov SCON, #0x52 ; serial mode 1 rx, fake tx done X X mov A, PCON ; for 4800 baud X setb ACC.7 X mov PCON, A X ret X X; ----------------------------------------------------------------------- X; PUTC( A=char ) Xputc: jnb TI, putc ; wait for tx free X clr TI X mov SBUF, A ; send it X ret X X; ----------------------------------------------------------------------- X; GETC() A=char Xgetc: jnb RI, getc X clr RI X mov A, SBUF X ret X X; ----------------------------------------------------------------------- X; GETS( DPTR=start of string ) A not hurt, DPTR at start of string Xgets: push ACC X push DPL X push DPH X mov A, R3 X push ACC X X clr A X mov R3, A Xgets_nxt: lcall getc X cjne A, #8, gets_notbs X ajmp gets_bs Xgets_notbs: cjne A, #'\r', gets_good X clr A X movx @DPTR, A X X pop ACC X mov R3, A X pop DPH X pop DPL X pop ACC X ret X Xgets_bs: mov A, R3 ; backspaced too far X jz gets_nxt X dec A X mov R3, A X X mov A, #8 ; "\b \b" X lcall putc X mov A, #' ' X lcall putc X mov A, #8 X lcall putc X X setb C ; this is "dec DPTR" X mov A, DPL X subb A, #0 X mov DPL, A X mov A, DPH X subb A, #0 X mov DPH, A X ajmp gets_nxt X Xgets_good: movx @DPTR, A X lcall putc X inc DPTR X inc R3 X ajmp gets_nxt X X; ---------------------------------------------------------------------- X; HEXPARSE( DPTR=string ) A not hurt, DPTR advanced, R0/R1 [H/L] return Xhexparse: push ACC X Xhp_char: movx A, @DPTR ; get char X X clr C X subb A, #'a' X jc hp_notalpha ; < 'a' not hex alpha char X subb A, #5+1 X jnc hp_notalpha ; > 'f' not hex aplha char X movx A, @DPTR X clr C X subb A, #'a'-10 X sjmp hp_nybble X Xhp_notalpha: movx A, @DPTR X clr C X subb A, #'0' X jc hp_notdigit ; < '0' not hex digit X subb A, #9+1 X jnc hp_notdigit ; > '9' not hex digit X movx A, @DPTR X clr C X subb A, #'0' X Xhp_nybble: inc DPTR X X anl A, #0x0f X push ACC ; R0 R1 X mov A, R0 ; HHHH LLLL hhhh llll X swap A X anl A, #0xf0 X mov R0, A X mov A, R1 X swap A ; shift left by nybble X anl A, #0x0f X orl A, R0 X mov R0, A X mov A, R1 X swap A X anl A, #0xf0 X mov R1, A X pop ACC X orl A, R1 X mov R1, A ; LLLL hhhh llll aaaa X X ; debugging X ; push ACC X ; push DPL X ; push DPH X ; mov DPH, R0 X ; mov DPL, R1 X ; lcall putword X ; lcall putnl X ; pop DPH X ; pop DPL X ; pop ACC X X sjmp hp_char X Xhp_notdigit: pop ACC X ret X X; ---------------------------------------------------------------------- X; EATSPACE( DPTR=string ) A not hurt, DPTR advanced Xeatspace: push ACC Xeatspace_loop: movx A, @DPTR X cjne A, #' ', eatspace_done X inc DPTR X sjmp eatspace_loop Xeatspace_done: pop ACC X ret X X; ----------------------------------------------------------------------- X; PUTS( DPTR=string ) A not hurt, DPTR at end of string Xputs: push ACC Xputs_ch: movx A, @DPTR ; get ch X jz puts_q ; null - finished str X lcall putc X inc DPTR X sjmp puts_ch ; go for next Xputs_q: pop ACC X ret X X; ----------------------------------------------------------------------- X; PUTNL() nothing hurt Xputnl: push ACC X mov A, #0x0d X lcall putc X mov A, #0x0a X lcall putc X pop ACC X ret X X; ----------------------------------------------------------------------- X; putword( DPTR=word) nothing hurt Xputword: push ACC X mov A, DPH X lcall putbyte X mov A, DPL X lcall putbyte X pop ACC X ret X X; ----------------------------------------------------------------------- X; putbyte( A=byte) nothing hurt Xputbyte: push ACC X push ACC X swap A X lcall putnyb X pop ACC X lcall putnyb X pop ACC X ret X X; ----------------------------------------------------------------------- X; putnyb( A=nybble ) A hurt Xputnyb: anl A, #0x0f X push ACC X clr C X subb A, #10 X jc pn_digit ; <= 9, then it's a digit X add A, #'a' ; alphabetic X lcall putc X pop ACC X ret X Xpn_digit: pop ACC ; it's a digit X add A, #'0' X lcall putc X ret X X; ----------------------------------------------------------------------- Xmain: lcall serinit X mov DPTR, #run_regs_psw ; initialize psw at least! X clr A X movx @DPTR, A X mov DPTR, #title_msg X lcall puts X Xnext_line: mov A, #'>' ; prompt X lcall putc X X mov DPTR, #linebuf ; get cmd X lcall gets X lcall putnl X Xnext_cmd: lcall eatspace X movx A, @DPTR X jz next_line X X ; -------------------------------------------------- X cjne A, #'g', cmd_notgo ; g --> lcall addr.. X push DPL X push DPH X push ACC X push PSW X X mov DPTR, #go_return ; come back to here.. X push DPL X push DPH X X mov A, R1 ; return on top of function X push ACC X mov A, R0 X push ACC X mov DPTR, #run_regs X movx A, @DPTR ; DPH X push ACC X inc DPTR X movx A, @DPTR ; DPL X push ACC X inc DPTR X movx A, @DPTR ; PSW X push ACC X inc DPTR X movx A, @DPTR ; ACC X pop PSW X pop DPL X pop DPH X ret ; enter it X Xgo_return: pop PSW X pop ACC X pop DPH X pop DPL X inc DPTR X sjmp next_cmd X X ; -------------------------------------------------- Xcmd_notgo: cjne A, #'R', cmd_notregs X inc DPTR X push DPH X push DPL X mov DPTR, #regs_msg ; "DPTR ACC PSW" X lcall puts X mov DPTR, #run_regs X movx A, @DPTR X acall putbyte ; xx X inc DPTR X movx A, @DPTR X acall putbyte ; xx X mov A, #' ' X acall putc X inc DPTR X movx A, @DPTR X acall putbyte ; xx X inc DPTR X mov A, #' ' X acall putc X acall putc X movx A, @DPTR X acall putbyte ; xx X acall putnl X pop DPL X pop DPH X sjmp next_cmd X X ; -------------------------------------------------- Xcmd_notregs: cjne A, #':', cmd_notenter ; : --> eat bytes.. X inc DPTR X mov A, R2 X push ACC X mov A, R3 X push ACC X mov A, R0 X mov R2, A X mov A, R1 X mov R3, A ; R2/R3 = mem ptr X Xenter_next: lcall eatspace X movx A, @DPTR X jz enter_done X X push DPL X clr A X mov R0, A X mov R1, A X lcall hexparse X pop ACC X cjne A, DPL, enter_number X sjmp enter_next X Xenter_number: push DPL X push DPH X mov DPH, R2 ; put low byte only X mov DPL, R3 X mov A, R1 X movx @DPTR, A X inc DPTR X mov R2, DPH X mov R3, DPL X pop DPH X pop DPL X sjmp enter_next X Xenter_done: pop ACC X mov R3, A X pop ACC X mov R2, A X ajmp next_cmd X X ; -------------------------------------------------- Xcmd_notenter: cjne A, #'?', cmd_nothelp X push DPL X push DPH X mov DPTR, #help_msg X lcall puts X pop DPH X pop DPL X inc DPTR X ajmp next_cmd X X ; -------------------------------------------------- Xcmd_nothelp: cjne A, #'l', cmd_notlist X push DPL X push DPH X push B X clr A X mov B, ACC X mov DPH, R0 X mov DPL, R1 X lcall putword ; addr: [16 bytes] X mov A, #':' X lcall putc X mov A, #' ' X lcall putc Xcl_nextbyte: movx A, @DPTR X lcall putbyte X mov A, #' ' X lcall putc X inc DPTR X inc B X mov A, B X cjne A, #16, cl_nextbyte X lcall putnl X mov R0, DPH X mov R1, DPL X pop B X pop DPH X pop DPL X inc DPTR X ajmp next_cmd X X ; -------------------------------------------------- Xcmd_notlist: cjne A, #'r', cmd_notread X mov A, R3 ; counter X push ACC X mov A, R1 ; base addr X push ACC X X inc DPTR ; get arg X lcall eatspace X push DPL X lcall hexparse X pop ACC X cjne A, DPL, nl_loop X mov A, #1 X mov R3, A X sjmp nl_start Xnl_loop: mov A, R1 X mov R3, A X Xnl_start: pop ACC X mov R1, A X mov A, R1 ; put address X lcall putbyte X mov A, #':' X lcall putc X Xnl_nextloop: mov A, R3 ; eat one loop X jz nl_endloop X dec A X mov R3, A X X mov A, #' ' X lcall putc X mov A, @R1 ; put byte X lcall putbyte X inc R1 ; inc address X X sjmp nl_nextloop X Xnl_endloop: lcall putnl X pop ACC X mov R3, A X ajmp next_cmd X X ; -------------------------------------------------- Xcmd_notread: cjne A, #'w', cmd_notwrite X mov A, R3 X push ACC X mov A, R1 X mov R3, A ; save addr X inc DPTR X Xnr_nextbyte: lcall eatspace X movx A, @DPTR X jz nr_earlyeol ; [addr] w [EOL] X push DPL X lcall hexparse ; [addr] w [NONHEX] X pop ACC X cjne A, DPL, nr_good X sjmp nr_earlyeol X Xnr_good: mov A, R3 ; R1 = value, R3 = addr X mov R0, A X mov A, R1 X mov @R0, A X ajmp nr_nextbyte X Xnr_earlyeol: pop ACC X mov R3, A X ajmp next_cmd X X ; -------------------------------------------------- Xcmd_notwrite: cjne A, #';', cmd_notcomment X ajmp next_line X Xcmd_notcomment: push DPL X clr A X mov R0, A X mov R1, A X lcall hexparse ; probably addr, see if ptr X pop ACC ; moved, else error X cjne A, DPL, cmd_more X sjmp cmd_error X X ; -------------------------------------------------- Xcmd_more: X ; debugging X ; push DPL X ; push DPH X ; mov DPTR, #number_msg X ; lcall puts X ; mov DPH, R0 X ; mov DPL, R1 X ; lcall putword X ; lcall putnl X ; pop DPH X ; pop DPL X ajmp next_cmd X Xcmd_error: mov DPTR, #error_msg X lcall puts X ajmp next_line X X; ----------------------------------------------------------------------- Xtitle_msg: .byte "\r\n8031 mon v3.0\r\n", 0 Xerror_msg: .byte "syntax error\r\n", 0 Xregs_msg: .byte "DPTR ACC PSW\r\n", 0 Xhelp_msg: .byte "8031 mon v3.0\r\n" X .byte "[addr] : [bytes]\tstore bytes\t" X .byte "[addr] g\t\tcall address\r\n" X .byte "[addr] l\t\tlist memory\t" X .byte "[addr] r [count]\tlist onchip\r\n" X .byte "[addr] w [bytes]\tstore onchip\t" X .byte "; [comment]\t\tcomment\r\n" X .byte "[value] D\t\tstore in DPTR\t" X .byte "[value] A\t\tstore in ACC\r\n" X .byte "[value] P\t\tstore in PSW\t" X .byte "R\t\t\tprint registers\r\n", 0 X X; ----------------------------------------------------------------------- X; sort of a bss segment X; ----------------------------------------------------------------------- X .org 0x8000 Xrun_regs: .skip 2 ; DPTR [H/L] Xrun_regs_psw: .skip 1 ; PSW X .skip 1 ; ACC Xlinebuf: .skip 256 X X .end END_OF_FILE if test 10618 -ne `wc -c <'new.asm'`; then echo shar: \"'new.asm'\" unpacked with wrong size! fi # end of 'new.asm' fi echo shar: End of shell archive. exit 0