//
/* --------------------------------------------------------------------------------------------------------
	manu_cal.java	コンピュータのしくみ(手動計算機)					ver. 1.00 (JDK 1.02)
																		ueyama@infonet.co.jp 2009.02.21
-------------------------------------------------------------------------------------------------------- */
import java.applet.*;
import java.awt.*;

public class manu_cal extends Applet implements Runnable
{
//					   Bus  Acc  Reg  M0   M1   M2   M3
	int			Sox[]={ 31, 163, 323, 431, 515, 599, 683};				// 「〜を」スイッチ表示 X座標値
	int			Sby = 28;												// 「Iを」スイッチ表示 Y座標値
	int			Soy = 34;												// 「〜を」スイッチ表示 Y座標値
	int			Sot[]={  0,   2,   1,   0,   0,   0,   1};				// 表示回路の種類
//					   Acc  Reg  M0   M1   M2   M3   Reg
	int			Six[]={112, 272, 380, 464, 548, 632, 776};				// 「〜に」スイッチ表示 X座標値
	int			Siy = 218;												// 「〜に」スイッチ表示 Y座標値
	int			Rx[]={ 75, 312, 312, 558, 558, 558, 558, 772};			// レジスタ表示 X座標値
	int			Ry[]={285, 285, 306, 285, 302, 319, 336, 285};			// レジスタ表示 Y座標値
	int			Ro[]={ 63,  80,  80,  42,  42,  42,  42,  62};			// レジスタ名表示 X座標オフセット値
	int			Rv[]={  0,   0,   0,   0,   0,   0,   0,   0};			// In, Acc, Reg, M0, M1, M2, M3, Out の値
	int			Bi[]={112, 196, 380, 464, 548, 632, 776};				// 入力信号のバスとの接続位置 (X座標値)
	int			Bo[]={112, 172, 332, 440, 524, 608, 692,   0};			// 出力信号のバスとの接続位置 (X座標値)
	int			Adr=0;													// Memory Address (0〜3)
	int			Mr=-1;													// 読み出しレジスタ・メモリアドレス
	int			Mw=-1;													// 書き込みレジスタ・メモリアドレス
	int			Com=-1;													// 命令 No.
	int			Md=0;													// 演算モード  0: ADD  1: AND  2: NOT
	boolean		Dm=false;												// 表示モード  true: 8bit  false: 1bit
	boolean		Wri=false;												// 書き込み実行
	boolean		Z=true;													// 全レジスタ 0 Flag
	boolean		Cs=false;												// true: 演算実行中
	boolean		Bm=false;												// 「〜を」スイッチ ON 時の表示モード
	int			T=0;													// タイマー
	int			Mx=0;													// ドット(マーカー)の表示座標
	int			Wait=128;
	Thread		th=null;
	Image		Img;
	
	public void init()													// 初期設定
	{
		String bg=getParameter("bgcolor");
		int 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){};
	}

	public void start()
	{
		if(th==null)
		{
			th=new Thread(this);
			th.start();
		}
	}
	
	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_g(int x, int y, int m, int n, int c)				// 画像の表示
	{
		int			w=0, h=0, ox=0, oy=0;
		Graphics	gx=getGraphics();
		switch(c)
		{
			case  0: w=910; h=258; ox=   0; oy=  0; break;				// 回路図
			case  1: w= 52; h= 23; ox= 910; oy=  0; break;				// 命令ボタン
			case  2: w= 26; h= 23; ox= 910; oy=115; break;				// ボタン
			case  3: w= 22; h= 19; ox= 841; oy=517; break;				// "レ" ボタン (小)
			case  4: w= 60; h=  4; ox= 988; oy=272; break;				// ドット
			case  5: w= 11; h= 11; ox= 988; oy=115; break;				// ラジオボタン
			case  6: w=  7; h= 10; ox=1010; oy=115; break;				// 0,1
			case  7: w= 73; h= 11; ox= 910; oy=184; break;				// 文字
			case  8: w=129; h= 18; ox= 910; oy=283; break;				// レジスタ
			case  9: w= 86; h= 13; ox= 669; oy=516; break;				// 「I を」スイッチ (1bit)
			case 10: w= 86; h= 41; ox= 669; oy=529; break;				// 「I を」スイッチ (8bit)
			case 11: w= 20; h= 98; ox=1006; oy=301; break;				// 「〜を」スイッチ (1bit)
			case 12: w= 48; h= 98; ox= 910; oy=301; break;				// 「〜を」スイッチ (8bit)
			case 13: w= 11; h= 19; ox=1066; oy=  0; break;				// 「〜に」スイッチ
			case 14: w= 24; h= 12; ox=1024; oy=115; break;				// 1, 8
			case 15: w= 40; h= 30; ox= 988; oy=127; break;				// 演算回路
			case 16: w= 13; h=101; ox=1028; oy=127; break;				// レジスタ入力信号
			case 17: w= 13; h= 89; ox=1046; oy=268; break;				// 演算回路入力信号
			case 18: w= 46; h= 20; ox= 988; oy=228; break;				// Acc 入力信号
			case 19: w= 26; h= 11; ox=1046; oy=357; break;				// Acc 入力信号
			case 20: w= 42; h= 13; ox= 841; oy=536; break;				// チェックボックス
		}
		gx.clipRect(x, y, w, h);
		gx.clearRect(x, y, w, h);
		gx.drawImage(Img,x-(ox+m*w),y-(oy+n*h),this);
		gx.dispose();
	}
	
	public void dsp_bus(int r, int w, int c)							// バスの信号表示
	{																	// r: 読み出しレジスタ No.  w: 書き込み 〃
		int mx, mn;
		Graphics	gx=getGraphics();
		mn=Math.min(Bi[w],Bo[r]);
		mx=Math.max(Bi[w],Bo[r]);
		gx.clipRect(mn, 34, mx-mn, 5);
		gx.clearRect(mn, 34, mx-mn, 5);
		gx.drawImage(Img,112,34-(516+5*c),this);
		gx.dispose();
	}

	public void dsp_reg(int x, int y, int n)							// レジスタ値の2進数表示
	{
		int i,j;
		for(i=0,j=128; i<8; i++,j/=2) dsp_g(x+16*i+5, y+4, ((n & j)==0)?0:1, 0, 6);
	}

	public void dsp_fig()												// 回路図の表示
	{
		int i;
		dsp_g(0,0,0,(Dm)?0:1,0);										// 回路図の表示
		dsp_g(214, 115, 0, Md, 15);										// 演算回路の表示
		for(i=0; i<3; i++) dsp_g(211, 163+i*15, (Md==i)?1:0, 0, 5);		// Radio Button (ADD/AND/NOT)
		dsp_g(Sox[0],(Dm)?0:28,(Mr==0)?1:0,0,(Dm)?10:9);				// 「Iを」スイッチ の表示
		for(i=1; i<7; i++) dsp_g(Sox[i],Soy,(Mr==i)?1:0,Sot[i],(Dm)?12:11);	// 「〜を」スイッチ の表示
		for(i=0; i<7; i++) dsp_g(Six[i],Siy,0,0,13);					// 「〜に」スイッチ の表示
		dsp_g(665, 382, 0, 0,14);										// "1" の表示
		dsp_g(650, 383, (Dm)?0:1, 0, 5);								// Radio Button "1" の表示
		dsp_g(696, 382, 1, 0,14);										// "8" の表示
		dsp_g(681, 383, (Dm)?1:0, 0, 5);								// Radio Button "8" の表示
	}

	public void paint(Graphics g)										// 画面の表示
	{
		int i;
		g.clearRect(0, 0, size().width, size().height);
		dsp_fig();														// 回路図の表示
		dsp_g(463, Ry[3]+3, 0, 8, 7);									// "メモリ" の表示
		for(i=0; i<8; i++) dsp_g(Rx[i]-Ro[i], Ry[i]+3, 0, i, 7);		// レジスタ名の表示
		for(i=0; i<8; i++) dsp_g(Rx[i], Ry[i], 0, 0, 8);				// レジスタの表示
		for(i=0; i<8; i++) dsp_reg(Rx[i],Ry[i],Rv[i]);					// レジスタ値の2進数表示
		for(i=0; i<4; i++) dsp_g(501, Ry[i+3]+3, (Adr==i)?1:0, 0, 5);	// Radio Button (address) の表示
		for(i=0; i<5; i++) dsp_g(196+60*i,376,(Cs && i<4)?2:0,i,1);		// 命令ボタン の表示
		dsp_g(182,308,(Rv[0]==0)?2:0,0, 3);								// "レ" ボタン(小) の表示
		dsp_g(506,376,(Wait==1024)?2:0,2,2);							// "<<" ボタン の表示
		dsp_g(536,376,(Wait==16)?2:0,1,2);								// ">>" ボタン の表示
		dsp_g(506+Mx*8,370,0,0, 4);										// ドットの表示
		dsp_g(596,376,(Z)?2:0,0,2);										// "レ" ボタン の表示
		dsp_g(760,382,0,(Bm)?1:0,20);									// チェックボックス の表示
	}

	public void run()
	{
		int a, i;
		while(true)
		{
			try
			{
				th.sleep(Wait);
			}
			catch (InterruptedException e){}
			T++;
			if(T==4)
			{
				reg_write(Mr, Mw);
				dsp_reg(Rx[Mw+1],Ry[Mw+1],Rv[Mw+1]);					// レジスタ値の2進数表示
				if(Com==4 && Wri) Cs=!Cs;								// 演算処理の状態を切り替える
			}
		}
	}
	
	public void stop()
	{
		if(th!=null)
		{
			th.stop();
			th=null;
		}
	}
	
	public int bin_ed(int n, int m)										// レジスタ値の更新
	{
		int p=(int)Math.pow(2,m);										// p = 2 ^ m
		if((n & p) ==0) n+=p;											// 値の更新
		else n-=p;
		return n;
	}
	
	public void dsp_sw(int r)											// 「〜を」スイッチ の表示
	{
		if(r==0) dsp_g(Sox[0],(Dm)?0:28,1,0,(Dm)?10:9);					// 「Iを」スイッチ の表示
		else	 dsp_g(Sox[r],Soy,1,Sot[r],(Dm)?12:11);					// 「〜を」スイッチ の表示
	}

	public void reg_write(int r, int w)									// 入力信号とレジスタ値の表示
	{																	// r: 読み出しレジスタ No.  w: 書き込み 〃
		int i;
		if(w>=0)
		{
			dsp_g(Six[w],Siy,1,0,13);									// 「〜に」スイッチ の表示
			if(r>=0)
			{
				if(w==1)												// 演算
				{
					switch(Md)											// Md  0: ADD  1: AND  2: NOT
					{
						case 0: Rv[2]=Rv[1] + Rv[r]; break;				// ADD
						case 1: Rv[2]=Rv[1] & Rv[r]; break;				// AND
						case 2: Rv[2]=255-Rv[r]; break;					// NOT
					}
					dsp_g(196,Siy-184,(Dm)?3:1,0,17);					// 演算回路入力信号の表示
					if(Md<2) dsp_g(163,127,1,(Dm)?1:0,18);				// アキュムレータからの入力信号の表示
					dsp_g(259,124,1,(Dm)?1:0,19);						// 演算回路出力信号の表示
				}
				else
				{
					Rv[w+1]=Rv[r];										// Rv[]: In,Acc,Reg,M0,M1,M2,M3,Out の値
					dsp_g(Six[w],Siy-184,(Dm)?3:1,0,16);				// レジスタ入力信号の表示
				}
				dsp_bus(r,w,1);											// バスの信号(赤色)表示
				dsp_reg(Rx[w+1],Ry[w+1],Rv[w+1]);						// レジスタ値の2進数表示
				Wri=true;
			}
		}
	}

	public boolean mouseDown(Event e, int mx, int my)					// マウスがクリックされたときの処理
	{
		int a, i, l, m=0, n=0;
		if(my<95)														// 「〜を」スイッチをクリック
		{
			if(mx<105 && inside(my,21,46)) Mr=0;
			for(i=1;i<7;i++) if(inside(mx,Sox[i]-10,Sox[i]+29) && my>60) Mr=i;
			if(Mr>=0)
			{
				dsp_sw(Mr);												// 「〜を」スイッチ の表示
				if(Bm)													// 全レジスタの入力信号表示
				{
					dsp_g(196,Siy-184,1,0,17);							// 演算回路入力信号の表示
					for(i=0;i<7; i++) if(i!=1) dsp_g(Six[i],Siy-184,1,0,16);	// レジスタ入力信号の表示
					dsp_bus(0,6,1);										// バスの信号(赤色)表示
				}
			}
		}
		if(inside(my,209,244) && Mr>=0)									// 「〜を」スイッチが ON であれば…
		{
			for(i=0;i<7;i++) if(inside(mx,Six[i]-10,Six[i]+29)) Mw=i;	// 「〜に」スイッチをクリック
			if(Mw>=0)
			{
				if(Bm)													// 全レジスタの入力信号表示
				{
					dsp_g(196,Siy-184,0,0,17);							// 演算回路入力信号の表示
					for(i=0;i<7; i++) if(i!=1) dsp_g(Six[i],Siy-184,0,0,16);	// レジスタ入力信号の表示
					dsp_bus(0,6,0);										// バスの信号(赤色)表示
				}
				reg_write(Mr, Mw);										// 入力信号とレジスタ値の表示
			}
		}
		if(inside(my,116,165))											// レジスタ、メモリをクリック ?
		{
			if(Mr<0)
			{
				for(i=0; i<6; i++) if(inside(mx,Six[i]+13,Six[i]+50)) Mr=i+1;
				if(Mr>=0) dsp_sw(Mr);									// 「〜を」スイッチ の表示
			}
			else if(Mw<0)
			{
				for(i=0; i<7; i++) if(inside(mx,Six[i]+13,Six[i]+50)) Mw=i;
				if(Mw>=0) reg_write(Mr, Mw);							// 入力信号とレジスタ値の表示
			}
		}
		if(inside(mx,208,258) && inside(my,161,201))					// 演算モードの変更
		{
			Md=(my-161)/15;												// 演算モード
			dsp_g(214, 115, 0, Md, 15);									// 演算回路の表示
			for(i=0; i<3; i++) dsp_g(211,163+i*15,(Md==i)?1:0,0,5);		// Radio Button (ADD/AND/NOT) の表示
		}
		if(inside(my,285,353))											// レジスタテーブルをクリック ?
		{
			if(inside(mx,492,552))										// Radio Button をクリック
			{
				Adr=(my-285)/18;										// アドレス
				for(i=0;i<4;i++) dsp_g(501,Ry[i+3]+3,(Adr==i)?1:0,0,5);	// Radio Button (address) の表示
			}
			else														// レジスタテーブルをクリック
			{
				for(i=0; i<8; i++)
				{
					if(inside(mx,Rx[i],Rx[i]+129) && inside(my,Ry[i]+1,Ry[i]+16))
					{
						m=7-(mx-Rx[i])/16; 
						Rv[i]=bin_ed(Rv[i], m);							// レジスタの値を更新
						dsp_reg(Rx[i],Ry[i],Rv[i]);						// レジスタ値の2進数表示
						if(i==0) dsp_g(182,308,(Rv[0]==0)?2:0,0, 3);	// "レ" ボタン(小) の表示
					}
					if(Rv[i]>0)
					{
						Z=false;
						dsp_g(596,376,0,0,2);							// "レ" ボタン有効の表示
					}
				}
			}
			if(inside(mx,182,204) && inside(my,308,327) && Rv[0]>0)		// "レ" ボタン(小) をクリック
			{
				Rv[0]=0;
				dsp_reg(Rx[0],Ry[0],Rv[0]);								// レジスタ値の2進数表示
				dsp_g(182,308,1,0,3);									// "レ" ボタン(小) の表示
			}
		}
		if(my>376)														// ボタン等をクリック ?
		{
			if(inside(mx,196,488) && (mx-196)%60<52)					// 命令ボタンをクリック
			{
				Com=(mx-196)/60;
				if((Com<4 && !Cs) || Com==4)
				{
					dsp_g(196+60*Com,376,1,Com,1);						// 命令ボタン の表示
					switch(Com)											// 命令の処理
					{
						case 0: Mr=0; Mw=0; 			break;			// IN
						case 1: Mr=1; Mw=6;				break;			// OUT
						case 2: Mr=Adr+3; Mw=0;			break;			// READ
						case 3: Mr=1; Mw=Adr+2;			break;			// WRITE
						case 4: Mr=(Cs)?2:Adr+3; Mw=(Cs)?0:1; break;	// CALC   2step 実行の処理も行う
					}
					dsp_sw(Mr);											// 「〜を」スイッチ の表示
					T=0;
					Wri=true;
				}
			}
			if(inside(mx,506,562))										// "<<" or ">>" ボタン
			{
				if(inside(mx,506,532) && Wait<1024)						// "<<" ボタン
				{
					Wait*=2; Mx--;
					dsp_g(506,376,1,2,2);								// "<<" ボタン の表示
				}
				if(inside(mx,536,562) && Wait>16)						// ">>" ボタン
				{
					Wait/=2; Mx++;
					dsp_g(536,376,1,1,2);								// "<<" ボタン の表示
				}
				dsp_g(506+Mx*8,370,0,0,4);								// ドットの表示
			}
			if(inside(mx,596,622) && !Z)								// "レ" ボタン
			{
				dsp_g(596,376,1,0,2);									// "レ" ボタン の表示
				for(i=0; i<8; i++) Rv[i]=0;								// レジスタ値のクリア
				for(i=0; i<8; i++) dsp_reg(Rx[i],Ry[i],Rv[i]);			// レジスタ値の2進数表示
				Z=true;
			}
			if(inside(mx,638,722))										// 表示モード (1,8bit) の変更
			{
				Dm=((mx-638)/42==0)?false:true;							// 表示モード
				dsp_fig();												// 回路図の書き換え
			}
			if(inside(mx,760,802))										// 表示モード の変更
			{
				Bm=(Bm)?false:true;
				dsp_g(760,382,0,(Bm)?1:0,20);							// チェックボックス の表示
			}
		}
		return true;
	}
	
	public boolean mouseUp(Event e, int mx, int my)						// マウスがクリックされたときの処理
	{
		int i,m;
		if(inside(mx,182,204) && inside(my,308,327)) dsp_g(182,308,2,0,3);	// "レ" ボタン(小) をクリック
		if(my>376)														// ボタン等をクリック ?
		{
			if(inside(mx,196,488))										// 命令ボタン
			{
				m=(mx-196)/60;
				for(i=0; i<5; i++) dsp_g(196+60*i,376,(Cs && i<4)?2:0,i,1);	// 命令ボタン の表示
			}
			if(inside(mx,506,532));										// "<<" ボタン
			{
				dsp_g(506,376,(Wait==1024)?2:0,2,2);					// "<<" ボタン の表示
				dsp_g(536,376,(Wait==16)?2:0,1,2);						// ">>" ボタン の表示
			}
			if(inside(mx,536,562));										// ">>" ボタン
			{
				dsp_g(506,376,(Wait==1024)?2:0,2,2);					// "<<" ボタン の表示
				dsp_g(536,376,(Wait==16)?2:0,1,2);						// ">>" ボタン の表示
			}
			if(inside(mx,596,622))
			{
				dsp_g(596,376,2,0,2);									// "レ" ボタン の表示
				dsp_g(182,308,2,0,3);									// "レ" ボタン(小) の表示
			}
		}
		if(Wri)
		{
			if(Mr==0) dsp_g(Sox[0],(Dm)?0:28,0,0,(Dm)?10:9);			// 「Iを」スイッチを元に戻す
			else dsp_g(Sox[Mr],Soy,0,Sot[Mr],(Dm)?12:11);				// 「〜を」スイッチを元に戻す
			dsp_g(Six[Mw],Siy,0,0,13);									// 「〜に」スイッチを元に戻す
			if(Mw==1)
			{
				dsp_g(196,Siy-184,(Dm)?2:0,0,17);						// レジスタ入力信号の表示
				dsp_g(163,127,0,(Dm)?1:0,18);							// レジスタ入力信号の表示
				dsp_g(259,124,0,(Dm)?1:0,19);							// レジスタ入力信号の表示
			}
			else dsp_g(Six[Mw],Siy-184,(Dm)?2:0,0,16);					// レジスタ入力信号を元に戻す
			dsp_bus(Mr, Mw, (Dm)?2:0);									// バスの信号を元に戻す
			Wri=false;
			Mr=-1; 
			Mw=-1;
		}
		return true;
	}
}
//
戻る