/* ex.c */ #include "as.h" #include "ex.h" #include #include #include page *memory[1024]; int stackpointer, framepointer, programcounter; int error_code, error_value, location_counter, clear_space; int trace, single_step; union { int i; float f; struct { byte ba,bb,bc,bd; } s; } converter; void control_c_catcher(void) { trace=1; single_step=1; } void error(void) { fprintf(stderr,"\nPC+%d: error signalled.\n", programcounter); switch (error_code) { case ER_address_range: fprintf(stderr, "---- Address %d out of range (0-%d)\n", error_value, 1024*1024-1); break; case ER_memory_access: fprintf(stderr, "---- Read from unallocated memory address %d\n", error_value); break; case ER_divide_zero: fprintf(stderr, "---- Division by zero\n"); break; case ER_halt: fprintf(stderr, "---- Executed STOP instruction\n"); break; case ER_illegal_opcode: fprintf(stderr, "---- Instruction with illegal opcode %d\n", error_value); break; case ER_bad_io: fprintf(stderr, "---- Invalid i/o code %d\n", error_value); break; default: fprintf(stderr, "---- Unknown signal %d detail %d\n", error_code, error_value); break; } } void init_cpu(void) { int i; for (i=0; i<1024; i+=1) memory[i]=NULL; stackpointer=512*1024; framepointer=stackpointer; programcounter=0; single_step=0; trace=0; error_code=0; } void store_byte(int address, int value) { int pagenum=address>>10; int offset=address&1023; if (pagenum<0 || pagenum>1023) { error_code=ER_address_range; error_value=address; error(); return; } if (memory[pagenum]==NULL) memory[pagenum]=malloc(sizeof(page)); (*memory[pagenum])[offset]=value; } void store_int(int address, int value) { converter.i=value; store_byte(address,converter.s.ba); store_byte(address+1,converter.s.bb); store_byte(address+2,converter.s.bc); store_byte(address+3,converter.s.bd); } void store_float(int address, float value) { converter.f=value; store_byte(address,converter.s.ba); store_byte(address+1,converter.s.bb); store_byte(address+2,converter.s.bc); store_byte(address+3,converter.s.bd); } int read_byte(int address) { int pagenum=address>>10; int offset=address&1023; if (pagenum<0 || pagenum>1023) { error_code=ER_address_range; error_value=address; error(); return; } if (memory[pagenum]==NULL) { error_code=ER_memory_access; error_value=address; error(); return; } return ((*memory[pagenum])[offset]); } int read_int(int address) { converter.s.ba=read_byte(address); converter.s.bb=read_byte(address+1); converter.s.bc=read_byte(address+2); converter.s.bd=read_byte(address+3); return (converter.i); } float read_float(int address) { converter.s.ba=read_byte(address); converter.s.bb=read_byte(address+1); converter.s.bc=read_byte(address+2); converter.s.bd=read_byte(address+3); return (converter.f); } int pop(void) { stackpointer-=4; return (read_int(stackpointer)); } float popf(void) { stackpointer-=4; return (read_float(stackpointer)); } int tos(void) { return (read_int(stackpointer-4)); } int tosf(void) { return (read_float(stackpointer-4)); } int push(int v) { store_int(stackpointer,v); stackpointer+=4; } int pushf(float v) { store_float(stackpointer,v); stackpointer+=4; } void loadprog(char *name) { int olc; FILE *fin=fopen(name,"r"); if (fin==NULL) { fprintf(stderr,"Can't open \"%s\"\n", name); exit(1); } converter.s.ba=fgetc(fin); converter.s.bb=fgetc(fin); converter.s.bc=fgetc(fin); converter.s.bd=fgetc(fin); programcounter=converter.i; converter.s.ba=fgetc(fin); converter.s.bb=fgetc(fin); converter.s.bc=fgetc(fin); converter.s.bd=fgetc(fin); location_counter=converter.i; olc=location_counter; while (1) { int b; b=fgetc(fin); if (b==EOF) break; store_byte(location_counter,b); location_counter+=1; } fclose(fin); clear_space=(location_counter+1023)&~1023; stackpointer=clear_space; framepointer=clear_space; } void print_opcode(int opc) { switch (opc) { case BADP : printf("BADP "); break; case LOAD : printf("LOAD "); break; case STOR : printf("STOR "); break; case LOADN : printf("LOADN "); break; case LOADF : printf("LOADF "); break; case POP : printf("POP "); break; case STI : printf("STI "); break; case LDI : printf("LDI "); break; case DUP : printf("DUP "); break; case ADD : printf("ADD "); break; case ADDF : printf("ADDF "); break; case SUB : printf("SUB "); break; case SUBF : printf("SUBF "); break; case MUL : printf("MUL "); break; case MULF : printf("MULF "); break; case DIV : printf("DIV "); break; case DIVF : printf("DIVF "); break; case MOD : printf("MOD "); break; case FLOAT : printf("FLOAT "); break; case FIX : printf("FIX "); break; case NOT : printf("NOT "); break; case AND : printf("AND "); break; case OR : printf("OR "); break; case EQL : printf("EQL "); break; case EQLF : printf("EQLF "); break; case NEQ : printf("NEQ "); break; case NEQF : printf("NEQF "); break; case LSS : printf("LSS "); break; case LSSF : printf("LSSF "); break; case GTR : printf("GTR "); break; case GTRF : printf("GTRF "); break; case LEQ : printf("LEQ "); break; case LEQF : printf("LEQF "); break; case GEQ : printf("GEQ "); break; case GEQF : printf("GEQF "); break; case INCSP : printf("INCSP "); break; case DECSP : printf("DECSP "); break; case INCFP : printf("INCFP "); break; case DECFP : printf("DECFP "); break; case JUMP : printf("JUMP "); break; case PJZ : printf("PJZ "); break; case POPJMP : printf("POPJMP"); break; case POPFP : printf("POPFP "); break; case LDFP : printf("LDFP "); break; case INIT : printf("INIT "); break; case STOP : printf("STOP "); break; case BADN : printf("BADN "); break; default: printf("#%03d ",opc); break; } } void print_fprelative(int offset, int final) { if (offset<0) printf(" FP%d =%d", offset, final); else printf(" FP+%d =%d", offset, final); } void print_operand(int final) { printf(" %d", final); } void print_floperand(int final) { converter.i=final; printf(" %f", converter.f); } void print_stack(void) { int adr,e=error_code; printf(" stack: "); if (stackpointer==clear_space) { printf("empty\n"); return; } for (adr=stackpointer; adr>stackpointer-20 && adr>=clear_space; adr-=4) { if (adr==stackpointer) printf("SP:"); if (adr==framepointer) printf("FP:"); if (adr==stackpointer) printf("0 "); else { int v=read_int(adr); if (v>10000000) printf("%d/%f ",v,read_float(adr)); else printf("%d ",v); } } printf("... \n"); error_code=e; } void exec_inst(void) { int a, b, opc, opd, opdval, oldpc; float fa, fb; char cmd[100]; oldpc=programcounter; b=read_byte(programcounter); if (error_code) return; programcounter+=1; opc=b&~OPERAND; opd=b&OPERAND; if (opd==0) { opdval=0; } else { opc|=OPERAND; opdval=read_int(programcounter); if (opd==FP_RELATIVE_OPERAND) { b=opdval; opdval+=framepointer; } if (error_code) { programcounter-=1; return; } programcounter+=4; } if (trace) { printf("--FP=%d SP=%d\n", framepointer, stackpointer); print_stack(); printf(" PC=%d: ",oldpc); print_opcode(opc); if (opd==FP_RELATIVE_OPERAND) print_fprelative(b,opdval); else if (opd!=0) if (opc==LOADF) print_floperand(opdval); else print_operand(opdval); } if (single_step) { while (1) { printf("\n : "); fgets(cmd,20,stdin); if (cmd[0]=='\n') break; if (cmd[0]=='x' || cmd[0]=='X') exit(1); if (cmd[0]=='t' || cmd[0]=='T') { single_step=0; trace=1; break; } if (cmd[0]=='g' || cmd[0]=='G') { single_step=0; trace=0; break; } if (cmd[0]=='r' || cmd[0]=='R') { int locn, conts, ec; float contf; ec=error_code; locn=atoi(cmd+1); conts=read_int(locn); contf=read_float(locn); printf("%d: %d or %f\n", locn, conts, contf); error_code=ec; } } } switch (opc) { case BADP : error_code=ER_illegal_opcode; error_value=opc; error(); return; case LOAD : push(read_int(opdval)); break; case STOR : store_int(opdval,tos()); break; case LOADN : push(opdval); break; case LOADF : push(opdval); break; case POP : pop(); break; case STI : b=pop(); a=pop(); store_int(a,b); push(b); break; case LDI : a=pop(); b=read_int(a); push(b); break; case DUP : a=tos(); push(a); break; case ADD : b=pop(); a=pop(); push(a+b); break; case ADDF : fb=popf(); fa=popf(); pushf(fa+fb); break; case SUB : b=pop(); a=pop(); push(a-b); break; case SUBF : fb=popf(); fa=popf(); pushf(fa-fb); break; case MUL : b=pop(); a=pop(); push(a*b); break; case MULF : fb=popf(); fa=popf(); pushf(fa*fb); break; case DIV : b=pop(); a=pop(); if (b==0) { error_code=ER_divide_zero; error(); push(0); } else push(a/b); break; case DIVF : fb=popf(); fa=popf(); if (fb==0) { error_code=ER_divide_zero; error(); pushf(0.0); } else pushf(fa/fb); break; case MOD : b=pop(); a=pop(); if (b==0) { error_code=ER_divide_zero; error(); push(0); } else push(a%b); break; case FLOAT : a=pop(); pushf((float)a); break; case FIX : fa=popf(); push((int)fa); break; case NOT : a=pop(); if (a==0) push(1); else push(0); break; case AND : b=pop(); a=pop(); if (a==0 || b==0) push(0); else push(1); break; case OR : b=pop(); a=pop(); if (a==1 || b==1) push(1); else push(0); break; case EQL : b=pop(); a=pop(); if (a==b) push(1); else push(0); break; case EQLF : fb=popf(); fa=popf(); if (fa==fb) push(1); else push(0); break; case NEQ : b=pop(); a=pop(); if (a!=b) push(1); else push(0); break; case NEQF : fb=popf(); fa=popf(); if (fa!=fb) push(1); else push(0); break; case LSS : b=pop(); a=pop(); if (ab) push(1); else push(0); break; case GTRF : fb=popf(); fa=popf(); if (fa>fb) push(1); else push(0); break; case LEQ : b=pop(); a=pop(); if (a<=b) push(1); else push(0); break; case LEQF : fb=popf(); fa=popf(); if (fa<=fb) push(1); else push(0); break; case GEQ : b=pop(); a=pop(); if (a>=b) push(1); else push(0); break; case GEQF : fb=popf(); fa=popf(); if (fa>=fb) push(1); else push(0); break; case INCSP : stackpointer+=opdval; break; case DECSP : stackpointer-=opdval; break; case INCFP : framepointer+=opdval; break; case DECFP : framepointer-=opdval; break; case JUMP : programcounter=opdval; break; case PJZ : a=pop(); if (a==0) programcounter=opdval; break; case POPJMP : b=programcounter; programcounter=pop(); if (programcounter<100) { switch (programcounter) { case 1: a=pop(); if (trace || single_step) printf("\nOUTPUT: %d\n",a); else printf("%d ",a); break; case 2: fa=popf(); if (trace || single_step) printf("\nOUTPUT: %f\n",fa); else printf("%f ",fa); break; case 3: a=pop(); if (trace || single_step) printf("\nOUTPUT: \""); while (1) { b=read_byte(a); if (b==0) break; printf("%c",b); a+=1; } if (trace || single_step) printf("\"\n"); break; case 4: if (trace || single_step) printf("\nINPUT(%%d): "); fgets(cmd,20,stdin); sscanf(cmd,"%d",&a); store_int(256,a); break; case 5: if (trace || single_step) printf("\nINPUT(%%f): "); fgets(cmd,20,stdin); sscanf(cmd,"%f",&fa); store_float(256,fa); break; default: error_code=ER_bad_io; error_value=programcounter; programcounter=pop(); error(); return; } programcounter=pop(); } break; case POPFP : framepointer=pop(); break; case LDFP : push(framepointer); break; case INIT : framepointer=clear_space; stackpointer=clear_space; break; case STOP : error_code=ER_halt; programcounter-=1; return; case BADN : error_code=ER_illegal_opcode; error_value=opc; error(); return; default: error_code=ER_illegal_opcode; error_value=opc; error(); return; } if (error_code) error(); } void main(int argc, char *argv[]) { char *name; int i; signal(SIGINT,(void *)control_c_catcher); name="a.exe"; init_cpu(); for (i=1; i