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