合肥工业大学计组实验五
Posted 上衫_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了合肥工业大学计组实验五相关的知识,希望对你有一定的参考价值。
step1 分析命令:
这十条命令为:CLA、COM、SHR、CSL、STP、ADD、STA、LDA、JMP、BAN
实现这些命令所需的模块有:PC、ACC、ALU、CU、ROM、RAM
step2 分析模块:
PC
由于PC需要增加停机功能和跳转功能,所以PC应该增加接口来实现停机与跳转指令。
ACC
新增模块ACC,ACC为累加器,CLA、COM、SHR、CSL这四条指令直接操作ACC中的数据,ADD指令将ACC作为操作数,所以ACC应该有一个读数据、一个写数据、使写数据能的接口。(后期实验发现忘记给ACC加一个时钟控制信号了,不加时钟控制信号的话ACC中的数据会出错,一个时钟周期内可能被写两次。)
CU
由于CU要控制ACC和PC完成指令,所以CU应该增加输出来控制ACC和PC。
ALU
ALU需要完成对ACC最高位的判断,并将判断结果传送给PC以便PC完成BAN指令。
其余模块无需改变
step3 新增模块图示:
step4 cpu数据通路设计:
除了图中画红线的其余名字一样的连到一起。
Step5 指令设计:
这次实验我将指令的位数更改为13位,[12:9]为操作码,[8:0]为立即数或地址。
Step6 模块设计:
PC:
1. module PC(
2. input clk,
3. input rst,
4. input stop,
5. input ban,
6. input p_wr_en,
7. input wire [12:0] jmp,
8. output reg [12:0] pc
9. );
10. reg state;
11. initial begin
12. pc=8'd0;
13. state=1;
14. end
15. always@* begin
16. if(stop==1)
17. state<=0;
18. if(rst==1)
19. pc<=0;
20. end
21. always@(posedge clk) begin
22. if(state==1)
23. pc<=pc+1'd1;
24. end
25. always@(negedge clk) begin
26. if(p_wr_en==1)
27. pc<=jmp-1;
28. if(ban==1)
29. pc<=pc+jmp-1;
30. end
31. endmodule
ROM:
1. module ROM(
2. input wire [12:0] pc,
3. output reg [15:0] ins
4. );
5.
6. reg [15:0] ROM_data [255:0];
7. integer i;
8.
9. initial $readmemb("D:/vivadowork/TEN-CPU/ONE_CPU.srcs/sources_1/new/ROM_initial.txt",ROM_data);
10.
11. always@(pc) begin
12. ins<=ROM_data[pc];
13. end
14. endmodule
RAM:
1. module RAM(
2. input clk,
3. input m_wr_en,
4. input wire [15:0] in_data,
5. input wire [8:0] index,
6. output wire [15:0] out_data
7. );
8.
9. reg [15:0] initdata [1023:0];
10. integer i;
11. initial $readmemb("D:/vivadowork/TEN-CPU/ONE_CPU.srcs/sources_1/new/RAM_initial.txt",initdata);
12.
13. always@(posedge clk ) begin
14. begin if (m_wr_en==0)
15. initdata[index]<=in_data;
16. end
17. end
18.
19. assign out_data=initdata[index];
20. endmodule
CU:
根据不同指令输出不同的数据来控制各个模块来完成指令。
1. module CU(
2. input wire [3:0] opcode,
3. output reg p_wr_en,
4. output reg m_wr_en,
5. output reg a_wr_en,
6.
7. output reg stop,
8. output reg [3:0] alu_op
9. );
10. always@(opcode)begin
11. case(opcode)
12. 4'b0001: begin //cla
13. p_wr_en<=0;
14. stop<=0;
15. m_wr_en<=1;
16. a_wr_en<=1;
17. alu_op<=4'b0111;
18. end
19. 4'b0010: begin//com
20. p_wr_en<=0;
21. stop<=0;
22. m_wr_en<=1;
23. a_wr_en<=1;
24. alu_op<=4'b1000;
25. end
26. 4'b0011: begin //shr
27. p_wr_en<=0;
28. stop<=0;
29. m_wr_en<=1;
30. a_wr_en<=1;
31. alu_op<=4'b1001;
32. end
33. 4'b0100: begin //csl
34. p_wr_en<=0;
35. stop<=0;
36. m_wr_en<=1;
37. a_wr_en<=1;
38. alu_op<=4'b1010;
39. end
40. 4'b0101: begin //stp
41. p_wr_en<=0;
42. stop<=1;
43. m_wr_en<=1;
44. a_wr_en<=0;
45. end
46. 4'b0110: begin //add
47. p_wr_en<=0;
48. stop<=0;
49. m_wr_en<=1;
50. a_wr_en<=1;
51. alu_op<=4'b0001;
52. end
53. 4'b0111: begin //sta
54. p_wr_en<=0;
55. stop<=0;
56. m_wr_en<=0;
57. a_wr_en<=0;
58.
59. end
60. 4'b1000: begin //lda
61. p_wr_en<=0;
62. stop<=0;
63. m_wr_en<=1;
64. a_wr_en<=1;
65. alu_op<=4'b1011;
66. end
67. 4'b1001: begin //jmp
68. p_wr_en<=1;
69. stop<=0;
70. m_wr_en<=1;
71. a_wr_en<=0;
72. end
73. 4'b1010: begin //ban
74. p_wr_en<=1;
75. stop<=0;
76. m_wr_en<=1;
77. a_wr_en<=0;
78. alu_op<=4'b1100;
79. end
80. endcase
81. end
82. endmodule
ALU:
1. module ALU(
2. input wire[15:0] in1,
3. input wire[15:0] in2,
4. input wire[3:0] alu_op,
5. output reg ban,
6. output reg[15:0] z
7. );
8. always @(*)
9. begin
10. case(alu_op)
11. 4'b0001: z<=in1+in2;
12. 4'b0010: z<=in1-in2;
13. 4'b0011: z<=in1&in2;
14. 4'b0100: z<=in1|in2;
15. 4'b0101: z<=in1<<in2;
16. 4'b0110: z<=in1>>in2;
17. 4'b0111: z<=0; //cla
18. 4'b1000: z<=~in1; //com
19. 4'b1001: z<={{in1[15]},in1[15:1]}; //shr
20. 4'b1010: z<={{in1[14:0]},in1[15]}; //csl
21. 4'b1011: z<=in2;
22. 4'b1100: ban<=in1[15]==1 ? 1 : 0;
23. // 4'b0111: z<={{6{imm[8]}},imm}+in1;
24. // 4'b1000: z<=out_data;
25. endcase
26. end
27. endmodule
ACC:
1. module ACC(
2. input a_wr_en,
3. input clk,
4. input wire [15:0]in_data,
5. output wire [15:0]acc_data
6. );
7. reg [0:15]acc;
8. initial begin
9. acc=16'd0;
10. end
11. assign acc_data=acc;
12. always@( posedge clk)
13. begin
14. if(a_wr_en==1)
15. acc=in_data;
16. end
17.
18.
19. endmodule
顶层封装:
1. module CPU(
2. input clk,
3. input rst,
4. output stop,
5. output ban,
6. output p_wr_en,
7. output a_wr_en,
8. output wire [12:0] pc,
9. output wire [15:0] ins,
10. output wire [3:0] alu_op,
11. output m_wr_en,
12. output wire [15:0] z,
13. output wire [15:0]acc_data,
14. output wire [15:0]out_data
15. );
16.
17.
18. PC f_pc(
19. .clk(clk),
20. .rst(rst),
21. .pc(pc),
22. .stop(stop),
23. .ban(ban),
24. .p_wr_en(p_wr_en),
25. .jmp({{4{ins[8]}},ins[8:0]}));
26.
27. ROM f_rom(
28. .pc(pc),
29. .ins(ins));
30.
31. RAM f_ram(
32. .clk(clk),
33. .m_wr_en(m_wr_en),
34. .in_data(acc_data),
35. .index(ins[8:0]),
36. .out_data(out_data)
37. );
38.
39. CU f_cu(
40. .opcode(ins[12:9]),
41. .p_wr_en(p_wr_en),
42. .a_wr_en(a_wr_en),
43. .stop(stop),
44. .alu_op(alu_op),
45. .m_wr_en(m_wr_en) //
46. );
47.
48. ALU f_alu(
49. .ban(ban),
50. .in1(acc_data),
51. .in2(out_data),
52. .alu_op(alu_op),
53. .z(z)
54. );
55.
56. ACC f_acc(
57. .a_wr_en(a_wr_en),
58. .clk(clk),
59. .in_data(z),
60. .acc_data(acc_data)
61. );
62. endmodule
Step6 模拟仿真
1. 仿真文件
1. module test_CPU;
2. reg clk;
3. reg rst;
4. wire stop;
5. wire ban;
6. wire p_wr_en;
7. wire a_wr_en;
8. wire [12:0] pc;
9. wire [12:0] ins;
10. wire m_wr_en;
11. wire [3:0] alu_op;
12. wire [15:0] z;
13. wire [15:0] out_data;
14. wire [15:0] acc_data;
15.
16. initial begin
17. clk=1'd0;
18. forever #10 clk=~clk;
19. end
20.
21. initial begin
22. rst=1'd0;
23. #120 $stop;
24. end
25.
26. CPU test(
27. .clk(clk),
28. .rst(rst),
29. .stop(stop),
30. .ban(ban),
31. .p_wr_en(p_wr_en),
32. .acc_data(acc_data),
33. .z(z),
34. .pc(pc),
35. .ins(ins),
36. .a_wr_en(a_wr_en),
37. .alu_op(alu_op),
38. .m_wr_en(m_wr_en),
39. .out_data(out_data)
40. );
41. endmodule
2. 仿真:
(一)第一次仿真
ROM初始化数据为:
1000000000001 //lda
0010000000000 //com
0011000000000 //shr
0001000000000 //cla
0101000000000 //stp
RAM初始化数据为:
1010001111010100
0000110101110011
仿真结果:
(二)第二次仿真
ROM初始化数据为:
1000000000000 //lda
0110000000001 //add
0111000000000 //sta
1000000000011 //lda
1010000000010 //ban
0101000000000 //stp
1001000001000 //jmp
0101000000000 //stp
RAM初始化数据为:
1010001111010100
0000110101110011
0000000000000010
1111111111111111
0001000000000000
在执行这些指令的过程中我发现了一些错误所以将代码修改了一下:
修改如下:
一.当执行ban指令跳转后,ban值一直为1,所以pc一直在执行ban操作,所以要在ALU的其他操作中增加ban输出为0的操作防止出错。同时cu中有一些操作没有对应的ALU操作为防止执行ban指令后出错,更改cu和ALU。
1. module ALU(
2. input wire[15:0] in1,
3. input wire[15:0] in2,
4. input wire[3:0] alu_op,
5. output reg ban,
6. output reg[15:0] z
7. );
8. always @(*)
9. begin
10. case(alu_op)
11. 4'b0001: begin z<=in1+in2;ban<=0; end
12. 4'b0010: begin z<=in1-in2;ban<=0; end
13. 4'b0011: begin z<=in1&in2;ban<=0; end
14. 4'b0100: begin z<=in1|in2;ban<=0; end
15. 4'b0101: begin z<=in1<<in2;ban<=0; end
16. 4'b0110: begin z<=in1>>in2;ban<=0; end
17. 4'b0111: begin z<=0; ban<=0; end//cla
18. 4'b1000: begin z<=~in1; ban<=0; end//com
19. 4'b1001: begin z<={{in1[15]},in1[15:1]};ban<=0; end //shr
20. 4'b1010: begin z<={{in1[14:0]},in1[15]}; ban<=0; end//csl
21. 合肥工业大学计组实验五