OpenCores
URL https://opencores.org/ocsvn/System09/System09/trunk

Subversion Repositories System09

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /System09/trunk/Tools
    from Rev 66 to Rev 74
    Reverse comparison

Rev 66 → Rev 74

/as09/pseudo.c
0,0 → 1,324
/*
* pseudo --- pseudo op processing
*/
 
#define RMB 0 /* Reserve Memory Bytes */
#define FCB 1 /* Form Constant Bytes */
#define FDB 2 /* Form Double Bytes (words) */
#define FCC 3 /* Form Constant Characters */
#define ORG 4 /* Origin */
#define EQU 5 /* Equate */
#define ZMB 6 /* Zero memory bytes */
#define FILL 7 /* block fill constant bytes */
#define OPT 8 /* assembler option */
#define NULL_OP 9 /* null pseudo op */
#define PAGE 10 /* new page */
#define INCLUDE 11 /* include <file> or "file" ver TER_2.0 */
#define END 12 /* include <file> terminator ver TER_2.0 */
#define IFD 13 /* if define <symbol> ver TER_2.0 */
#define IFND 14 /* if not define <symbol> ver TER_2.0 */
#define ELSE 15 /* else (for IF statements) ver TER_2.0 */
#define ENDIF 16 /* endif (for IF statements) ver TER_2.0 */
#define BSS 17 /* block storage segment (RAM) ver TER_2.09 */
#define CODE 18 /* code segment ver TER_2.09 25 Jul 89 */
#define DATA 19 /* data segment ver TER_2.09 25 Jul 89 */
#define AUTO 20 /* data segment ver TER_2.09 25 Jul 89 */
 
struct oper pseudo[] = {
"=", PSEUDO, EQU, 0, /* ver TER_2.09 25 Jul 89 */
"auto", PSEUDO, AUTO, 0, /* ver TER_2.09 25 Jul 89 */
"bss", PSEUDO, BSS, 0, /* ver TER_2.09 25 Jul 89 */
"bsz", PSEUDO, ZMB, 0,
"code", PSEUDO, CODE, 0, /* ver TER_2.09 25 Jul 89 */
"data", PSEUDO, DATA, 0, /* ver TER_2.09 25 Jul 89 */
"else", PSEUDO, ELSE, 0, /* ver TER_2.0 6/17/89 */
"end", PSEUDO, END, 0, /* ver TER_2.0 6/17/89 */
"endif",PSEUDO, ENDIF, 0, /* ver TER_2.0 6/17/89 */
"equ", PSEUDO, EQU, 0,
"fcb", PSEUDO, FCB, 0,
"fcc", PSEUDO, FCC, 0,
"fdb", PSEUDO, FDB, 0,
"fill", PSEUDO, FILL, 0,
"ifd", PSEUDO, IFD, 0, /* ver TER_2.0 6/17/89 */
"ifnd", PSEUDO, IFND, 0, /* ver TER_2.0 6/17/89 */
"include", PSEUDO, INCLUDE, 0, /* ver TER_2.0 6/17/89 */
"nam", PSEUDO, NULL_OP,0,
"name", PSEUDO, NULL_OP,0,
"opt", PSEUDO, OPT, 0,
"org", PSEUDO, ORG, 0,
"pag", PSEUDO, PAGE, 0,
"page", PSEUDO, PAGE, 0,
"ram", PSEUDO, BSS, 0, /* ver TER_2.09 25 Jul 89 */
"rmb", PSEUDO, RMB, 0,
"spc", PSEUDO, NULL_OP,0,
"ttl", PSEUDO, NULL_OP,0,
"zmb", PSEUDO, ZMB, 0
};
 
/*
* do_pseudo --- do pseudo op processing
*/
do_pseudo(op)
int op; /* which op */
{
char fccdelim, *strsave();
int fill;
int c; /*test variable ver TER_2.0 6/18/89 */
char *skip_white(), *savept; /* savept is pointer to string save */
FILE *FdTemp, *fopen(); /* ver TER_2.0 6/17/89 */
void pouterror(), NewPage(), IfMachine(); /* rel TER_2.0 6/18/89 */
void PC_Exchange(); /* ver TER_2.09 25 Jul 89 */
 
if( op != EQU && *Label )
install(Label,Pc);
 
P_force++;
 
#ifdef DEBUG3
printf("%s, line no. ",Argv[Cfn]); /* current file name */
printf("%d: ",Line_num); /* current line number */
printf(" Pseudo Op=%u\n",op);
#endif
 
switch(op){
case RMB: /* reserve memory bytes */
if( eval() ){
Pc += Result;
f_record(); /* flush out bytes */
}
else
error("Undefined Operand during Pass One");
break;
case ZMB: /* zero memory bytes */
if( eval() )
while( Result-- )
emit(0);
else
error("Undefined Operand during Pass One");
break;
case FILL: /* fill memory with constant */
eval();
fill = Result;
if( *Optr++ != ',' )
error("Bad fill");
else{
Optr = skip_white(Optr);
eval();
while( Result-- )
emit(fill);
}
break;
case FCB: /* form constant byte(s) */
do{
Optr = skip_white(Optr);
eval();
if( Result > 0xFF ){
if(!Force_byte)
warn("Value truncated");
Result = lobyte(Result);
}
emit(Result);
}while( *Optr++ == ',' );
break;
case FDB: /* form double byte(s) */
do{
Optr = skip_white(Optr);
eval();
eword(Result);
}while( *Optr++ == ',' );
break;
case FCC: /* form constant characters */
if(*Operand==EOS)
break;
fccdelim = *Optr++;
while( *Optr != EOS && *Optr != fccdelim)
emit(*Optr++);
if(*Optr == fccdelim)
Optr++;
else
error("Missing Delimiter");
break;
case ORG: /* origin */
if( eval() ){
Old_pc = Pc = Result;
f_record(); /* flush out any bytes */
}
else
error("Undefined Operand during Pass One");
break;
case EQU: /* equate */
if(*Label==EOS){
error("EQU requires label");
break;
}
if( eval() ){
install(Label,Result);
Old_pc = Result; /* override normal */
}
else
error("Undefined Operand during Pass One");
break;
case OPT: /* assembler option */
P_force=0;
if( head(Operand,"l") )
Lflag=1;
else if (head(Operand,"nol"))
Lflag=0;
else if (head(Operand,"c")){
Cflag=1;
Ctotal=0;
}
else if (head(Operand,"noc"))
Cflag=0;
else if (head(Operand,"contc")){
Cflag=1;
}
else if (head(Operand,"s"))
Sflag = 1;
else if (head(Operand,"cre"))
CREflag = 1;
else if (head(Operand,"p50")){ /* turn on 50 lines/page flag */
Pflag50 = 1;
Pflag75 = 0;
} /* separately. ver TER_2.0 6/17/89 */
else if (head(Operand,"p75")){ /* turn on 75 lines/page flag */
Pflag50 = 0;
Pflag75 = 1;
} /* separately. ver TER_2.0 6/17/89 */
else if (head(Operand,"crlf")) /* add <CR> <LF> to */
CRflag = 1; /* S record ver TER_2.08 */
else if (head(Operand,"nnf")) /* no extra line no. */
nfFlag = 0; /* w include files ver TER_2.08 */
else
error("Unrecognized OPT");
break;
case PAGE: /* go to a new page */
P_force=0;
N_page = 1;
if (Pass == 2 )
if (Lflag) NewPage();
break;
case NULL_OP: /* ignored psuedo ops */
P_force=0;
break;
case INCLUDE: /* case INCLUDE added ver TER_2.0 6/17/89 */
P_force=0; /* no PC in printed output */
if ((c=FNameGet(InclFName))==0)
error("Improper INCLUDE statement");
else
{
if (FdCount > MAXINCFILES)
error("too many INCLUDE files");
else
{
if ((FdTemp = fopen(InclFName,"r"))==0)
{
printf("%s, line no. ",Argv[Cfn]);
/* current file name */
printf("%d: ",Line_num); /* current line number */
Page_lines++; /* increment lines per page */
printf("warning:can't open INCLUDE file %s\n",InclFName);
}
else
{
if ((savept=strsave(InclFName))==0)
error("out of memory for INCLUDE file name");
else
{
InclFiles[FdCount].fp=Fd; /* save current fp */
if (nfFlag)
{
InclFiles[FdCount].line_num=Line_num;
/* save current line count */
Line_num=0; /* reset for new file */
}
InclFiles[FdCount].name=Argv[Cfn];
/* save pointer to current name */
Argv[Cfn]=savept;
/* now replace pointer to current name with
pointer to name of Include file */
Fd=FdTemp; /* now replace current file with
INCLUDE fp */
FdCount++; /* and increment "stack" */
#ifdef DEBUG2
printf("pseudo INCLUDE: FdCount=%d\n",FdCount);
printf(" new input file pointer=%d\n",Fd);
printf(" new file name=%s\n",Argv[Cfn]);
#endif
}
}
}
}
break;
case END:
P_force=0;
if (FdCount>0) /* skip END statements in files
received from CLI arguments */
{
fclose(Fd); /* close file from this level nest */
FdCount--; /* "pop stack" */
Fd=InclFiles[FdCount].fp; /* restore fp from
nested stack */
if(nfFlag) Line_num=InclFiles[FdCount].line_num;
Argv[Cfn]=InclFiles[FdCount].name;
/* restore file name pointer */
#ifdef DEBUG2
printf("pseudo END: FdCount=%d\n",FdCount);
printf(" new input file pointer=%d\n",Fd);
printf(" new file name=%s\n",Argv[Cfn]);
#endif
}
break;
case IFD:
#ifdef DEBUG3
printf("case IFD: in pseudo\n");
#endif
P_force=0;
c=eval_ifd();
IfMachine(c);
break;
case IFND:
P_force=0;
c=eval_ifnd();
IfMachine(c);
break;
case ELSE:
P_force=0;
IfMachine(IF_ELSE);
break;
case ENDIF:
P_force=0;
IfMachine(IF_ENDIF);
break;
case CODE: /* CODE,DATA,BSS,AUTO ver TER_2.09 */
PC_Exchange(0);
break;
case DATA:
PC_Exchange(1);
break;
case BSS:
PC_Exchange(2);
break;
case AUTO:
PC_Exchange(3);
break;
default:
fatal("Pseudo error");
break;
}
}
 
 
/*
* PC_Exchange --- Save current PC and recover requested one
added ver TER_2.09
*/
void PC_Exchange(PC_ptr_new)
int PC_ptr_new; /* request 0=CODE,1=DATA,2=BSS */
{
P_force = 0; /* no PC in output cuz wrong first time (?) */
PC_Save[PC_ptr] = Pc; /* save current PC */
PC_ptr = PC_ptr_new; /* remember which one we're using */
Old_pc = Pc = PC_Save[PC_ptr]; /* recover the one requested */
f_record(); /* flush out any bytes, this is really an ORG */
}
/as09/symtab.c
0,0 → 1,157
/*
* install --- add a symbol to the table
*/
install(str,val)
char *str;
int val;
{
struct link *lp;
struct nlist *np,*p,*backp;
struct nlist *lookup();
int i;
char *LastChar(); /* ver TER_2.0 */
 
if( !alpha(*str) ){
error("Illegal Symbol Name");
return(NO);
}
if( (np = lookup(str)) != NULL ){
if (*LastChar(str) == '@') { /* redefinable symbol ver TER_2.0 */
np->def = val; /* redefined */
return(YES);
}
if( Pass==2 ){
np->def2 = 2; /* defined for this pass=Pass ver TER_2.0 */
if( np->def == val )
return(YES);
else{
error("Phasing Error");
return(NO);
}
}
error("Symbol Redefined");
return(NO);
}
/* enter new symbol */
#ifdef DEBUG
printf("Installing %s as %d\n",str,val);
#endif
np = (struct nlist *) alloc(sizeof(struct nlist));
if( np == (struct nlist *)ERR ){
error("Symbol table full");
return(NO);
}
np->name = alloc(strlen(str)+1);
if( np->name == (char *)ERR ){
error("Symbol table full");
return(NO);
}
strcpy(np->name,str);
np->def = val;
np->def2 = 1; /* defined for this pass=Pass ver TER_2.0 */
np->Lnext = NULL;
np->Rnext = NULL;
lp = (struct link *) alloc(sizeof(struct link));
np->L_list = lp;
lp->L_num = Line_num;
lp->next = NULL;
p = root;
backp = NULL;
while (p != NULL)
{
backp = p;
i = strcmp (str,p->name);
if (i<0)
p=p->Lnext;
else p=p->Rnext;
}
if (backp == NULL)
root = np;
else if (strcmp(str,backp->name)<0)
backp->Lnext = np;
else backp->Rnext = np;
return (YES);
}
 
/*
* lookup --- find string in symbol table
*/
struct nlist *
lookup(name)
char *name;
{
struct nlist *np;
int i;
char *c; /* ver TER_2.0 */
 
c = name; /* copy symbol pointer */
while(alphan(*c)) /* search for end of symbol */
c++; /* next char */
*c = EOS; /* disconnect anything after for good compare */
/* end of mods for ver TER_2.0 */
 
np = root; /* and now go on and look for symbol */
while (np != NULL)
{
i = strcmp(name,np->name);
if (i == 0)
{
Last_sym = np->def;
return (np);
}
else if (i < 0)
np = np->Lnext;
else np = np->Rnext;
}
Last_sym = 0;
/* if (Pass == 2)
error ("symbol Undefined on pass 2"); */
/* commented out ver TER_2.0 2 Jul 89 */
/* function used in IFD */
return (NULL);
}
 
 
#define NMNE (sizeof(table)/ sizeof(struct oper))
#define NPSE (sizeof(pseudo)/ sizeof(struct oper))
/*
* mne_look --- mnemonic lookup
*
* Return pointer to an oper structure if found.
* Searches both the machine mnemonic table and the pseudo table.
*/
struct oper *
mne_look(str)
char *str;
{
struct oper *low,*high,*mid;
int cond;
 
/* Search machine mnemonics first */
low = &table[0];
high = &table[ NMNE-1 ];
while (low <= high){
mid = low + (high-low)/2;
if( ( cond = strcmp(str,mid->mnemonic)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return(mid);
}
 
/* Check for pseudo ops */
low = &pseudo[0];
high = &pseudo[ NPSE-1 ];
while (low <= high){
mid = low + (high-low)/2;
if( ( cond = strcmp(str,mid->mnemonic)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return(mid);
}
 
return(NULL);
}
/as09/output.c
0,0 → 1,42
/*
* stable --- prints the symbol table in alphabetical order
*/
stable(ptr)
 
struct nlist *ptr;
{
if (ptr != NULL)
{
stable (ptr->Lnext);
printf ("%-10s %04X\n",ptr->name,ptr->def);
stable (ptr->Rnext);
}
}
/*
* cross -- prints the cross reference table
*/
cross(point)
 
struct nlist *point;
{
struct link *tp;
int i = 1;
if (point != NULL)
{
cross (point->Lnext);
printf ("%-10s %04X *",point->name,point->def);
tp = point->L_list;
while (tp != NULL)
{
if (i++>10)
{
i=1;
printf("\n ");
}
printf ("%04d ",tp->L_num);
tp = tp->next;
}
printf ("\n");
cross (point->Rnext);
}
}
/as09/ifd.c
0,0 → 1,246
/* IfMachine() --- This function implements the IFD & IFND conditional
assembly machine.
version 1.0 made for release TER_2.0 cross assembler 27 Jun 89
*/
 
#define FALSE_BLOCK 0 /* values for state variable */
#define TRUE_BLOCK 1
#define POP_TEST 2
#define ELSE_TEST 3
#define FALSE 0
#define TRUE 1
 
void IfMachine(Token)
int Token; /* input token from calling machine */
/* See file as.h for definition (globals) */
{
static int State = TRUE_BLOCK, StackPt = 0, IfStack[MAXIFD];
/* State variable, pointer to "IF stack pointer" and "Stack" */
int Hiatus; /* flag to break out of FSM & resume normal processing */
 
Hiatus=FALSE; /* infinite loop to operate machine
until time to break out */
do /* test at end */
{
 
#ifdef DEBUG3
printf("IfMachine state=%u , token=%u\n",State,Token);
#endif
 
if (State == TRUE_BLOCK) /* a block of statements processed normally */
switch(Token) {
case IF_TRUE:
IfStack[StackPt]=TRUE;
if (++StackPt > MAXIFD) { /* check for over flow */
StackPt = MAXIFD;
error("Error:IFD/IFND nested too deep");
}
/* print_line() will be done in normal processing */
Hiatus = TRUE; /* resume normal line processing */
break;
case IF_FALSE:
IfStack[StackPt]=TRUE;
if (++StackPt > MAXIFD) { /* check for over flow */
StackPt = MAXIFD;
error("Error:IFD/IFND nested too deep");
}
if (Pass == 2 && Lflag && !N_page) /* need to print here */
print_line(); /* cuz will not return to normal */
Token = GetToken(); /* get next line & examine for IF */
State = FALSE_BLOCK; /* change state */
break;
case IF_ELSE:
if (StackPt == 0) /* bad IF nesting */
error("Error: ELSE without IF");
if (Pass == 2 && Lflag && !N_page)
print_line();
Token = GetToken(); /* get next line & examine for IF */
State = FALSE_BLOCK;
break;
case IF_ENDIF:
if (StackPt == 0) /* bad IF nesting */
error("Error: ENDIF without IF");
else
StackPt--; /* popped state must be TRUE */
Hiatus = TRUE;
break;
/* case NORMAL is not implemented as it represents normal line
processing. */
case IF_END: /* file ended with improperly nested IFD */
/* this code can't actually be reached at present
in a TRUE_BLOCK */
fatal("Error: file ended before IFD/IFND/ELSE/ENDIF");
break;
default: /* This code can't be reached at the present.
Logically would happen if EOF but handled
else where */
fatal("Can't get here from there.");
break;
}
else if (State == FALSE_BLOCK) /* statements not processed */
switch(Token) {
case IF_TRUE: /* doesn't make any diff. Just nest IFs */
case IF_FALSE:
IfStack[StackPt]=FALSE;
if (++StackPt > MAXIFD) {
StackPt = MAXIFD;
error("Error:IFD/IFND nested too deep");
}
if (Pass == 2 && Lflag && !N_page)
print_line();
Token = GetToken();
break;
case IF_ELSE:
/* if (Pass == 2 && Lflag && !N_page) */
/* print_line(); */
State = ELSE_TEST;
break;
case IF_ENDIF:
State = POP_TEST;
break;
case IF_END: /* file ended with improperly nested IFD */
fatal("Fatal Error: file ended before last ENDIF");
/* Fatal will exit assembler. Things are too
messed up. Include file handling is else where
and don't want to duplicate here. */
break;
case IF_NORMAL: /* normal line in a FALSE BLOCK */
if (Pass == 2 && Lflag && !N_page)
print_line();
Token = GetToken();
break;
default:
fatal("Fatal Error: file ended before last ENDIF");
/* must be EOF or something else terrible */
break;
}
else if (State == POP_TEST) { /* pop up outside nest state */
if (StackPt == 0) { /* bad IF nesting */
error("Error: ENDIF without IF");
if (Pass == 2 && Lflag && !N_page)
print_line();
State = TRUE;
}
else {
StackPt--; /* pop stack */
if (IfStack[StackPt] == TRUE) { /* back to normal */
/* had to come from FALSE block cuz TRUE block cannot
be inside FALSE block */
if (Pass == 2 && Lflag && !N_page)
print_line();
State = TRUE;
Hiatus = TRUE; /* sleep for normal line processing */
}
else { /* gotta be that stack == FALSE, still inside FALSE nest */
if (Pass == 2 && Lflag && !N_page)
print_line();
State = FALSE;
Token = GetToken();
}
}
}
else if (State == ELSE_TEST) { /* change state */
if (IfStack[StackPt-1] == TRUE) {
State = TRUE_BLOCK;
Hiatus = TRUE;
}
else
State = FALSE_BLOCK;
}
}
while (Hiatus == FALSE); /* loop if not exit */
}
 
 
/* GetToken() --- get another line from within False Block and extract token
as would be done in pseudo.c. Returns token id:
IF_TRUE IFD/IFND evaluated to TRUE
IF_FALSE IFD/IFND evaluated to FALSE
IF_ELSE ELSE pseudo op
IF_ENDIF ENDIF pseudo op
IF_END END pseudo op
IF_NORMAL none of the above, perhaps assy code
IF_EOF encountered end of file
This function exists because conditional assembly was added
as pseudo op rather than with key character ("%") and did
not want to disturb original software topology */
 
int GetToken() /* get another line and find token in it */
{ /* similar to make_pass() except one line at a time */
/* most variables & constants are global */
 
struct nlist *lookup();
 
#ifndef IBM
if (FGETS(Line,MAXBUF-1,Fd) == (char *)NULL)
#else
if (fgets(Line,MAXBUF,Fd) == (char *)NULL)
#endif
return(IF_EOF); /* banged into eof */
Line_num++;
P_force=0;
N_page=0;
if (!parse_line())
return(IF_NORMAL); /* comment line */
if (*Op==EOS) /* skipping over label, probably. */
return(IF_NORMAL); /* strcmp() returns 0 if arg1 is NULL string */
 
if (strcmp(Op,"ifd")==0)
return(eval_ifd());
else if (strcmp(Op,"ifnd")==0)
return(eval_ifnd());
else if (strcmp(Op,"else")==0)
return(IF_ELSE);
else if (strcmp(Op,"endif")==0)
return(IF_ENDIF);
else if (strcmp(Op,"end")==0)
return(IF_END);
else
return(IF_NORMAL); /* or might be garbage...but who cares?
This is FALSE BLOCK */
}
 
 
/*
* eval_ifd() --- evaluate an if define statement for TRUE or FALSE
*/
 
int
eval_ifd()
{
struct nlist *np; /* symbol structure */
 
if (*Operand==EOS) {
warn("No symbol for IFD");
return(IF_FALSE); /* nothing to check */
}
if ((np=lookup(Operand)) == NULL)
return(IF_FALSE); /* not defined at all...yet */
else
if(np->def2 == Pass)
return(IF_TRUE); /* defined for this pass */
 
return(IF_FALSE); /* not defined this pass */
}
 
/*
* eval_ifnd() --- evaluate an if not define statement for TRUE or FALSE
*/
 
int
eval_ifnd()
{
struct nlist *np; /* symbol structure */
 
if (*Operand==EOS) {
warn("No symbol for IFND");
return(IF_TRUE); /* nothing to check */
}
if ((np=lookup(Operand)) == NULL)
return(IF_TRUE); /* not defined at all...yet */
else
if(np->def2 == Pass)
return(IF_FALSE); /* defined for this pass */
 
return(IF_TRUE); /* not defined this pass */
}
/as09/as.c
0,0 → 1,313
char mapdn();
char *alloc();
/*
* as --- cross assembler main program
 
Note: Compile with define DEBUG for function module debug
statements. Compile with define DEBUG2 for version 2 debug
statements only. Compile with define IBM to use original, non-
Amiga, non-MAC, non-UNIX fgets() function. Amiga version will
accept IBM generated source code but not the other way around.
Note added version (TER) 2.01 19 June 1989.
 
Additional modifications to cleanup output listing made by
Donald W. Coates 1/5/92. Version changed to 2.10
*/
main(argc,argv)
int argc;
char **argv;
{
char **np;
char *i;
FILE *fopen();
int j = 0;
void do_op(),f_record(); /* added for ANSI C compat ver TER_2.0 6/18/89 */
 
printf("Assembler release DWC_2.0 version 2.11\n");
printf("May 6, 2004 (c) Motorola (free ware)\n");
 
if(argc < 2){
printf("Usage: %s [files]\n",argv[j]);
exit(1);
}
Argv = argv;
initialize();
while ((j<argc) && (*argv[j] != '-'))
j++;
N_files = j-1;
if (j < argc )
{
argv[j]++;
while (j<argc)
{
for (i = argv[j]; *i != 0; i++)
if ((*i <= 'Z') && (*i >= 'A'))
*i = *i + 32;
if (strcmp(argv[j],"l")==0)
Lflag = 1;
else if (strcmp(argv[j],"nol")==0)
Lflag = 0;
else if (strcmp(argv[j],"c")==0)
Cflag = 1;
else if (strcmp(argv[j],"noc")==0)
Cflag = 0;
else if (strcmp(argv[j],"s")==0)
Sflag = 1;
else if (strcmp(argv[j],"cre")==0)
CREflag = 1;
else if (strcmp(argv[j],"crlf")==0) /* test for crlf option */
CRflag = 1; /* add <CR><LF> to S record */
/* ver TER_1.1 June 3, 1989 */
else if (strcmp(argv[j],"nnf")==0) /* test for nnf option */
nfFlag=0; /* nfFlag=1 means number INCLUDE */
/* separately. ver TER_2.0 6/17/89 */
else if (strcmp(argv[j],"p50")==0){ /* page every 50 lines */
Pflag50 = 1; /* ver (TER) 2.01 19 Jun 89 */
Pflag75 = 0;
} /* separately. ver TER_2.0 6/17/89 */
else if (strcmp(argv[j],"p75")==0){ /* page every 75 lines */
Pflag50 = 0; /* ver (DWC) 2.10 8 Oct 2001 */
Pflag75 = 1;
}
j++;
}
}
root = NULL;
 
Cfn = 0;
np = argv;
Line_num = 0; /* reset line number */
while( ++Cfn <= N_files )
if((Fd = fopen(*++np,"r")) == NULL)
printf("as: can't open %s\n",*np);
else{
make_pass();
fclose(Fd);
}
if( Err_count == 0 ){
Pass++;
re_init();
Cfn = 0;
np = argv;
Line_num = 0;
FdCount=0; /* Resets INCLUDE file nesting ver TER_2.0 6/17/89 */
while( ++Cfn <= N_files)
if((Fd = fopen(*++np,"r")) != NULL)
{
make_pass();
fclose(Fd);
}
printf ("Program + Init Data = %d bytes\n",F_total); /* print total bytes */
printf ("Error count = %d\n",Err_count); /* rel TER_2.0 */
if (Sflag == 1)
{
printf ("\n\f\n");
stable (root);
}
if (CREflag == 1)
{
printf ("\n\f\n");
cross (root);
}
if (CRflag == 1)
fprintf(Objfil,"S9030000FC%c\n",CR); /* ver TER_1.1 print w <CR> */
else
fprintf(Objfil,"S9030000FC\n"); /* at least give a decent ending */
fclose(Objfil); /* close file correctly ver TER_1.1 */
}
else /* just note errors, TER_2.0 */
{
printf ("Program + Init Data = %d bytes\n",F_total); /* print total bytes */
printf ("Error count = %d\n",Err_count);
}
fwd_done();
exit(Err_count); /* neat for UNIX cuz can test return value in script
but on other systems like Amiga, mostly just makes
further script statements fail if >10, else
nothing. Therefore, printed out byte count
and error level. ver (TER) 2.02 19 Jun 89 */
}
 
initialize()
{
FILE *fopen();
int i = 0;
 
#ifdef DEBUG
printf("Initializing\n");
#endif
Err_count = 0;
Pc = 0;
Pass = 1;
Lflag = 0;
Cflag = 0;
Ctotal = 0;
Sflag = 0;
CREflag = 0;
N_page = 0;
Line[MAXBUF-1] = NEWLINE;
 
strcpy(Obj_name,Argv[1]); /* copy first file name into array */
do {
if (Obj_name[i]=='.')
Obj_name[i]=0;
}
while (Obj_name[i++] != 0);
strcat(Obj_name,".s19"); /* append .out to file name. */
if( (Objfil = fopen(Obj_name,"w")) == NULL)
fatal("Can't create object file");
fwdinit(); /* forward ref init */
localinit(); /* target machine specific init. */
}
 
re_init()
{
#ifdef DEBUG
printf("Reinitializing\n");
#endif
Pc = 0;
E_total = 0;
P_total = 0;
Ctotal = 0;
N_page = 0;
fwdreinit();
}
 
make_pass()
{
#ifdef IBM
char *fgets(); /* the original line */
#else
char *FGETS(); /* use own FGETS which is rewrite of lib function */
/* such that it discards <CR> so can read code */
/* generated on IBM */
/* June 3, 1989 rev TER_1.1 */
#endif
 
#ifdef DEBUG
printf("Pass %d\n",Pass);
#endif
 
#ifndef IBM
while( FGETS(Line,MAXBUF-1,Fd) != (char *)NULL ){ /* changed to FGETS */
/* which does not pass on <CR> June 3, 1989 */
/* rev TER_1.1 */
#else
while( fgets(Line,MAXBUF,Fd) != (char *)NULL ){
 
#endif
 
Line_num++;
P_force = 0; /* No force unless bytes emitted */
N_page = 0;
if(parse_line())
process();
if(Pass == 2 && Lflag && !N_page)
print_line();
P_total = 0; /* reset byte count */
Cycles = 0; /* and per instruction cycle count */
}
f_record();
}
 
 
/*
* parse_line --- split input line into label, op and operand
*/
parse_line()
{
register char *ptrfrm = Line;
register char *ptrto = Label;
char *skip_white();
 
if( *ptrfrm == '*' || *ptrfrm == '\n' || *ptrfrm == ';' )
/* added check for ';' ver TER_1.1 */
/* June 3, 1989 */
return(0); /* a comment line */
 
while( delim(*ptrfrm)== NO ) /* parsing Label */
*ptrto++ = *ptrfrm++;
if(*--ptrto != ':')ptrto++; /* allow trailing : */
*ptrto = EOS;
 
ptrfrm = skip_white(ptrfrm);
if (*ptrfrm == ';') { /* intercept comment after label, ver TER_2.0 */
*Op = *Operand = EOS; /* comment, no Opcode or Operand */
return(1); }
ptrto = Op;
 
while( delim(*ptrfrm) == NO) /* parsing Opcode */
*ptrto++ = mapdn(*ptrfrm++);
*ptrto = EOS;
 
ptrfrm = skip_white(ptrfrm);
if (*ptrfrm == ';') { /* intercept comment, ver TER_2.0 */
*Operand = EOS; /* comment, no Operand */
return(1); }
 
ptrto = Operand;
while( (*ptrfrm != NEWLINE) && (*ptrfrm != ';')) /* ver TER_2.0 */
*ptrto++ = *ptrfrm++; /* kill comments */
*ptrto = EOS;
 
#ifdef DEBUG
printf("Label-%s-\n",Label);
printf("Op----%s-\n",Op);
printf("Operand-%s-\n",Operand);
#endif
return(1);
}
 
/*
* process --- determine mnemonic class and act on it
*/
process()
{
register struct oper *i;
struct oper *mne_look();
 
Old_pc = Pc; /* setup `old' program counter */
Optr = Operand; /* point to beginning of operand field */
 
if(*Op==EOS){ /* no mnemonic */
if(*Label != EOS)
install(Label,Pc);
}
else if( (i = mne_look(Op))== NULL)
error("Unrecognized Mnemonic");
else if( i->class == PSEUDO )
do_pseudo(i->opcode);
else{
if( *Label )install(Label,Pc);
if(Cflag)Cycles = i->cycles;
do_op(i->opcode,i->class);
if(Cflag)Ctotal += Cycles;
}
}
 
#ifndef IBM
char *FGETS(s, n, iop) /* get at most n chars from iop */
/* Added rev TER_1.1 June 3, 1989 */
/* Adapted from Kernighan & Ritchie */
/* An fgets() that is IBM proof. Not needed if
this IS an IBM */
 
char *s;
int n;
register FILE *iop;
{
register int c;
register char *cs;
 
cs=s;
while (--n > 0 && (c = getc(iop)) != EOF) /* read chars if not file end */
{
if ((*cs = c) != CR) cs++; /* incr buffer pointer if not CR */
/* If CR, leave to be written over */
if (c == '\n')
break;
}
*cs = '\0'; /* replace NEWLINE with NULL as in standard fgets() */
return((c == EOF && cs == s) ? NULL : s); /* return NULL if this is EOF */
}
#endif
/as09/table09.h
0,0 → 1,152
struct oper table[] = {
 
"abx", INH, 58, 3,
"adca", GEN, 137, 2,
"adcb", GEN, 201, 2,
"adda", GEN, 139, 2,
"addb", GEN, 203, 2,
"addd", LONGIMM, 195, 4,
"anda", GEN, 132, 2,
"andb", GEN, 196, 2,
"andcc", IMM, 28, 3,
"asl", GRP2, 8, 4,
"asla", INH, 72, 2,
"aslb", INH, 88, 2,
"asr", GRP2, 7, 4,
"asra", INH, 71, 2,
"asrb", INH, 87, 2,
"bcc", REL, 36, 3,
"bcs", REL, 37, 3,
"beq", REL, 39, 3,
"bge", REL, 44, 3,
"bgt", REL, 46, 3,
"bhi", REL, 34, 3,
"bhs", REL, 36, 3,
"bita", GEN, 133, 2,
"bitb", GEN, 197, 2,
"ble", REL, 47, 3,
"blo", REL, 37, 3,
"bls", REL, 35, 3,
"blt", REL, 45, 3,
"bmi", REL, 43, 3,
"bne", REL, 38, 3,
"bpl", REL, 42, 3,
"bra", REL, 32, 3,
"brn", REL, 33, 3,
"bsr", REL, 141, 7,
"bvc", REL, 40, 3,
"bvs", REL, 41, 3,
"clr", GRP2, 15, 4,
"clra", INH, 79, 2,
"clrb", INH, 95, 2,
"cmpa", GEN, 129, 2,
"cmpb", GEN, 193, 2,
"cmpd", P2GEN, 131, 5,
"cmps", P3GEN, 140, 5,
"cmpu", P3GEN, 131, 5,
"cmpx", LONGIMM, 140, 4,
"cmpy", P2GEN, 140, 5,
"com", GRP2, 3, 4,
"coma", INH, 67, 2,
"comb", INH, 83, 2,
"cpx", LONGIMM, 140, 4, /* for compatibility with old code */
"cwai", IMM, 60, 20,
"daa", INH, 25, 2,
"dec", GRP2, 10, 4,
"deca", INH, 74, 2,
"decb", INH, 90, 2,
"eora", GEN, 136, 2,
"eorb", GEN, 200, 2,
"exg", RTOR, 30, 8,
"inc", GRP2, 12, 4,
"inca", INH, 76, 2,
"incb", INH, 92, 2,
"jmp", GRP2, 14, 1,
"jsr", NOIMM, 141, 5,
"lbcc", P2REL, 36, 6,
"lbcs", P2REL, 37, 6,
"lbeq", P2REL, 39, 6,
"lbge", P2REL, 44, 6,
"lbgt", P2REL, 46, 6,
"lbhi", P2REL, 34, 6,
"lbhs", P2REL, 36, 6,
"lble", P2REL, 47, 6,
"lblo", P2REL, 37, 6,
"lbls", P2REL, 35, 6,
"lblt", P2REL, 45, 6,
"lbmi", P2REL, 43, 6,
"lbne", P2REL, 38, 6,
"lbpl", P2REL, 42, 6,
"lbra", P1REL, 22, 5,
"lbrn", P2REL, 33, 5,
"lbsr", P1REL, 23, 9,
"lbvc", P2REL, 40, 6,
"lbvs", P2REL, 41, 6,
"lda", GEN, 134, 2,
"ldaa", GEN, 134, 2,
"ldab", GEN, 198, 2,
"ldb", GEN, 198, 2,
"ldd", LONGIMM, 204, 3,
"lds", P2GEN, 206, 4,
"ldu", LONGIMM, 206, 3,
"ldx", LONGIMM, 142, 3,
"ldy", P2GEN, 142, 4,
"leas", INDEXED, 50, 2,
"leau", INDEXED, 51, 2,
"leax", INDEXED, 48, 2,
"leay", INDEXED, 49, 2,
"lsl", GRP2, 8, 4,
"lsla", INH, 72, 2,
"lslb", INH, 88, 2,
"lsr", GRP2, 4, 4,
"lsra", INH, 68, 2,
"lsrb", INH, 84, 2,
"mul", INH, 61, 11,
"neg", GRP2, 0, 4,
"nega", INH, 64, 2,
"negb", INH, 80, 2,
"nop", INH, 18, 2,
"ora", GEN, 138, 2,
"oraa", GEN, 138, 2,
"orab", GEN, 202, 2,
"orb", GEN, 202, 2,
"orcc", IMM, 26, 3,
"pshs", RLIST, 52, 5,
"pshu", RLIST, 54, 5,
"puls", RLIST, 53, 5,
"pulu", RLIST, 55, 5,
"rol", GRP2, 9, 4,
"rola", INH, 73, 2,
"rolb", INH, 89, 2,
"ror", GRP2, 6, 4,
"rora", INH, 70, 2,
"rorb", INH, 86, 2,
"rti", INH, 59, 15,
"rts", INH, 57, 5,
"sbca", GEN, 130, 2,
"sbcb", GEN, 194, 2,
"sex", INH, 29, 2,
"sta", NOIMM, 135, 2,
"staa", NOIMM, 135, 2,
"stab", NOIMM, 199, 2,
"stb", NOIMM, 199, 2,
"std", NOIMM, 205, 3,
"sts", P2NOIMM, 207, 4,
"stu", NOIMM, 207, 3,
"stx", NOIMM, 143, 3,
"sty", P2NOIMM, 143, 4,
"suba", GEN, 128, 2,
"subb", GEN, 192, 2,
"subd", LONGIMM, 131, 4,
"swi", INH, 63, 19,
"swi2", P2INH, 63, 20,
"swi3", P3INH, 63, 20,
"sync", INH, 19, 4,
"sys", SYS, 0, 19,
"tfr", RTOR, 31, 6,
"tst", GRP2, 13, 4,
"tsta", INH, 77, 2,
"tstb", INH, 93, 2
 
};
 
/as09/ffwd.c
0,0 → 1,85
/*
* file I/O version of forward ref handler
*/
 
#define FILEMODE 0644 /* file creat mode */
#define UPDATE 2 /* file open mode */
#define ABS 0 /* absolute seek */
 
int Forward =0; /* temp file's file descriptor */
char Fwd_name[] = { "Fwd_refs" } ;
 
/*
* fwdinit --- initialize forward ref file
*/
fwdinit()
{
Forward = open(Fwd_name,O_CREAT | O_TRUNC | O_WRONLY, FILEMODE); //creat(Fwd_name,FILEMODE);
if(Forward <0)
fatal("Can't create temp file");
close(Forward); /* close and reopen for reads and writes */
Forward = open(Fwd_name,UPDATE);
if(Forward <0)
fatal("Forward ref file has gone.");
}
 
/*
* fwdreinit --- reinitialize forward ref file
*/
fwdreinit()
{
F_ref = 0;
Ffn = 0;
lseek(Forward,0L,ABS); /* rewind forward refs */
read(Forward,&Ffn,sizeof(Ffn));
read(Forward,&F_ref,sizeof(F_ref)); /* read first forward ref into mem */
#ifdef DEBUG
printf("First fwd ref: %d,%d\n",Ffn,F_ref);
#endif
}
 
/*
* fwdmark --- mark current file/line as containing a forward ref
*/
fwdmark()
{
write(Forward,&Cfn,sizeof(Cfn));
write(Forward,&Line_num,sizeof(Line_num));
}
 
/*
* fwdnext --- get next forward ref
*/
fwdnext()
{
int stat;
 
stat = read(Forward,&Ffn,sizeof(Ffn));
#ifdef DEBUG
printf("Ffn stat=%d ",stat);
#endif
stat = read(Forward,&F_ref,sizeof(F_ref));
#ifdef DEBUG
printf("F_ref stat=%d ",stat);
#endif
if( stat < 2 ){
F_ref=0;Ffn=0;
}
#ifdef DEBUG
printf("Next Fwd ref: %d,%d\n",Ffn,F_ref);
#endif
}
 
/*
* fwd_done --- closes & deletes forward reference file
*/
fwd_done()
{
int stat;
 
stat = close(Forward); /* Have to close first on MS-DOS or you leave lost clusters. */
#ifndef DEBUG
if( stat == 0 ) /* If close was successful, delete file */
unlink(Fwd_name);
#endif
}
/as09/eval.c
0,0 → 1,199
/*
* eval --- evaluate expression
*
* an expression is constructed like this:
*
* expr ::= expr + term |
* expr - term ;
* expr * term ;
* expr / term ;
* expr | term ;
* expr & term ;
* expr % term ;
* expr ^ term ;
*
* term ::= symbol |
* * |
* constant ;
*
* symbol ::= string of alphanumerics with non-initial digit
*
* constant ::= hex constant |
* binary constant |
* octal constant |
* decimal constant |
* ascii constant;
*
* hex constant ::= '$' {hex digits};
*
* octal constant ::= '@' {octal digits};
*
* binary constant ::= '%' { 1 | 0 };
*
* decimal constant ::= {decimal digits};
*
* ascii constant ::= ''' any printing char;
*
*/
eval()
{
int left,right; /* left and right terms for expression */
char o; /* operator character */
 
#ifdef DEBUG
printf("Evaluating %s\n",Optr);
#endif
Force_byte = NO;
Force_word = NO;
if(*Optr=='<'){
Force_byte++;
Optr++;
}
else if(*Optr=='>'){
Force_word++;
Optr++;
}
left = get_term(); /* pickup first part of expression */
 
while( is_op(*Optr)){
o = *Optr++; /* pickup connector and skip */
right = get_term(); /* pickup current rightmost side */
switch(o){
case '+': left += right; break;
case '-': left -= right; break;
case '*': left *= right; break;
case '/': left /= right; break;
case '|': left |= right; break;
case '&': left &= right; break;
case '%': left %= right; break;
case '^': left = left^right; break;
}
}
 
Result= left;
#ifdef DEBUG
printf("Result=%x\n",Result);
printf("Force_byte=%d Force_word=%d\n",Force_byte,Force_word);
#endif
return(YES);
}
 
/*
* is_op --- is character an expression operator?
*/
is_op(c)
char c;
{
if( any(c,"+-*/&%|^"))
return(YES);
return(NO);
}
 
 
/*
* get_term --- evaluate a single item in an expression
*/
get_term()
{
char hold[MAXBUF];
char *tmp;
int val = 0; /* local value being built */
int minus; /* unary minus flag */
struct nlist *lookup(),*pointer;
struct link *pnt,*bpnt;
 
if( *Optr == '-' ){
Optr++;
minus =YES;
}
else
minus = NO;
 
while( *Optr == '#' ) Optr++;
 
/* look at rest of expression */
 
if(*Optr=='%'){ /* binary constant */
Optr++;
while( any(*Optr,"01"))
val = (val * 2) + ( (*Optr++)-'0');
}
else if(*Optr=='@'){ /* octal constant */
Optr++;
while( any(*Optr,"01234567"))
val = (val * 8) + ((*Optr++)-'0');
}
else if(*Optr=='$'){ /* hex constant */
Optr++;
while( any(*Optr,"0123456789abcdefABCDEF"))
if( *Optr > '9' )
val = (val * 16) + 10 + (mapdn(*Optr++)-'a');
else
val = (val * 16) + ((*Optr++)-'0');
}
else if( any(*Optr,"0123456789")){ /* decimal constant */
while(*Optr >= '0' && *Optr <= '9')
val = (val * 10) + ( (*Optr++)-'0');
}
else if(*Optr=='*'){ /* current location counter */
Optr++;
val = Old_pc;
}
else if(*Optr=='\''){ /* character literal */
Optr++;
if(*Optr == EOS)
val = 0;
else
val = *Optr++;
}
else if( alpha(*Optr) ){ /* a symbol */
tmp = hold; /* collect symbol name */
while(alphan(*Optr))
*tmp++ = *Optr++;
*tmp = EOS;
pointer = lookup(hold);
if (pointer != NULL)
{
if (Pass == 2)
{
pnt = pointer->L_list;
bpnt = NULL;
while (pnt != NULL)
{
bpnt = pnt;
pnt = pnt->next;
}
pnt = (struct link *) alloc(sizeof(struct link));
if (bpnt == NULL)
pointer->L_list = pnt;
else bpnt->next = pnt;
pnt->L_num = Line_num;
pnt->next = NULL;
}
val = Last_sym;
}
else{
if(Pass==1){ /* forward ref here */
fwdmark();
if( !Force_byte )
Force_word++;
val = 0;
}
else /* added ver TER_2.0 2 Jul 89 */
error("Symbol undefined Pass 2");
}
if(Pass==2 && Line_num==F_ref && Cfn==Ffn){
if( !Force_byte )
Force_word++;
fwdnext();
}
}
else
/* none of the above */
val = 0;
 
if(minus)
return(-val);
else
return(val);
}
/as09/as.h
0,0 → 1,167
/*
* machine independent definitions and global variables
*/
 
#define YES 1
#define NO 0
#define ERR (-1)
 
#define MAXBUF 128
#define MAXOP 10 /* longest mnemonic */
#define MAXLAB 16
#define E_LIMIT 32
#define P_LIMIT 64
#define MAXINCFILES 30 /* nestinf levels for INCLUDE files at one time */
/* ver TER_2.0 6/17/89 */
#define MAXIFD 30 /* max nesting levels for IFD/IFND statements */
/* ver TER_2.0 2 Jul 89 */
#define IF_FALSE 0 /* tokens for IfMachine (conditional assembly) */
#define IF_TRUE 1 /* added ver TER_2.0 27Jun89 */
#define IF_ELSE 2
#define IF_ENDIF 3
#define IF_NORMAL 4
#define IF_END 5
#define IF_EOF 6 /* end tokens */
 
/* Character Constants */
#define NEWLINE '\n'
#define CR 0x0D /* <CR> or ^M ver TER_1.1 June 3, 1989 */
#define TAB '\t'
#define BLANK ' '
#define EOS '\0'
 
/* Opcode Classes */
#define INH 0 /* Inherent */
#define GEN 1 /* General Addressing */
#define IMM 2 /* Immediate only */
#define REL 3 /* Short Relative */
#define P2REL 4 /* Long Relative */
#define P1REL 5 /* Long Relative (LBRA and LBSR)*/
#define NOIMM 6 /* General except for Immediate */
#define P2GEN 7 /* Page 2 General */
#define P3GEN 8 /* Page 3 General */
#define RTOR 9 /* Register To Register */
#define INDEXED 10 /* Indexed only */
#define RLIST 11 /* Register List */
#define P2NOIMM 12 /* Page 2 No Immediate */
#define P2INH 13 /* Page 2 Inherent */
#define P3INH 14 /* Page 3 Inherent */
#define GRP2 15 /* Group 2 (Read/Modify/Write) */
#define LONGIMM 16 /* Immediate mode takes 2 bytes */
#define BTB 17 /* Bit test and branch */
#define SETCLR 18 /* Bit set or clear */
#define CPD 19 /* compare d 6811 */
#define XLIMM 20 /* LONGIMM for X 6811 */
#define XNOIMM 21 /* NOIMM for X 6811 */
#define YLIMM 22 /* LONGIMM for Y 6811 */
#define YNOIMM 23 /* NOIMM for Y 6811 */
#define FAKE 24 /* convenience mnemonics 6804 */
#define APOST 25 /* A accum after opcode 6804 */
#define BPM 26 /* branch reg plus/minus 6804 */
#define CLRX 27 /* mvi x,0 6804 */
#define CLRY 28 /* mvi y,0 6804 */
#define LDX 29 /* mvi x,expr 6804 */
#define LDY 30 /* mvi y,expr 6804 */
#define MVI 31 /* mvi 6804 */
#define EXT 32 /* extended 6804 */
#define BIT 33 /* bit manipulation 6301 */
#define SYS 34 /* syscalls (really swi) */
#define PSEUDO 35 /* Pseudo ops */
 
/* global variables */
int Line_num =0; /* current line number */
int Err_count =0; /* total number of errors */
char Line[MAXBUF] = {0}; /* input line buffer */
char Label[MAXLAB] = {0}; /* label on current line */
char Op[MAXOP] = {0}; /* opcode mnemonic on current line */
char Operand[MAXBUF] = {0}; /* remainder of line after op */
/* (up to ';' rel TER_2.0) */
char *Optr =0; /* pointer into current Operand field */
int Result =0; /* result of expression evaluation */
int Force_word =0; /* Result should be a word when set */
int Force_byte =0; /* Result should be a byte when set */
int Pc =0; /* Program Counter */
int Old_pc =0; /* Program Counter at beginning */
 
int Last_sym =0; /* result of last lookup */
 
int Pass =0; /* Current pass # */
int N_files =0; /* Number of files to assemble */
FILE *Fd =0; /* Current input file structure */
int Cfn =0; /* Current file number 1...n */
int Ffn =0; /* forward ref file # */
int F_ref =0; /* next line with forward ref */
char **Argv =0; /* pointer to file names */
 
int E_total =0; /* total # bytes for one line */
int E_bytes[E_LIMIT] = {0}; /* Emitted held bytes */
int E_pc =0; /* Pc at beginning of collection*/
 
int Lflag = 0; /* listing flag 0=nolist, 1=list*/
 
int P_force = 0; /* force listing line to include Old_pc */
int P_total =0; /* current number of bytes collected */
int P_bytes[P_LIMIT] = {0}; /* Bytes collected for listing */
 
int Cflag = 0; /* cycle count flag */
int Cycles = 0; /* # of cycles per instruction */
long Ctotal = 0; /* # of cycles seen so far */
int Sflag = 0; /* symbol table flag, 0=no symbol */
int N_page = 0; /* new page flag */
int Page_num = 2; /* page number */
int CREflag = 0; /* cross reference table flag */
int CRflag = 0; /* flag to add <CR><LF> to S record */
/* added ver TER_1.1 June 3, 1989 */
int nfFlag = 1; /* if=1 number INCLUDE files separate */
/* ver TER_2.0 June 17, 1989 */
int FdCount = 0; /* INCLUDE files "stack" pointer */
/* ver TER_2.0 June 17, 1989 */
char InclFName[MAXBUF]={0}; /* current INCLUDE file name */
int F_total = 0; /* total bytes emitted in S file */
/* ver (TER) 2.02 19 Jun 89 */
int Page_lines = 0; /* total lines this page */
/* ver (TER) 2.02 19 Jun 89 */
int Pflag50 = 0; /* if 1 then form feed every 50 lines */
/* ver (TER) 2.02 19 Jun 89 */
int Pflag75 = 0; /* if 1 then form feed every 75 lines */
/* ver (DWC) 2.10 8 Oct 2001 */
int PC_Save[4] = {0,0,0,0}; /* saved contents of CODE,DATA,BSS,AUTO PCs */
/* ver TER_2.09 25 July 89 */
int PC_ptr = 0; /* index or pointer to current PC */
/* initialized to CODE ver TER_2.09 25 July 89 */
 
struct link { /* linked list to hold line numbers */
int L_num; /* line number */
struct link *next; /* pointer to next node */
};
 
struct nlist { /* basic symbol table entry */
char *name;
int def; /* value of symbol, assigned by user */
int def2; /* value assign by assembler, e.g. defined this pass? */
/* added ver TER_2.0 4 Jul 89 */
struct nlist *Lnext ; /* left node of the tree leaf */
struct nlist *Rnext; /* right node of the tree leaf */
struct link *L_list; /* pointer to linked list of line numbers */
};
 
struct oper { /* an entry in the mnemonic table */
char *mnemonic; /* its name */
char class; /* its class */
int opcode; /* its base opcode */
char cycles; /* its base # of cycles */
};
 
struct nlist *root; /* root node of the tree */
 
FILE *Objfil =0; /* object file's file descriptor*/
char Obj_name[] = {" "};
 
struct InclFile { /* The INCLUDE files nesting "stack" */
/* added ver TER_2.0 6/17/89 */
FILE *fp; /* saved file pointer (next level up) */
int line_num; /* saved line number count */
char *name; /* saved file name */
};
 
struct InclFile InclFiles[MAXINCFILES]; /* the nesting stack itself */
/as09/do09.c
0,0 → 1,603
/*
* MC6809 specific processing
*/
 
#define PAGE2 0x10
#define PAGE3 0x11
#define IPBYTE 0x9F /* extended indirect postbyte */
#define SWI 0x3F
 
/* register names */
 
#define RD 0
#define RX 1
#define RY 2
#define RU 3
#define RS 4
#define RPC 5
#define RA 8
#define RB 9
#define RCC 10
#define RDP 11
#define RPCR 12
 
/* convert tfr/exg reg number into psh/pul format */
int regs[] = { 6,16,32,64,64,128,0,0,2,4,1,8,0};
int rcycl[]= { 2,2, 2, 2, 2, 2, 0,0,1,1,1,1,0};
 
/* addressing modes */
#define IMMED 0 /* immediate */
#define IND 1 /* indexed */
#define INDIR 2 /* indirect */
#define OTHER 3 /* NOTA */
 
/*
* localinit --- machine specific initialization
*/
localinit()
{
}
 
/*
* do_op --- process mnemonic
*
* Called with the base opcode and it's class. Optr points to
* the beginning of the operand field.
*/
void do_op(opcode,class)
int opcode; /* base opcode */
int class; /* mnemonic class */
{
int dist; /* relative branch distance */
int src,dst;/* source and destination registers */
int pbyte; /* postbyte value */
int amode; /* indicated addressing mode */
int j;
 
amode = set_mode(); /* pickup indicated addressing mode */
 
switch(class){
case INH: /* inherent addressing */
emit(opcode);
return;
case GEN: /* general addressing */
do_gen(opcode,amode);
return;
case IMM: /* immediate addressing */
if( amode != IMMED ){
error("Immediate Operand Required");
return;
}
Optr++;
eval();
emit(opcode);
emit(lobyte(Result));
return;
case REL: /* short relative branches */
eval();
dist = Result - (Pc+2);
emit(opcode);
if( (dist >127 || dist <-128) && Pass==2){
error("Branch out of Range");
emit(lobyte(-2));
return;
}
emit(lobyte(dist));
return;
case P2REL: /* long relative branches */
eval();
dist = Result - (Pc+4);
emit(PAGE2);
emit(opcode);
eword(dist);
return;
case P1REL: /* lbra and lbsr */
if( amode == IMMED)
Optr++; /* kludge for C compiler */
eval();
dist = Result - (Pc+3);
emit(opcode);
eword(dist);
return;
case NOIMM:
if( amode == IMMED ){
error("Immediate Addressing Illegal");
return;
}
do_gen(opcode,amode);
return;
case P2GEN:
emit(PAGE2);
if( amode == IMMED ){
emit(opcode);
Optr++;
eval();
eword(Result);
return;
}
do_gen(opcode,amode);
return;
case P3GEN:
emit(PAGE3);
if( amode == IMMED ){
emit(opcode);
Optr++;
eval();
eword(Result);
return;
}
do_gen(opcode,amode);
return;
case RTOR: /* tfr and exg */
emit(opcode);
src = regnum();
while(alpha(*Optr))Optr++;
if(src==ERR){
error("Register Name Required");
emit(0);
return;
}
if(*Optr++ != ','){
error("Missing ,");
emit(0);
return;
}
dst = regnum();
while(alpha(*Optr))Optr++;
if(dst==ERR){
error("Register Name Required");
emit(0);
return;
}
if( src==RPCR || dst==RPCR){
error("PCR illegal here");
emit(0);
return;
}
if( (src <=5 && dst >=8) ||
(src >=8 && dst <=5)){
error("Register Size Mismatch");
emit(0);
return;
}
emit( (src<<4)+dst );
return;
case INDEXED: /* indexed addressing only */
if( *Optr == '#'){
Optr++; /* kludge city */
amode = IND;
}
if( amode != IND ){
error("Indexed Addressing Required");
return;
}
do_indexed(opcode);
return;
case RLIST: /* pushes and pulls */
if(*Operand == EOS){
error("Register List Required");
return;
}
emit(opcode);
pbyte = 0;
do{
j = regnum();
if( j == ERR || j==RPCR)
error("Illegal Register Name");
else if(j==RS && (opcode==52))
error("Can't Push S on S");
else if(j==RU && (opcode==54))
error("Can't Push U on U");
else if(j==RS && (opcode==53))
error("Can't Pull S from S");
else if(j==RU && (opcode==55))
error("Can't Pull U from U");
else{
pbyte |= regs[j];
Cycles += rcycl[j];
}
while(*Optr != EOS && alpha(*Optr))Optr++;
}while( *Optr++ == ',' );
emit(lobyte(pbyte));
return;
case P2NOIMM:
if( amode == IMMED )
error("Immediate Addressing Illegal");
else{
emit(PAGE2);
do_gen(opcode,amode);
}
return;
case P2INH: /* Page 2 inherent */
emit(PAGE2);
emit(opcode);
return;
case P3INH: /* Page 3 inherent */
emit(PAGE3);
emit(opcode);
return;
case LONGIMM:
if( amode == IMMED ){
emit(opcode);
Optr++;
eval();
eword(Result);
}
else
do_gen(opcode,amode);
return;
case GRP2:
if( amode == IND ){
do_indexed(opcode+0x60);
return;
}
else if( amode == INDIR){
Optr++;
emit(opcode + 0x60);
emit(IPBYTE);
eval();
eword(Result);
Cycles += 7;
if(*Optr == ']'){
Optr++;
return;
}
error("Missing ']'");
return;
}
eval();
if(Force_word){
emit(opcode+0x70);
eword(Result);
Cycles += 3;
return;
}
if(Force_byte){
emit(opcode);
emit(lobyte(Result));
Cycles += 2;
return;
}
if(Result>=0 && Result <=0xFF){
emit(opcode);
emit(lobyte(Result));
Cycles += 2;
return;
}
else {
emit(opcode+0x70);
eword(Result);
Cycles += 3;
return;
}
case SYS: /* system call */
emit(SWI);
eval();
emit(lobyte(Result));
return;
default:
fatal("Error in Mnemonic table");
}
}
 
 
/*
* do_gen --- process general addressing mode stuff
*/
do_gen(op,mode)
int op;
int mode;
{
if( mode == IMMED){
Optr++;
emit(op);
eval();
emit(lobyte(Result));
return(0);
}
else if( mode == IND ){
do_indexed(op+0x20);
return(0);
}
else if( mode == INDIR){
Optr++;
emit(op+0x20);
emit(IPBYTE);
eval();
eword(Result);
Cycles += 7;
if(*Optr == ']'){
Optr++;
return(0);
}
error("Missing ']'");
return(0);
}
else if( mode == OTHER){
eval();
if(Force_word){
emit(op+0x30);
eword(Result);
Cycles += 3;
return(0);
}
if(Force_byte){
emit(op+0x10);
emit(lobyte(Result));
Cycles += 2;
return(0);
}
if(Result>=0 && Result <=0xFF){
emit(op+0x10);
emit(lobyte(Result));
Cycles += 2;
return(0);
}
else {
emit(op+0x30);
eword(Result);
Cycles += 3;
return(0);
}
}
else {
error("Unknown Addressing Mode");
return(0);
}
}
 
/*
* do_indexed --- handle all wierd stuff for indexed addressing
*/
do_indexed(op)
int op;
{
int pbyte;
int j,k;
int predec,pstinc;
 
Cycles += 2; /* indexed is always 2+ base cycle count */
predec=0;
pstinc=0;
pbyte=128;
emit(op);
if(*Optr=='['){
pbyte |= 0x10; /* set indirect bit */
Optr++;
if( !any((char)']',Optr))
error("Missing ']'");
Cycles += 3; /* indirection takes this much longer */
}
j=regnum();
if(j==RA){
Cycles++;
abd_index(pbyte+6);
return(0);
}
if(j==RB){
Cycles++;
abd_index(pbyte+5);
return(0);
}
if(j==RD){
Cycles += 4;
abd_index(pbyte+11);
return(0);
}
eval();
Optr++;
while(*Optr=='-'){
predec++;
Optr++;
}
j=regnum();
while( alpha(*Optr) )Optr++;
while(*Optr=='+'){
pstinc++;
Optr++;
}
if(j==RPC || j==RPCR){
if( pstinc || predec ){
error("Auto Inc/Dec Illegal on PC");
return(0);
}
if(j==RPC){
if(Force_word){
emit(pbyte+13);
eword(Result);
Cycles += 5;
return(0);
}
if(Force_byte){
emit(pbyte+12);
emit(lobyte(Result));
Cycles++;
return(0);
}
if(Result>=-128 && Result <=127){
emit(pbyte+12);
emit(lobyte(Result));
Cycles++;
return(0);
}
else {
emit(pbyte+13);
eword(Result);
Cycles += 5;
return(0);
}
}
/* PCR addressing */
if(Force_word){
emit(pbyte+13);
eword(Result-(Pc+2));
Cycles += 5;
return(0);
}
if(Force_byte){
emit(pbyte+12);
emit(lobyte(Result-(Pc+1)));
Cycles++;
return(0);
}
k=Result-(Pc+2);
if( k >= -128 && k <= 127){
emit(pbyte+12);
emit(lobyte(Result-(Pc+1)));
Cycles++;
return(0);
}
else{
emit(pbyte+13);
eword(Result-(Pc+2));
Cycles += 5;
return(0);
}
}
if(predec || pstinc){
if(Result != 0){
error("Offset must be Zero");
return(0);
}
if(predec>2 || pstinc>2){
error("Auto Inc/Dec by 1 or 2 only");
return(0);
}
if((predec==1 && (pbyte&0x10) != 0) ||
(pstinc==1 && (pbyte&0x10) != 0)){
error("No Auto Inc/Dec by 1 for Indirect");
return(0);
}
if(predec && pstinc){
error("Can't do both!");
return(0);
}
if(predec)
pbyte += predec+1;
if(pstinc)
pbyte += pstinc-1;
pbyte += rtype(j);
emit(pbyte);
Cycles += 1 + predec + pstinc;
return(0);
}
pbyte += rtype(j);
if(Force_word){
emit(pbyte+0x09);
eword(Result);
Cycles += 4;
return(0);
}
if(Force_byte){
emit(pbyte+0x08);
emit(lobyte(Result));
Cycles++;
return(0);
}
if(Result==0){
emit(pbyte+0x04);
return(0);
}
if((Result >= -16) && (Result <= 15) && ((pbyte&16)==0)){
pbyte &= 127;
pbyte += Result&31;
emit(pbyte);
Cycles++;
return(0);
}
if(Result >= -128 && Result <= 127){
emit(pbyte+0x08);
emit(lobyte(Result));
Cycles++;
return(0);
}
emit(pbyte+0x09);
eword(Result);
Cycles += 4;
return(0);
}
 
 
/*
* abd_index --- a,b or d indexed
*/
 
abd_index(pbyte)
int pbyte;
{
int k;
 
Optr += 2;
k=regnum();
pbyte += rtype(k);
emit(pbyte);
return(0);
}
 
/*
* rtype --- return register type in post-byte format
*/
rtype(r)
int r;
{
switch(r){
case RX: return(0x00);
case RY: return(0x20);
case RU: return(0x40);
case RS: return(0x60);
}
error("Illegal Register for Indexed");
return(0);
}
 
/*
* set_mode --- determine addressing mode from operand field
*/
set_mode()
{
register char *p;
 
if( *Operand == '#' )
return(IMMED); /* immediate addressing */
p = Operand;
while( *p != EOS && *p != BLANK && *p != TAB){/* any , before break */
if( *p == ',')
return(IND); /* indexed addressing */
p++;
}
if( *Operand == '[')
return(INDIR); /* indirect addressing */
return(OTHER); /* NOTA */
}
 
/*
* regnum --- return register number of *Optr
*/
regnum()
{
if( head(Optr,"D" ))return(RD);
if( head(Optr,"d" ))return(RD);
if( head(Optr,"X" ))return(RX);
if( head(Optr,"x" ))return(RX);
if( head(Optr,"Y" ))return(RY);
if( head(Optr,"y" ))return(RY);
if( head(Optr,"U" ))return(RU);
if( head(Optr,"u" ))return(RU);
if( head(Optr,"S" ))return(RS);
if( head(Optr,"s" ))return(RS);
if( head(Optr,"PC" ))return(RPC);
if( head(Optr,"pc" ))return(RPC);
if( head(Optr,"PCR" ))return(RPCR);
if( head(Optr,"pcr" ))return(RPCR);
if( head(Optr,"A" ))return(RA);
if( head(Optr,"a" ))return(RA);
if( head(Optr,"B" ))return(RB);
if( head(Optr,"b" ))return(RB);
if( head(Optr,"CC" ))return(RCC);
if( head(Optr,"cc" ))return(RCC);
if( head(Optr,"DP" ))return(RDP);
if( head(Optr,"dp" ))return(RDP);
return(ERR);
}
 
 
/as09/as09.c
0,0 → 1,15
//#include "stdafx.h"
#include <stdio.h>
#include <fcntl.h>
#include "as.h"
#include "table09.h"
#include "as.c"
#include "do09.c"
#include "pseudo.c"
#include "ifd.c" /* ver TER_2.0 2 Jul 89 */
#include "eval.c"
#include "symtab.c"
#include "util.c"
#include "ffwd.c"
#include "output.c"
 
/as09/util.c
0,0 → 1,391
/*
* fatal --- fatal error handler
*/
fatal(str)
char *str;
{
pouterror(); /* added ver TER_2.0 4 Jul 89 */
printf("%s\n",str);
 
#ifdef IBM /* changed ver TER_2.0 */
exit(-1);
#else
exit(10); /* Amiga & UNIX prefer positive numbers for error
minimal error is 10 (no system prob) */
#endif
}
 
/*
* error --- error in a line
* print line number and error
*/
error(str)
char *str;
{
/* if(N_files > 1) commented out test for N_files in rel TER_2.0
because a single command line source file
(which is what N_files counts) can have multiple
include source files. */
pouterror();
printf("%s\n",str);
}
/*
* warn --- trivial error in a line
* print line number and error
*/
warn(str)
char *str;
{
/* if(N_files > 1) commented out in rel TER_2.0 same reason as above */
printf("%s, line no.",Argv[Cfn]); /* current file name */
printf("%d: ",Line_num); /* current line number */
printf("Warning --- %s\n",str);
Page_lines++;
}
 
 
/*
* delim --- check if character is a delimiter
*/
delim(c)
char c;
{
if( any(c," \t\n"))
return(YES);
return(NO);
}
 
/*
* skip_white --- move pointer to next non-whitespace char
*/
char *skip_white(ptr)
char *ptr;
{
while(*ptr==BLANK || *ptr==TAB)
ptr++;
return(ptr);
}
 
/*
* eword --- emit a word to code file
*/
eword(wd)
int wd;
{
emit(hibyte(wd));
emit(lobyte(wd));
}
 
/*
* emit --- emit a byte to code file
*/
emit(byte)
{
#ifdef DEBUG
printf("%2x @ %4x\n",byte,Pc);
#endif
if(Pass==1){
Pc++;
return(YES);
}
if(P_total < P_LIMIT)
P_bytes[P_total++] = byte;
E_bytes[E_total++] = byte;
Pc++;
if(E_total == E_LIMIT)
f_record();
}
 
/*
* f_record --- flush record out in `S1' format
*/
void f_record() /* made void for ANSI C compat ver TER_2.0 6/18/89 */
{
int i;
int chksum;
 
if(Pass == 1)
return;
if(E_total==0){
E_pc = Pc;
return;
}
F_total += E_total; /* total bytes in file ver (TER)2.01 19 Jun 89 */
chksum = E_total+3; /* total bytes in this record */
chksum += lobyte(E_pc);
chksum += E_pc>>8;
fprintf(Objfil,"S1"); /* record header preamble */
hexout(E_total+3); /* byte count +3 */
hexout(E_pc>>8); /* high byte of PC */
hexout(lobyte(E_pc)); /* low byte of PC */
for(i=0;i<E_total;i++){
chksum += lobyte(E_bytes[i]);
hexout(lobyte(E_bytes[i])); /* data byte */
}
chksum =~ chksum; /* one's complement */
hexout(lobyte(chksum)); /* checksum */
if (CRflag == 1) /* test for CRflag added ver TER_1.1 */
fprintf(Objfil,"%c\n",CR); /* print in IBM format for some PROM boxes */
else
fprintf(Objfil,"\n"); /* this is original statement */
E_pc = Pc;
E_total = 0;
}
 
char *hexstr = { "0123456789ABCDEF" } ;
 
hexout(byte)
int byte;
{
 
byte = lobyte(byte);
fprintf(Objfil,"%c%c",hexstr[byte>>4],hexstr[byte&017]);
}
 
/*
* print_line --- pretty print input line
*/
print_line()
{
int i;
register char *ptr;
 
printf ("%04d ",Line_num);
if(P_total || P_force)
printf("%04X",Old_pc);
else
printf(" ");
 
for(i=0;i<P_total && i<6;i++)
printf(" %02X",lobyte(P_bytes[i]));
for(;i<6;i++)
printf(" ");
printf(" ");
 
if(Cflag){
if(Cycles)
printf("[%2d ] ",Cycles);
else
printf(" ");
}
ptr = Line;
while( *ptr != '\n' ) /* just echo the line back out */
putchar(*ptr++);
for(;i<P_total;i++){
if( i%6 == 0 )
printf("\n "); /* force data alignment DWC 1-5-92 */
printf(" %02X",lobyte(P_bytes[i]));
}
if (Pflag50 && (++Page_lines>=50)) /* form feed if flag set */
NewPage(); /* ver (TER) 2.02 19 Jun 89 */
 
if (Pflag75 && (++Page_lines>=75)) /* form feed if flag set */
NewPage(); /* ver (DWC) 2.10 8 Oct 2001 */
 
 
printf("\n");
}
 
/*
* any --- does str contain c?
*/
any(c,str)
char c;
char *str;
{
while(*str != EOS)
if(*str++ == c)
return(YES);
return(NO);
}
 
/*
* mapdn --- convert A-Z to a-z
*/
char mapdn(c)
char c;
{
if( c >= 'A' && c <= 'Z')
return((char)(c+040)); /* cast value to char for ANSI C, ver TER_2.0 */
return(c);
}
 
/*
* lobyte --- return low byte of an int
*/
lobyte(i)
int i;
{
return(i&0xFF);
}
/*
* hibyte --- return high byte of an int
*/
hibyte(i)
int i;
{
return((i>>8)&0xFF);
}
 
/*
* head --- is str2 the head of str1?
*/
head(str1,str2)
char *str1,*str2;
{
while( *str1 != EOS && *str2 != EOS){
if( *str1 != *str2 )break;
str1++;
str2++;
}
if(*str1 == *str2)return(YES);
if(*str2==EOS)
if( any(*str1," \t\n,+-];*") )return(YES);
return(NO);
}
 
/*
* alpha --- is character a legal letter
*/
alpha(c)
char c;
{
if( c<= 'z' && c>= 'a' )return(YES);
if( c<= 'Z' && c>= 'A' )return(YES);
if( c== '_' )return(YES);
if( c== '.' )return(YES);
return(NO);
}
/*
* alphan --- is character a legal letter or digit
*/
alphan(c)
char c;
{
if( alpha(c) )return(YES);
if( c<= '9' && c>= '0' )return(YES);
if( c == '$' )return(YES); /* allow imbedded $ */
if( c == '@' )return(YES); /* allow imbedded @, added ver TER_2.0
added to permit redefinable variables */
return(NO);
}
 
/*
* white --- is character whitespace?
*/
white(c)
char c;
{
if( c == TAB || c == BLANK || c == '\n' )return(YES);
return(NO);
}
 
/*
* alloc --- allocate memory
*/
char *
alloc(nbytes)
int nbytes;
{
char *malloc();
 
return(malloc(nbytes));
}
 
/*
* FNameGet --- Find a file name <file> or "file" in the Operand string
added ver TER_2.0 6/17/89
note: this routine will return a file name with white
space if between delimeters. This is permitted in
AmigaDOS. Other DOS may hiccup or just use name up to white space
*/
 
int
FNameGet(NameString)
char *NameString; /* pointer to output string */
{
char *frompoint; /* pointers to input string, don't bash Operand */
char *topoint; /* pointer to output string, don't bash NameString */
 
frompoint=Operand; /* include file name is in parsed string Operand */
topoint=NameString; /* copy of pointer to increment in copying */
if (*frompoint != '<' && *frompoint != '"') return(0); /* bad syntax */
frompoint++; /* skip < or " */
 
while (*frompoint != '>' && *frompoint != '"') /* look for delimeter */
{
if (*frompoint == EOS) return(0); /* missing delimeter */
*topoint++ = *frompoint++; /* copy path & file name for DOS */
}
 
*topoint=EOS; /* terminate file name */
#ifdef DEBUG2
printf("FNameGet: file name=%s\n",NameString);
#endif
return(1); /* proper syntax anyway */
}
 
/*
* --- strsave() find a place to save a string & return pointer to it
added ver TER_2.0 6/18/89 function taken from
Kernighan & Ritchie 78
*/
char *strsave(s)
char *s;
{
char *p;
 
if ((p = alloc(strlen(s)+1)) != NULL)
strcpy(p,s);
return(p);
}
 
/*
* pouterror() ---- print out standard error header
added rel TER_2.0 6/18/89
*/
 
void pouterror()
{
printf("%s, line no. ",Argv[Cfn]); /* current file name */
printf("%d: ",Line_num); /* current line number */
/* NOTE: THERE IS NO \n ! Calling procedure supplies suffixing
error message and \n. viz. file pseudo.c procedure do_pseudo
in case INCLUDE. Note also that error count is incremented. */
Err_count++;
Page_lines++; /* increment lines per page */
}
 
/*
* New Page() --- form feed a new page, print heading & inc page number
Moved here from do_pseudo (pseudo.c) in ver (TER) 2.02
19 Jun 89 so that can call from print_line() as well
for p50 option.
*/
 
void NewPage()
{
Page_lines = 0; /* ver TER_2.08 so that OPT PAGE works */
printf ("\n\f\n");
printf ("%-10s",Argv[Cfn]);
printf (" ");
printf (" ");
printf ("page %3d\n",Page_num++);
}
 
 
/*
* LastChar() ----- return a pointer to the last character in a string
Exception: will return garbage if NULL string
*/
 
char *LastChar(strpt)
char *strpt; /* pointer to string to be examined */
{
char *c;
 
c=strpt; /* don't zap original */
while (*c != EOS) /* search for end */
c++;
return(--c); /* back up one to last character */
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.