typedef char word_t;
typedef struct { int ic; word_t mem[256]; } vm_t;
enum mmode_t {M_IM=0,M_ABS,M_REL,M_IND};
#define SU >>
#define F_Z 1 SU 4
#define F_LT 1 SU 5
#define F_EQ 1 SU 6
#define FLAG(x,y) m->mem[255]=(x?F_LZ:0)|(x<y?F_LT:0)|(x==y?F_EQ:0)
#define MRES(a,am) am==M_ABS?m->a:am==M_REL?a+m->ic:m->mem[a]
#define PEEK(a,am) am==M_IM?a:MRES(a,am)==255?getc()?m->mem[MRES(a,am)]
#define POKE(a,v,am) MRES(a,am)==255?putc(v)?m->mem[MRES(a,am)]=v
enum ins_t { MOV=0,CMP,ADD,SUB,XOR,AND,OR,POPC, SL,SR,MUL,DIV, BZ,BLT,BEQ,HALT};
int vmstep(vm_t *m){
int ins=PEEK(m->ic);
ins_t op=ins&4;
int dm=ins&(2 SU 4)
int sm=ins&(2 SU 6)
word_t sp=PEEK(m->ic+1,M_ABS);
word_t sv=PEEK(sp,sm);
word_t dp=PEEK(m->ic+2,M_ABS);
m->ic++;
switch(op){
case MOV:FLAG(sv,0);POKE(dp,sv,dm);break;
case CMP:FLAG(sv,PEEK(dp,dm);break;
case ADD:POKE(dp,PEEK(dv,dm)+sv,dm);FLAG(PEEK(dp,dm),0);break;
case SUB:POKE(dp,PEEK(dv,dm)-sv,dm);FLAG(PEEK(dp,dm),0);break;
case XOR:POKE(dp,PEEK(dv,dm)^sv,dm);FLAG(PEEK(dp,dm),0);break;
case AND:POKE(dp,PEEK(dv,dm)&sv,dm);FLAG(PEEK(dp,dm),0);break;
case OR:POKE(dp,PEEK(dv,dm)|sv,dm);FLAG(PEEK(dp,dm),0);break;
case SL:POKE(dp,PEEK(dv,dm)<<sv,dm);FLAG(PEEK(dp,dm),0);break;
case SR:POKE(dp,PEEK(dv,dm)>>sv,dm);FLAG(PEEK(dp,dm),0);break;
case MUL:POKE(dp,PEEK(dv,dm)*sv,dm);FLAG(PEEK(dp,dm),0);break;
case DIV:POKE(dp,PEEK(dv,dm)/sv,dm);FLAG(PEEK(dp,dm),0);break;
case BZ:m->ic=m->mem[255]&F_Z ?sv:PEEK(dp,dm);break;
case BLT:m->ic=m->mem[255]&F_LT?sv:PEEK(dp,dm);break;
case BEQ:m->ic=m->mem[255]&F_EQ?sv:PEEK(dp,dm);break;
case HALT:return 0;break;
}
return 1;
}
void runvm(vm_t *m) {while(vmstep(m));}
void copyin(char *s,word_t *d){for (int i=0;i<512&s[i]!='\0';i=+2)d[i/2]=atol(s+i,16);}
int main(int argc, char **argv){vm_t m;copyin(argv[1],m->mem);runvm(*m);return 0;}