オリジナルCPU「DL166」のレジスタをLEDドットマトリックスで見える化する:オリジナルCPUでバイナリコード入門(6)(2/3 ページ)
オリジナル4ビットCPUを用いてバイナリコードを学ぶ本連載。第6回は、「Tang Nano 9K」に移植したオリジナルCPU「DL166」のレジスタをLEDドットマトリックスで見える化する。
LEDドットマトリクスの表示方法
11〜14行目に当たるリスト2は、LEDドットマトリクスで8個のレジスタの表示とTang Nano搭載のLEDにc_flagの値を表示するためのコードです。
11: wire [2:0]i=counter[15:13]; 12: assign col ={4'b0000,regs[i]}; 13: assign row ={i!=7,i!=6,i!=5,i!=4,i!=3,i!=2,i!=1,i!=0}; 14: assign leds={5'b11111,!c_flag};
11行目でcounterの13〜15ビット目の3ビット分をiというシンボルで参照できるように設定しています。12行目は、col、LEDドットマトリックスでいうと8ビット長の横のラインを表します。上位4ビットを0とし、下位4ビットはr0〜r7までのレジスタの値を代入しています。13行目でiが0〜7までカウントアップを繰り返す中、それぞれのレジスタを表示する順番が来たらそのビットを1から0にします。すると、rowはカソードに接続されていますので、col側との電位差が生じそのドットのLEDが点灯するという仕掛けです。
ただこの書き方はポータビリティーの点で問題を起こす可能性があります。この記述でうまくいかない場合は「i!=7」のところを「(i==7)?0:1」としてください。
14行目は、Tang Nano搭載の6個並んだオレンジのLEDの最下位にオーバーフローを示すc_flagの値を反映するようにしています。ちなみに上位5ビットまでは消灯するように設定しています。リスト2は4行と短いコードですが、密度の高い仕事をさせています。
CPUの動作の記述
行番号の順番でいくと説明が前後しますが、30〜49行目に当たるリスト3ではCPUに関わる動作を記述しています。
30行目でdoutにメモリからフェッチしてきた命令セットをセットします。regs[7]は現在のプログラムカウンターの値が定義されています。31行目ではcounter[23]の値の立ち上がりまたはrstの立ち下がりで32行以下のブロックが実行されます。32行目でrstの値が0、すなわちリセットのタクトスイッチが押された状態であればレジスタ群とキャリーフラグを0にします。そうでなければ34〜48行目のコードを実行します。
34行目では、外部入力である4ビットのスイッチの値をregs[5]に格納します。今回は未接続なので全て1がregs[5]に格納されます。34〜48行目は命令セットのデコードと実行を行っています。これらの説明は連載第2回記事で説明しているのでここでは省きます。39行目は、クロック(clk)の立ち上がりでcounterのカウントアップを行っています。
30: assign dout = ram[regs[7]]; 31: always @(posedge counter[23] or negedge rst) 32: if(rst==0) {regs[0],regs[1],regs[2],regs[3],regs[4],regs[6],regs[7],c_flag}=0; 33: else begin 34: regs[5]=btn; 35: /*MOV*/ if (0==(dout&192)) regs[(dout&56)>>3]=regs[dout&7]; 36: /*ADD*/ if (64==(dout&248)) begin if (regs[0]+regs[dout&7]>15) c_flag=1;regs[0]=regs[dout&7]+regs[0];end 37: /*OR*/ if (72==(dout&248)) regs[0]=regs[0]|regs[dout&7]; 38: /*AND*/ if (80==(dout&248)) regs[0]=regs[0]®s[dout&7]; 39: /*XOR*/ if (88==(dout&248)) regs[0]=regs[0]^regs[dout&7]; 40: /*NOT*/ if (104==(dout&248)) regs[dout&7]=~regs[dout&7]; 41: /*RLOTATE*/ if (112==(dout&248)) regs[dout&7]=((regs[dout&7])>>1)|((regs[dout&7]&1) << 3); 42: /*LLOTATE*/ if (120==(dout&248)) regs[dout&7]=((regs[dout&7])<<1)|((regs[dout&7]&8) >> 3); 43: /*INC*/ if (96==(dout&248)) begin if (regs[dout&7]+1>15) c_flag=1;regs[dout&7]=regs[dout&7]+1;end 44: /*JMP*/ if (144==(dout&240)) regs[7]=dout&15; 45: /*MVI*/ if (160==(dout&240)) regs[0]=dout&15; 46: /*JNC*/ if (128==(dout&240)) begin regs[7]=((c_flag)?regs[7]+1:dout&15);c_flag=0;end 47: /*PC++*/ if ((144!=(dout&240)&&(128!=(dout&240)))) regs[7]=regs[7]+1; 48: end 49: always @(posedge clk) counter <= counter + 1;
Copyright © ITmedia, Inc. All Rights Reserved.