// npu simulator 24 Dec 2012 // Prabhas Chongstitvatana var M = [0]; // memory var RA = [0,0,0,0]; // registers 32 var RB = [0,0,0,0]; var RC = [0,0,0,0]; var RD = [0,0,0,0]; var LDS = [0,0,0,0]; // local data store NPE var PC, IR; var op, a1, a2, a3, runflag, lastpc; // ---------- graphics display using raphael.js ---------- // set up canvas with frame var paper = Raphael(10, 10, 340, 340); var frm = paper.rect(0,0,340,340); frm.attr("stroke","black"); // draw frame function pixplot(x,y){ var pix = paper.rect(x,y,5,5); pix.attr("stroke","#fff"); pix.attr("fill","blue"); } function println(m){ document.write(m + '
'); } // state of cursor to put pixel var oldj = 0; var xi = 0, yi = 0; function printdot(c){ if(c < 50) pixplot(xi,yi); xi += 5; } function plot(i,j,color){ if( RA[j] != oldj ){ oldj = RA[j]; yi += 5; xi = 0; } printdot(RA[color]); printdot(RB[color]); printdot(RC[color]); printdot(RD[color]); } // --------------- object code loader -------------- // object code var obj = [ // mandelbrot 64 x 64 16, 105, 0, 0, // Q fractional part 12 bits 12, 16, 0, 0, 16, 104, 0, 0, 12, 5, 0, 0, 16, 108, 0, 0, 12, 3, 0, 0, 16, 106, 0, 0, 12, 17, 0, 0, 10, 100, 0, 0, 10, 101, 1, 0, 10, 102, 2, 0, 10, 103, 3, 0, 12, 4, 0, 0, 25, 0, 0, 0, 25, 1, 1, 1, 16, 107, 0, 0, 12, 2, 0, 0, 12, 23, 0, 0, 20, 12, 0, 0, 21, 12, 12, 12, 20, 13, 1, 1, 21, 12, 13, 13, 18, 14, 12, 13, 26, 8, 14, 3, 30, 36, 8, 0, 19, 15, 12, 13, 18, 20, 15, 4, 20, 21, 0, 1, 21, 12, 21, 21, 18, 21, 21, 21, 18, 22, 21, 5, 33, 8, 0, 20, 33, 8, 1, 22, 33, 8, 23, 2, 22, -1, 2, 2, 31, 18, 2, 0, 34, 5, 0, 0, 22, 512, 4, 4, 22, -1, 17, 17, 31, 13, 17, 0, 22, -128, 5, 5, 22, -1, 16, 16, 31, 6, 16, 0, 34, 4, 0, 0, -1 ]; // data at 100 var data = [ 9, -6144, -6016, -5888, -5760, 4096, 64, 16, 256, 16384 ]; // encode instruction function enc4(op, a1, a2, a3){ a1 = (a1 << 10) & 0x00fffc00; return (op << 24)| a1 | (a2 << 5)| a3; } function loadobj(){ var k = 0; var i = 0; while( obj[k] > 0 ){ // op, a1, a2, a3 M[i] = enc4(obj[k],obj[k+1],obj[k+2],obj[k+3]); k += 4; i++; } lastpc = i; println('load '+ i + ' instructions'); k = data[0]; i = 0; while( i < k ){ M[100+i] = data[i+1]; i++; } } // --------- show internal state of npu ---------- // number of cycle per instruction var inst_cycle = [ 9,9,7,7,9,9,9,7,7,7, 7,7,7,7,7,7,7,7,7,6, 6,7,7,7,7,7,7,7,7 ]; // display instruction mnemonic var opsym = [ 'ld', 'st', 'ldr', 'str', 'ldx', 'stx', 'ldw', 'bc', 'add', 'sub', 'mul', 'ashr', 'addi', 'and', 'or', 'xor', 'lt','le','eq', 'jmp', 'jz', 'jnz', 'rnd', 'mvt', 'sys' ]; function showInst(){ println(PC+': '+opsym[op-10]+' '+signx(a1)+' '+a2+' '+a3); } // dump R[0,1,2,3], LDS[.] function dumpInternal(){ println('R[0] '+RA[0]+' '+RB[0]+' '+RC[0]+' '+RD[0]); println('R[1] '+RA[1]+' '+RB[1]+' '+RC[1]+' '+RD[1]); println('R[2] '+RA[2]+' '+RB[2]+' '+RC[2]+' '+RD[2]); println('R[3] '+RA[3]+' '+RB[3]+' '+RC[3]+' '+RD[3]); println('LDS '+LDS[0]+' '+LDS[1]+' '+LDS[2]+' '+LDS[3]); } // ------------- npu simulator ------------- // a is 14-bit, sign extended function signx(a){ if( a & 0x02000 ) return a | 0xffffc000; return a; } // instruction decode function opcode(){ return ((IR >> 24) & 0x0ff); } function ads(){ return ((IR >> 10) & 0x03fff); } function r1(){ return ((IR >> 5) & 0x01f); } function r2(){ return (IR & 0x01f); } // all R[k] are zero function testz(k){ if( RA[k] != 0 ) return 0; if( RB[k] != 0 ) return 0; if( RC[k] != 0 ) return 0; if( RD[k] != 0 ) return 0; return 1; } function execute(op){ var disp; switch(op){ case 10: LDS[a2] = M[a1]; break; // ld case 11: M[a1] = LDS[a2]; break; // st case 12: // ldr RA[a1] = LDS[0]; RB[a1] = LDS[1]; RC[a1] = LDS[2]; RD[a1] = LDS[3]; break; case 13: // str LDS[0] = RA[a1]; LDS[1] = RB[a1]; LDS[2] = RC[a1]; LDS[3] = RD[a1]; break; case 14: // ldx switch(a1){ case 0: LDS[0] = M[RA[a2]+RA[a3]]; break; case 1: LDS[1] = M[RB[a2]+RB[a3]]; break; case 2: LDS[2] = M[RC[a2]+RC[a3]]; break; case 3: LDS[3] = M[RD[a2]+RD[a3]]; break; } break; case 15: // stx switch(a1){ case 0: M[RA[a2]+RA[a3]] = LDS[0]; break; case 1: M[RB[a2]+RB[a3]] = LDS[1]; break; case 2: M[RC[a2]+RC[a3]] = LDS[2]; break; case 3: M[RD[a2]+RD[a3]] = LDS[3]; break; } break; case 16: // ldw LDS[0] = M[a1]; LDS[1] = M[a1]; LDS[2] = M[a1]; LDS[3] = M[a1]; break; case 17: // bc RA[a1] = LDS[a2]; RB[a1] = LDS[a2]; RC[a1] = LDS[a2]; RD[a1] = LDS[a2]; break; case 18: // add RA[a1] = RA[a2] + RA[a3]; RB[a1] = RB[a2] + RB[a3]; RC[a1] = RC[a2] + RC[a3]; RD[a1] = RD[a2] + RD[a3]; break; case 19: // sub RA[a1] = RA[a2] - RA[a3]; RB[a1] = RB[a2] - RB[a3]; RC[a1] = RC[a2] - RC[a3]; RD[a1] = RD[a2] - RD[a3]; break; case 20: // mul RA[a1] = RA[a2] * RA[a3]; RB[a1] = RB[a2] * RB[a3]; RC[a1] = RC[a2] * RC[a3]; RD[a1] = RD[a2] * RD[a3]; break; case 21: // ashr RA[a2] = RA[a3] >> a1; RB[a2] = RB[a3] >> a1; RC[a2] = RC[a3] >> a1; RD[a2] = RD[a3] >> a1; break; case 22: // addi disp = signx(a1); RA[a2] = RA[a3] + disp; RB[a2] = RB[a3] + disp; RC[a2] = RC[a3] + disp; RD[a2] = RD[a3] + disp; break; case 23: // and RA[a1] = RA[a2] & RA[a3]; RB[a1] = RB[a2] & RB[a3]; RC[a1] = RC[a2] & RC[a3]; RD[a1] = RD[a2] & RD[a3]; break; case 24: // or RA[a1] = RA[a2] | RA[a3]; RB[a1] = RB[a2] | RB[a3]; RC[a1] = RC[a2] | RC[a3]; RD[a1] = RD[a2] | RD[a3]; break; case 25: // xor RA[a1] = RA[a2] ^ RA[a3]; RB[a1] = RB[a2] ^ RB[a3]; RC[a1] = RC[a2] ^ RC[a3]; RD[a1] = RD[a2] ^ RD[a3]; break; case 26: // lt RA[a1] = RA[a2] < RA[a3]; RB[a1] = RB[a2] < RB[a3]; RC[a1] = RC[a2] < RC[a3]; RD[a1] = RD[a2] < RD[a3]; break; case 27: // le RA[a1] = RA[a2] <= RA[a3]; RB[a1] = RB[a2] <= RB[a3]; RC[a1] = RC[a2] <= RC[a3]; RD[a1] = RD[a2] <= RD[a3]; break; case 28: // eq RA[a1] = RA[a2] == RA[a3]; RB[a1] = RB[a2] == RB[a3]; RC[a1] = RC[a2] == RC[a3]; RD[a1] = RD[a2] == RD[a3]; break; case 29: PC = a1; break; // jmp case 30: if( testz(a2) ) PC = a1; break; // jz case 31: if( !testz(a2) ) PC = a1; break; // jnz case 33: // mvt if( RA[a1] != 0 ) RA[a2] = RA[a3]; if( RB[a1] != 0 ) RB[a2] = RB[a3]; if( RC[a1] != 0 ) RC[a2] = RC[a3]; if( RD[a1] != 0 ) RD[a2] = RD[a3]; break; case 34: // sys if(a1 == 4) runflag = 0; if(a1 == 5) plot(17,16,23); // just for mandelbrot break; } } var icnt,cycle; function main(){ loadobj(); icnt = 0; cycle = 0; PC = 0; runflag = 1; while(runflag){ IR = M[PC]; op = opcode(); a1 = ads(); a2 = r1(); a3 = r2(); // showInst(); PC++; execute(op); // dumpInternal(); cycle += inst_cycle[op-10]; icnt++; if(icnt > 3000000) runflag = 0; } println('execute ' + icnt + ' instructions ' + cycle + ' cycles'); } function test(){ loadobj(); for(PC = 0; PC < lastpc; PC++){ IR = M[PC]; op = opcode(); a1 = ads(); a2 = r1(); a3 = r2(); showInst(); } // dumpInternal(); } main();