//
/*
--------------------------------------------------------------------------------------------------------
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; i0) // 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(PC616) 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
// 戻る