Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- `timescale 1ns / 1ps
- /*
- * ALU for simple 8-bit CPU.
- */
- module alu (input [7:0] a,b,
- input [3:0] opcode,
- output reg [7:0] y);
- /* Decode the instruction */
- always @*
- case (opcode)
- 4'h0 /* OR */: y <= a | b;
- 4'h1 /* AND */: y <= a & b;
- 4'h2 /* NOTA */: y <= ~a;
- 4'h3 /* XOR */: y <= a ^ b;
- 4'h4 /* ADD */: y <= a + b;
- 4'h5 /* SUB */: y <= a - b;
- 4'h6 /* RSHIFT1 */: y <= a >> 1;
- 4'h7 /* RSHIFTN */: y <= a >> b;
- default: y <= 8'bZ;
- endcase
- endmodule //alu
- /*
- * Control Unit for simple 8-bit CPU.
- */
- module control ( input clk, reset, interrupt,
- input [7:0] datamem_data, datamem_address, regfile_out1, regfile_out2, alu_out,
- output reg [3:0] alu_opcode,
- output reg [7:0] regfile_data, output [7:0] usermem_data,
- output reg [1:0] regfile_read1, regfile_read2, regfile_writereg,
- output reg [7:0] usermem_address, pc_jmpaddr,
- output reg rw, regfile_regwrite, pc_jump);
- /* Flags */
- reg [1:0] stage;
- reg [7:0] instruction_c;
- reg [7:0] instruction;
- reg [7:0] prevaddr;
- reg [7:0] umd;
- parameter STAGE1 = 0, STAGE2 = 1, RESET = 2, INTERRUPT=3;
- assign usermem_data=rw?umd:8'bz;
- reg is_onecyc, is_rts;
- always @(*) begin
- if (stage==2'b00) begin
- instruction_c<=datamem_data;
- is_onecyc <= (datamem_data[7:4] <= 4'h7);
- is_rts <= (datamem_data == 4'hb);
- end
- end
- always @(posedge clk)
- begin
- /* Check for reset*/
- if(reset == 1)
- begin
- stage <= 2'b10;
- end
- else if(interrupt == 1)
- begin
- stage <=2'b11;
- end
- /* Stage 1: Fetch instruction, execute it in case it does not require an operand: */
- case (stage)
- STAGE1:
- begin
- // $display("Stage 1!");
- pc_jump <= 0;
- rw <=0 ;
- instruction <= datamem_data;
- if (is_onecyc)
- begin
- // $display("No-Operand instruction will be executed!");
- rw <= 0;
- regfile_regwrite <= 1;
- regfile_read1 <= instruction_c[3:2];
- regfile_read2 <= instruction_c[1:0];
- alu_opcode <= instruction_c[7:4];
- regfile_writereg <= instruction_c[1:0];
- regfile_data <= alu_out;
- stage <= 0;
- end
- else if (is_onecyc==0)
- if (is_rts) /* RTS */
- begin
- pc_jump <= 1;
- pc_jmpaddr <= prevaddr;
- stage <= 0;
- end
- else
- stage <= 1;
- end
- STAGE2:
- begin
- // $display("Stage 2!");
- case (instruction_c[7:4])
- 4'h8 /* LD */:
- begin
- rw <= 0;
- regfile_writereg <= instruction[1:0];
- regfile_regwrite <= 1;
- regfile_data <= datamem_data;
- end
- 4'h9 /* JMP */:
- begin
- rw <= 0;
- pc_jump <= 1;
- pc_jmpaddr <= datamem_data;
- end
- 4'ha /* CALL */:
- begin
- rw <= 0;
- prevaddr <= datamem_address + 1;
- pc_jump <= 1;
- pc_jmpaddr <= datamem_data;
- end
- 4'hc /* BEQ */:
- begin
- rw <= 0;
- regfile_regwrite <= 0;
- regfile_read1 <= instruction[3:2];
- regfile_read2 <= instruction[1:0];
- if(regfile_out1 == regfile_out2)
- begin
- prevaddr <= datamem_address + 1;
- pc_jump <= 1;
- pc_jmpaddr <= datamem_data;
- end
- end
- 4'hd /* BNE */:
- begin
- rw <= 0;
- regfile_regwrite <= 0;
- regfile_read1 <= instruction[3:2];
- regfile_read2 <= instruction[1:0];
- if(regfile_out1 != regfile_out2)
- begin
- prevaddr <= datamem_address + 1;
- pc_jump <= 1;
- pc_jmpaddr <= datamem_data;
- end
- end
- 4'he /* ST */:
- begin
- rw <= 1;
- usermem_address <= datamem_data;
- regfile_read1 <= instruction[3:2];
- umd <= regfile_out1;
- end
- 4'hf /* LDUMEM */:
- begin
- rw <= 0;
- usermem_address <= datamem_data;
- regfile_writereg <= instruction[1:0];
- regfile_regwrite <= 1;
- regfile_data <= usermem_data;
- end
- endcase
- stage <= 2'h0;
- end
- RESET:
- begin
- {instruction, alu_opcode, regfile_data, umd, usermem_address} <= 8'b0;
- {regfile_read1, regfile_read2, regfile_writereg} <= 3'b0;
- {rw, regfile_regwrite, pc_jump} <= 1'b0;
- stage <= 2'b0;
- end
- INTERRUPT:
- begin
- prevaddr <= datamem_address;
- pc_jump <= 1;
- pc_jmpaddr <= 8'hfe;
- end
- endcase
- end
- /* Stage 2: Fetch the operand and execute the relevant instruction: */
- endmodule //control
- module pc(input clk, reset, jump,
- input [7:0] jmpaddr,
- output reg[7:0] data);
- always @(posedge clk) begin
- if (reset == 1)
- data <= 8'b0;
- else if (reset == 0)
- begin
- if (jump == 1)
- data <= jmpaddr;
- else if (jump == 0)
- data <= data + 1;
- end
- end
- endmodule //pc
- /*
- * Register file for simple 8-bit CPU.
- */
- module regfile (input [1:0] readreg1, readreg2, sreadreg1, sreadreg2, writereg,
- input [7:0] data,
- input clk, clr, regwrite,
- output [7:0] read1, read2, sread1, sread2);
- reg [7:0] registerfile [3:0];
- reg [7:0] storeregisterfile [3:0];
- integer i;
- always @(negedge clk) begin
- if(regwrite == 1)
- begin
- registerfile[writereg] <= data;
- storeregisterfile[writereg] <= data;
- end
- if(clr == 1)
- begin
- for(i = 0; i <= 3; i = i + 1)
- begin
- registerfile[i] <= 8'b0;
- storeregisterfile[i] <= 8'b0;
- end
- end
- end
- assign sread1 = storeregisterfile[sreadreg1];
- assign sread2 = storeregisterfile[sreadreg2];
- assign read1 = registerfile[sreadreg1];
- assign read2 = registerfile[sreadreg2];
- endmodule //regfile
- module cpu(input clk, reset, interrupt,
- input [7:0] datamem_data,
- inout [7:0] usermem_data,
- output [7:0] datamem_address, usermem_address,
- output rw);
- wire [1:0] regfile_read1, regfile_read2, regfile_writereg;
- wire [7:0] pc_jumpaddr, regfile_data, regfile_out1, regfile_out2;
- wire [7:0] alu_out;
- wire [3:0] alu_opcode;
- wire pc_jump;
- wire regfile_regwrite;
- pc pc0(clk, reset, pc_jump, pc_jumpaddr, datamem_address);
- regfile reg0(regfile_read1, regfile_read2, regfile_writereg,
- regfile_data, clk, reset, regfile_regwrite,
- regfile_out1, regfile_out2);
- alu alu0(regfile_out1, regfile_out2, alu_opcode, alu_out);
- control cntrl0(clk, reset, interrupt, datamem_data, datamem_address, regfile_out1, regfile_out2,
- alu_out, alu_opcode,
- regfile_data, usermem_data, regfile_read1, regfile_read2,
- regfile_writereg, usermem_address,
- pc_jumpaddr, rw, regfile_regwrite,
- pc_jump);
- endmodule //cpu
- /*
- * Testbench for simple 8-bit CPU.
- */
- // Added small program memory for simulation
- module programmem(input [7:0] pgmaddr, output [7:0] pgmdata);
- reg [7:0] pmemory[255:0];
- assign pgmdata=pmemory[pgmaddr];
- initial
- begin
- pmemory[0]=8'h80; // load from next location
- pmemory[1]=8'hAA;
- pmemory[2]=8'h20; // NOT
- pmemory[3]=8'h90; // jump to 2 (or 0 to reload)
- pmemory[4]=8'h02;
- end
- endmodule
- // Simple user memory for simulation
- module usermem(input clk, input [7:0] uaddr, inout [7:0] udata, input rw);
- reg [7:0] umemory[255:0];
- assign udata=rw?8'bz:umemory[uaddr];
- always @(negedge clk)
- if (rw==1) umemory[uaddr]<=udata;
- initial
- begin
- umemory[0]=8'h00;
- umemory[1]=8'h33;
- umemory[2]=8'hAA;
- end
- endmodule
- module cpu_tb;
- reg clk, reset, interrupt;
- wire [7:0] datamem_data, usermem_data, datamem_address, usermem_address, idata;
- wire rw;
- programmem pgm(datamem_address,idata);
- usermem umem(clk, usermem_address,usermem_data,rw);
- cpu dut0(clk, reset, interrupt, idata, usermem_data,
- datamem_address, usermem_address, rw);
- initial
- begin
- $display("NopCPU testbench. All waveforms will be dumped to the dump.vcd file.");
- clk = 1'b0;
- reset = 1'b1;
- interrupt = 1'b0;
- repeat(4) #10 clk = !clk;
- reset = 1'b0;
- end
- always
- #1 clk = !clk;
- //always
- //#20 interrupt = ~interrupt;
- initial
- #5000 $finish;
- endmodule //cpu_tb
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement