Beispiel #1
0
void cpu_execute(struct cpu* cpu) {
  cpu->pc += 2;
  uint8_t vx = cpu->v[cpu->opcode.x];
  uint8_t vy = cpu->v[cpu->opcode.y];
  switch (cpu->opcode.op) {
    case 0x0:
      switch (cpu->opcode.n) {
        case 0x0: return cpu_clear(cpu);
        case 0xE: return cpu_jump(cpu, cpu->stack[--cpu->sp]);
        default:  return cpu_error(cpu);
      }
    case 0x1: return cpu_jump(cpu, cpu->opcode.addr);
    case 0x2: return cpu_call(cpu, cpu->opcode.addr);
    case 0x3: return cpu_skip(cpu, vx == cpu->opcode.kk);
    case 0x4: return cpu_skip(cpu, vx != cpu->opcode.kk);
    case 0x5: return cpu_skip(cpu, vx == vy);
    case 0x6: return cpu_assign_register(cpu, cpu->opcode.x, cpu->opcode.kk);
    case 0x7: return cpu_assign_register(cpu, cpu->opcode.x, vx + cpu->opcode.kk);
    case 0x8:
      switch (cpu->opcode.n) {
        case 0x0: return cpu_assign_register(cpu, cpu->opcode.x, vy);
        case 0x1: return cpu_assign_register(cpu, cpu->opcode.x, vx | vy);
        case 0x2: return cpu_assign_register(cpu, cpu->opcode.x, vx & vy);
        case 0x3: return cpu_assign_register(cpu, cpu->opcode.x, vx ^ vy);
        case 0x4: return cpu_add_carry(cpu, vx, vy);
        case 0x5: return cpu_subtract_borrow(cpu, vx, vy);
        case 0x6: return cpu_shift_right(cpu);
        case 0x7: return cpu_subtract_borrow(cpu, vy, vx);
        case 0xE: return cpu_shift_left(cpu);
        default:  return cpu_error(cpu);
      }
    case 0x9: return cpu_skip(cpu, vx != vy);
    case 0xA: return cpu_assign_i(cpu, cpu->opcode.addr);
    case 0xB: return cpu_jump(cpu, cpu->opcode.addr + cpu->v[0]);
    case 0xC: return cpu_random(cpu);
    case 0xD: return cpu_draw(cpu);
    case 0xE:
      switch (cpu->opcode.kk) {
        case 0x9E: return cpu_skip(cpu, SDL_GetKeyboardState(NULL)[key_map[vx]]);
        case 0xA1: return cpu_skip(cpu, !SDL_GetKeyboardState(NULL)[key_map[vx]]);
        default:   return cpu_error(cpu);
      }
    case 0xF:
      switch (cpu->opcode.kk) {
        case 0x07: return cpu_assign_register(cpu, cpu->opcode.x, cpu->delay_timer);
        case 0x0A: return cpu_wait_key_press(cpu);
        case 0x15: return cpu_assign_delay_timer(cpu, vx);
        case 0x18: return cpu_assign_sound_timer(cpu, vx);
        case 0x1E: return cpu_assign_i(cpu, cpu->i + vx);
        case 0x29: return cpu_assign_i(cpu, vx * 5);
        case 0x33: return cpu_store_bcd(cpu);
        case 0x55: return cpu_copy_to_memory(cpu);
        case 0x65: return cpu_copy_from_memory(cpu);
        default:   return cpu_error(cpu);
      }
    }
  return cpu_error(cpu);
}
Beispiel #2
0
Datei: cpu.c Projekt: ezrec/vasm
/* Does not do much useful parsing yet. */
int parse_operand(char *p,int len,operand *op,int requires)
{
  p=skip(p);
  if(len==2&&(p[0]=='r'||p[0]=='R')&&p[1]>='0'&&p[1]<='3'){
    op->type=OP_REG;
    op->basereg=p[1]-'0';
  }else if(p[0]=='#'){
    op->type=OP_IMM32;
    p=skip(p+1);
    op->offset=parse_expr(&p);
  }else{
    int parent=0;
    expr *tree;
    op->type=-1;
    if(*p=='('){
      parent=1;
      p=skip(p+1);
    }
    tree=parse_expr(&p);
    if(!tree)
      return 0;
    p=skip(p);
    if(parent){
      if(*p==','){
	p=skip(p+1);
	if((*p!='r'&&*p!='R')||p[1]<'0'||p[1]>'3'){
	  cpu_error(0);
	  return 0;
	}
	op->type=OP_REGIND;
	op->basereg=p[1]-'0';
	p=skip(p+2);
      }
      if(*p!=')'){
	cpu_error(0);
	return 0;
      }else
	p=skip(p+1);
    }
    if(op->type!=OP_REGIND)
      op->type=OP_ABS;
    op->offset=tree;
  }
  if(requires==op->type)
    return 1;
  if(requires==OP_ALL_DEST&&op->type!=OP_IMM32)
    return 1;
  if(requires==OP_MEM&&OP_ISMEM(op->type))
    return 1;
  if(requires==OP_ALL)
    return 1;
  return 0;
}
Beispiel #3
0
Datei: cpu.c Projekt: kusma/vasm
static taddr absval(expr *tree,section *sec,taddr pc,int bits,int sgn)
{
  taddr val;
  if(!eval_expr(tree,&val,sec,pc))
    cpu_error(0);
  if(!sgn){
    if(val<0||val>=(1<<bits))
      cpu_error(1,bits);
  }else{
    if(val<-(1<<(bits-1))||val>=(1<<(bits-1)))
      cpu_error(1,bits);
  }
  return val&((1<<bits)-1);
}
Beispiel #4
0
Datei: cpu.c Projekt: kusma/vasm
static taddr dooffset(int rel,expr *tree,section *sec,taddr pc,rlist **relocs,int roffset,int size,taddr mask)
{
  taddr val;
  if(!eval_expr(tree,&val,sec,pc)){
    taddr addend=val;
    symbol *base;
    if(find_base(tree,&base,sec,pc)!=BASE_OK){
      general_error(38);
      return val;
    }
    if(rel==REL_PC){
      val-=pc;
      addend+=roffset/8;
    }
    if(rel!=REL_PC||!LOCREF(base)||base->sec!=sec){
      add_nreloc_masked(relocs,base,addend,rel,size,roffset,mask);
      return 0;
    }
  }
#if 0
  if(val<-(1<<(size-1))||val>((1<<(size-1))-1))
    cpu_error(1,size);
#endif
  return val&mask;
}
Beispiel #5
0
Datei: cpu.c Projekt: ezrec/vasm
static char *fill_operand(operand *p,section *sec,taddr pc,char *d,rlist **relocs,int roffset)
{
  taddr val;
  if(!p||p->type==OP_REG)
    return d;
  /* FIXME: Test for valid operand, create reloc */
  if(!eval_expr(p->offset,&val,sec,pc)){
    nreloc *reloc=new_nreloc();
    rlist *rl=mymalloc(sizeof(*rl));
    rl->type=REL_ABS;
    reloc->offset=roffset*8;
    reloc->size=16;
    reloc->sym=find_base(p->offset,sec,pc);
    if(!reloc->sym){
      cpu_error(2);
    }else{
      rl->reloc=reloc;
      rl->next=*relocs;
      *relocs=rl;
    }
  }
  *d++=val>>24;
  *d++=val>>16;
  *d++=val>>8;
  *d++=val;
  return d;
}
Beispiel #6
0
Datei: cpu.c Projekt: ezrec/vasm
/* Convert an instruction into a DATA atom including relocations,
   if necessary. */
dblock *eval_instruction(instruction *p,section *sec,taddr pc)
{
  /* Auch simpel. Fehlerchecks fehlen. */
  taddr size=instruction_size(p,sec,pc);
  dblock *db=new_dblock();
  int c=opt_inst(p,sec,pc);
  char *d;
  taddr val;
  db->size=size;
  d=db->data=mymalloc(size);
  *d=c;
  if(p->qualifiers[0]){
    if(c>5)
      cpu_error(1,p->qualifiers[0]);
    else if(!strcmp(p->qualifiers[0],"b"))
      *d|=128;
    else if(strcmp(p->qualifiers[0],"w"))
      cpu_error(1,p->qualifiers[0]);
  }
  d++;
  if(c==5){
    /* addq */
    taddr val;
    if(!eval_expr(p->op[0]->offset,&val,sec,pc)||val>15)
      cpu_error(0);
    *d=((val<<4)|operand_code(p->op[1]));
    return db;
  }
  if(c==7){
    expr *tree=p->op[0]->offset;
    if(!(tree->type==SYM&&tree->c.sym->sec==sec&&tree->c.sym->type==LABSYM&&
	 tree->c.sym->pc-pc>=-128&&tree->c.sym->pc-pc<=127))
      cpu_error(0);
    else
      *d=tree->c.sym->pc-pc;
    return db;
  }

  *d=((operand_code(p->op[0])<<4)|operand_code(p->op[1]));
  d++;
  d=fill_operand(p->op[0],sec,pc,d,&db->relocs,d-db->data);
  d=fill_operand(p->op[1],sec,pc,d,&db->relocs,d-db->data);
  return db;
}
Beispiel #7
0
Datei: cpu.c Projekt: kusma/vasm
static int chkval(expr *tree,section *sec,taddr pc,int bits,int sgn)
{
  taddr val;
  if(!eval_expr(tree,&val,sec,pc))
    cpu_error(0);
  if(!sgn){
    if(val<0||val>=(1<<bits))
      return 0;
  }else{
    if(val<-(1<<(bits-1))||val>=(1<<(bits-1)))
      return 0;
  }
  return 1;
}
Beispiel #8
0
Datei: cpu.c Projekt: kusma/vasm
int parse_operand(char *p,int len,operand *op,int required)
{
  char *start = p;
  int indir = 0;

  p = skip(p);
  if (len>0 && required!=DATAOP && check_indir(p,start+len)) {
    indir = 1;
    p = skip(p+1);
  }

  switch (required) {
    case IMMED:
      if (*p++ != '#')
        return PO_NOMATCH;
      p = skip(p);
      break;
    case INDIR:
    case INDIRX:
    case INDX:
    case INDY:
    case DPINDIR:
      if (!indir)
        return PO_NOMATCH;
      break;
    default:
      if (indir)
        return PO_NOMATCH;
      break;
  }

  if (required < ACCU)
    op->value = parse_expr(&p);
  else
    op->value = NULL;

  switch (required) {
    case INDX:
    case INDIRX:
      if (*p++ == ',') {
        p = skip(p);
        if (toupper((unsigned char)*p++) != 'X')
          return PO_NOMATCH;
      }
      else
        return PO_NOMATCH;
      break;
    case ACCU:
      if (len != 0) {
        if (len!=1 || toupper((unsigned char)*p++) != 'A')
          return PO_NOMATCH;
      }
      break;
    case DUMX:
      if (toupper((unsigned char)*p++) != 'X')
        return PO_NOMATCH;
      break;
    case DUMY:
      if (toupper((unsigned char)*p++) != 'Y')
        return PO_NOMATCH;
      break;
  }

  if (required==INDIR || required==INDX || required==INDY
      || required==DPINDIR || required==INDIRX) {
    p = skip(p);
    if (*p++ != ')') {
      cpu_error(2);  /* missing closing parenthesis */
      return PO_CORRUPT;
    }
  }

  p = skip(p);
  if (p-start < len)
    cpu_error(1);  /* trailing garbage in operand */
  op->type = required;
  return PO_MATCH;
}
Beispiel #9
0
Datei: cpu.c Projekt: kusma/vasm
int parse_operand(char *p,int len,operand *op,int req)
{
  int r;
  char *s,*start=p;

  op->type=-1;
  p=skip(p);

  if(req>=OP_REG&&req<=OP_LR){
    int reg;
    s=skip_reg(p,&r);
    if(s!=p){
      if((req==OP_REG&&r<=31)||
	 (req==OP_SREG&&r<=15)||
	 (req==OP_PC&&r==31)||
	 (req==OP_LR&&r==26)||
	 (req==OP_MREG&&(r==0||r==6||r==16||r==24))){
	op->type=OP_REG;
	op->reg=r;
      }else
	return 0;
    }else
      return 0;
    p=skip(s);
  }else if(req==OP_MREG){
    int first;
    s=skip_reg(p,&r);
    if(s==p)
      return 0;
    if(r==0)
      op->dreg=0;
    else if(r==6)
      op->dreg=1;
    else if(r==16)
      op->dreg=2;
    else if(r==24)
      op->dreg=3;
    else
      return 0;
    s=skip(s);
    if(*s!='-')
      return 0;
    p=skip(s+1);
    first=r;
    s=skip_reg(p,&r);
    if(s==p) 
      return 0;
    p=skip(s);
    op->reg=(r-first)&31;
  }else if(req==OP_IND){
    p=skip(p);
    if(*p!='(') return 0;
    p=skip(p+1);
    s=skip_reg(p,&r);
    if(s==p) return 0;
    if(r>15) return 0;
    p=skip(s);
    op->reg=r;
    if(*p!=')') return 0;
    p=skip(p+1);
    op->type=OP_IND;
  }else if(req==OP_VIND){
    int nodisp=0;
    p=skip(p);
    if(*p=='('){
      char *m;
      m=s=skip(p+1);
      s=skip_reg(s,&r);
      if((m!=s)||(*s=='0')) nodisp=1;
    }
    if(!nodisp){
      op->offset=parse_expr(&p);
      if(!op->offset) return 0;
    }else
      op->offset=0;
    if(*p!='(') return 0;
    p=skip(p+1);
    s=skip_reg(p,&r);
    if (s==p){
      /* Special case: Allow '0' instead of a register */
      if (*p=='0'){
	p=skip(p+1);
	op->reg=15;
      }
      else return 0;
    }else{
      if(r>14) return 0;
      p=skip(s);
      op->reg=r;
    }
    op->dreg=15;
    if(*p=='+'&&p[1]=='='){
      p=skip(p+2);
      s=skip_reg(p,&r);
      if(s==p) return 0;
      if(r>14) return 0;
      p=skip(s);
      op->dreg=r;
    }
    if(*p!=')') return 0;
    p=skip(p+1);
    op->type=OP_IND;
  }else if(req==OP_PREDEC){
    p=skip(p);
    if(p[0]!='-'||p[1]!='-') return 0;
    p=skip(p+2);
    if(*p!='(') return 0;
    p=skip(p+1);
    s=skip_reg(p,&r);
    if(s==p) return 0;
    p=skip(s);
    if(*p!=')') return 0;
    p=skip(p+1);
    op->reg=r;
    op->type=OP_PREDEC;
  }else if(req==OP_POSTINC){
    p=skip(p);
    if(*p!='(') return 0;
    p=skip(p+1);
    s=skip_reg(p,&r);
    if(s==p) return 0;
    p=skip(s);
    if(*p!=')') return 0;
    p=skip(p+1);
    if(*p++!='+') return 0;
    if(*p!='+') return 0;
    p=skip(p+1);
    op->reg=r;
    op->type=OP_POSTINC;
  }else if(req==OP_REGIND){
    p=skip(p);
    if(*p!='(') return 0;
    p=skip(p+1);
    s=skip_reg(p,&op->reg);
    if(s==p) return 0;  
    p=skip(s);
    if(*p!=',') return 0;
    p=skip(p+1);
    s=skip_reg(p,&op->dreg);
    if(s==p) return 0;
    p=skip(s);
    if(*p!=')') return 0;
    op->type=OP_REGIND;
    p=skip(p+1);
  }else if(req==OP_IMMIND||
	   req==OP_IMMINDSP||
	   req==OP_IMMINDSD||
	   req==OP_IMMINDR0||
	   req==OP_IMMINDS||
	   req==OP_IMMINDPC){
    op->offset=0;
    if(*p=='('){
      char *p2;
      p2=skip(p+1);
      s=skip_reg(p2,&r);
      if(s!=p2){
	p=skip(s);
	if(*p==')'){
	  p=skip(p+1);
	  op->offset=number_expr(0);
	}
      }
    }
    if(!op->offset){
      op->offset=parse_expr(&p);
      if(!op->offset) return 0;
      p=skip(p);
      if(*p!='(') return 0;
      p=skip(p+1);
      s=skip_reg(p,&r);
      if(s==p) return 0;
      p=skip(s);
      if(*p!=')') return 0;
    }
    if(req==OP_IMMINDSP&&r!=25) return 0;
    if(req==OP_IMMINDPC&&r!=31) return 0;
    if(req==OP_IMMINDSD&&r!=24) return 0;
    if(req==OP_IMMINDR0&&r!=0) return 0;
    if(req==OP_IMMINDS&&r>15) return 0;
    op->reg=r;
    op->type=OP_IMMIND;
    p=skip(p+1);
  }else if(req>=OP_IMM4&&req<=OP_IMM32&&skip_reg(p,&r)==p){
    op->type=OP_IMM32;
    op->offset=parse_expr(&p);
    simplify_expr(op->offset);
    p=skip(p);
  }else if((req==OP_ABS||req==OP_REL)&&skip_reg(p,&r)==p){
    op->type=req;
    op->offset=parse_expr(&p);
    simplify_expr(op->offset);
    p=skip(p);
  }else if(req==OP_VREG||req==OP_VREGM||req==OP_VREGMM||req==OP_VREGA80){
    s=skip_reg(p,&r);
    op->offset=0;
    if(s!=p){
      if (*s=='+'||*s=='-'){
        if(req==OP_VREG) return 0;
        op->offset=parse_expr(&s);
      }
      p=skip(s);
      op->type=OP_VREG;
      if(req==OP_VREG){
	op->reg=(0xE<<6)|r;
	op->dreg=0x3c;
      }else{
	op->reg=(0xE<<6);
	op->dreg=r<<2;
      }
    }else if(*p=='-'){
      p=skip(p+1);
      op->type=OP_VREG;
      op->reg=(0xF<<6);
      op->dreg=0x3c;
    }else{
      int size,vert,x,y,inc=15<<2;
      expr *e;
      if(*p=='H'||*p=='h')
	vert=0;
      // Disable vertical registers in 48-bit instructions for now
      else if((req!=OP_VREG)&&(*p=='V'||*p=='v'))
	vert=1;
      else
	return 0;
      p=skip(p+1);
      if(*p=='X'||*p=='x'){
	size=2;
	p=skip(p+1);
      }else if(*p=='1'&&p[1]=='6'){
	size=2;
	p=skip(p+2);
      }else if(*p=='Y'||*p=='y'){
	size=4;
	p=skip(p+1);
      }else if(*p=='3'&&p[1]=='2'){
	size=4;
	p=skip(p+2);
      }else if(*p=='8'){
	size=1;
	p=skip(p+1);
      }else{
	size=1;
	p=skip(p);
      }
      if(*p!='(') return 0;
      p=skip(p+1);
      e=parse_expr(&p);
      if(e->type!=NUM) return 0;
      y=e->c.val;
      p=skip(p);
#if 1
      if(req!=OP_VREG&&*p=='+'){
	p++;
	if(*p!='+') return 0;
	if(vert) {
	  cpu_error(4);
	  return 0;
	}
	p=skip(p+1);
	inc|=2;
      }
#endif
      if(*p!=',') return 0;
      p=skip(p+1);
      if((*p=='c')||(*p=='C'))
      {
	p++;
	if (*p!='b'&&*p!='B') return 0;
	p++;
	if (*p!='+') return 0;
	inc|=1;
      }
      e=parse_expr(&p);
      if(e->type!=NUM) return 0;
      x=e->c.val;
      p=skip(p);
#if 1
      if(req!=OP_VREG&&*p=='+'){
	p++;
	if(*p!='+') return 0;
	if(!vert) {
	  cpu_error(4);
	  return 0;
	}
	p=skip(p+1);
	inc|=2;
      }
#endif
      if(*p!=')') return 0;
      p=skip(p+1);
      if(req!=OP_VREG&&*p=='*'){
	p=skip(p+1);
	inc|=1;
      }
      if(req!=OP_VREG&&*p=='+'){
	p=skip(p+1);
	s=skip_reg(p,&r);
	if(s==p) return 0;
	p=skip(s);
	inc&=~0x3c;
	inc|=(r<<2);
      }
      if(req==OP_VREGA80){
	if(size==1){
	  op->reg=(vert<<6)|((x&48)<<3);
	}else if(size==2){
	  if(x&16) return 0;
	  op->reg=(vert<<6)|(8<<6)|((x&32)<<2);
	}else{
	  if(x&48) return 0;
	  op->reg=(vert<<6)|(12<<6);
	}
	if(y<0||y>63) return 0;
	op->reg|=y&63;
	inc|=(x&15)<<6;
      }else{
	if(vert){
	  if(size==1){
	    op->reg=(1<<6)|((x&48)<<3);
	  }else if(size==2){
	    if(x&16) return 0;
	    op->reg=(9<<6)|((x&32)<<2);
	  }else{
	    if(x&48) return 0;
	    op->reg=13<<6;
	  }
	  if(y<0||y>63||(y&15)) return 0;
	  op->reg|=(y&48)|(x&15);
	}
	else{
	  if(size==1){
	    if(x&15) return 0;
	    op->reg=(x&48)<<3;
	  }else if(size==2){
	    if(x&31) return 0;
	    op->reg=(8<<6)|((x&32)<<2);
	  }else{
	    if(x) return 0;
	    op->reg=12<<6;
	  }
	if(y<0||y>63) return 0;
	op->reg|=y&63;
	}
      }
      op->dreg=inc;
      op->type=OP_VREG;
    }
  }else
    return 0;

  if(req==OP_VREGMM||req==OP_IMM32M||req==OP_VIND){
    int vecmod=0,i;
    while(1){
      if(!strncasecmp(p,"rep",3)&&isspace((unsigned char)p[3])){
	expr *e;
	taddr x;
	p=skip(p+3);
	if((*p=='r')&&(p[1]=='0')&&!isdigit(p[2])){
	  p=skip(p+2);
	  vecmod|=7<<16;
	  i=0;
	}else{
	  e=parse_expr(&p);
	  if(e->type!=NUM) return 0;
	  x=e->c.val;
	  for(i=0;i<8;i++){
	    if((1<<i)==x){
	      vecmod|=i<<16;
	      break;
	    }
	  }
	}
	if(i>=8) return 0;
	p=skip(p);
	continue;
      }
      for(i=0;i<sizeof(vflags)/sizeof(vflags[0]);i++){
	if((!strncasecmp(p,vflags[i],strlen(vflags[i])))&&
	   (!isalpha(p[strlen(vflags[i])]))){
	  if(vecmod&0x380) return 0;
	  vecmod|=i<<7;
	  p=skip(p+strlen(vflags[i]));
	  continue;
	}
      }
      for (i=0;i<sizeof(sru)/sizeof(sru[0]);i++){
	if(!strncasecmp(p,sru[i],strlen(sru[i]))){
	  p=skip(p+strlen(sru[i]));
	  p=skip_reg(p,&r);
	  if((r<0)||(r>7)) return 0;
	  vecmod|=(1<<6)|(i<<3)|r;
	  continue;
	}
      }
      for (i=0;i<sizeof(accs)/sizeof(accs[0]);i++){
	if((!strncasecmp(p,accs[i],strlen(accs[i])))&&
	   (!isalpha(p[strlen(accs[i])]))){
	  if(vecmod&0x40) return 0;
	  vecmod|=i;
	  p=skip(p+strlen(accs[i]));
	  continue;
	}
      }
      if(!strncasecmp(p,"ena",3)){
	if(vecmod&0x40) return 0;
	p=skip(p+3);
	vecmod|=32;
      }
      if(!strncasecmp(p,"setf",4)){
	p=skip(p+4);
	vecmod|=1<<20;
	continue;
      }
      break;
    }

    op->vecmod=vecmod;
  }

  if(p>=start+len)
    return 1;
  else
    return 0;
}
Beispiel #10
0
Datei: cpu.c Projekt: kusma/vasm
/* Convert an instruction into a DATA atom including relocations,
   if necessary. */
dblock *eval_instruction(instruction *p,section *sec,taddr pc)
{
  dblock *db=new_dblock();
  int c,sz,enc,cc,ww,m=0;
  unsigned long code,code2,code3;
  rlist *relocs=0;

  if(p->qualifiers[0]){
    int i;
    for(i=0;i<15;i++){
      if(!strcmp(p->qualifiers[0],ccs[i])){
	cc=i;
	break;
      }
    }
    if(i>15) ierror(0);
  }else
    cc=14;

  c=translate(p,sec,pc);
  enc=mnemonics[c].ext.encoding;

  db->size=sz=oplen(enc);
  db->data=mymalloc(db->size);

  code=mnemonics[c].ext.code;

  switch(enc){
  case EN_ARITHR16:
    if(cc!=14) cpu_error(3);
    code=0x40000000|(code<<24);
    code|=(p->op[0]->reg<<16)|(p->op[1]->reg<<20);
    break;
  case EN_ARITHI16:
    if(cc!=14) cpu_error(3);
    code=0x60000000|((code>>1)<<25);
    code|=(p->op[0]->reg<<16)|(absval(p->op[1]->offset,sec,pc,5,0)<<20);
    break;
  case EN_FIX16:
    if(cc!=14) cpu_error(3);
    break;
  case EN_IBRANCH16:
    if(cc!=14) cpu_error(3);
    code|=(p->op[0]->reg<<16);
    break;
  case EN_RBRANCH16:
    code=0x18000000;
    code|=cc<<23;
    code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,0,7,0xfe)>>1)&127)<<16;
    break;
  case EN_MREG16:
    if(cc!=14) cpu_error(3);
    code|=(p->op[0]->dreg<<21)|(p->op[0]->reg<<16);
    break;
  case EN_RBRANCH32:
    if(code==0x90000000)
      code|=cc<<24;
    else
      code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,8,4,0xF000000)>>24)&0xf)<<24;
    code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,16,16,0x1fffe)>>1)&0x7fffff);
    code|=((reloffset(p->op[0]->offset,sec,pc,&relocs,0,7,0xfe0000)>>17)&0x7f)<<16;
    break;
  case EN_FUNARY32:
    code=0xC0000040|(code<<21);
    code|=p->op[0]->reg<<16;
    code|=p->op[1]->reg<<11;
    code|=cc<<7;
    break;
  case EN_ARITHR32:
    code=0xC0000000|(code<<21);
    code|=p->op[0]->reg<<16;
    if(p->op[2]){
      code|=p->op[1]->reg<<11;
      code|=p->op[2]->reg;
    }else{
      code|=p->op[0]->reg<<11;
      code|=p->op[1]->reg;
    }      
    code|=cc<<7;
    break;
  case EN_ARITHI32:
    code=0xC0000040|(code<<21);
    code|=p->op[0]->reg<<16;
    if(p->op[2]){
      code|=p->op[1]->reg<<11;
      code|=absval(p->op[2]->offset,sec,pc,6,1);
    }else{
      code|=p->op[0]->reg<<11;
      code|=absval(p->op[1]->offset,sec,pc,6,1);
    }
    code|=cc<<7;
    break;
  case EN_ADDCMPB64:
    // Large offset: invert CC, place a long branch after
    // so we really generate the following:
    //   addcmpb<~cc> d, a, b, skip
    //   b <destination>
    // skip:
    //   <rest of code>
    m=1;
    if(cc&1) cc--; else cc++;
  case EN_ADDCMPB32:
    code=0x80000000|(code<<14);
    code|=cc<<24;
    code|=p->op[0]->reg<<16;
    if(code&0x4000){
      code|=absval(p->op[1]->offset,sec,pc,4,1)<<20;
    }else{
      code|=p->op[1]->reg<<20;
    }
    if(code&0x8000){
      code|=absval(p->op[2]->offset,sec,pc,6,0)<<8;
      if(m)
	code|=4;
      else
	code|=((reloffset(p->op[3]->offset,sec,pc,&relocs,16,9,0x1ff)>>1)&0xff);
    }else{