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

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

K-COM4(4ビットCPU)

AHDLによる4ビットCPUの設計


8ビット計算機(K-COM)をもとに,小規模化を目的とした4ビット計算機(K-COM4)を設計した.
変更点は,ALUとデータバスを4ビットに変更した.命令レジスタは8ビットのままとし,4ビットに分割した命令を2回読み込むことで動作するようにした.これに伴い,フェッチサイクルを4サイクルに変更した.実行サイクルは最大で2サイクルであるので,合計で最大6サイクルとなる.
命令コードは8ビット計算機と同じである.

k-com4sm

図1 4ビット計算機の状態遷移図



K-COM4のAHDL記述をリスト1に示す.命令レジスタは8ビット,プログラムカウンタは5ビットでK-COMと変わらないが,その他の8ビットレジスタだったものは,4ビットに変更されている.
ステートマシンは最大の6サイクルなので3ビット必要となり,S0からS5の状態を持つ.
命令レジスタへの命令の読み込みは上位4ビット,下位4ビットの順となっている.メモリへのデータの格納も4ビットずつで,0番地から9番地までROMとしてプログラムを記述した.
RAMは10番地のみ,30番地と31番地はそれぞれ入力ポート,出力ポートである.


リスト1 K-COM4のAHDL記述



SUBDESIGN k_com4
(
clock : INPUT; % clock assigned as OSC %
reset : INPUT; % reset assigned as TS4 %
in_port[3..0] : INPUT; % input port assigned as KU7-KU0 %
out_port[3..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 %
keygu : OUTPUT;
)
VARIABLE
% Clock generatior %
s_clk : DFF; % select clock for controller %
t_clk : DFF; % trigger clock for register and flag latch %
% Registers & flags %
pc[4..0] : DFFE; % Program counter %
ir[7..0] : DFFE; % Instruction register %
acc[3..0] : DFFE; % Accumlator %
alu[3..0] : DFFE; % ALU latch %
c : DFFE; % carry flag %
z : DFFE; % Zero flag %
% memory, I/O %
mem[3..0] : DFFE; % if use RAM, define mem[] and modify memory section %
out_port[3..0] : DFFE; % output port mapped on memory map %
% NODE %
mem_in[3..0], mem_out[3..0] : NODE; % memory input and output nodes %
acc_c[4..0], mem_c[4..0], alu_c[4..0] : NODE; % for arith. cal. in ALU section %
a_bus[4..0] : NODE; % address bus from PC or IR_L %
select[8..0] : NODE; % control signal to select active resgister %
% state machine %
ss: MACHINE WITH STATES(s0, s1, s2, s3, s4, s5);
% s0: fetch cycle, IR(7..4) <- mem(PC) %
% s2: fetch cycle, IR(3..0) <- mem(PC) %
% s1,s3: fetch cycle, pc <- pc +1 %
% s4: exec cycle 1 %
% s5: exec cycle 2%

BEGIN

keygu=GND;

% Clock generator %
s_clk.prn = !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 %

% Registers, halt %
acc[].clrn = !reset;
acc[].clk = t_clk.q;
acc[].ena = select[6];
acc_c[3..0] =acc[3..0].q; % add 1 bit for arithmetic cal. %
acc_c[4] = GND;
mem_c[3..0] = mem_out[3..0];
mem_c[4] = 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;
pc[].clrn = !reset;
pc[].clk = t_clk.q;
pc[].ena = select[4];
ir[].clrn = !reset;
ir[].clk = t_clk.q;
ir[7..4].ena = select[3];
ir[3..0].ena = select[8];
halt = (ir[].q == H"FF"); % IR=FF means halt %

% ALU %
CASE ir[7..5].q IS
WHEN 0 => alu_c[] = acc_c[] + mem_c[]; % arithmetic add%
alu[3..0].d=alu_c[3..0];
c.d = alu_c[4];
z.d = (alu_c[3..0] == 0);
c.ena = select[5];
z.ena = select[5];
WHEN 1 => alu_c[] = acc_c[] - mem_c[]; % arithmetic sub%
alu[3..0].d = alu_c[3..0];
c.d = alu_c[4];
z.d = (alu_c[3..0] == 0);
c.ena = select[5];
z.ena = select[5];
WHEN 2 => alu_c[] = acc_c[] !& mem_c[]; % logic NAND %
alu[3..0].d = alu_c[3..0];
c.d = alu_c[4];
z.d = (alu_c[3..0] == 0);
c.ena = select[5];
z.ena = select[5];
WHEN 3 => IF ( ir[4..0].q == H"1F" ) THEN
alu[2..0].d = acc[3..1].q; % Right shift%
alu[3].d = GND;
c.d = acc[0].q;
z.d = (acc[3..1].q == 0);
ELSE
alu[3..1].d = acc[2..0].q; % left shift%
alu[0].d = GND;
c.d = acc[3].q;
z.d = (acc[2..0].q == 0);
END IF;
c.ena = select[5];
z.ena = select[5];
WHEN OTHERS => alu[3..0].d = acc[3..0].q; % store also useing ALU %
c.ena = GND;
z.ena = GND;
END CASE;


% Control %
ss.clk = s_clk.q;
ss.reset = reset;
TABLE
ss, ir[7..5].q, c, z => select[8..0], ss, fe;
s0, B"XXX", X, X => B"000001001", s1, 1; % select8: IR(3..0) latch%
s1, B"XXX", X, X => B"000010000", s2, 1; % select7: PC load%
s2, B"XXX", X, X => B"100000001", s3, 1; % select6: ACC latch %
s3, B"XXX", X, X => B"000010000", s4, 0; % select5: ALU latch %
s4, B"0XX", X, X => B"000100000", s5, 0; % select4: PC count up or load enable %
s5, B"0XX", X, X => B"001000010", s0, 1; % select3: IR(7..4) latch%
s4, B"100", X, X => B"001000000", s0, 1; % select2: memory read/write %
s4, B"101", X, X => B"000100000", s5, 0; % select1: ACC data select from ALU or memory %
s5, B"101", X, X => B"000000110", s0, 1; % select0: address select PC(1) or IR(4..0)(0) %
s4, B"110", 0, X => B"000000000", s0, 1;
s4, B"110", 1, X => B"010010000", s0, 1;
s4, B"111", X, 0 => B"010010000", s0, 1;
s4, B"111", X, 1 => B"000000000", s0, 1;
END TABLE;

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;
CASE select[2..1] IS
WHEN 0 => acc[].d = mem_out[]; % ACC 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;
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;

% Memory %
mem[].clk = t_clk.q;
out_port[].clk = t_clk.q;
ir[7..4].d=mem_out[];
ir[3..0].d=mem_out[];
CASE a_bus[] IS
WHEN 0 => mem_out[] = H"8"; % ROM section %
WHEN 1 => mem_out[] = H"8";
WHEN 2 => mem_out[] = H"0";
WHEN 3 => mem_out[] = H"9";
WHEN 4 => mem_out[] = H"B";
WHEN 5 => mem_out[] = H"F";
WHEN 6 => mem_out[] = H"F";
WHEN 7 => mem_out[] = H"F";
WHEN 8 => mem_out[] = H"1";
WHEN 9 => mem_out[] = H"2";
WHEN 10 => mem[3..0].d = mem_in[]; mem[3..0].ena = select[2]; mem_out[] = mem[3..0].q; % RAM section %
WHEN 30 => mem_out[] = in_port[]; % Input prot %
WHEN 31 => out_port[].d = mem_in[]; out_port[].ena = select[2]; % Output prot %
WHEN OTHERS =>mem_out[] = H"F"; % data fix to F, when other address is accessed %
END CASE;

END;


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