/* written by t-izumi@se.ritsumei.ac.jp 乗算器の無いCPUで多ワード乗算をするためのアセンブリコード …の参考のためのCプログラム コンパイル gcc -g -Wall -omulti.exe multi.c 実行 multi.exe 数1 数2 補足…わかりやすいようにあまりチューンアップはしていません。    動作の本質を把握するための参考まで。 */ #include #include unsigned char memory[256]; #define MULADDR 128 /* MULADDR+0 ... A0 MULADDR+1 ... A1 MULADDR+2 ... B0 MULADDR+3 ... B1 MULADDR+4 ... P0 MULADDR+5 ... P1 MULADDR+6 ... P2 MULADDR+7 ... P3 MULADDR+8 ... BLOOP MULADDR+9 ... AADD MULADDR+10... BSHIFT MULADDR+11... PSHIFT */ unsigned char R0,R1,R2,R3,R4,R5,R6,R7,SP; int tmp; unsigned char FC,FZ,FS,FV; void printstatus(char *str){ static int heading=0; int i; if (!heading) { printf(" R0 R1 R2 R3 R4 R5 R6 R7 FC FZ FS FV\n"); heading=1; } printf("%-3s ",str); printf("%02x %02x %02x %02x %02x %02x %02x %02x %2x %2x %2x %2x ", R0,R1,R2,R3,R4,R5,R6,R7,FC,FZ,FS,FV); for (i=0;i<12;i++) printf(" %02x",memory[MULADDR+i]); printf("\n"); return ; } void mul(void){ /* R4に変数として使うメモリ領域の先頭アドレスをセット */ R4=MULADDR; /* P出力のリセット */ R5=R4+4; /* P出力領域の先頭アドレス */ R0=4; /* P出力ワード数分繰り返し */ R1=0; /* 書込値0 */ do { memory[R5]=R1; /* P出力を0にする */ R5=R5+1; /* 次のアドレスの計算 */ R0=R0-1;FZ=(R0==0)?1:0; /* ループカウンタのデクリメント*/ } while (!FZ); /* ゼロになるまでループ */ /* B入力16ビット分繰り返し*/ R0=16; /* ループ数16 */ do { memory[R4+8]=R0; /* ループカウンタ BLOOP 書込 */ printstatus("LPB"); R3=0; /* R1を加算の繰上に使う、初期値0 */ R0=memory[R4+2]; /* B入力下位バイト取得 */ R0=R0&1;FZ=(R0==0)?1:0; /* 最下位ビットの確認 */ if (!FZ) { printstatus("ADD"); /* Aの値を加算(多ワード) */ R5=R4+0; /* R5にAの対象ワードのアドレスをセット、下位から */ R6=R4+6; /* R6にPの対象ワードのアドレスをセット、位置は※ */ R0=2; /* 2ワード分のループ */ do { memory[R4+9]=R0; /* ループカウンタ AADD 書込 */ R0=memory[R5]; /* Aの対象ワードを読出 */ R1=memory[R6]; /* Pの対象ワードを読出 */ R3=R3&1;FZ=(R3==0)?1:0; /* 下位からの繰上の確認 */ if (FZ) { /* 下位からの繰上がない場合 */ tmp=R1+R0+0;FC=(tmp>255)?1:0;R1=tmp&255; /* 符号無加算(論理加算) */ if (FC) { /* 上位への繰上が発生 */ R3=1; } else { /* 上位への繰上はなし */ R3=0; } } else { /* 下位からの繰上がない場合 */ tmp=R1+R0+1;FC=(tmp>255)?1:0;R1=tmp&255; /* 符号無加算(論理加算) */ if (FC) { /* 上位への繰上が発生 */ R3=1; } else { /* 上位への繰上はなし */ R3=0; } } memory[R6]=R1; /* この桁の結果を書込 */ R5=R5+1; /* 次のワードのアドレスを計算 */ R6=R6+1; /* 次のワードのアドレスを計算 */ R0=memory[R4+9]; /* ループカウンタ AADD 読出 */ R0=R0-1;FZ=(R0==0)?1:0; /* AADD=AADD-1 */ } while (!FZ); /* do while AADD!=0 */ } printstatus("SRP"); /* P出力を右シフト(多ワード) */ R5=R4+7; /* R5に対象ワードのアドレスをセット、上位から */ /* R3をビットの繰下に使う、初期値は加算の最終繰上 */ R0=4; /* 4ワード分のループ */ do { memory[R4+11]=R0; /* ループカウンタ PSHIFT 書込 */ R0=memory[R5]; /* このワードを読出 */ R0=R0>>1; /* 右シフト */ R3=R3&1;FZ=(R3==0)?1:0; /* 前のワードの最下位ビットを確認 */ if (!FZ) { /* 前ワードの最下位ビットが1なら */ R0=R0|128; /* このワードの最上位ビットを1にセット */ } R3=memory[R5]; /* 繰下のためにこのワードを取っておく */ memory[R5]=R0; /* このワードの結果を書込 */ R5=R5-1; /* 次のワードのアドレスを計算 */ R0=memory[R4+11]; /* ループカウンタ PSHIFT 読出 */ R0=R0-1;FZ=(R0==0)?1:0; /* PSHIFT=PSHIFT-1 */ } while (!FZ); /* do while PSHIFT!=0 */ printstatus("SRB"); /* B入力右シフト(多ワード) */ R5=R4+3; /* R5に対象ワードのアドレスをセット、上位から */ R3=0; /* R3をビットの繰下に使う、初期値0 */ R0=2; /* 2ワード分のループ */ do { memory[R4+10]=R0; /* ループカウンタ BSHIFT 書込 */ R0=memory[R5]; /* このワードを読出 */ R0=R0>>1; /* 右シフト */ R3=R3&1;FZ=(R3==0)?1:0; /* 前のワードの最下位ビットを確認 */ if (!FZ) { /* 前ワードの最下位ビットが1なら */ R0=R0|128; /* このワードの最上位ビットを1にセット */ } R3=memory[R5]; /* 繰下のためにこのワードを取っておく */ memory[R5]=R0; /* このワードの結果を書込 */ R5=R5-1; /* 次のワードのアドレスを計算 */ R0=memory[R4+10]; /* ループカウンタ BSHIFT 読出 */ R0=R0-1;FZ=(R0==0)?1:0; /* BSHIFT=BSHIFT-1 */ } while (!FZ); /* do while BSHIFT!=0 */ printstatus("LPE"); R0=memory[R4+8]; /* ループカウンタ BLOOP 読出 */ R0=R0-1;FZ=(R0==0)?1:0; /* BLOOP=BLOOP-1 */ } while (!FZ); /* do while BLOOP!=0 */ return; } int main(int argc, char **argv){ unsigned long a,b,p; SP=255; if (argc>=3) { a=atoi(argv[1]); b=atoi(argv[2]); } else { a=0x1234; b=0x5678; } memory[MULADDR+0]=(a>>0)&0xff; memory[MULADDR+1]=(a>>8)&0xff; memory[MULADDR+2]=(b>>0)&0xff; memory[MULADDR+3]=(b>>8)&0xff; mul(); printstatus("RSL"); p=p*256+memory[MULADDR+7]; p=p*256+memory[MULADDR+6]; p=p*256+memory[MULADDR+5]; p=p*256+memory[MULADDR+4]; printf("%04lx*%04lx=%04lx ...", a,b,p); if (a*b==p) { printf("OK\n"); printf("%ld*%ld=%ld\n", a,b,p); } else { printf("NG\n"); } return 0; }