#include #include #include /* For maximum efficiency compile as: gcc umc.c -o umc -O2 -DNOCHECKS for macs it is necessary to define the uint type: gcc umc.c -o umc -O2 -DNOCHECKS -DNEEDUINT */ #ifdef NEEDUINT typedef unsigned int uint; #endif void error(char *s) { printf("%s\n",s); exit(1); } // We assume that an uint is an unsigned integer of 32 bits typedef struct platterarray { int sig; // a marker of a platter array int len; // length of buffer in uint's uint * buffer; } PlatterArray; // Creates a platter array // receives the size in platter numbers PlatterArray * mkPlatterArray(int size) { PlatterArray *x; x = (PlatterArray*)malloc(sizeof(PlatterArray)); x->len = size; x->sig = 0xabcd; x->buffer = (uint*)malloc(size*4); memset(x->buffer,0,size*4); return x; } inline void chkPlatterArray(PlatterArray *parray,uint offset) { #ifndef NOCHECKS if(parray->sig!=0xabcd) { error("chkPlatterArray, access to invalid Platter Array"); } else if (offset>=parray->len) { error("chkPlatterArray, out of bounds access to Platter Array"); } #endif } void destroyPlatterArray(PlatterArray *parray) { #ifndef NOCHECKS if(parray->sig!=0xabcd) { error("destroyPlatterArray, access to invalid Platter Array"); } #endif free(parray->buffer); free(parray); } inline uint readPlatterArray(PlatterArray *parray,uint offset) { chkPlatterArray(parray,offset); return parray->buffer[offset]; } inline void writePlatterArray(PlatterArray *parray,uint offset,uint val) { chkPlatterArray(parray,offset); parray->buffer[offset]=val; } // Global machine state PlatterArray * programPtr; uint registers[8]; uint finger; inline uint readReg(uint idx) { #ifndef NOCHECKS if (idx>7) error("readReg, argument out of range"); #endif return registers[idx]; } inline void writeReg(uint idx,uint val) { #ifndef NOCHECKS if (idx>7) error("setReg, argument out of range"); #endif registers[idx]=val; } /* Swap the bytes of a buffer for endianness insensitivity, if needed */ void swapArray(unsigned int *p,int len) { // test if we need to fix endianness uint x = 1; unsigned char *c = (unsigned char *)&x; if(*c==0) return; // endianness matches that of the codex // otherwise we must correct it unsigned int *q = p + len; while(p> (8*1)) | ((*p & 0xff000000) >> (8*3)); p++; } } void readCodex(char *s) { FILE * h; int size; h = fopen(s,"rb"); // open binary file for reading if(h==NULL) error("Non existing file argument"); fseek(h,0,SEEK_END); size = ftell(h); fseek(h,0,SEEK_SET); programPtr = mkPlatterArray(size/4); fread(programPtr->buffer,size,1,h); // warning, no error checking swapArray(programPtr->buffer,size/4); fclose(h); } void load(char *s) { readCodex(s); } // State for the execution of the machine uint op; uint ra; uint rb; uint rc; uint val; void pregs(void) { int i; printf(" "); for(i=0;i<8;i++) { printf(":%d",registers[i]); } printf(" \n"); } inline void fetchOperator() { uint word; word = readPlatterArray(programPtr,finger); op = word >> 28; if(op<13) { ra = (word >> 6) & 7; rb = (word >> 3) & 7; rc = (word >> 0) & 7; } else { ra = (word >> 25) & 7; val = word & 0x1ffffff; } //printf("Op %d (%d,%d,%d) %d\n",op,ra,rb,rc,val); //pregs(); } inline void advanceFinger() { finger++; } inline void output(uint c) { #ifndef NOCHECKS if(c>255) error ("output, can't output a non-character"); #endif putchar(c); } inline uint mkPlatterArrayH(int size) { return (uint)mkPlatterArray(size); } inline PlatterArray * findPlatterArray(uint val) { if(val==0) return programPtr; else return (PlatterArray*)val; } /* PlatterArray * platterArrays[10000000]; uint fresh; // Not even bounds checking!! uint mkPlatterArrayH(int size) { platterArrays[++fresh] = mkPlatterArray(size); return fresh; } PlatterArray * findPlatterArray(uint val) { if(val==0) return programPtr; else return platterArrays[val]; } */ inline void loadProgram(uint pa,uint offset) { PlatterArray *orig; finger = offset; if(pa!=0) { destroyPlatterArray(programPtr); orig = findPlatterArray(pa); programPtr = mkPlatterArray(orig->len); memcpy(programPtr->buffer,orig->buffer,orig->len*4); } } void spin() { int running = 1; while(running) { fetchOperator(); advanceFinger(); switch(op) { case 0: // conditional move if(readReg(rc)!=0) // only move is reg c is non-zero { writeReg(ra,readReg(rb)); } break; case 1: // read array writeReg(ra,readPlatterArray(findPlatterArray(readReg(rb)),readReg(rc))); break; case 2: // write array writePlatterArray(findPlatterArray(readReg(ra)),readReg(rb),readReg(rc)); break; case 3: // addition writeReg(ra,readReg(rb)+readReg(rc)); break; case 4: // product writeReg(ra,readReg(rb)*readReg(rc)); break; case 5: // division writeReg(ra,readReg(rb)/readReg(rc)); break; case 6: // not-and writeReg(ra,~(readReg(rb) & readReg(rc))); break; case 7: // halt running = 0; break; case 8: // allocation writeReg(rb,mkPlatterArrayH(readReg(rc))); break; case 9: // de-allocation destroyPlatterArray(findPlatterArray(readReg(rc))); break; case 10: // output output(readReg(rc)); break; case 11: // input writeReg(rc,getchar()); break; case 12: loadProgram(readReg(rb),readReg(rc)); break; case 13: writeReg(ra,val); break; default: error("spin, undefined operator"); } } } int main(int argc,char ** argv) { if(argc == 2) { load(argv[1]); // Disable buffering setvbuf(stdout, 0, _IONBF , 0); spin(); } else { printf("Usage: umc \n"); } return 0; }