HOME > AHDLによる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;

< 前の記事へ


ページトップに戻る



ESP32 Wifi Bluetooth開発ボード

Arduino Nano Every
​​
Raspberry Pi pico

FPGA XILINX Artix-7