Skip to content
This repository was archived by the owner on Jul 3, 2021. It is now read-only.

Commit becda8c

Browse files
committed
Initial commit
0 parents  commit becda8c

17 files changed

+8425
-0
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

ALU.v

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module ALU(
2+
input wire [7:0] A,
3+
input wire [7:0] B,
4+
input wire [3:0] op, //功能码,选择运算类型(预留4位,实际1位就行)
5+
output wire [7:0] E,
6+
output wire [1:0] cc //编码两个操作数,左边用于标识AB是否相等,相等的话为1.
7+
//右边用于标识A是否大于B,1表示A大于B,0表示A小于B
8+
9+
);
10+
assign E = ( op == 4'h0 )? A+B :
11+
(op == 4'h1) ? A-B : 8'hxx;
12+
13+
assign cc = {A==B,A>B} ; //拼接运算符
14+
15+
endmodule
16+
17+
//OP=0000 加法 A+B
18+
//OP=0001 减法 A-B
19+
//否则:不定值,以后扩充运算符

PC.v

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//用于给出指令在指令储存器中的地址
2+
//在时钟信号的上升沿更新,而且需要一个控制信号,在控制信号为0的时候初始化PC寄存器
3+
module PC(
4+
input wire [7:0] new_pc, //目标地址,可能是跳转地址或者是下一条指令的地址
5+
output reg [7:0] pc, //指令地址,输出信号
6+
input wire clk, //时钟周期
7+
input wire rst_
8+
);
9+
always @(posedge clk or negedge rst_)
10+
begin
11+
if(rst_==1'b0)
12+
begin
13+
pc<=0;
14+
end
15+
else //返回指令地址
16+
begin
17+
pc<=new_pc;
18+
end
19+
end
20+
21+
endmodule

RAM.v

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module RAM(
2+
input wire [7:0] addr, //地址总线
3+
input wire [7:0] in, //数据总线
4+
output wire [7:0] out, //数据输出
5+
input wire rd_, //控制读信号(低电平有效)
6+
input wire wr_, //控制写信号(低电平有效)
7+
input wire clk
8+
);
9+
reg [7:0] mem [0:255]; //存储单元,共256个,每一个8位
10+
11+
assign out = (rd_==1'b0)? mem[addr] : 8'hxx; //读数据
12+
13+
always @(posedge clk)
14+
if(wr_==1'b0) //写信号有效时写入数据
15+
mem[addr] <= in; //线网型尽可能连续赋值
16+
17+
endmodule

REGFILE.v

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module REGFILE(
2+
input wire [2:0] srcA,
3+
input wire [2:0] srcB,
4+
output wire [7:0] A,
5+
output wire [7:0] B,
6+
input wire [2:0] dstM,
7+
input wire [2:0] dstE,
8+
input wire [7:0] M,
9+
input wire [7:0] E,
10+
input wire clk
11+
);
12+
13+
reg [7:0] rf [0:7];
14+
assign A = (srcA==3'b000)? 8'h00 : rf[srcA]; //如果srcA是0必须返回一个零值
15+
assign B = (srcB==3'o0)? 8'h00 : rf[srcB]; //同上
16+
17+
always @(posedge clk)
18+
begin
19+
if(dstM!=3'o0)
20+
rf[dstM] <= M;
21+
if(dstE!=3'o0 && dstE!=dstM) //如果两个地址是同一个地址,需要有一个优先级(POP指令会涉及),令M端口优先(栈顶的值存入EXP中)
22+
rf[dstE] <= E;
23+
end
24+
endmodule

ROM.v

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module ROM(
2+
input wire [7:0] addr, //8位地址输入
3+
output wire [23 :0] out //需要输出一整条指令,需要三个字节24位
4+
);
5+
6+
reg [7:0] mem [0:255]; //存储单元
7+
8+
assign out = {mem[addr],mem[addr+1],mem[addr+2]}; //连续输出三个字节
9+
10+
initial
11+
$readmemh("rom.txt",mem,0,255); //利用系统任务读入
12+
13+
endmodule

TINYCPU.v

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
`include "tinyCPU.h"
2+
3+
`define ins rom_data[23:20] // -> icode (ROM中高四位)
4+
`define fun rom_data[19:16] // -> ifun (ROM中低四位),功能码
5+
`define rA rom_data[14:12] //只用3位来表示Ra(一共8个寄存器,3位寻址)
6+
`define rB rom_data[10:8] //只用3位
7+
`define rC rom_data[6:4] //第三个字节高四位的低三位用来表示rC
8+
9+
module TINYCPU(
10+
//连接RAM端口
11+
output wire [7:0] ram_addr, //写RAM地址
12+
output wire [7:0] ram_wdat, //向RAM写数据总线
13+
input wire [7:0] ram_rdat, //读总线
14+
output wire ram_rd_,ram_wr_, //控制信号
15+
16+
//连接ROM端口
17+
output wire [7:0] rom_addr,
18+
input wire [23:0] rom_data,
19+
20+
//时钟信号与复位信号(CPU复位->PC寄存器置0,从0取出第一条地址)
21+
input wire clk,rst_
22+
);
23+
24+
wire [7:0] valA,valB,valC,valP,valE,valM,aluB,new_pc;
25+
wire [1:0] cc;
26+
wire [2:0] dstE, dstM;
27+
28+
PC pc( .new_pc(new_pc),.pc(rom_addr),.clk(clk),.rst_(rst_)); //实例化一个PC寄存器
29+
30+
assign valC = (`ins==`JXX && `fun==`JMP) ? rom_data[15:8] : rom_data[7:0]; //如果取出来了一个无条件转移指令,输出第二个字节,否则其他的是第三个字节
31+
32+
assign valP = rom_addr + ((`ins==`HLT )? 0:
33+
(`ins==`NOP )? 1:
34+
(`ins==`JXX && `fun==`JMP) ? 2:3); //下一条指令的地址
35+
36+
REGFILE regfile(.srcA(`rA),.srcB(`rB),.A(valA),.B(valB),.dstM(dstM),.dstE(dstE),.M(valM),.E(valE),.clk(clk) ); //实例化译码器,虽然全部读出来了但是不一定全都用,这样可以简化电路
37+
38+
assign aluB= (`ins==`LD||`ins==`ST||`ins==`OPI)?valC:valB; //状态信号
39+
40+
ALU alu(.A(valA),.B(aluB),.op(`fun),.E(valE),.cc(cc)); //实例化一个运算器
41+
//访存阶段:
42+
assign ram_addr=valE; //地址就是运算器输出的结果
43+
assign ram_wdat=valB;
44+
assign valM=ram_rdat; //从RAM读出来的值写到valM端口
45+
assign ram_rd_ = (`ins==`LD) ? 1'b0 : 1'b1; //LD命令,rd_信号有效
46+
assign ram_wr_ = (`ins==`ST) ? 1'b0 : 1'b1;
47+
//写回阶段:
48+
assign dstM = (`ins==`LD) ? `rB : 3'o0; //代替写使能信号,不是LD的话全写0,表示不写入寄存器
49+
assign dstE = (`ins==`OPR) ? `rC :
50+
(`ins==`OPI) ? `rB : 3'o0;
51+
//其他指令不应该修改寄存器内容
52+
assign new_pc= (
53+
(`ins == `JXX && `fun == `JMP)||
54+
(`ins == `JXX && `fun == `BEQ && cc[1:1])||
55+
(`ins == `JXX && `fun == `BNE && ~cc[1:1])||
56+
(`ins == `JXX && `fun == `BLT && ~cc[1:1] && ~cc[0:0])||
57+
(`ins == `JXX && `fun == `BGT && ~cc[1:1] && cc[0:0]))? valC :valP;
58+
//如果成功转移则为valC,不转移则为下一条指令valP
59+
60+
endmodule

0 commit comments

Comments
 (0)