//
/* -------------------------------------------------------------------------------------------------------- v8.java 仮想コンピュータ (petit8) ver. 1.01 (JDK 1.02) update: 2004.05.09 ueyama@infonet.co.jp 2004.02.20 -------------------------------------------------------------------------------------------------------- */ import java.applet.*; import java.awt.*; import java.util.*; public class v8 extends Applet implements Runnable { //Reg: m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 mA mB mC mD mE mF Acc Ir Out In Pc Ix Frg int Rx[] ={180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, 8,180,180, 20, 20, 37}; int Ry[] ={ 99,117,135,153,171,189,207,225,243,261,279,297,315,333,351,369, 45,45,414, 0,189,270,342}; int Fx=37, Fy=342; // Flag register X,Y int Reg[]=new int[22]; // Register/Memory value String Lbl[]=new String[16]; // Label Name String Asm[]={"NOP","CLR","IN","OUT","INC","DEC","INC_X","DEC_X", // OP code "SFT_L","SFT_R","NOT","-","-","-","-","-","-", // "READ","WRITE","ADD","SUB","CMP","AND","OR","INC_M", // "DEC_M","SET_X","JMP","JEZ","JNZ","JCS","JCC", // 31 "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F", // operand "$0","$1","$2","$3","$4","$5","$6","$7","$8","$9","$A","$B","$C","$D","$E","$F", "IX","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15", "%0","%1","%2","%3","%4","%5","%6","%7","%8","%9","%10","%11","%12","%13","%14","%15", "0000","0001","0010","0011","0100","0101","0110","0111", "1000","1001","1010","1011","1100","1101","1110","1111", // 111 "#0000","#0001","#0010","#0011","#0100","#0101","#0110","#0111", "#1000","#1001","#1010","#1011","#1100","#1101","#1110","#1111", // 127 "STORE","END"}; // Assembler int Frm[]={-1,-1,19,16,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,16,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1}; int To[] ={-1,16,16,18,16,16,16,16,16,22,22,21,21,-1,-1,-1,-1,16,0,16,16,16,16,16,0,0,21,20,20,20,20,20}; int Frf, Trf, Fre, Tre, Ysf, Yef, Yse, Yee, Opb=-1, Pofs=0; int Acc; // Accumulator int PC; // Program Counter int Op, Ad; // Operand & Address int C=0, Z=0, O=0; // C,Z,O Flag int Clk=0; // Clock int Cf=6; // Clock Frequency boolean Dsp=true; // Display int End=-1; // End point TextArea Tasm = new TextArea(10,16); // Text area String Prg[]=new String[32]; // program boolean Run= false; // true: false: int Clock=1024; // wait time (Clock) int Bgc; // 背景色 String Chk="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:;,$%# \r\n\t"; // for Err check String Mes=""; boolean Err=false; Image Img; Graphics gr; Thread th=null; public void start() { if(th==null) { th=new Thread(this); th.start(); } } public void init() // 初期設定 { int i; gr=getGraphics(); String bg=getParameter("BgColor"); Bgc=Integer.valueOf(bg,16).intValue(); setBackground(new Color(Bgc)); MediaTracker mt=new MediaTracker(this); Img=getImage(getCodeBase(), getParameter("figure")); mt.addImage(Img, 0); try { mt.waitForID(0); } catch(InterruptedException e){}; setLayout(null); add(Tasm); Tasm.reshape(420,63,240,325); for(i=0; i<22; i++) Reg[i]=0; // レジスタ類初期値設定 for(i=0; i<32; i++) Prg[i]=""; } public boolean inside(int x, int a, int b) // マウスの位置座標チェック { return (x<=Math.max(a,b) && x>=Math.min(a,b)) ? true:false; } public void dsp_reg(int n, int c) // レジスタ 値の表示 { int i, j=(n>19)? 3:7; String bin=Integer.toString(Reg[n], 2)+" "; // 2進数 文字列 for(i=bin.length(); i<((n>19)? 5:9); i++) bin="0"+bin; for(i=j; i>=0; i--) // 2進数の表示 { dsp_g(Rx[n]+i*17+5, Ry[n]+3, c, Integer.parseInt(bin.substring(i,i+1)), 0); } dsp_g(Fx+ 5,Fy+3,0,C,0); // C フラグの表示 dsp_g(Fx+22,Fy+3,0,Z,0); // Z フラグの表示 } public void dsp_g(int x, int y, int c, int m, int n) // 画像の表示 { int w=0, h=0, ox=0, oy=0; Graphics gx=gr.create(); switch(c) { case 0: w= 8; h= 12; ox=684; oy= 38; break; // 2進数 case 1: w=296; h= 35; ox=410; oy= 76; break; // IR へのバス(赤) case 2: w=296; h= 35; ox= 15; oy= 64; break; // 同上 (通常) case 3: w=137; h= 19; ox=410; oy= 0; break; // レジスタ枠 (太 8 bit) case 4: w= 69; h= 19; ox=410; oy= 57; break; // レジスタ枠 (4 bit) case 5: w=137; h= 19; ox=410; oy= 19; break; // レジスタ枠 (8 bit) case 6: w= 69; h= 19; ox=548; oy= 57; break; // レジスタ枠 (2 bit) case 8: w=124; h= 6; ox=410; oy=111; break; // ▲ case 9: w=124; h= 6; ox=410; oy=117; break; // ▼ case 10: w= 44; h= 23; ox=410; oy=123; break; // ボタン case 11: w=127; h= 15; ox=410; oy=331; break; // "Assemblar Program" case 16: w= 30; h= 9; ox=410; oy=307; break; // "clock" case 17: w= 42; h= 11; ox=410; oy=316; break; // "Display" case 18: w= 13; h= 13; ox=684; oy= 0; break; // Check Box case 19: w= 43; h= 13; ox=542; oy=123; break; // Niemonic case 21: w= 42; h= 11; ox=710; oy= 0; break; // Clock Frequency case 22: w=406; h=433; ox= 0; oy= 0; break; } gx.clipRect(x, y, w, h); gx.drawImage(Img,x-(ox+m*w),y-(oy+n*h),this); gx.dispose(); } public int sel_no(int n) // レジスタ表示枠 No. { if(n==17) return 4; // Instruction Register if(n<20) return 5; // Memory, Acc, Port else if(n<22) return 4; // PC, IR else return 6; // Flag Register } public void dsp_button() // ボタンの表示 { dsp_g(110, 449, 10, 0, 0); // CLR dsp_g(172, 449, 10, (Clock==16384)?2:0, 1); // SLOW dsp_g(277, 449, 10, (Clock==16)?2:0, 2); // FAST dsp_g(461, 449, 10, 0, (Run)?4:3); // RUN dsp_g(509, 449, 10, 0, 5); // STEP dsp_g(616, 414, 10, 0, 6); // LOAD dsp_g(616, 449, 10, 2, 0); // CREAN dsp_g(413, 449, 10, 0, 7); // RESET dsp_g(229, 447, 16, 0, 0); // "clock" dsp_g(358, 457, 17, 0, 0); // "Display" dsp_g(342, 455, 18, (Dsp)?1:0, 0); // Check Box dsp_g(227, 460, 21, 0, Cf); // Clock Frequency } public void dsp_nmc() // ニーモニックの表示 { int m=Reg[17]/16, n=Reg[17]%16; int h, v; v=(m==0)?n:m; h=(m==0)?0:1; if(n==0 && Op<27) n=Reg[21]; // Index addressing dsp_g(80, 4, 19, 1, 0); // オペランドの消去 if(PC==End) dsp_g(15, 4, 19, 3, 0); // "END" else { dsp_g(15, 4, 19, h, v); // 命令 if(m>0) dsp_g(80, 4, 19, 2, n); // オペランド } } public void paint(Graphics g) // 画面の表示 { int i,j; g.clearRect(0, 0, size().width, size().height); dsp_g(0, 0, 22, 0, 0); for(i=0; i<22; i++) dsp_reg(i, 0); dsp_button(); dsp_g(475, 44, 11, 0, 0); } public void cpu_run() // 命令の実行 { Clk++; if(Clk%2==0) // excute cycle { excute(); if(Reg[20]戻る21 || i==n) Reg[i]=0; // Reg[19] は Input Port のためクリアしない for(i=20; i<22; i++) if(n>21 || i==n) Reg[i]=0; for(i=0; i<32; i++) if(n>21) Prg[i]=""; if(n>21) C=Z=O=PC=Clk=0; Run=false; } public int flag(int m, int n) // フラグ m=0: Z flag only { if(m>0) C=(n>255 || n<0)?1:0; Z=(n%256==0)?1:0; return n&255; } public int reg_no(int n) // レジスタ(メモリ)No. の算出 { int r=(n==0)?Frm[Op]:To[Op]; if(r==0) { r=Reg[17]%16; if(r==0) r=Reg[21]; // Index Register } return r; } public void fetch() // 命令のフェッチ { int i; Reg[17]=Reg[Reg[20]]; // 命令レジスタにメモリデータをコピー Op=Reg[17]; // 命令(Reg[17]:命令レジスタ) PC=Reg[20]; if(Op>15) { Ad=Op%16; // operand if(Ad==0) Ad=Reg[21]; // index addressing Op=Op/16+16; // ope code } else if(Op==2) Ad=19; // INPUT else if(Op==3) Ad=18; // OUTPUT if((Frf=Frm[Op])>=0) // レジスタ表示色変更 { Frf=reg_no(0); dsp_g(Rx[Frf], Ry[Frf], sel_no(Frf), 1, 0); } if((Trf=To[Op])>=0) // レジスタ表示色変更 { Trf=reg_no(1); dsp_g(Rx[Trf], Ry[Trf], sel_no(Trf), 1, 0); } Ysf=Ry[0]; Yef=Ry[PC]; dsp_reg(17, 0); // 命令レジスタの表示 dsp_nmc(); if(Dsp && Trf>=0) { if(PC>0) dsp_exec(1); if(PC>0) dsp_bus(Yse, Yee); if(Opb>0) dsp_reg(Opb, 0); dsp_fetch(0); dsp_bus(Ysf, Yef); } } public void dsp_fetch(int n) // フェッチ動作表示 { int i; dsp_g(15, 64, 1+n, 0, 0); // IR へのデータバス dsp_g(Rx[0], Ry[PC], 3, n, 0); // メモリ (命令) dsp_g(Rx[20], Ry[20], 4, n, 0); // プログラムカウンタ } public void dsp_bus(int s, int e) // データバス表示 { gr.setXORMode(new Color(51,255,255)); for(int i=0; i<8; i++) gr.drawLine(Rx[0]+i*17+9, s, Rx[0]+i*17+9, e); gr.setPaintMode(); } public void excute() // 命令の実行 { int i; Acc=Reg[16]; // Accumulator switch(Op) { case 0: break; // NOP case 1: Acc=flag(0, 0); break; // CLEAR case 2: Ad=19; Acc=flag(0, Reg[Ad]); break; // INPUT case 3: Ad=18; Reg[Ad]=flag(0, Acc); break; // OUTPUT case 4: Acc=flag(0, Acc+1); break; // INC_ACC case 5: Acc=flag(0, Acc-1); break; // DEC_ACC case 6: Reg[21]++; Reg[21]&=15; Z=(Reg[21]==0)?1:0; break; // INC_IX case 7: Reg[21]--; Reg[21]&=15; Z=(Reg[21]==0)?1:0; break; // DEC_IX case 8: Acc*=2; C=Acc/256; Acc%=256; Z=(Acc==0)?1:0; break;// SHIFT_L case 9: C=Acc%2; Acc/=2; Z=(Acc==0)?1:0; break; // SHIFT_R case 10: Acc=flag(0, 255-Acc); break; // NOT case 11: C=0; break; // CLR_C case 12: C=1; break; // SET_C case 17: Acc=flag(0, Reg[Ad]); break; // READ case 18: Reg[Ad]=flag(0, Acc); break; // WRITE case 19: Acc=flag(1, Acc+Reg[Ad]); break; // ADD case 20: Acc=flag(1, Acc-Reg[Ad]); break; // SUB case 21: flag(1, Acc - Reg[Ad]); Acc=Reg[16]; break; // CMP case 22: Acc=flag(0, Acc & Reg[Ad]); break; // AND case 23: Acc=flag(0, Acc | Reg[Ad]); break; // OR case 24: Reg[Ad]=flag(0, Reg[Ad]+1); break; // INC case 25: Reg[Ad]=flag(0, Reg[Ad]-1); break; // DEC case 26: Reg[21]=Ad; break; // SET_IX case 27: Reg[20]=Ad-1; break; // JUMP case 28: if(Z==1) Reg[20]=Ad-1; break; // JUMP_Z case 29: if(Z==0) Reg[20]=Ad-1; break; // JUMP_NZ case 30: if(C==1) Reg[20]=Ad-1; break; // JUMP_C case 31: if(C==0) Reg[20]=Ad-1; break; // JUMP_NC } Reg[16]=Acc; dsp_reg(16, 0); dsp_reg(21, 0); dsp_reg(Ad, 0); if((Fre=Frm[Op])>=0) // レジスタ表示色変更 { Fre=reg_no(0); dsp_g(Rx[Fre], Ry[Fre], sel_no(Fre), 1, 0); } if((Tre=To[Op])>=0) // レジスタ表示色変更 { Tre=reg_no(1); dsp_g(Rx[Tre], Ry[Tre], sel_no(Tre), 1, 0); } if(Tre*Fre>=0 && Tre>=0) { if(Ry[Tre] 16) dsp_g(Rx[17]+68, Ry[17], 4, n, 0); // 命令レジスタ オペランド部 赤枠 if(Fre>=0) // データバス (Op: Ope-code) { d=(Tre==16 && Fre<19)?8:9; if(Op!=21) dsp_g(Rx[Tre]+7, Ry[Tre]+((d==8)?19:-6), d, n, 0); // ▲ or ▼ dsp_g(Rx[Fre], Ry[Fre], 3, n, 0); // レジスタ赤太枠 dsp_g(Rx[Tre], Ry[Tre], sel_no(Tre), n, 0); // レジスタ枠 } } public boolean is_legal(String c, String s) { int i; for(i=0; i =0) { if(d.equals("$") && is_legal("0123456789ABCDEF", n)) m=Integer.parseInt(n,16); else if(d.equals("#") && is_legal("01", n)) m=Integer.parseInt(n,2); else if(d.equals("%") && is_legal("0123456789", n)) m=Integer.parseInt(n,10); } else if(is_legal("0123456789", s)) m=Integer.parseInt(s); return m; } public void err_mes(int i, String s) // error message { Mes="Program Error: line "+i+", "+s; Err=true; } public boolean mouseDown(Event e, int x, int y) // マウスがクリックされたときの処理 { int i=0,j=0,k=0,l=0,m=0,n=0,r=-1,s=0,v=0; String c,d,p,q; boolean lf=false; Err=false; Mes=""; gr.clearRect(420,390,240,20); if(inside(x, 616, 660) && inside(y, 414, 437)) // *** LOAD *** { dsp_g(616, 414, 10, 1, 6); End=-1; Pofs=0; for(i=0; i<16; i++) Lbl[i]=""; for(i=0; i<32; i++) Prg[i]=""; p=Tasm.getText(); StringTokenizer st=new StringTokenizer(p,"\n\r"); n=st.countTokens(); if(n==0) {Mes="Program Error: program not found."; Err=true;} for(i=0; st.hasMoreTokens(); i++) { q=st.nextToken(); if((m=q.indexOf(";"))>0) q=q.substring(0,m); // Comment Prg[i]=q.toUpperCase(); if(!is_legal(Chk, Prg[i])) err_mes(i+1, q); // Error Check StringTokenizer ec=new StringTokenizer(Prg[i],"\t "); for(j=0; ec.hasMoreTokens(); j++) // missing operand { q=ec.nextToken(); for(k=17; k<32; k++) // 要オペランド命令 { if(Asm[k].equals(q)) { if(!ec.hasMoreTokens()) { err_mes(i+1, Prg[i]); break; } } } } if(Err) break; } if(!Err) { for(i=0; i 0) // Label { Lbl[s]=q.substring(0,m); q=st.nextToken(); lf=true; } for(k=0; k<130; k++) { if(Asm[k].equals(q)) { if(k<16) Reg[s]=k; else if(k<32) Reg[s]=k%16*16; else if(k<128) Reg[s]+=k%16; else if(k==128) // STORE { m=-1; l=0; // *1 if(st.hasMoreTokens()) { m=cal_adr(st.nextToken("\t, ")); if(m>15) err_mes(i+1, Prg[i]); // *1 if(m>=0 && st.hasMoreTokens()) { if((v=cal_adr(st.nextToken()))>=0) Reg[m]=v; else m=-1; Pofs++; l++; } } if(l<1) err_mes(i+1, Prg[i]); // *1 } else if(k==129) End=s; // END break; } } if(j==0 && (k>129 || inside(k,32,127))) err_mes(i+1, Prg[i]); if(Err) break; j++; } if(Reg[s]>0) s++; if(End>=0 || Err) break; } if(!Err) { if(lf) // ラベルの処理 { // for(i=0; i<16; i++) System.out.println("i="+i+", Prg="+Prg[i]+", l="+Lbl[i]); for(i=0; i<16; i++) { s=0; j=0; while(!Prg[j].equals("")) { if(Prg[j].indexOf(Lbl[i])>0) Reg[s]+=i; if(Prg[j].indexOf("STORE")==-1) s++; j++; } } for(i=0; !Prg[i].equals(""); i++) // Illegal label { StringTokenizer ec=new StringTokenizer(Prg[i],",:\t "); while(ec.hasMoreTokens()) { q=ec.nextToken(); if(q.indexOf("STORE")>=0) break; for(k=0; k<130; k++) if(Asm[k].equals(q)) break; if(k==130) for(k=0; k<16; k++) if(Lbl[k].equals(q)) break; if(k==16) { err_mes(i+1, Prg[i]); break; } } } } } if(!Err) { if(End<0) err_mes(i+1, "\"END\" expected."); else { for(i=0; i<16; i++) dsp_reg(i, 0); Mes="Assemble completed."; } } } } if(y>449) { if(inside(x, 110, 154)) // *** CLR *** { repaint(); clr_reg(32); // 全レジスタ・メモリのクリア dsp_g(461, 449, 10, 0, (Run)?4:3); // RUN or STOP dsp_g(509, 449, 10, 0, 5); // STEP for(i=0; i<22; i++) dsp_reg(i, 0); } if(inside(x, 172, 321)) // *** SLOW & FAST *** { if(x<216 && Clock<16384) {Clock*=2; dsp_g(172, 449, 10, 1, 1);} if(x>277 && Clock>16) {Clock/=2; dsp_g(277, 449, 10, 1, 2);} Cf=(int)(Math.log((double)(Clock/16))/Math.log(2)); dsp_g(227, 460, 21, 0, Cf); // Clock Frequency } if(inside(x, 413, 457)) // *** RESET *** { PC=Reg[20]=Clk=0; dsp_g(413, 449, 10, 1, 7); // RESET dsp_g(509, 449, 10, (PC==End)?2:0, 5); // STEP dsp_reg(20, 0); } if(inside(x, 461, 504)) // *** RUN *** { dsp_g(461, 449, 10, 1, (Run)?4:3); Run=!Run; if(Run && End<0) { Mes="Error: Program empty !"; Run=false; dsp_g(461, 449, 10, 1, 3); } } if(inside(x, 509, 553)) // *** STEP *** { if(PC 616) repaint(); // *** CLEAN *** if(inside(x,342,355) && inside(y,453,466)) { Dsp=!Dsp; dsp_g(342, 455, 18, (Dsp)?1:0, 0); // Check Box } } else if(x<316) // レジスタ値の編集 { if(inside(x,Rx[0],Rx[0]+136)) { if(inside(y,Ry[0], Ry[15]+18)) r=(y-Ry[0])/18; // Memory if(inside(y,Ry[19],Ry[19]+18)) r=19; // Input Port if(inside(y,Ry[16],Ry[16]+18)) r=16; // Accumulator if(inside(y,Ry[18],Ry[18]+18)) r=18; // Output Port } if(inside(x,Rx[17],Rx[17]+136) && inside(y,Ry[17],Ry[17]+18)) r=17; // Instruction Regidter if(inside(x,Rx[20],Rx[20]+ 68) && inside(y,Ry[20],Ry[20]+18)) r=20; // Program Counter if(inside(x,Rx[21],Rx[21]+ 68) && inside(y,Ry[21],Ry[21]+18)) r=21; // Program Counter if(r>=0) { m=7-(x-Rx[r]+((r>19)?68:0))/17; n=1; for(i=0; i< m; i++) n*=2; Reg[r]+=((Reg[r] & n) ==0)? n:-n; dsp_reg(r, 0); } if(inside(x,Fx,Fx+17) && inside(y,Fy,Fy+18)) {C=(C==0)?1:0; dsp_g(Fx+ 5,Fy+3,0,C,0);} // C Flag if(inside(x,Fx+18,Fx+34) && inside(y,Fy,Fy+18)) {Z=(Z==0)?1:0; dsp_g(Fx+22,Fy+3,0,Z,0);} // Z Flag } if(Mes.indexOf("Error")>=0) gr.setColor(new Color(204,0,0)); else gr.setColor(new Color(102,102,102)); Font f=new Font("Helvetica", Font.PLAIN, 10); gr.drawString(Mes, 423, 406); return true; } public boolean mouseUp(Event e, int x, int y) // マウスボタンが離されたときの処理 { if(inside(x, 616, 660) && inside(y, 414, 437)) dsp_g(616, 414, 10, 0, 6); // *** STORE *** if(y>449) { if(inside(x, 172, 216)) dsp_g(172, 449, 10, (Clock==16384)?2:0, 1); // *** SLOW *** if(Clock>16) dsp_g(277, 449, 10, 0, 2); if(inside(x, 277, 321)) dsp_g(277, 449, 10, (Clock==16)?2:0, 2); // *** FAST *** if(Clock<16384) dsp_g(172, 449, 10, 0, 1); if(inside(x, 413, 457)) // *** RESET *** { dsp_g(413, 449, 10, 0, 7); // RESET dsp_g(461, 449, 10, 0, (Run)?4:3); // RUN } if(inside(x, 461, 504)) dsp_g(461, 449, 10, 0, (Run)?4:3); // *** RUN *** if(inside(x, 509, 553)) dsp_g(509, 449, 10, (PC==End)?2:0, 5); // *** STEP *** } return true; } public void stop() { if(th!=null) { th.stop(); th=null; } } } // *1 2004.05.09 //