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

Subversion Repositories System09

[/] [System09/] [trunk/] [Tools/] [as09/] [do09.c] - Rev 134

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 *      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(int opcode,int 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);
}
 
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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