16ビット版VerilogによるK-COMの設計
本で書いた16ビット版のK-COM16のVerilogによる設計例です. サブルーチンコール,割り込み機能の追加,命令とアドレス空間を拡張しています. (仕様の詳細は書籍をご参照いただければ幸いです)クロックジェネレータ
module clock16(reset, gclk, tclk, sclk ); input reset, gclk; output tclk, sclk; reg tclk, sclk; always @(posedge gclk or posedge reset) if (reset) sclk <=0; else sclk <= ~sclk; always @(negedge gclk or posedge reset) if (reset) tclk <=0; else tclk <= ~tclk; endmoduleプログラムカウンタおよび命令レジスタ
module pcir16(reset, tclk, halt, pc, ir, a_bus, d_bus, select); input reset, tclk; input [9:0] select; input [15:0] d_bus; output halt; output [11:0] a_bus; output [11:0] pc; output [15:0] ir; reg [11:0] pc, as; reg [15:0] ir; always @(posedge tclk or posedge reset) begin if (reset) begin pc<=0; ir<=0; end else begin if(select[4]) begin if(~select[8] & ~select[7]) pc<=pc+12'b1; if(~select[8] & select[7]) pc<=ir[11:0]; if(select[8] & ~select[7]) pc<=as; if(select[8] & select[7]) pc<=12'hf00; end else if(select[9]) as<=pc; else if(select[3]) ir<=d_bus; end end assign a_bus=(select[0]) ? pc: ir[11:0]; assign halt=(ir==12'hfff); endmoduleALUおよびアキュームレータ
module alu16(reset, tclk, ir, select, acc, latch, c, z, d_bus); input reset, tclk; input [9:0] select; input [15:0] ir; output [15:0] acc, latch; output z, c; inout [15:0] d_bus; reg c, sc, z, sz; reg [15:0] acc, sacc, latch; always @(posedge tclk or posedge reset) begin if (reset) begin acc<=0; latch<=0; c<=0; z<=0; end else begin if(select[5]) begin casex(ir[15:12]) 4'b0000: begin {c,latch}<=acc + d_bus; z<=((acc + d_bus)==16'h0000); end 4'b0001: begin {c,latch}<=acc - d_bus; z<=((acc - d_bus)==16'h0000); end 4'b0010: begin {c,latch}<=~(acc & d_bus); z<=(~(acc & d_bus)==16'h0000); end 4'b0011: begin {c,latch}<=acc << 1; z<=((acc <<1 )==16'h0000); end 4'b1110: begin sacc<=acc; sc<=c; sz<=z; end 4'b1111: begin acc<=sacc; c<=sc; z<=sz; end default: latch<=acc; endcase end if(select[6]) acc<=d_bus; end end assign d_bus= (select[1]) ? latch: 16'bz; endmoduleメモリおよびI/Oポート
module mem16(tclk, a_bus, inp, oup, select, d_bus); input tclk; input [11:0] a_bus; input [15:0] inp; input [9:0] select; output [15:0] oup; inout [15:0] d_bus; reg [15:0] mem[6:6] ; // max size ... [0:4095] reg [15:0] oup; function [15:0] memout; // memory read input [11:0] a_bus; case(a_bus) 0:memout =16'h8FFE; // LD FFEH ROM area 1:memout =16'h0006; // ADD 006H 2:memout =16'h9FFF; // ST FFFH 3:memout =16'h2006; // NAND 005H 4:memout =16'hB000; // JPNZ 000H 5:memout =16'h0000; // DB 00 00H 3840:memout =16'hE000; // PUSH interupt routine 3841:memout =16'h8FFE; // LD FFEH 3842:memout =16'h9006; // ST 006H 3843:memout =16'hF000; // PULL 3844:memout =16'hD000; // RET 4094:memout =inp; // input port default: memout = mem[a_bus]; endcase endfunction always @(posedge tclk) begin if(select[2] & select[1]) // memory write if (a_bus==4095) oup<=d_bus; // output port else mem[a_bus]<=d_bus; end assign d_bus = (~select[2] & ~select[1])? memout(a_bus): 16'bz; endmoduleコントローラ
module control16(reset, ipt, sclk, ir, c, z, select, i); input reset, ipt, sclk, c, z; input [15:0] ir; output i; output [9:0] select; reg i; reg [2:0] ss; reg [9:0] select; // details of select signals // select9: AS latch // select8: Return from sub-routine or interrupt // select7: PC count-up or PC load (jump) // select6: ACC latch // select5: ALU latch // select4: PC count up or load enable // select3: IR latch // select2: memory read(0)/write(1) // select1: ACC data select from ALU or memory // select0: address select PC(1) or IR_L(0) always @(posedge sclk or posedge reset) begin if (reset) begin ss<=3'b000; i<=0; end else case (ss) 3'b000: if(ipt & ~i) begin select<=10'b1000000000; ss<=3'b100; i<=1; end // interupt 1: as<-pc else begin select<=10'b0000001001; ss<=3'b001; end // fetch cycle 1 3'b001: begin select<=10'b0000010000; ss<=3'b010; end // fetch cycle 2 3'b010: casex (ir[15:12]) // exec cycle 1 4'b0XXX: begin select<=10'b0000100000; ss<=3'b011; end // alu operation 1 4'b1000: begin select<=10'b0001000000; ss<=3'b000; end // LD 4'b1001: begin select<=10'b0000100000; ss<=3'b011; end // ST 4'b1010: begin if(~c) begin select<=10'b0000000000; ss<=3'b000; end // JPC: c=0, nop if(c) begin select<=10'b0010010000; ss<=3'b000; end // JPC: c=1, jump end 4'b1011: begin if(~z) begin select<=10'b0010010000; ss<=3'b000; end // JPNZ: z=0, jump if(z) begin select<=10'b0000000000; ss<=3'b000; end // JPNZ: z=1, nop end 4'b1100: begin select<=10'b1000000000; ss<=3'b011; end // CALL 1 4'b1101: begin select<=10'b0100010000; ss<=3'b000; i<=0; end // RET 4'b1110: begin select<=10'b0000100000; ss<=3'b000; end // PUSH 4'b1111: begin select<=10'b0001100000; ss<=3'b000; end // PULL endcase 3'b011: casex (ir[15:12]) // exec cycle 2 4'b0XXX: begin select<=10'b0001000010; ss<=3'b000; end // alu operation 2 4'b1001: begin select<=10'b0000000110; ss<=3'b000; end // ST 2 4'b1100: begin select<=10'b0010010000; ss<=3'b000; end // CALL 2 endcase 3'b100: begin select<=10'b0110010000; ss<=3'b000; end // interupt 2: pc<-F000H endcase end endmoduleK-COM16のトップモジュール
module kcom16(reset,ipt,clk,tclk,sclk,a_bus,pc,d_bus,ir,acc,latch,c,z,select,inp,oup,halt,i); input reset, ipt, clk; input [15:0] inp; output tclk, sclk, c, z, halt, i; output [11:0] a_bus, pc; output [9:0] select; output [15:0] d_bus, ir, acc, latch, oup; wire gclk; assign gclk= clk & ~halt; clock16 clock16(reset, gclk, tclk, sclk); pcir16 pcir16(reset, tclk, halt, pc, ir, a_bus, d_bus, select); alu16 alu16(reset, tclk, ir, select, acc, latch, c, z, d_bus); mem16 mem16(tclk, a_bus, inp, oup, select, d_bus); control16 control16(reset, ipt, sclk, ir, c, z, select, i); endmodule
ESP32 Wifi Bluetooth開発ボード |
Arduino Nano Every |
Raspberry Pi pico |
FPGA XILINX Artix-7 |