SystemVeriogでTD4をAltera DE0 Boardに
以前に読んだCPUの創り方という本に載っている4bitのCPU「TD4」をAlteraのFPGA Board DE0に移植してみました。無駄にmoduleの数を増やしています。こことかこことかを参考にしました。
TD4.h
`define OPCODE_WIDTH 4 `define DATA_WIDTH 4
TD4.v
`include "TD4.h" module TD4( input CLK, RST, input [`DATA_WIDTH-1:0] SW, output [9:0] LEDG ); wire [`DATA_WIDTH-1:0] _OUT_, _IN_; wire CLK1Hz; CLKGEN u_clkgen(.*); TD4_CORE u_td4_core (.*, .CLK(CLK1Hz)); // assign LEDG[4] = CLK1Hz; assign LEDG[3:0] = _OUT_; assign LEDG[9:`DATA_WIDTH] = {10-`DATA_WIDTH{1'b0}}; assign _IN_ = SW; endmodule
TD4_CORE.v
`include "TD4.h" module TD4_CORE( input CLK, RST, input [`DATA_WIDTH-1:0] _IN_, output wire [`DATA_WIDTH-1:0] _OUT_ ); wire LOAD0, LOAD1, LOAD2, LOAD3; wire [`DATA_WIDTH-1:0] ALU_IN, ALU_OUT; wire [`DATA_WIDTH-1:0] A, B, IM, PC; wire [`DATA_WIDTH+`OPCODE_WIDTH-1:0] INST; wire [`OPCODE_WIDTH-1:0] OP; wire C, Cnext; assign OP = INST[`DATA_WIDTH+`OPCODE_WIDTH-1:`DATA_WIDTH]; assign IM = INST[`DATA_WIDTH-1:0]; // ROM ROM rom(.*); // OpCode Decode OpDecode u_opdecode (.*); // ALU ALU u_alu (.*); // Register + Register Control RegRW u_regrw(.*); endmodule
OpDecode.v
include "TD4.h" module OpDecode( input [`OPCODE_WIDTH-1:0] OP, input [`DATA_WIDTH-1:0] A, B, _IN_, input C, output wire LOAD0, LOAD1,LOAD2, LOAD3, output wire [`DATA_WIDTH-1:0] ALU_IN ); // Opcode decode assign SELECT_A = OP[0] | OP[3]; assign SELECT_B = OP[0]; assign LOAD0 = OP[2] | OP[3]; assign LOAD1 = ~OP[2] | OP[3]; assign LOAD2 = OP[2] | ~OP[3]; assign LOAD3 = ~OP[2] | ~OP[3] | (~OP[0] & C); // Data selector assign ALU_IN = (~SELECT_B & ~SELECT_A) ? A : (~SELECT_B & SELECT_A) ? B : ( SELECT_B & ~SELECT_A) ? _IN_ : `DATA_WIDTH'd0; endmodule
ALU.v
`include "TD4.h" module ALU( input [`DATA_WIDTH-1:0] ALU_IN, input [`DATA_WIDTH-1:0] IM, output wire [`DATA_WIDTH-1:0] ALU_OUT, output wire Cnext ); // ALU assign {Cnext, ALU_OUT} = {1'b0,ALU_IN}+{1'b0,IM}; endmodule
RegRW.v
`include "TD4.h" module RegRW ( input CLK, RST, input LOAD0, LOAD1, LOAD2, LOAD3, input [`DATA_WIDTH-1:0] ALU_OUT, input Cnext, output reg [`DATA_WIDTH-1:0] A, B, PC, _OUT_, output reg C ); always @(posedge CLK, posedge RST) begin if (RST) begin A <= `DATA_WIDTH'd0; B <= `DATA_WIDTH'd0; PC <= `DATA_WIDTH'd0; C <= Cnext; end else begin if (~LOAD0) A <= ALU_OUT; if (~LOAD1) B <= ALU_OUT; if (~LOAD2) _OUT_ <= ALU_OUT; if (~LOAD3) PC <= ALU_OUT; else PC <= PC + `DATA_WIDTH'd1; C <= Cnext; end end endmodule
ROM.v
`include "TD4.h" module ROM ( input [`DATA_WIDTH-1:0] PC, output [`DATA_WIDTH+`OPCODE_WIDTH-1:0] INST ); reg [`DATA_WIDTH+`OPCODE_WIDTH-1:0] _ROM_ [2**`DATA_WIDTH-1:0]; assign INST = _ROM_[PC]; // Ramen timer initial begin _ROM_[0] = 8'b10110111; // OUT 0111 # LED _ROM_[1] = 8'b00000001; // ADD A,0001 _ROM_[2] = 8'b11100001; // JNC 0001 # loop 16 times _ROM_[3] = 8'b00000001; // ADD A,0001 _ROM_[4] = 8'b11100011; // JNC 0011 # loop 16 times _ROM_[5] = 8'b10110110; // OUT 0110 # LED _ROM_[6] = 8'b00000001; // ADD A,0001 _ROM_[7] = 8'b11100110; // JNC 0110 # loop 16 times _ROM_[8] = 8'b00000001; // ADD A,0001 _ROM_[9] = 8'b11101000; // JNC 1000 # loop 16 times _ROM_[10] = 8'b10110000; // OUT 0000 # LED _ROM_[11] = 8'b10110100; // OUT 0100 # LED _ROM_[12] = 8'b00000001; // AND 0001 _ROM_[13] = 8'b11101010; // JNC 1010 # loop 16 times _ROM_[14] = 8'b10111000; // OUT 1000 # LED _ROM_[15] = 8'b11111111; // JMP 1111 end endmodule
CLKGEN.v
module CLKGEN ( input CLK, RST, output reg CLK1Hz ); reg [25:0] cnt; wire cnt_1Hz; always @(posedge CLK, posedge RST) begin if (RST) begin cnt <= 26'd0; CLK1Hz <= 1'b0; end else begin cnt <= cnt_1Hz ? 26'd0 : cnt+26'd1; CLK1Hz <= cnt >= 26'd25_000_000; end end assign cnt_1Hz = (cnt==26'd49_999_999); endmodule