OpenCores
URL https://opencores.org/ocsvn/mips32/mips32/trunk

Subversion Repositories mips32

[/] [mips32/] [trunk/] [Classic-MIPS/] [ReadMe.txt] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jjf
SimpleMIPS说明:
2
        1:实现单周期的MIPS指令集
3
        2: 最高时钟频率可达 5.4ns <=> 185MHz
4
 
5
 
6
PipelineMIPS说明:
7
        1: 实现IF, ID, EX, MEM, WB的五级流水结构
8
        2:未使用旁路与阻塞前:
9
                1)数据冒险,要求等待3个nop指令。
10
                        ori $t0, $zero, 10
11
                        nop
12
                        nop
13
                        nop
14
                        add $s0, $s0, $t0
15
                ori与add之间需要等待3个nop指令,以满足$t0的正常功能。
16
 
17
                2)按照书Page206方式修改IF级(decode.v)
18
                        a:使时钟周期的前半段执行写操作,后半段执行读操作,使得读操作读取到最新的内容。
19
                        b:经过实践分析发现:
20
                                I: 这种方法确实可以缩短数据冒险等待时间,由3个nop指令减少为2个nop指令。
21
                                II: 但是严重影响了时序!!!这种方法使得寄存器输出reg1_data和reg2_data只能维持半个时钟周期,
22
                                        缩短了后续参与ALU运算的时间。
23
                                III: 考虑到时序的代价, 本设计放弃了这个优化方法。
24
        3: 最高时钟频率可达: 3.4ns <=> 294MHz
25
 
26
 
27
PipelineMIPS_opt说明:
28
        1:在PipelineMips中加入旁路与阻塞机制。
29
        2: 在WB级引入旁路机制,使得读操作可以读取到最新的内容, 作用与上一节.2.2)相同,可以减少一个nop指令的等待时间, 但是对时序没有影响。
30
                具体修改在decode.v中,对reg1_data和reg2_data使用一个选择器MUX进行旁路,如果读操作与写操作同时进行时,对读操作进行
31
                旁路,使得读操作获取最新的数据。
32
                    /* create a bypath for reg1 output */
33
            if(regwrite_flag && write_reg == rs)
34
                reg1_data <= write_data;
35
            else
36
                reg1_data <= registers[rs];
37
            /* create a bypath for reg2 output */
38
            if( regwrite_flag && write_reg == rt)
39
                reg2_data <= write_data;
40
            else
41
                reg2_data <= registers[rt];
42
        3:按照书Page.211,加入了旁路机制, 包括多选器和旁路单元。
43
                旁路单元的设计参照Page.210,但是MEM冒险的控制策略使用上面的,而不是下面的, 即没有加黑体的。
44
                assign forwardA_ex_mem_condition = (ex_mem_regwrite_flag == 1'b1) && (ex_mem_rd != 0) && (ex_mem_rd == id_ex_rs);
45
                assign forwardA_mem_wb_condition = (mem_wb_regwrite_flag == 1'b1) && (mem_wb_rd != 0) && ( mem_wb_rd == id_ex_rs);
46
 
47
                assign forwardB_ex_mem_condition = (ex_mem_regwrite_flag == 1'b1) && (ex_mem_rd != 0) && (ex_mem_rd == id_ex_rt);
48
                assign forwardB_mem_wb_condition = (mem_wb_regwrite_flag == 1'b1) && (mem_wb_rd != 0) && ( mem_wb_rd == id_ex_rt);
49
        4:按照书Page.214,加了了阻塞机制。
50
                lw $t0, 0($zero)
51
                addi $s0, $t0, $t1
52
                由于addi需要访问lw的$t0寄存器,即使加了了旁路机制,lw之后仍然必须阻塞一个时钟周期,否则addi无法访问到$s0的正确值。
53
        5: 1)当使用Block_Ram作为数据存储器时, 由于读操作有一个时钟周期的延时,因此读操作的结果没有使用寄存器缓冲。在加入旁路机制后,Block_Ram的输出到ALU的输入是关键路径,
54
                严重影响了时序。
55
           2)如果使用Distributed Ram作为数据存储器, 读操作是没有延时的, 那么读操作的结果可以缓存到流水线寄存器中,时序能够得到缓解。
56
           3)在Ram.v中同时例化了Block_Ram和Distributed Ram,用户可通过定义宏 __BLOCK_RAM__ 来选择Ram的种类。
57
        6: 1)在不优化控制冒险的条件下:
58
                        beq, bne, j等分支和跳转指令后面, 需要等待3个nop指令。
59
           2)实现了书Page.215中"假设分支不发生"的控制冒险解决策略。
60
                        假设分支不会发生。如果MEM级检测分支条件不成立, 则继续执行;
61
                                                                如果MEM级检测分支条件成立, 则清除(FLUSH)分支指令后的三个指令,具体做法如下:
62
                                                                1)IF级的reg_instruction设置成NOP
63
                                                                2)ID级的控制信号全部清除成0。
64
                                                                3)EX级的控制信号全部清除成0.
65
        7:最高时钟频率:5.4ns <=> 185MHz
66
 
67
PipelineMIPS_opt2说明:
68
        1)在Ram.v模块,RAM的输入地址舍弃低2位。
69
                因为MIPS中, 要求RAM的地址总是被4整除,而本设计的RAM的数据宽度都是32-bit的, 因此可以将地址右移2位, 相当于舍弃低2位。
70
                这要求,用户写汇编时, 必须保证地址总是4的整数倍!!!
71
                assign addr = ALU_out[9:2];
72
        2)a:经综合后时序分析可知, PipelineMIPS_opt工程相对于PipelineMIPS工程时序恶化的原因是:
73
                        EX级加入旁路机制后,增加了EX级的关键路径。关键路径如下:
74
                                mem/reg_write_reg ->EX级旁路单元(bypath_ctr) -> EX旁路选择器(bypass) ->ALU/ALU_out -> ALU/zero_flag
75
          b:优化方法1:
76
                为了缩短上述关键路径, 将旁路单元bypath_ctr移到ID级执行。
77
                在ID级提前执行旁路单元,因为旁路单元所需的数据都可以提前拿到,然后将计算到的forward_a, forward_b寄存器缓存, 然后传输到EX级。
78
                        优化后的关键路径如下:
79
                        mem/ram_out -> EX旁路选择器(bypass) -> ->ALU/ALU_out -> ALU/zero_flag
80
                优化方法将关键路径延时从5.4ns减少到了4.4ns.
81
          c)优化方法2:
82
                为了进一步缩短关键路径,将zero_flag的计算从EX级的ALU转移到MEM级计算。
83
                因为ALU单元先计算出ALU_out, 然后根据ALU_out计算出zero_flag, 因此zero_flag的延时比ALU_out更长。
84
                由于ALU_out会通过流水线寄存器传到MEM级,因此可以在MEM级计算zero_flag,从而缩短EX级的关键路径。
85
                        优化后的关键路径如下:
86
                        mem/ram_out ->EX旁路选择器(bypass) ->ALU/ALU_out
87
                优化方法将关键路径延时从4.4ns减少到了3.8ns.
88
        3)相比于PipelineMIPS工程, PipelineMIPS_opt2加入了旁路、阻塞与分支预测机制,解决了数据冒险和控制冒险问题,代价是关键路径延长了0.4ns(3.4ns->3.8ns).
89
                相比于SimpleMIPS工程,使用流水线, 时钟频率从185MHz提高到263MHz.
90
 
91
        4)最高时钟频率: 3.8ns <=> 263MHz
92
 
93
PipelineMIPS_opt3说明:
94
        1:在IF阶段,调整Flush和Hazard关系。
95
                Flush的优先级高于Hazard.
96
        2: 优化JUMP指令。
97
                在IF阶段提前解码,判断当前指令是否是JUMP指令。
98
                如果当前指令是JUMP指令, 判断后续流水线中是否有branch指令,如果有branch指令,阻塞直到branch指令完成.(因为如果Jump前面有branch指令, 那么Jump不一定会执行)
99
                                        如果后续流水线中没有branch指令, IF级马上JUMP到新地址, 而不需要等到MEM级。
100
        3:通过面积换时序的方法,将时间延时从3.8ns减少到3.1ns。
101
                具体改动如下:
102
                1) ALU.v中添加了c_addsub_0模块实现add/sub功能,缩短了ALU运算延时。
103
                        !!发现DSP实现比LUT实现慢很多!!!所以c_addsub_0是用16个LUT实现的。
104
                2)添加了bypath2.v模块, 将ALUSrc_flag放入了旁路选择器中bypath2, 这样ALU.v缩短了一个选择器的延时,
105
                        但是代价是增加了较多的LUT实现bypath2模块。
106
                3)mem/isFlush信号曾经是关键信号路径,因为zero_flag的运算使得isFlush信号延时很长。因此使用了ALU_out比较器代替了
107
                        zero_flag参与运算,缩短了isFlush延时, 代价是使用较多的LUT实现zero_flag的比较器。
108
                        //    assign isFlush =  ((ctr_m[3:2] == `BRANCH_OP_BEQ) && (zero_flag == 1'b1)) ||
109
                        //                ( (ctr_m[3:2] == `BRANCH_OP_BNE) && (zero_flag == 1'b0) );
110
                                assign isFlush =  ((ctr_m[3:2] == `BRANCH_OP_BEQ) && (ALU_out == 32'h0)) ||
111
                                                ( (ctr_m[3:2] == `BRANCH_OP_BNE) && (ALU_out != 32'h0) );
112
                4)execute/ALU_ctr中, instruction->ALUcmd->ALU_out是关键路径。因此,将ALU_ctr模块从execute迁移到decode级计算。
113
        4:经过上述优化,最高时钟频率: 3.1ns <=> 322MHz
114
 
115
PipelineMIPS_opt4说明:
116
        1:为了实现jal jr等跳转指令, 将MIPS寄存器中的$ra(第31号寄存器)挪到fetch中, 因为只有fetch级会使用到$ra.
117
                jal与jr的使用,可实现函数调用的功能。保存调用函数的地址,返回后继续执行。
118
                ###jal调用函数, jr函数返回。
119
                具体例子见 /TestBenchs/function/code.smd
120
 
121
                !!!但是不支持函数的嵌套调用!!!(即主函数调用的子函数调用其他函数, 否则$ra被覆盖导致功能错误)
122
 
123
        2: jal指令与j指令大致相同, 只是额外执行 $ra = [PC] + 4, 即暂存下一条指令的地址。因此使用jal调用函数。
124
        3: jr指令做了修改,在硬件上进行了缩减, 使其只支持 jr $ra, 即只能跳转到$ra指令的位置.因此使用jr实现函数返回。
125
        4:经过上述优化,最高时钟频率: 3.1ns <=> 322MHz
126
        5:资源使用情况, 基于xc7z045ffg900-2芯片。
127
                FF: 1463
128
                LUT: 1744
129
 
130
PipelineMIPS_opt4_example说明:
131
        1: 例化PipelineMIPS_opt4,烧录流水灯/TestBenchs/led/code.smd程序,创建工程、生成位流并上板子测试。测试工程正常。
132
 
133
 
134
PipelineMIPS_opt5_cache
135
        1: 在PipelineMIPS_opt4基础上加入一个直接映射的cache
136
        2: cache说明
137
                1)cache: 块大小是8个字(8x32),64项。故大小:64x8x32= 16K bit = 2K byte
138
                2)cache命中时,读写都是单周期内完成。
139
                3)cache对于写缺失采用写回策略。
140
        3:加入cache后,时序稍微变差,最高时钟频率: 3.4ns <=> 294MHz
141
 
142
PipelineMIPS_opt5_cache_example3
143
        1: 例化PipelineMIPS_opt5_cache, 烧录除法运算/TestBenchs/cache_example/code.smd程序,创建工程、生成位流并上板子测试。测试工程正常。
144
        2:测试了以下功能, 且正常。
145
                1)使用BRAM_Controller IP实现对主存的访问. (主存是True Dual Port, 一个Port给cache, 一个Port给用户使用)
146
                2)测试了MIPS调用除法函数DIV。
147
                3)测试了cache的读写、缺失、重分配和写回等功能。
148
        3:存储器的正常工作如下:
149
                1)通过用户Port(BRAM_Controller)向主存写入运算的操作数,addr = 0, 4
150
                2)MIPS读操作数,这时发生读缺失,从主存分配数据到cache中。
151
                3)MIPS进行除法运算,计算结果保存到cache的地址addr = 32, 36
152
 
153
                /* 一:为了让MIPS的cache每次加载到用户写入到主存的最新操作数, 那么应该让addr = 0, 4的cache失效,以便下次
154
                从主存重新分配 */
155
                4) "lw $t0, 2048($zero)", 该指令让 addr = 0,4的cache失效
156
 
157
                /* 二:为了让用户读取到计算结果, 需要让addr = 32, 36对应的cache写回到主存中 */
158
                5) "lw $t1, 2080($zero)", 该指令让 addr = 32, 36对应的cache写回到主存中,然后用户通过BRAM_Controller可以
159
                读取计算结果。
160
        4:在有cache的系统中,当用户通过BRAM_Controller访问主存时,需要注意cache与主存的一致性问题。
161
 
162
 
163
PipelineMIPS_opt6_cache_bht
164
        1: 在fetch级,加入了一个1024项的BHT(branch history table),用动态分支预测提高分支的准确率。
165
        2:BHT包含1024项, 使用分支指令地址的低位进行索引,每项大小是33-bit:
166
                1):bit:32, 预测位,预测该分支指令是否发生。
167
                        如果该位为1,表示预测分支发生,将bit[31:0]作为下一条指令地址。
168
                        如果该位为0,表示预测分支不发生, 下一条指令地址为当前指令地址 + 4.
169
                2): bit[31:0] 分支指令发生时对应的跳转目标地址。
170
        3:测试
171
                1)没有使用bht前,采用预测不发生的策略,预测准确率大约50%
172
                  使用bht后,根据局部性原理, 预测准确率可 >50%.
173
                2)测试发现, bht确实可以有效提高预测准确率,以提高运行速度。
174
 
175
        4: 集成cache和bht后,综合报告如下:
176
                1) 加入bht后, 最高工作频率: 3.5ns => 285.7MHz
177
                        关键路径依然是cache, 从reg_ALU_out -> isCacheDone.
178
                2) 资源使用
179
                        FF:                     1626
180
                        LUT:                    3004
181
                        MEMORY LUT:             983
182
                        BRAM:                   7.5
183
 
184
PipelineMIPS_opt7_cache_bht
185
        1: 将bht的预测位,由1-bit扩展到2-bit,以提高准确率.
186
        4: 集成cache和bht后,综合报告如下:
187
                1) 加入bht后, 最高工作频率: 3.6ns => 277.8MHz
188
                        关键路径依然是cache, 从reg_ALU_out -> isCacheStall.
189
                2) 资源使用
190
                        FF:                     1630
191
                        LUT:                    3163
192
                        MEMORY LUT:             1015
193
                        BRAM:                   7.5
194
 
195
PipelineMIPS_opt8_cache_bht
196
        1: 在PipelineMIPS_opt7_cache_bht基础上, 对SimpleCache做了稍微修改。
197
                去掉了cache_done信号, 直接输出isCacheStall信号, 使接口简洁一些。
198
        2:资源和时序几乎相同。
199
 
200
PipelineMIPS_opt9_cache_bht
201
        1:目的是完善j, jal, jr三个跳转指令,可实现对$ra寄存器的读写,进而实现函数的嵌套调用。
202
                目前j, jal, jr指令已完善。 jr指令可支持任何寄存器, 不限于$ra。
203
 
204
                此外还修复了lw指令在decode的一个bug。 当isHazard是, 应保持reg_pc <= reg_pc,否则会导致跳转跳转指令
205
                地址出错。
206
 
207
        2:修改
208
                1)将$ra从fetch级挪回到decode级, 并放置在registers寄存器堆中,使得$ra能够正常访问。
209
                2) jal指令的执行较为特殊, 需要生成regwrite_flag信号、特殊设置$rt、特殊计算reg_ALU_out等值,
210
                        以实现 $ra <-- [PC] + 4.
211
                3)将jal. j, jr等指令当成特殊的条件分支指令处理,使用BHT进行分支动态预测。
212
                        相对于branch指令, 跳转指令的分支一定会发生,因此可以特殊的条件分支处理,并且在fetch级利用BHT
213
                        进行分支动态预测, 在mem级对BHT进行修正。
214
        3:修改后,资源报告如下:
215
                FF:                     1709
216
                LUT:                    3171
217
                MEMORY LUT:             1015
218
                BRAM:                   7.5
219
        4:修改后时序得到了优化,最高工作频率: 3.5ns => 285.7.1MHz。
220
        5: 此外在大多数测试程序中发现,消耗的周期数有所减少,性能略有提升。
221
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.