AHDLによるK-COMの設計
K-COMの全回路構成を図1のように設計した.そのAHDLによる記述例をリスト1に示す.
図1 K-COMの全回路構成
クロック
クロックはボードに装備された発振器(OSC)により供給した.クロックはD-FFを二つを用いて分周され, 半周期ずれた正論理の信号が作られている.選択信号とトリガ信号が,それぞれs_clkとt_clkの出力である.強制終了(halt)のため,二つのD-FFのクロック信号にはhaltの反転との論理積を供給している.
ALUおよびアキュームレータ
ALUおよびアキュームレータについて説明する.データのビット数は8ビットであり,論理演算時は8ビットのデータにより各ビットの計算を行えばよいが, 算術演算時の桁上がりを得るため1ビット足して,合計9ビットの算術演算回路を作成し, 8ビットまでを計算結果とし,9ビットめをキャリー信号に接続している.
命令レジスタの上位3ビットで場合分けして,CASE文により演算処理を記述した. shift命令時は命令レジスタの下位5ビットがシフトの方向を決めるので, 更にIF文によりシフト方向別の記述を行った.
STORE命令時はアキュームレータのデータがALUを素通りするが, この場合はCASE文のWHEN OTHERSの項で記述している.
その他,keygu,keygl信号は,FPGAボードの入力キーを動作させるための信号である.
プログラムカウンタおよび命令レジスタ
次に,プログラムカウンタおよび命令レジスタのについて説明する.プロプログラムカウンタは,通常クロックによりカウントアップしているが, ジャンプ時(ロード信号発生時)に命令レジスタの下位5ビットがプログラムカウンタに転送される.
命令レジスタの全ビットが1の時は強制停止信号(halt)が生成される.
メモリおよびI/Oポート
メモリおよびI/Oポートについて説明する.K-COMの仕様ではメモリ領域は特にROM,RAMの区別がされていないが, 全てのメモリ領域をRAMとするとプログラム書き込みのための回路が別途必要なので, メモリ領域をプログラム格納と定数データ用のROM領域と変数データ用のRAM領域に分けて記述した. CASE文でアドレスに応じた領域の記述を行い,ROM領域を選択された時は固定データを返す. ROM領域にはあらかじめプログラムを書き込んである. RAM領域はD-FFにより作成し,8ビット×RAM領域のバイト数で使用するD-FFのビット数をのみを宣言して, 不要な回路の生成を省いた.
コントローラ
コントローラはステートマシンとして記述される.フェッチサイクルが2サイクル,実行サイクルが最大2サイクルであるので合計4状態となり, S0からS3のステートマシンとして記述されている. データ転送を行うためのレジスタ及びメモリのイネーブル信号が選択信号(select)の値により制御される. 合計8本の選択信号でK-COMの全メモリ及びレジスタの制御が可能で,選択信号の割り当ては, コメントブロックに記述されている.
ステートマシンの状態遷移がTABLE文によって記述され,フェッチ動作,実行動作及び, その時の選択信号が同一のTABLE文で記述されている. feはフェッチまたは実行動作を外部に示す出力線である. K-COMでは,ALU出力とメモリ出力の双方がトライステートバッファによりデータバスに接続される構造を とっているが,それらの接続制御もコントローラにより行われる. その他,ledclkl信号は,FPGAボードのLEDを動作させるための信号である.
リスト1 K-COMのAHDL記述
SUBDESIGN k_com ( clock : INPUT; % clock assigned as OSC % reset : INPUT; % reset assigned as TS4 % in_port[7..0] : INPUT; % input port assigned as KU7-KU0 % keygu : OUTPUT; % KEYGU used to enable KU7-KU0 % out_port[7..0] : OUTPUT; % output port assigned as SG4 and SG3 % pc[4..0] : OUTPUT; % program counter assigned as SG2 and SG1 % halt : OUTPUT; % halt assigned as LED4 % fe : OUTPUT; % fe=(1:fetch, 0:exec) assigned as LED3 % c : OUTPUT; % carry flag assigned as LED2 % z : OUTPUT; % zero flag assigned as LED1 % ) VARIABLE % Clock generatior % s_clk : DFF; % select clock for controller % t_clk : DFF; % trigger clock for register and flag latch % % Register % pc[4..0] : DFFE; % Program counter % ir[7..0] : DFFE; % Instruction register % acc[7..0] : DFFE; % Accumlator % alu[7..0] : DFFE; % ALU latch % % flag register % c : DFFE; % carry flag % z : DFFE; % Zero flag % % memory I/O % mem[7..0] : DFFE; % if use RAM, define mem[] and modify memory section % out_port[7..0] : DFFE; % output port mapped on memory map % % NODE % mem_in[7..0], mem_out[7..0] : NODE; % memory input and output nodes % acc_c[8..0], mem_c[8..0], alu_c[8..0] : NODE; % for arith. cal. in ALU section % a_bus[4..0] : NODE; % address bus from PC or IR_L % select[7..0] : NODE; % control signal to select active resgister % % state machine % ss: MACHINE OF BITS(state[1..0]) WITH STATES(s0 = B"00", % fetch cycle: IR <- mem(PC) % s1 = B"01", % fetch cycle: pc <- pc +1 % s2 = B"10", % exec cycle 1 % s3 = B"11"); % exec cycle 2 % BEGIN % key enable % keygu = GND; % Clock generator % s_clk.clrn = !reset; t_clk.clrn = !reset; s_clk.d = !s_clk.q; t_clk.d = !t_clk.q; s_clk.clk = !halt & clock; % trigger delayed half period % t_clk.clk = !halt & !clock; % clock disenabled with halt % % Register % acc[].clrn = !reset; acc[].clk = t_clk.q; acc[].ena = select[6]; ir[].clrn = !reset; ir[].clk = t_clk.q; ir[].ena = select[3]; halt = (ir[].q == H"FF"); % IR=FF means halt % % PC IR % pc[].clrn = !reset; pc[].clk = t_clk.q; pc[].ena = select[4]; IF select[7] THEN pc[].d = ir[4..0].q; % Jump: JPC or JPNZ % ELSE pc[].d = pc[].q + 1; % count up PC % END IF; IF select[0] THEN a_bus[] = pc[].q; %fetch cycle: read instruction % ELSE a_bus[] = ir[4..0].q; % exec cycle: read opeland % END IF; % ALU % acc_c[7..0] =acc[7..0].q; % add 1 bit for arithmetic cal. % acc_c[8] = GND; mem_c[7..0] = mem_out[7..0]; mem_c[8] = GND; alu[].clk = t_clk.q; alu[].ena = select[5]; c.clk = t_clk.q; z.clk = t_clk.q; c.clrn = !reset; z.clrn = !reset; CASE ir[7..5].q IS WHEN 0 => alu_c[] = acc_c[] + mem_c[]; % arithmetic add % alu[7..0].d=alu_c[7..0]; c.d = alu_c[8]; z.d = (alu_c[7..0] == 0); c.ena = select[5]; z.ena = select[5]; WHEN 1 => alu_c[] = acc_c[] - mem_c[]; % arithmetic sub % alu[7..0].d = alu_c[7..0]; c.d = alu_c[8]; z.d = (alu_c[7..0] == 0); c.ena = select[5]; z.ena = select[5]; WHEN 2 => alu_c[] = acc_c[] !& mem_c[]; % logic NAND % alu[7..0].d = alu_c[7..0]; c.d = alu_c[8]; z.d = (alu_c[7..0] == 0); c.ena = select[5]; z.ena = select[5]; WHEN 3 => IF ( ir[4..0].q ==1 ) THEN alu[6..0].d = acc[7..1].q; % Right shift % alu[7].d = GND; c.d = acc[0].q; z.d = (acc[7..1].q == 0); ELSE alu[7..1].d = acc[6..0].q; % left shift % alu[0].d = GND; c.d = acc[7].q; z.d = (acc[6..0].q == 0); END IF; c.ena = select[5]; z.ena = select[5]; WHEN OTHERS => alu[7..0].d = acc[7..0].q; % store also useing ALU % c.ena = GND; z.ena = GND; END CASE; % Control % % select7: PC load % % select6: ACC latch % % select5: ALU latch % % select4: PC count up or load enable % % select3: IR latch % % select2: memory read/write % % select1: ACC data select from ALU or memory % % select0: address select PC(1) or IR_L(0) % ss.clk = s_clk.q; ss.reset = reset; TABLE ss, ir[7..5].q, c, z => select[7..0], ss, fe; s0, B"XXX", X, X => B"00001001", s1, 1; s1, B"XXX", X, X => B"00010000", s2, 0; s2, B"0XX", X, X => B"00100000", s3, 0; s3, B"0XX", X, X => B"01000010", s0, 1; s2, B"100", X, X => B"01000000", s0, 1; s2, B"101", X, X => B"00100000", s3, 0; s3, B"101", X, X => B"00000110", s0, 1; s2, B"110", 0, X => B"00000000", s0, 1; s2, B"110", 1, X => B"10010000", s0, 1; s2, B"111", X, 0 => B"10010000", s0, 1; s2, B"111", X, 1 => B"00000000", s0, 1; END TABLE; CASE select[2..1] IS WHEN 0 => acc[].d = mem_out[]; % ACC & IR read from memory % WHEN 1 => acc[].d = alu[].q; % ACC read from ALU % WHEN 2 => mem_in[] = alu[].q; % ALU write to memory % WHEN 3 => mem_in[] = alu[].q; % ALU write to memory % END CASE; % Memory % mem[].clk = t_clk.q; out_port[].clk = t_clk.q; ir[].d=mem_out[]; CASE a_bus[] IS % ROM section % WHEN 0 => mem_out[] = H"84"; WHEN 1 => mem_out[] = H"05"; WHEN 2 => mem_out[] = H"BF"; WHEN 3 => mem_out[] = H"FF"; WHEN 4 => mem_out[] = H"01"; WHEN 5 => mem_out[] = H"02"; % RAM section % WHEN 6 => mem[7..0].d = mem_in[]; mem[7..0].ena = select[2]; mem_out[] = mem[7..0].q; % Input / Output prot % WHEN 30 => mem_out[] = in_port[]; WHEN 31 => out_port[].d = mem_in[]; out_port[].ena = select[2]; % data fix to FF, when ther addres accessed % WHEN OTHERS =>mem_out[] = H"FF"; END CASE; END;
ESP32 Wifi Bluetooth開発ボード |
Arduino Nano Every |
Raspberry Pi pico |
FPGA XILINX Artix-7 |