000000 ランダム
 HOME | DIARY | PROFILE 【お気に入りブログ登録】 【ログイン】

CPUを作ろう ~計算機教材とマイコンと電子工作~

K-COMの設計


AHDLによるK-COMの設計



K-COMの全回路構成を図1のように設計した. そのAHDLによる記述例をリスト1に示す.

クロックはボードに装備された発振器(OSC)により供給した.クロックはD-FFを二つを用いて分周され,半周期ずれた正論理の信号が作られている.選択信号とトリガ信号が,それぞれs_clkとt_clkの出力である.強制終了(halt)のため,二つのD-FFのクロック信号にはhaltの反転との論理積を供給している.

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ポートについて説明する.
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を動作させるための信号である.

k-com-block
図1 K-COMの全回路構成



リスト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;


Copyright (c) 1997-2018 Rakuten, Inc. All Rights Reserved.