【原创】DE2实验解答—lab09 (Quartus II)(Verilog HDL)(Digital Logic)
Laboratory Exercise 9
简单的处理器
图1所示的数字系统包含一些16位的寄存器,一个多选器,一个加/减单元,一个计数器和一个控制单元。数据通过16位的DIN输入。经由16位的多选器,数据可加载到多个寄存器,比如:R0,… ,R7和A。当然,多选器也可以使数据从一个寄存器传输到另一个寄存器。图中多选器的输出叫做总线,通常用来作为数据通道。
加法器或减法器的执行过程:首先通过多选器加载一个16位的数字到寄存器A。然后在总线上加载另一个16位的数字。加/减单元执行指定的运算,结果输出到寄存器G。G中的数据可按需求传输到其他寄存器。
由控制单元决定每个时钟系统执行的操作。指定的数据何时加载到总线上和用哪个寄存器加载数据都由控制单元决定。比如:若控制单元指定信号R0out和Ain有效,那木多选器将把寄存器R0的数据放到总线上并且在下一个有效时钟沿这个数据加载到寄存器A。
类似这样的系统通常叫做处理器。它以指令形式执行操作。表1列出本练习所支持的指令。左列是指令名称和操作数。RX←[RY]的含义是将寄存器RY的数据加载到寄存器RX。指令mv的功能是将数据从一个寄存器复制到另一个寄存器。指令mvi是将常量加载到寄存器。
每条指令以9位的IIIXXXYYY的形式存储在IR寄存器中,III表示指令,XXX表示RX寄存器,YYY表示RY寄存器。虽然4条指令只需要2位就可以编码,为后续练习将要添加的指令,我们使用3位来编码。因此,IR必须连接到DIN的16位中的9位,如图一所示。对于mvi指令来说,YYY无含义并且立即数#D必须在mvi指令存储到IR后加载到16位的DIN。
有些指令,比如加、减,要在总线上多次传输数据,需要多于一个时钟周期才能完成。控制单元使用一个2位的计数器来逐步执行这些指令。当Run信号有效,处理器开始执行DIN输入指令;当指令结束,Done置位。表2列出在表1的指令执行中每步有效的控制信号。注意在最开始只有控制信号IRin有效,表中未列出。
Part I
设计并实现图1所示的处理器。
1. 为本练习创建一个新工程。
2. 生成相应的Verilog文件,编译。
3. 对代码进行功能仿真。
4. 创建一个新工程,例化本电路。对应DE2的资源添加相应的输入/出。
SW15-0 |
DIN |
SW17 |
Run |
KEY0 |
Resetn |
KEY1 |
Clock |
LEDR15-0 |
Buswires |
LEDR17 |
Done |
5. 分配引脚,编译、下载。
6. 测试。
代码part 1:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 // a simple processor
2 //可以实现4种指令。
3
4 module proc(DIN,Resetn,Clock,Run,Done,BusWires);
5 input [15:0] DIN; //16-bit数据输入
6 input Resetn,Clock,Run;
7 output Done;
8 output [15:0] BusWires;
9
10 //declare variables
11
12 reg [15:0] BusWires;
13 reg [0:7] Rin,Rout; //8个16-bit寄存器的输入/出控制
14 reg [15:0] Sum;
15 reg IRin,Done,DINout,Ain,Gin,Gout,AddSub;
16 wire [1:0] Tstep_Q; //4个阶段计数输出
17 wire [2:0] I; //3-bit指令码
18 wire [0:7] Xreg,Yreg; //2个8-bit寄存器
19 wire [15:0] R0,R1,R2,R3,R4,R5,R6,R7,A,G; //9个16-bit寄存器
20 wire [1:9] IR; //IIIXXXYYY
21 wire [1:10] Sel; //多路器的选择位
22
23 wire Clear=~Resetn | Done | (~Run & ~Tstep_Q[1] & ~Tstep_Q[0]); //clear
24 upcount Tstep(Clear,Clock,Tstep_Q); //T0-T3 4个阶段
25 assign I=IR[1:3]; //指令位
26 dec3to8 decX(IR[4:6],1'b1,Xreg); //译码,用于选择R0-R7
27 dec3to8 decY(IR[7:9],1'b1,Yreg);
28
29 //指令列表:
30 //000: mv
31 //001: mvi
32 //010: add
33 //011: sub
34
35 always @(Tstep_Q or I or Xreg or Yreg)
36 begin
37 //specify initial values
38 Done=1'b0;
39 Ain=1'b0;
40 Gin=1'b0;
41 Gout=1'b0;
42 AddSub=1'b0;
43 IRin=1'b0;
44 DINout=1'b0;
45 Rin=8'b0;
46 Rout=8'b0;
47
48 case(Tstep_Q)
49 2'b00: //store DIN in IR in time step 0
50 begin
51 IRin=1'b1;
52 end
53 2'b01: //define signals in time step 1
54 case(I)
55 3'b000: //mv Rx,Ry
56 begin
57 Rout=Yreg;
58 Rin=Xreg;
59 Done=1'b1;
60 end
61 3'b001: //mvi Rx,#D
62 begin
63 DINout=1'b1;
64 Rin=Xreg;
65 Done=1'b1;
66 end
67 3'b010,2'b011: //add,sub
68 begin
69 Rout=Xreg;
70 Ain=1'b1;
71 end
72 default: ;
73 endcase
74 2'b10: //define signals in time step 2
75 case(I)
76 3'b010: //add
77 begin
78 Rout=Yreg;
79 Gin=1'b1;
80 end
81 3'b011: //sub
82 begin
83 Rout=Yreg;
84 AddSub=1'b1;
85 Gin=1'b1;
86 end
87 default: ;
88 endcase
89 2'b11: //define signals in time step 3
90 case(I)
91 3'b010,3'b011: //add,sub
92 begin
93 Gout=1'b1;
94 Rin=Xreg;
95 Done=1'b1;
96 end
97 default: ;
98 endcase
99 endcase
100 end
101
102 regn reg_0(BusWires,Rin[0],Clock,R0);
103 //instantiate other registers and the adder/subtracter unit
104 regn reg_1(BusWires,Rin[1],Clock,R1);
105 regn reg_2(BusWires,Rin[2],Clock,R2);
106 regn reg_3(BusWires,Rin[3],Clock,R3);
107 regn reg_4(BusWires,Rin[4],Clock,R4);
108 regn reg_5(BusWires,Rin[5],Clock,R5);
109 regn reg_6(BusWires,Rin[6],Clock,R6);
110 regn reg_7(BusWires,Rin[7],Clock,R7);
111 regn reg_A(BusWires,Ain,Clock,A);
112 regn #(.n(9)) reg_IR(DIN[15:7],IRin,Clock,IR);
113
114 //alu
115 always @(AddSub or A or BusWires)
116 begin
117 if(!AddSub)
118 Sum=A+BusWires;
119 else
120 Sum=A-BusWires;
121 end
122
123 regn reg_G(Sum,Gin,Clock,G);
124
125 //define the bus
126 assign Sel={Rout,Gout,DINout};
127
128 always @(*)
129 begin
130 if(Sel==10'b10_0000_0000)
131 BusWires=R0;
132 else if(Sel==10'b01_0000_0000)
133 BusWires=R1;
134 else if(Sel==10'b00_1000_0000)
135 BusWires=R2;
136 else if(Sel==10'b00_0100_0000)
137 BusWires=R3;
138 else if(Sel==10'b00_0010_0000)
139 BusWires=R4;
140 else if(Sel==10'b00_0001_0000)
141 BusWires=R5;
142 else if(Sel==10'b00_0000_1000)
143 BusWires=R6;
144 else if(Sel==10'b00_0000_0100)
145 BusWires=R7;
146 else if(Sel==10'b00_0000_0010)
147 BusWires=G;
148 else
149 BusWires=DIN;
150 end
151 endmodule
152
153 module upcount(Clear,Clock,Q);
154 input Clear,Clock;
155 output [1:0] Q;
156 reg [1:0] Q;
157
158 always @(posedge Clock)
159 if(Clear)
160 Q<=2'b0;
161 else
162 Q<=Q+1'b1;
163 endmodule
164
165 module dec3to8(W,En,Y);
166 input [2:0] W;
167 input En;
168 output [0:7] Y;
169 reg [0:7] Y;
170
171 always @(W or En)
172 begin
173 if(En==1)
174 case(W)
175 3'b000: Y=8'b1000_0000;
176 3'b001: Y=8'b0100_0000;
177 3'b010: Y=8'b0010_0000;
178 3'b011: Y=8'b0001_0000;
179 3'b100: Y=8'b0000_1000;
180 3'b101: Y=8'b0000_0100;
181 3'b110: Y=8'b0000_0010;
182 3'b111: Y=8'b0000_0001;
183 endcase
184 else
185 Y=8'b0000_0000;
186 end
187 endmodule
188
189 module regn(R,Rin,Clock,Q);
190 parameter n=16;
191 input [n-1:0] R;
192 input Rin,Clock;
193 output [n-1:0] Q;
194 reg [n-1:0] Q;
195
196 always @(posedge Clock)
197 if(Rin)
198 Q<=R;
199 endmodule
200
仿真结果:
例化:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //part 1 top module
2
3 module part1(SW,KEY,LEDR);
4 input [17:0] SW;
5 input [1:0] KEY;
6 output [17:0] LEDR;
7
8 proc u0(
9 .DIN(SW[15:0]),
10 .Resetn(KEY[0]),
11 .Clock(KEY[1]),
12 .Run(SW[17]),
13 .Done(LEDR[17]),
14 .BusWires(LEDR[15:0])
15 );
16
17 endmodule
18
19
Part II
本练习给处理器外加一个只读存储器和计数器,计数器用来产生存储器的地址。存储器为32*16-bit。
代码part 2:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //part 2 top module
2 //加上外部存储器的处理器
3
4 //引脚说明:
5 //--------------------------------------------------------
6 // SW17-Run KEY0-Resetn KEY1-MClock
7 // KEY2-PClock LEDR15-0-BusWires LEDR17-Done
8
9 module part2(
10 input [2:0] KEY,
11 input [17:17] SW,
12 output [17:0] LEDR
13 );
14
15 wire Done,Resetn,PClock,MClock,Run;
16 wire [15:0] DIN,BusWires;
17 wire [4:0] pc; //计数输出,srom的地址0-31
18
19 assign Resetn=KEY[0];
20 assign PClock=KEY[0]; //processor的时钟
21 assign MClock=KEY[2]; //srom的时钟
22 assign Run=SW[17];
23
24 proc m0(DIN,Resetn,PClock,Run,Done,Buswires);
25 assign LEDR[15:0] =BusWires;
26 assign LEDR[17]=Done;
27
28 sromlpm m1(pc,MClock,DIN);
29 count5 m2(Resetn,MClock,pc);
30
31 endmodule
32
33 //count5
34 module count5(Resetn,Clock,Q);
35 input Resetn,Clock;
36 output reg [4:0] Q;
37
38 always @(posedge Clock)
39 if(Resetn==0)
40 Q<=5'b0;
41 else
42 Q<=Q+1'b1;
43 endmodule
44
45
46
47
Conclusion
本实验把简单的处理器拆解成基本逻辑电路。单个实现不难,主要是对控制电路的理解,实现处理器分步执行的概念。
Reference
《数字逻辑基础与Verilog设计》2nd ,ch 7.14.2 夏宇闻 译。