-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
751 lines (361 loc) · 763 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>2024 北航计算机学院外推杂记</title>
<link href="/2024/09/30/post_graduate/"/>
<url>/2024/09/30/post_graduate/</url>
<content type="html"><![CDATA[<h1 id="2024-北航计算机向外校推免保研经验帖"><a href="#2024-北航计算机向外校推免保研经验帖" class="headerlink" title="2024 北航计算机向外校推免保研经验帖"></a>2024 北航计算机向外校推免保研经验帖</h1><p>写下这篇文章的时间是 2024 年 9 月 30 日,大伙沉浸在国庆将至的喜悦中,自习室相比往常显得冷清,在这个时候对过去一年做出些许总结倒也多几分禅意(雾)。</p><p>我是没有写日记的习惯的,这可能与从小对学校布置的作业以外的任务持怠惰态度有关(正经人谁天天写日记啊);但总有一些曲折又引人入胜的经历,我不想我对它的独特感受被时间的沙砾打磨而逐渐失去闪光;当然,也是为了满足我庸俗的分享欲和发扬好为人师的缺点,一家之言,还请以审慎态度观之(看个乐呵得了)。</p><p>文章以时间铺叙,分为三个阶段陈述;原谅一个工科生的作文水平,这是我能想到最好懂的叙事顺序了。</p><hr><p><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/post_graduate/resume.pdf">个人资料</a></p><h1 id="找寻与重塑(2023-09-2024-05)"><a href="#找寻与重塑(2023-09-2024-05)" class="headerlink" title="找寻与重塑(2023.09 - 2024.05)"></a>找寻与重塑(2023.09 - 2024.05)</h1><p>如您所见,第一阶段持续的时间长达半年,符合直觉的是这个阶段对我保研的路径也产生了重大影响。</p><h2 id="2023-09-2023-10"><a href="#2023-09-2023-10" class="headerlink" title="2023.09-2023.10"></a>2023.09-2023.10</h2><p>大三秋季学期刚刚开始,当时由于在暑假参加了编译比赛并获得了不错的成绩(尽管外卡奖项没有加分),自信心得到了极大的补足,正好迎来了凭奖项免修编译实验课程的好政策,故余下了些许空余时间。</p><p>刚进入大三的我,对保去哪和如何保这两个问题的答案尚且模糊,只知道要有科研经历有竞赛还要考专业知识云云;当时由于大二冯如杯的失利和那一年的迷茫期,导致我还没有一段像样的科研经历,因此抱着图快的心态光速加入<a href="https://argithun.github.io/2023/10/25/pro-exp1/">本校的一个课题组</a>。</p><p>课题组的老师人非常好,不压力学生,会给予正常的引导,在我们学业中的时候也不会要求推进项目,做的项目也有大公司背书,如果一直这样干下去,无疑是安逸且能拿到成果的,但这样就够吗,我问自己。</p><p>我不知道。</p><p>人在安逸的环境中是会迷茫且心虚的,这种不安感可能是我们这种小镇做题家普遍存在的心态。</p><h2 id="2023-11-2024-01"><a href="#2023-11-2024-01" class="headerlink" title="2023.11-2024.01"></a>2023.11-2024.01</h2><p>众多周知,在高校圈中,top2 始终是大家趋之若鹜的学术殿堂,每年的大三学生围绕如何保研 top2 也是各显神通;偶然的一个晚上,看到 THU 网研院在群里的实习生招聘通知,其中发通知的学长我也较为熟识,我觉得这是个机会,但此时我在北航已有一个课题组了,再进一个组不知是否能忙过来。</p><p>生活是一场贪心算法吗,至少我目前的眼见没法支持动态规划;撑死胆大的,饿死胆小的,大不了后续再退出,也看看 top2 到底是个什么水平。</p><p>经过一下午对计网知识的预习和 10 分钟的简单面试,就这样,我的<a href="https://argithun.github.io/2023/11/22/NISL_lab1/">第二段科研经历</a>开始了,当然,本校的课题组也同时推进。</p><p>陌生的项目,全新的知识,那段时间还被 <a href="https://argithun.github.io/2024/01/03/db4/">PostgreSQL 源码解析</a>,<a href="https://argithun.github.io/2023/12/01/ruby/">Ruby 大作业</a>,<a href="https://argithun.github.io/2023/12/10/android/">安卓大作业</a>轮番轰炸;幸亏编译实验免修了,否则我可能就要升天了。</p><p>THU 的科研压力果然名不虚传,经常半小时前还在学校上必修课,下课就得赶去 THU 开会了;带我们的导师是一个 2021 年入职的助理教授,自身非常优秀,对学生的要求也很严格,包括但不限于在实验室时长,阅读文献数量,学术品位等方面的要求,每天(甚至包括节假日中的一两天)项目组的师姐都会不辞辛苦地与我们同步项目进度;那段时间虽然忙得不得不使用 todo list,但确让我从以往对课业成绩和竞赛加分的焦虑中解放出来。</p><p>不知道从哪听来的理论:当存量竞争发展到一定地步,一定需要有人去开辟新的赛道,将其拉回增量竞争的良性循环;我想除了竞赛和课业外,有产出的科研也是一条不错的路,且是一条很少有人能在大三坚持到底的路。</p><p>网研院的项目稳步推进着,此课题的氛围是极好的,窃以为在组里学到的计网前沿知识比上课要多得多;但当时的我似乎忽略了,我真得对网络安全领域抱持着基本的热情吗,抑或是一时的新鲜感在支撑项目的推进。</p><h2 id="2024-02-2024-05"><a href="#2024-02-2024-05" class="headerlink" title="2024.02-2024.05"></a>2024.02-2024.05</h2><p>本校和 THU 网研院的项目虽然推进平稳,但基本得到 2024 年暑期才能有初步成果,而那个时候各个大学的夏令营已经基本结束了;不得不承认,急功近利的心态驱使我找寻下一个机会。</p><p>一个经典的命题:机会是给有准备的人,还是有准备的人具有发现机会的慧眼;从理性来看,我选后者,但从我自身的经历以及本文尽量谦谨的文风来看,我还是选前者吧哈哈。</p><p>一天,微信弹出 S 君的私信(从大一玩到现在的兄弟,祝他申请留学顺利),“THU 知识工程实验室大模型安全的项目来吗,缺人手”,在和 S 君简单交流实验室的情况后,果断报名,就冲着项目周期短,且领域符合现在大伙对大模型趋之若鹜的心态;带我的是一位从北航保到 THU 计科的老学长,学长非常和蔼,对项目节奏的把控也很精准,<a href="https://arxiv.org/abs/2406.11682">该项目</a>似乎没有遇到什么困难就顺利投稿 KDD 了。</p><p>至此,三个实验室的科研任务并行,再加上大三下特有的池沼课程计网实验,以及不得不去靠 ppt 混分的冯如杯,使我深刻体会到操作系统进程调度的时间片轮转算法。</p><p>这里插入一个在各个实验室工作时有意思的发现,参加科研工作的几种范式:</p><ul><li>一对一:有一个师兄/师姐每周同步课题情况,本科生只需要处理好每周分配的任务即可;这种模式的好处是大概率该项目已经有一个基础的蓝图,可以快速出成果,但缺点就是这种模式很难培养学术能力;</li><li>一对多:处于一个项目小组中,每周召开组会,讨论任务进展和下周的计划;这种模式适用极其广泛,使学生有一定的学术参与度,但基本上也只能专注于自身负责的模块的工作;</li><li>多对多:处于实验室大组中,导师将本科生当作研究生培养,每周的小组会和每月的大组会都允许参加,承担的项目也是具有开拓性的;这种模式使学生能接触到自身工作之外的领域,对整个研究方向有大致的了解,十分培养科研能力,但如果指望能快速出成果,那要付出的时间精力恐怕得数倍于前两个。</li></ul><h1 id="tea-or-coffee(2024-06-2024-08)"><a href="#tea-or-coffee(2024-06-2024-08)" class="headerlink" title="tea or coffee(2024.06 - 2024.08)"></a>tea or coffee(2024.06 - 2024.08)</h1><p>夏令营,启动!</p><h2 id="2024-06"><a href="#2024-06" class="headerlink" title="2024.06"></a>2024.06</h2><p>每年的五、六月份都是夏令营填报的高峰,那是我总共报名的五个夏令营,分别是 南大计科、清华网研院、北大计科、复旦计科、上交电院。</p><p>南大计科今年夏令营的时间似乎是 6 月 1 号到 6 月 2 号,属于是最早的一批,但 3 号我有编译原理的期末,且根本没时间复习夏令营要考的专业课,于是就放弃了。</p><p>清华网研院的时间似乎是 6 月 17 号,当时也拿到了课题组老师工程博士(专博)的名额;老师只有一个要求,机试(4 小时 3 道题)做出一道题即可,我也恰好满足了此要求(别骂了,第二题 bug 半天找不到在哪),后面的面试也是等于没有,就是老师和学生们在会议室聊聊天;网研院夏令营不发优营 offer,可以当作一次预推免的模拟考试。</p><p>北大计科的时间似乎是六月底的两天天,当时由于有了网研院老师的口头 offer,故以去燕园玩两天的心态参加了夏令营;夏令营第一天开营仪式前,教室恰好在轮播北大校歌和《青春大概》,时光仿佛又回到了四年前暑假参加的北大优秀中学生夏令营,只觉得恍惚;那天晚上机试(2 小时 8 道题),不知道是不是前一天熬夜赶计网实验中期检查的后果,卡在第二题四十多分钟(结果是没认真读题),最后仅仅达到三道题的预期线草草收场;想着面试要不别去了,感觉没有被录入的希望了,况且已经有网研院的 offer;那天晚上未名湖很静,还有些许飘雨,我对北大是有特殊的情感的,高中的竞赛和升学经历也夹杂了些许遗憾,不如明天再来玩一天,我这样想。</p><p>面试在理教举行,当时和一位北航网安学院的兄弟候考,聊着聊着也没有什么紧张的了;面试开始,先是自我介绍,我将中心放在介绍我的三段科研经历上;而后,例行提问,问了我两个密码学相关的知识(没学过根本不会),看我没有学过就转问一道算法题了,比较简单,学过算法课就可以搞定;其后的提问都围绕项目展开,还会给予项目衍生出一些发散性问题,如果对项目有充分的了解是可以自如应对的,面试节奏很轻松;最后,老师好奇为什么机试发挥得不太好,可以解释一下,我也如实回答了上面的原因,其实到这里心里想的基本稳啦,毕竟都给我找补的机会了。面试结束,骑车绕未名湖转了一圈,似乎没有晚上看上去那么大,从一个不知名的小门出校回北航了。</p><p>当天晚上就收到了优营资格确认的电话,再三确认我没有别的 offer 后(有也别说哦),确认了北大计算机学院的学硕 offer;放下手机,立刻退掉了去上海的车票,复交的夏令营都拒绝参加了。</p><h2 id="2024-07-2024-08"><a href="#2024-07-2024-08" class="headerlink" title="2024.07-2024.08"></a>2024.07-2024.08</h2><p>暑期,北大计算机实验室和清华网研院的实验室工作同时开展,因为没有课业压力,每天过得很平静;这个时候困扰我最多的是到底接受哪个 offer,清华的网络安全可谓全国领先,但是专博的 offer 多少差点意思(评价来自本校计算机学院的一位大牛老师),虽然网研院组内对各个不同学位的实验室成员在学术培养上一视同仁,但不可否认的是,从选拔方式到就业空间,在社会角度上来看,学术型硕博就是比专业性硕博显得所谓“高贵”一些(无意引战,原谅我匮乏的词汇量)。</p><p>当不知道自己笃定的志向在何方时,最省事的做法就是每次选择能导向更多选择的选项,毕竟主动权和发展权都掌握在自己手上。</p><h1 id="白葡萄汽酒售罄了(2024-09)"><a href="#白葡萄汽酒售罄了(2024-09)" class="headerlink" title="白葡萄汽酒售罄了(2024.09)"></a>白葡萄汽酒售罄了(2024.09)</h1><h2 id="2024-09-10"><a href="#2024-09-10" class="headerlink" title="2024.09.10"></a>2024.09.10</h2><p>北大发来了夏令营邀约邮件,在系统上点击确认即可,这时基本就是铁 offer 了,可以方向地拒绝其他学校。</p><h2 id="2024-09-11"><a href="#2024-09-11" class="headerlink" title="2024.09.11"></a>2024.09.11</h2><p>中午给网研院的老师打了通电话,和老师说明情况后,决心离开,老师也没有阻拦;那天回望已经分配好的工位,走出清华 FIT 楼,说实话内心有些歉疚和不舍;这一年无数次在清华吃完晚饭,骑车穿过二校门,经过清华学堂的门口,肃穆而又略带轻松的氛围,倒也符合这所学校的气质。</p><h2 id="2024-09-18"><a href="#2024-09-18" class="headerlink" title="2024.09.18"></a>2024.09.18</h2><p>学院公布推免名额,卓工计划的挤占使名额略有缩减。</p><h2 id="2024-09-23"><a href="#2024-09-23" class="headerlink" title="2024.09.23"></a>2024.09.23</h2><p>学院公布推免名单,我由于投入几乎所有的课外时间到科研上,没有参加太多的竞赛,故加分没有那么高,最终排位专业 19,不过这个名次仅使用这一次,不适用后续的评奖等任何活动(导员原话)。</p><h2 id="2024-09-28"><a href="#2024-09-28" class="headerlink" title="2024.09.28"></a>2024.09.28</h2><p>填报预推免系统,记得选张好看的证件照(近三个月)。</p><h2 id="2024-09-29"><a href="#2024-09-29" class="headerlink" title="2024.09.29"></a>2024.09.29</h2><p>接受北大的复试和拟录取通知,保研之路行至终点。</p><hr><h1 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h1><p>29 号中午和两个也顺利上岸的室友外出小聚,原本用来冒充香槟的白葡萄汽酒售罄了,故只能用红葡萄汽酒代之。</p><blockquote><p>Is this the real life? Is this just fantasy?</p><p>Caught in a landslide, no escape from reality</p><p>Open your eyes, look up to the skies and see</p><p>I’m just a poor boy, I need no sympathy</p><p>Because I’m easy come, easy go, little high, little low</p><p>Any way the wind blows doesn’t really matter to me, to me</p></blockquote>]]></content>
</entry>
<entry>
<title>华为“毕昇”编译器模糊测试——项目二期</title>
<link href="/2024/02/01/pro-exp2/"/>
<url>/2024/02/01/pro-exp2/</url>
<content type="html"><![CDATA[<h1 id="华为“毕昇”编译器模糊测试——项目二期"><a href="#华为“毕昇”编译器模糊测试——项目二期" class="headerlink" title="华为“毕昇”编译器模糊测试——项目二期"></a>华为“毕昇”编译器模糊测试——项目二期</h1><p>在项目一期中,我们构建了针对编译优化模块的变异策略以服务于模糊测试,但该模块只能产生一系列 ir,这些 ir 经指定的优化模块处理后可以得到优化后的 ir,在优化处理过程中,内存的溢出或直接崩溃往往暗示了优化模块可能存在的 bug。<br>但这种检测是不够的,因为这种严重的 crash 在发生的可能性上往往很小,故我们需要对 ir 的执行结果进行差分测试,对比优化前后的 ir 的执行结果,若有差异则也可进行对比溯源,找到可能存在的 bug。</p><h2 id="优化测试模块总体架构"><a href="#优化测试模块总体架构" class="headerlink" title="优化测试模块总体架构"></a>优化测试模块总体架构</h2><p><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/pro_exp2_1.png"></p><h2 id="输出指令插入算法"><a href="#输出指令插入算法" class="headerlink" title="输出指令插入算法"></a>输出指令插入算法</h2><p>在我们变异生成的 ir 中,虽然有一些指令的处理逻辑,但这些被处理的变量没有输出,这样我们的差分模块就只能打开内存进行执行结果对比(难度太高,反正我短期内找不到识别内存中有效变量的值并进行差分的办法),故我们还是采用传统的输出对比的方式。<br>这就涉及输出指令(printf)的插入,直观的,不能为所有中间变量都插入输出指令,这会破坏优化位点,导致无意义的优化测试,故我设计出基于以下插入规则的启发式算法:</p><ul><li>一条指令可以被输出仅当:<ul><li>不为 void 类型</li><li>不是 Terminal 指令</li></ul></li><li>一条指令输出收益较大仅当:<ul><li>其没有 User 或其 User 类型为 void</li><li>依据其 Use 关系建树<ul><li>指令本身为节点,用到的 Value 为子节点</li><li>当前节点为 Call 指令则深入函数或直接为该边的长度赋予一个较大值</li><li>当前节点没有 Use 对象或 Use 对象都为常数 或 全局值,则停止</li><li>计算树的高度,越高则收益越大</li></ul></li><li>不在循环内(加分项)</li><li>收益的衡量和整个程序的 BasicBlock 数量相关,和指令所在块的指令条数相关。</li></ul></li></ul><p>这个算法为 ir 内一些“靠后”的变量产生输入,能更具代表性地反映程序的正确性。</p><h2 id="错误过滤器"><a href="#错误过滤器" class="headerlink" title="错误过滤器"></a>错误过滤器</h2><p>由于我们要对 ir 进行执行操作,这就对 ir 的合理性提出了更高的要求,这里定义“不合理的 ir”为:</p><ul><li>无法通过 llvm 自带的合理性检查</li><li>ir 执行过程中崩溃 (Core Dump)</li><li>ir 执行时间过长</li><li>ir 导致差分模块的误判<ul><li>优化前的 ir 执行结果不确定</li><li>异常导致 ir 执行结果未写入输出文件</li><li>优化后的 ir 执行结果不确定(poison 值)</li><li>未定义行为导致意料之外的执行结果</li></ul></li></ul><p>针对不同类型的 ir 及其细分情况,其初步的(有的比较生硬)解决办法是:</p><ul><li>ir 无法通过 llvm 自动检查 Assertion<ul><li>GlobalValue is not external<br>原因:在 llvm 源码中有专门对 GlobalValue 的检查,如果不初始化会被归入 External 的全局值类型<br>解决:在代码中 GlobalValue 声明时使用 Internal 的 LinkageType,并给予初始值,这两步缺一不可</li><li>Phi is not at the top of block<br>原因:llvm 自带的随机指令插入变异可能在 Phi 指令前插入一些指令<br>解决:在指令插入变异的函数末尾添加 Phi 指令提前的逻辑</li><li>XXX is not dominate all its use<br>原因:可能有很多种,目前解决的是插入循环导致一些指令的 dom 关系被破坏<br>解决:在插入循环时维护好前驱后继(特别是 Phi 指令和跳转指令)的关系,保证不破坏支配关系</li></ul></li><li>误判<ul><li>before 执行结果不确定<br>原因:未定义行为<br>解决:将 before 的 ir 执行两次,若结果不一致直接舍弃该变异体(<strong>处理比较消极,后续从源码上修改</strong>)</li><li>异常导致 before 执行结果无法写入文件<ul><li>除/模 0 异常<br>解决:对于 除/模 类指令检查第二操作数<ul><li>若为常数且为 0 则修改</li><li>若不为常数,则替换为该值 + 7 (<strong>需修改</strong>)</li></ul></li><li>移位异常<br>原因:移位操作数过大或为负数<br>解决:对于移位类指令检查第二操作数<ul><li>若为常数且过大或为负数则修改</li><li>若不为常数,则插入取模指令限制第二操作数</li></ul></li><li>GEP 指令异常<br>原因:GEP 指令偏移量为溢出或为负数<br>解决:获取其操作的指针的空间长度,对偏移量进行取模(Urem)</li><li>alloca 指令异常<br>原因:alloca 分配的空间长度为负数<br>解决:对于 alloca 指令检查第一操作数<ul><li>若为常数且为负数则修改为 16</li><li>若不为常数则直接置为 16(因为自动生成的 alloca 指令几乎不会用来存储数组) (<strong>需修改</strong>)</li></ul></li><li>store 指令异常<ul><li>store 写常量空间<br>原因:store 向一些存储常量的空间存入值<br>解决:溯源检查 store 写入的空间,若不能存入则删除此 store 指令</li><li>store 写溢出<br>原因:store 写的字段长度大于分配的空间的长度<br>解决:<ul><li>若空间皆为常量:检索对应 alloca 指令分配类型的长度,与 store 写入的数据类型长度对比,若溢出则删除该指令</li><li>否则:对写入目标的 alloca 指令进行 8 字节对齐,可以避免写溢出 (<strong>需修改</strong>)</li></ul></li></ul></li><li>call 指令调用 printf 函数的参数被修改<br>原因:llvm 自带的插入指令的变异会为行插入的指令找一个 User<br>解决:防止 call 指令成为该机制找到的 User</li></ul></li><li>溢出导致 after 打印 poison 值<br>原因:使用随机数导致各种算术指令的溢出<br>解决:<ul><li>最大程度避免使用随机数,现已实现语义相同的变异(拆分指令和合并后的指令执行后的结果相同)</li><li>对极易溢出的指令(移位),使用模数的方法进行限制</li><li>检查优化后的 ir 中有无 poison 值,若有则丢弃该变异体</li></ul></li></ul></li><li>崩溃(core dump)<ul><li>段错误(核心已转储)<ul><li>call 指令的对象和参数被改动<br>原因:llvm 自带的插入指令的变异会为行插入的指令找一个 User<br>解决:防止 call 指令成为该机制找到的 User </li><li>store 指令存入的值位数大于空间长度<br>原因:llvm 自带的插入指令的 sink 机制会生成一些存储值到其 alloca 出的空间的 store 指令<br>解决:不使用已有的 alloca 指令,为新的值新建 alloca 指令</li></ul></li></ul></li><li>ir 执行时间过长<ul><li>循环次数过多<br>解决:限制循环类变异插入循环的循环次数</li><li>循环深度过大<br>解决:循环类变异插入循环前检查深度</li><li>死循环<br>解决:限时执行(<strong>需修改</strong>)</li></ul></li></ul><h2 id="执行和结果对比"><a href="#执行和结果对比" class="headerlink" title="执行和结果对比"></a>执行和结果对比</h2><p>这里比较直接,先使用 c++ 执行一些命令行将 .ll 文件编译链接为可执行文件:</p><pre class=" language-cpp"><code class="language-cpp"><span class="token keyword">bool</span> <span class="token function">runAndSaveResult</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&</span>filename<span class="token punctuation">,</span> llvm<span class="token operator">::</span>Module <span class="token operator">&</span>M<span class="token punctuation">,</span> <span class="token keyword">bool</span> isBefore<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 1. 将 M 转化为 .ll 文件</span> <span class="token keyword">int</span> fd <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> std<span class="token operator">::</span>error_code EC <span class="token operator">=</span> llvm<span class="token operator">::</span>sys<span class="token operator">::</span>fs<span class="token operator">::</span><span class="token function">openFileForWrite</span><span class="token punctuation">(</span><span class="token string">"./result/executing.ll"</span><span class="token punctuation">,</span> fd<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>EC<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> raw_fd_ostream <span class="token function">OS</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> M<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span>OS<span class="token punctuation">,</span> <span class="token keyword">nullptr</span><span class="token punctuation">)</span><span class="token punctuation">;</span> OS<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">errs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">"Failed to open output file: "</span> <span class="token operator"><<</span> EC<span class="token punctuation">.</span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">"\n"</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 2. 使用 llc 将 .ll 文件编译成目标文件</span> std<span class="token operator">::</span>string objFile <span class="token operator">=</span> <span class="token string">"./result/executing.o"</span><span class="token punctuation">;</span> std<span class="token operator">::</span>string llFile <span class="token operator">=</span> <span class="token string">"./result/executing.ll"</span><span class="token punctuation">;</span> std<span class="token operator">::</span>string llcCommand <span class="token operator">=</span> <span class="token string">"llc "</span> <span class="token operator">+</span> llFile <span class="token operator">+</span> <span class="token string">" -opaque-pointers -filetype=obj -o "</span> <span class="token operator">+</span> objFile<span class="token punctuation">;</span> <span class="token keyword">int</span> llcResult <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">system</span><span class="token punctuation">(</span>llcCommand<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>llcResult <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">errs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">"Failed to execute llc command\n"</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 3. 使用 clang 将目标文件链接成可执行文件</span> std<span class="token operator">::</span>string executable <span class="token operator">=</span> <span class="token string">"./result/executing"</span><span class="token punctuation">;</span> std<span class="token operator">::</span>string clangCommand <span class="token operator">=</span> <span class="token string">"clang "</span> <span class="token operator">+</span> objFile <span class="token operator">+</span> <span class="token string">" -o "</span> <span class="token operator">+</span> executable <span class="token operator">+</span> <span class="token string">" -no-pie"</span><span class="token punctuation">;</span> <span class="token keyword">int</span> clangResult <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">system</span><span class="token punctuation">(</span>clangCommand<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>clangResult <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">errs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">"Failed to execute clang command\n"</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 4. 执行可执行文件,并将结果写入指定文件</span> std<span class="token operator">::</span>string execCommand <span class="token operator">=</span> <span class="token string">"timeout 20s "</span> <span class="token operator">+</span> executable <span class="token operator">+</span> <span class="token string">" > "</span> <span class="token operator">+</span> filename<span class="token punctuation">;</span> <span class="token keyword">int</span> execResult <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">system</span><span class="token punctuation">(</span>execCommand<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>execResult <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>isBefore<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> std<span class="token operator">::</span>string execCommandAddition <span class="token operator">=</span> <span class="token string">"timeout 20s "</span> <span class="token operator">+</span> executable <span class="token operator">+</span> <span class="token string">">"</span> <span class="token operator">+</span> <span class="token string">"./result/before_addition.txt"</span><span class="token punctuation">;</span> <span class="token keyword">int</span> execResultAddition <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">system</span><span class="token punctuation">(</span>execCommandAddition<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> std<span class="token operator">::</span>string execCommandAddition <span class="token operator">=</span> <span class="token string">"timeout 20s "</span> <span class="token operator">+</span> executable <span class="token operator">+</span> <span class="token string">">"</span> <span class="token operator">+</span> <span class="token string">"./result/after_addition.txt"</span><span class="token punctuation">;</span> <span class="token keyword">int</span> execResultAddition <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">system</span><span class="token punctuation">(</span>execCommandAddition<span class="token punctuation">.</span><span class="token function">c_str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>然后是对比输出的逻辑:</p><pre class=" language-cpp"><code class="language-cpp"><span class="token keyword">bool</span> <span class="token function">compareResults</span><span class="token punctuation">(</span><span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&</span>file1<span class="token punctuation">,</span> <span class="token keyword">const</span> std<span class="token operator">::</span>string <span class="token operator">&</span>file2<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 打开第一个文件</span> llvm<span class="token operator">::</span>ErrorOr<span class="token operator"><</span>std<span class="token operator">::</span>unique_ptr<span class="token operator"><</span>llvm<span class="token operator">::</span>MemoryBuffer<span class="token operator">>></span> File1BufferOrErr <span class="token operator">=</span> llvm<span class="token operator">::</span>MemoryBuffer<span class="token operator">::</span><span class="token function">getFile</span><span class="token punctuation">(</span>file1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>File1BufferOrErr<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">errs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">"Error opening file: "</span> <span class="token operator"><<</span> file1 <span class="token operator"><<</span> <span class="token string">"\n"</span><span class="token punctuation">;</span> <span class="token function">abort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> std<span class="token operator">::</span>unique_ptr<span class="token operator"><</span>llvm<span class="token operator">::</span>MemoryBuffer<span class="token operator">></span> File1Buffer <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token operator">*</span>File1BufferOrErr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 打开第二个文件</span> llvm<span class="token operator">::</span>ErrorOr<span class="token operator"><</span>std<span class="token operator">::</span>unique_ptr<span class="token operator"><</span>llvm<span class="token operator">::</span>MemoryBuffer<span class="token operator">>></span> File2BufferOrErr <span class="token operator">=</span> llvm<span class="token operator">::</span>MemoryBuffer<span class="token operator">::</span><span class="token function">getFile</span><span class="token punctuation">(</span>file2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>File2BufferOrErr<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">errs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">"Error opening file: "</span> <span class="token operator"><<</span> file2 <span class="token operator"><<</span> <span class="token string">"\n"</span><span class="token punctuation">;</span> <span class="token function">abort</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> std<span class="token operator">::</span>unique_ptr<span class="token operator"><</span>llvm<span class="token operator">::</span>MemoryBuffer<span class="token operator">></span> File2Buffer <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">move</span><span class="token punctuation">(</span><span class="token operator">*</span>File2BufferOrErr<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 比较两个文件的内容是否相同</span> <span class="token keyword">return</span> File1Buffer<span class="token operator">-</span><span class="token operator">></span><span class="token function">getBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> File2Buffer<span class="token operator">-</span><span class="token operator">></span><span class="token function">getBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>本阶段使编译器优化模块测试部分已经可以初步使用,但仍存在一些问题,其中最重要的是防止错误指令的生成,令人头痛的种种错误情况的收敛性仍然需要评估。</p>]]></content>
<categories>
<category> 项目实训 </category>
</categories>
<tags>
<tag> 软件测试 </tag>
<tag> 编译原理 </tag>
</tags>
</entry>
<entry>
<title>PostgreSQL 源码分析</title>
<link href="/2024/01/03/db4/"/>
<url>/2024/01/03/db4/</url>
<content type="html"><![CDATA[<h1 id="PostgreSQL-源码分析"><a href="#PostgreSQL-源码分析" class="headerlink" title="PostgreSQL 源码分析"></a>PostgreSQL 源码分析</h1><p>本学期的数据库课程大作业首次开放了源码分析赛道,经过挑选的三个小组将分别负责著名的开源数据库 PostgreSQL 的三个部分的源码解析:</p><ul><li>语句编译器、查询优化模块</li><li>存储模块</li><li>事务管理和并发控制模块</li></ul><p>我们小组负责的 PostgreSQL 存储部分的分析报告如下,文章太长故不在此页显示(在此致谢 njj,bh兄 和 jp兄):<br><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/postgresql%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A.pdf">PostgreSQL_memory_part 解析报告 pdf 版本链接</a></p>]]></content>
<categories>
<category> 数据库 </category>
</categories>
<tags>
<tag> 数据库 </tag>
<tag> PostgreSQL </tag>
</tags>
</entry>
<entry>
<title>云数据库实验</title>
<link href="/2024/01/02/db3/"/>
<url>/2024/01/02/db3/</url>
<content type="html"><![CDATA[<h1 id="云数据库实验报告"><a href="#云数据库实验报告" class="headerlink" title="云数据库实验报告"></a>云数据库实验报告</h1><p>使用华为研发的 GaussDB 进行基本的数据库操作(不得不说图形化界面确实降低了上手难度):</p><p><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%91%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A.pdf">实验报告 pdf 版本链接</a></p>]]></content>
<categories>
<category> 数据库 </category>
</categories>
<tags>
<tag> 云数据库 </tag>
<tag> GaussDB </tag>
</tags>
</entry>
<entry>
<title>数据库系统——综合篇</title>
<link href="/2024/01/01/db2/"/>
<url>/2024/01/01/db2/</url>
<content type="html"><![CDATA[<h1 id="数据库系统——综合篇"><a href="#数据库系统——综合篇" class="headerlink" title="数据库系统——综合篇"></a>数据库系统——综合篇</h1><h2 id="第一章-绪论"><a href="#第一章-绪论" class="headerlink" title="第一章 绪论"></a>第一章 绪论</h2><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><ul><li>数据:描述现实世界中各种事物的可以识别的符号。</li><li>信息:一种已经被加工为特定形式的数据。数据只有被加工为信息才有价值。<ul><li>信息是各种数据所包括的意义。</li><li>数据是信息的载体,是信息的具体表现形式。</li></ul></li><li>数据处理:从大量原始数据抽取和推导有价值信息的加工过程。包括:数据收集、组织、存储、加工、分类、检索、输出、传输等操作。</li><li>数据管理:数据处理一般性的基本操作,研究专门的技术——数据库管理技术。</li><li>数据库技术:按照某种数据结构对数据进行组织,将数据存储在计算机的二级存储中,并可以提供数据共享操作的数据管理技术。</li></ul><h3 id="什么是数据库系统"><a href="#什么是数据库系统" class="headerlink" title="什么是数据库系统"></a>什么是数据库系统</h3><p>建立在数据库管理系统之上,以满足实际应用需求的数据管理(组织、存储、使用)为主要功能的计算机软件系统。</p><h3 id="数据管理技术的发展"><a href="#数据管理技术的发展" class="headerlink" title="数据管理技术的发展"></a>数据管理技术的发展</h3><h4 id="人工管理阶段"><a href="#人工管理阶段" class="headerlink" title="人工管理阶段"></a>人工管理阶段</h4><ul><li>时间:20世纪50年代中期以前</li><li>背景:外存只有磁带、卡片、纸带等,没有磁盘等直接存取设备,没有OS。</li><li>特点:<ul><li>数据不在计算机上保存。</li><li>没有软件系统对数据进行管理。程序规定数据的逻辑结构与物理结构,程序与数据不具备独立性。</li><li>没有文件的概念,数据组织方式必须由程序员设计。</li><li>一组数据对应一个程序,数据是面向应用的,程序间不能共享数据。</li></ul></li></ul><h4 id="文件系统阶段"><a href="#文件系统阶段" class="headerlink" title="文件系统阶段"></a>文件系统阶段</h4><ul><li>时间:20世纪50年代后期到60年代中期。</li><li>背景:有磁盘、有文件系统。</li><li>特点:<ul><li>以文件形式保存在外存上。</li><li>文件多样化。</li><li>数据的存取基本上以记录为单位。</li><li>程序和数据有一定的独立性。</li><li>缺点:<ul><li>数据冗余度大,浪费空间并且易造成数据的不一致性。</li><li>数据和程序缺乏独立性。</li><li>不能反映现实世界事物之间的关系。</li></ul></li></ul></li></ul><h4 id="数据库系统阶段"><a href="#数据库系统阶段" class="headerlink" title="数据库系统阶段"></a>数据库系统阶段</h4><ul><li>时间:20世纪60年代后期开始</li><li>背景:有了大容量磁盘、光盘,计算机管理数据量大,关系复杂,共享性要求强。</li><li>==特点:==<ul><li>面向全组织的复杂的数据结构,不仅描述数据本身,还描述联系,使得整个组织<strong>结构化</strong>。==<strong>数据结构化是数据库与文件系统的根本区别。</strong>==</li><li>数据冗余度小,易扩充。</li><li>具有较高的数据和程序独立性。<ul><li><strong>数据物理独立性:存储结构改变时,逻辑结构可以不变。</strong></li><li><strong>数据逻辑独立性:逻辑结构改变时,应用程序可以不变。</strong></li></ul></li><li>提供了两方面映像功能(<strong>映像功能实现数据的独立性</strong>):<ul><li>存储结构与逻辑结构映像——实现物理独立性。</li><li>全局逻辑结构与某类应用所涉及的局部逻辑结构之间的映像——实现逻辑独立性。</li></ul></li><li>统一的数据控制功能。<ul><li>数据安全性控制。</li><li>数据完整性控制。</li><li>并发控制。</li><li>数据库恢复。</li></ul></li><li>数据的最小存取单位是数据项。</li></ul></li></ul><h3 id="数据库系统的组成"><a href="#数据库系统的组成" class="headerlink" title="数据库系统的组成"></a>数据库系统的组成</h3><ul><li>数据库:数据库中存储的数据是集成的、共享的。</li><li>用户:存储、维护和检索数据的各类请求。分为三类:<ul><li>终端用户</li><li>应用程序员</li><li>数据库管理员</li></ul></li><li>软件:包括DBMS和各种应用系统。</li><li>硬件:存储数据库和运行DBMS的硬件资源,如内存、外存。</li></ul><h3 id="数据模型"><a href="#数据模型" class="headerlink" title="数据模型"></a>数据模型</h3><p>数据模型用来抽象和表示现实世界中的数据和信息。</p><p>在数据库中,模型分为两类:**==概念模型和数据模型==**。</p><h4 id="数据模型的层次"><a href="#数据模型的层次" class="headerlink" title="数据模型的层次"></a>数据模型的层次</h4><p>现实世界 —— 信息世界(概念模型) —— 机器世界(数据模型)</p><ul><li>数据模型:按计算机系统的观点对数据建模。</li><li>概念模型:现实世界到信息世界的抽象,是用户和数据库设计人员进行交流的语言。</li></ul><h4 id="概念模型"><a href="#概念模型" class="headerlink" title="==概念模型=="></a>==概念模型==</h4><p>基于信息世界的主要概念,表达应用中的各种语义。具有较强的语义表达能力,能够方便、直接表达应用中的各种语义。应该简单、清晰、易于理解。</p><h5 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h5><ul><li>实体:客观存在并可以相互区分的事物。</li><li>属性:实体所具有的某一特性。</li><li>码:唯一标识实体的属性集。</li><li>域:某个(某些)属性的取值范围。</li><li>实体型:表示一类实体,用实体名称与属性名集合来抽象刻画。</li><li>联系:实体之间的联系,有名称、类型(3种),并且可以具有属性。</li></ul><h5 id="ER图"><a href="#ER图" class="headerlink" title="ER图"></a>ER图</h5><p>组成包含:实体、联系、属性。</p><ul><li>实体:长方形。</li><li>属性:椭圆形,用无向边连接属性。</li><li>联系:菱形,用无向边连接有关的实体,并在边上标注联系类型。</li><li>一些说明:<ul><li>同一个实体集内部各实体可以有一对一、一对多和多对多联系。</li><li>三个或以上的实体可能具有联系。</li><li>两个实体之间可能有多种联系。</li></ul></li></ul><h4 id="数据模型-1"><a href="#数据模型-1" class="headerlink" title="数据模型"></a>数据模型</h4><h5 id="三要素"><a href="#三要素" class="headerlink" title="==三要素=="></a>==三要素==</h5><ul><li>数据结构:由描述数据对象以及对象之间的联系的一组概念组成。是<strong>静态特性</strong>的描述,是<strong>刻画数据模型最重要的方面</strong>。<ul><li>描述对象的类型、内容和性质的概念,如域、属性。</li><li>描述对象之间联系的概念,如关系。</li></ul></li><li>数据操作:是对数据库中各种数据对象的实例允许执行的操作集合,包括操作以及操作规则。是数据模型的<strong>动态特性</strong>的描述。数据库主要有<strong>检索</strong>和<strong>更新</strong>两大类操作。</li><li>完整性约束:完整性规则的集合,是给定数据模型中<strong>数据及其联系所有的制约和依存规则</strong>,用以<strong>保证数据正确、相容</strong>。</li></ul><h5 id="分类"><a href="#分类" class="headerlink" title="==分类=="></a>==分类==</h5><ul><li>层次模型:树结构,用有向树表示一对多联系。<ul><li>特点:有且仅有一个结点没有双亲,其他节点仅有一个双亲。</li><li>优点:结构简单易于实现。</li><li>缺点:支持联系种类太少,数据操纵不方便。</li><li>代表:IBM的IMS数据库。</li></ul></li><li>网状模型:图结构,用有向图表示一对多联系。<ul><li>特点:可以有一个以上结点没有双亲,至少有一个结点有多于一个双亲。表达的联系种类丰富,结构复杂。</li></ul></li><li>关系模型:二维表<ul><li>特点:用关系描述实体与实体间的联系,可直接表示多对多联系,关系必须是规范化关系(不允许表套表),必须建立在数学概念基础上。</li></ul></li></ul><h3 id="数据库系统的结构"><a href="#数据库系统的结构" class="headerlink" title="数据库系统的结构"></a>数据库系统的结构</h3><p><strong>==三级模式、两级映像。==</strong></p><h4 id="模式"><a href="#模式" class="headerlink" title="模式"></a>模式</h4><p><strong>数据库中全体数据的逻辑结构和特性的描述。</strong></p><p>是三级模式的核心,不涉及物理存储细节,与具体应用程序和编程语言无关。</p><p>用模式DDL写出的一个数据库逻辑定义的全部语句称为某个数据库的模式。</p><h4 id="外模式"><a href="#外模式" class="headerlink" title="外模式"></a>外模式</h4><p>个别用户的数据视图,即<strong>与某一应用有关的数据的逻辑表示</strong>。通常是模式的子集,一个应用只能启用一个外模式。数据库提供外模式描述语言定义外模式。</p><h4 id="内模式"><a href="#内模式" class="headerlink" title="内模式"></a>内模式</h4><p>称为存储模式,是数据在数据库系统内部的表示,即<strong>对数据的物理结构和存储方式的描述</strong>。</p><h4 id="两级映象"><a href="#两级映象" class="headerlink" title="两级映象"></a>两级映象</h4><ul><li>外模式/模式映象定义某个外模式与模式之间的对应关系,当模式改变时,映像做出改变就可以保证外模式不变。——**==数据的逻辑独立性==**</li><li>模式/内模式映象定义数据逻辑结构与存储结构之间的对应关系,内模式改变时,修改该映象可以使得模式保持不变。——**==数据的物理独立性==**</li></ul><h4 id="三级模式结构的优点"><a href="#三级模式结构的优点" class="headerlink" title="三级模式结构的优点"></a>三级模式结构的优点</h4><ul><li>保证数据的独立性</li><li>简化用户接口,方便用户使用</li><li>有利于数据共享</li><li>有利于数据的安全保密</li></ul><h3 id="DBMS"><a href="#DBMS" class="headerlink" title="DBMS"></a>DBMS</h3><h4 id="主要功能"><a href="#主要功能" class="headerlink" title="主要功能"></a>主要功能</h4><ul><li>数据库定义功能:提供DDL语言描述外模式、模式和内模式,模式翻译程序把原模式翻译成目标模式,存入数据字典。</li><li>数据存取功能:提供DML语言进行增删查改。</li><li>数据库运行管理:并发控制、存取控制、完整性约束条件检查和执行……</li><li>数据组织、存储和管理</li><li>数据库的建立和维护</li></ul><h4 id="组成"><a href="#组成" class="headerlink" title="组成"></a>组成</h4><ul><li>语言编译处理程序</li><li>系统运行控制程序</li><li>系统建立和维护程序</li><li>数据字典</li></ul><h2 id="第二章-关系数据库"><a href="#第二章-关系数据库" class="headerlink" title="第二章 关系数据库"></a>第二章 关系数据库</h2><h3 id="关系的数学定义"><a href="#关系的数学定义" class="headerlink" title="关系的数学定义"></a>关系的数学定义</h3><ul><li>域</li><li>元组和分量</li><li>关系:笛卡尔积$D_1 * D_2 * …$的子集叫做在域$D_1 * D_2 * …$上的关系,用$R(D_1, D_2, …)$表示。$n$是关系的度或目($degree$)。</li></ul><h3 id="关系数据模型"><a href="#关系数据模型" class="headerlink" title="==关系数据模型=="></a>==关系数据模型==</h3><h4 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h4><ul><li>关系模型的==数据结构==——关系。</li><li>码<ul><li>候选码:关系中的某一个属性组,若它唯一标识元组并具有最小性则为候选码。</li><li>主码:选定一个候选码为主码。</li></ul></li><li>主属性:码中的属性。</li><li>非主属性:不在码中的属性。</li><li>关系模式:$R(U, D, dom, F, I)$,简记作$R(A_1, A_2,\dots,A_n)$。关系式关系模式在某一时刻的状态或内容。关系模式是相对稳定的,关系是动态的。</li><li>语义约束:<ul><li>==实体完整性==:要有属性或属性组合作为主码,主码不能为空或部分为空。</li><li>==参照完整性==:<ul><li>外码:某个R的属性(组)与另外一个基本关系S的主码对应,即为外码。R为参照关系,S为被参照关系(目标关系)。</li><li>参照完整性:外码或者等于S的主码,或者为空。</li></ul></li><li>用户定义完整性</li></ul></li></ul><h4 id="数据操作"><a href="#数据操作" class="headerlink" title="数据操作"></a>数据操作</h4><ul><li><p>特点:集合操作,操作对象都是集合。</p></li><li><p>基础:关系运算,分为代数方式和逻辑方式。</p><ul><li><p>关系代数</p></li><li><p>关系演算</p><ul><li>元组关系演算</li><li>域关系演算</li></ul></li></ul></li></ul><h3 id="关系代数"><a href="#关系代数" class="headerlink" title="关系代数"></a>关系代数</h3><p>共有9种:</p><ul><li>常规集合运算:并、差、交、广义笛卡尔积。</li><li>特有关系运算:选择、投影、连接、自然连接、求商。</li></ul><h4 id="传统集合运算"><a href="#传统集合运算" class="headerlink" title="传统集合运算"></a>传统集合运算</h4><p>是二目运算,除了笛卡尔积外,要求参加运算的两个关系必须是同类关系。</p><ul><li>并:将R和S的元组统一到一个集合。</li><li>差:从R中剔除S中存在的元组。</li><li>交:R和S的共同元组。</li><li>广义笛卡尔积:将R和S的元组并列。</li></ul><h4 id="专门的关系运算"><a href="#专门的关系运算" class="headerlink" title="专门的关系运算"></a>专门的关系运算</h4><ul><li>选择:在R中选择出满足条件的元组,记作$\sigma_F(R) = {t|t∈R,F(t)=true}$。</li><li>投影:从R中选出若干属性删除重复的行,记作$\pi_A(R)={t[A]|t∈R,A\sube U}$。</li><li>连接:R和S在属性X和Y上的连接(X,Y是连接属性,即X和Y包含同等数量的属性,且相应属性有共同的域),是从两个关系的广义笛卡尔积里选出满足比较条件θ的元组,记作 $R⋈S_{X \theta Y}={t|t=<r,s>\and s∈S\and r∈R\and r[X]\theta r[Y]}$。</li><li>自然连接:在相同属性列取值相等为条件的连接,要去掉重复属性列。</li><li>除法:关系S的属性是关系R属性的子集,记为$R\div S={t|t∈\pi_X(R)\and s∈S\and <t,s>∈R}$。(结果包含S中没有的属性)</li></ul><h3 id="关系演算"><a href="#关系演算" class="headerlink" title="关系演算"></a>关系演算</h3><h4 id="元组关系演算"><a href="#元组关系演算" class="headerlink" title="元组关系演算"></a>元组关系演算</h4><p>基本结构是元组演算表达式。</p><h4 id="域关系演算"><a href="#域关系演算" class="headerlink" title="域关系演算"></a>域关系演算</h4><p>类似于元组演算,公式中的变量对应元组各个分量的域变量。</p><h3 id="关系运算的安全约束"><a href="#关系运算的安全约束" class="headerlink" title="关系运算的安全约束"></a>关系运算的安全约束</h3><p>不产生无限关系和无穷验证的运算成为安全运算,其表达式称为安全表达式,对其采取的限制称为安全约束。</p><h3 id="数据库数据语言"><a href="#数据库数据语言" class="headerlink" title="数据库数据语言"></a>数据库数据语言</h3><ul><li>DDL:数据定义(描述)语言</li><li>DML:数据操纵语言,检索、插入、修改、删除。<ul><li>联机交互方式</li><li>宿主语言方式</li></ul></li><li>DCL:数据控制语言,完成安全性控制、完整性控制、并发控制等。</li><li>关系数据语言特点:<ul><li>一体化</li><li>非过程化</li><li>面向集合的存取方式</li><li>既可以独立使用又可以与主语言嵌套使用</li></ul></li></ul><h2 id="第三章-关系数据库标准语言SQL"><a href="#第三章-关系数据库标准语言SQL" class="headerlink" title="==第三章 关系数据库标准语言SQL=="></a>==第三章 关系数据库标准语言SQL==</h2><h3 id="SQL的特点"><a href="#SQL的特点" class="headerlink" title="==SQL的特点=="></a>==SQL的特点==</h3><ul><li>综合统一</li><li>高度非过程化</li><li>面向集合</li><li>以同一种语法结构提供两种使用方式</li><li>语言简捷、易学易用</li></ul><h3 id="基本概念-1"><a href="#基本概念-1" class="headerlink" title="基本概念"></a>基本概念</h3><ul><li>基本表:实际存在的</li><li>导出表:有视图(虚表)和快照。</li></ul><h3 id="检索"><a href="#检索" class="headerlink" title="==检索=="></a>==检索==</h3><ul><li>SELECT A FROM B:对应不去重的投影操作。</li><li>SELECT DISTINCT A FROM B:对应投影。</li><li>SELECT A FROM B WHERE C = D:选取检索,可以用AND、OR或NOT连接条件=,<>,>,>=,<,<=。可以使用BETWEEN a AND b表示某个区间。</li><li>SELECT A FROM B WHERE C = D ORDER BY A ASC:对A升序排列,如果降序可以写DESC。</li><li>WHERE后可以指明连接条件,选择需要的若干列。</li><li>外连接:<code>SELECT * FROM S, SC WHERE S.S#=SC.S#(*)</code></li><li>子查询:<ul><li>如果返回单值,可以直接用比较运算。</li><li>如果返回了多值,必须在比较运算符和子查询之间加入ANY或ALL。</li><li>IN与=ANY是等价的,NOT IN与!=ALL是等价的。</li><li>EXISTS:在子查询结果非空时为真。</li><li>NOT EXISTS:子查询结果为空时为真。</li></ul></li><li>并:UNION</li><li>交:INTERSECT</li><li>差:MINUS</li><li>COUNT:按列值记个数,COUNT(*)对行记数。</li><li>SUM:对数值列求和。</li><li>AVG:求数值列平均值。</li><li>MAX:求列的最大值。</li><li>MIN:求列的最小值。</li><li>GROUP BY A [HAVING B = C]。</li></ul><h3 id="表操作"><a href="#表操作" class="headerlink" title="表操作"></a>表操作</h3><h4 id="定义基本表"><a href="#定义基本表" class="headerlink" title="定义基本表"></a>定义基本表</h4><p><code>CREATE TABLE table_name (S# char(5) not null unique, SN char(20) not null, SA int, primary key(S#), check(SA >= 18))</code></p><h4 id="修改基本表"><a href="#修改基本表" class="headerlink" title="修改基本表"></a>修改基本表</h4><p><code>ALTER TABLE table_name [ADD <新列名><数据类型>][DROP<完整性约束名>][MODIFY<列名><数据类型>]</code></p><h4 id="删除基本表"><a href="#删除基本表" class="headerlink" title="删除基本表"></a>删除基本表</h4><p><code>DROP TABLE table_name</code></p><h4 id="定义视图"><a href="#定义视图" class="headerlink" title="定义视图"></a>定义视图</h4><p><code>CREATE VIEW view_name AS (SELECT ...)</code></p><ul><li>视图消解:将视图定义的子查询和用户查询结合,转换成对基本表的查询。</li><li>视图作用:<ul><li>检化用户操作</li><li>使用户能够以多种角度看待同一数据</li><li>提供一定程度的逻辑独立性</li><li>能够对数据提供安全保护</li></ul></li></ul><h3 id="数据更新"><a href="#数据更新" class="headerlink" title="数据更新"></a>数据更新</h3><h4 id="插入"><a href="#插入" class="headerlink" title="插入"></a>插入</h4><p><code>INSERT INTO table_name ([<属性列>{,<属性列>}]) VALUES(<值>{,<值>})</code></p><h4 id="修改"><a href="#修改" class="headerlink" title="修改"></a>修改</h4><p><code>UPDATE table_name SET <列名>=<表达式></code></p><h4 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h4><p><code>DELETE FROM table_name [WHERE <条件>]</code></p><h3 id="嵌入式SQL"><a href="#嵌入式SQL" class="headerlink" title="嵌入式SQL"></a>嵌入式SQL</h3><p>把SQL的最佳特性与程序设计语言的最佳特性结合,使SQL功能更强,灵活性更强。</p><p>预编译法:把嵌入在程序中的SQL语句翻译为高级语言源码,然后按主语言的通常方式进行编译、链接生成可执行代码。</p><h3 id="动态SQL"><a href="#动态SQL" class="headerlink" title="动态SQL"></a>动态SQL</h3><p>允许程序运行过程中临时组装SQL语句,有语句可变、条件可变、数据库对象,查询条件均可变三种形式。</p><h3 id="ODBC-JDBC"><a href="#ODBC-JDBC" class="headerlink" title="ODBC/JDBC"></a>ODBC/JDBC</h3><p>四个组件:应用程序、驱动程序管理器、驱动程序和数据源。</p><h2 id="第四章-数据库设计"><a href="#第四章-数据库设计" class="headerlink" title="第四章 数据库设计"></a>第四章 数据库设计</h2><h3 id="数据库设计概述"><a href="#数据库设计概述" class="headerlink" title="数据库设计概述"></a>数据库设计概述</h3><ul><li>数据库设计:对于一个给定的应用环境,<strong>设计优化的数据库逻辑和物理结构,建立数据库</strong>,使之能够有效地存储数据,为开发满足用户需求的应用系统奠定基础。</li><li>数据库设计的特点:要把<strong>数据设计</strong>和<strong>处理设计</strong>密切结合。</li><li>设计方法:<ul><li>手工试凑法:根据应用的数据要求与处理要求直接设计数据库的结构。</li><li>规范设计法:运用软工思想,<strong>整个设计过程划分为若干阶段,每个阶段只解决整个设计中的部分问题,是迭代和逐步求精的过程</strong>。</li></ul></li></ul><h3 id="数据库设计的基本步骤"><a href="#数据库设计的基本步骤" class="headerlink" title="数据库设计的基本步骤"></a>数据库设计的基本步骤</h3><ul><li>==需求分析==:现实世界</li><li>==概念结构设计==:概念模式,生成概念模型,ER图</li><li>==逻辑结构设计==:逻辑模式,生成DBMS支持的数据模型</li><li>物理结构设计:内模式,设计存储结构和存取方法</li><li>数据库实施</li><li>数据库运行维护</li></ul><h4 id="需求分析"><a href="#需求分析" class="headerlink" title="需求分析"></a>需求分析</h4><ul><li>目标:收集支持系统应用目标的基础数据及其处理。重点是“数据”和“处理”,包括<strong>处理要求,信息要求,安全性与完整性要求</strong>。</li><li>两个阶段:调查用户实际要求;分析表达需求,用数据流图和数据字典。</li><li>数据流图<ul><li>自顶向下逐步分解处理功能以及他们所用的数据。</li></ul></li><li>数据字典:需求分析阶段,可以看成<strong>数据元素表</strong>。<ul><li>包含每一个数据元素的名字、含义等各方面的描述。</li><li>从数据流图提取出所有原子数据项。</li><li>把有联系的数据项组合起来形成数据组。</li><li>以数据组为单位写出语义定义、类型定义、完整性约束定义等。</li></ul></li></ul><h4 id="概念结构设计"><a href="#概念结构设计" class="headerlink" title="==概念结构设计=="></a>==概念结构设计==</h4><p>ER图:参考上面第一章内容。</p><h5 id="设计概念结构四类方法"><a href="#设计概念结构四类方法" class="headerlink" title="设计概念结构四类方法"></a>设计概念结构四类方法</h5><ul><li>自顶向下</li><li>自底向上:最常用</li><li>逐步扩张</li><li>混合策略</li></ul><h5 id="数据抽象"><a href="#数据抽象" class="headerlink" title="数据抽象"></a>数据抽象</h5><ul><li>分类:定义某一概念作为现实世界中一组对象的类型。</li><li>聚集:定义某一类型的组成成分。</li><li>概括:定义类型之间的一种子集联系。</li></ul><h5 id="实体模型的调整原则"><a href="#实体模型的调整原则" class="headerlink" title="实体模型的调整原则"></a>实体模型的调整原则</h5><ul><li>属性不能再分,必须是<strong>不可分的数据项</strong>。</li><li>属性不能与其他实体有联系。</li><li>实体与属性之间保持1:1或n:1联系,不满足的情况可以将属性上升为实体。</li></ul><h5 id="集成局部ER图"><a href="#集成局部ER图" class="headerlink" title="集成局部ER图"></a>集成局部ER图</h5><ul><li>合并:解决各分ER图之间的冲突,将各分ER图合并成初步ER图。冲突主要包括属性冲突、命名冲突和结构冲突。</li><li>修改和重构:消除冗余生成基本ER图。</li></ul><h5 id="设计基本ER图"><a href="#设计基本ER图" class="headerlink" title="设计基本ER图"></a>设计基本ER图</h5><ul><li>消除冗余,可能存在冗余数据或冗余联系。</li></ul><h4 id="逻辑结构设计"><a href="#逻辑结构设计" class="headerlink" title="逻辑结构设计"></a>逻辑结构设计</h4><p>把概念结构转换为选用的DBMS所支持的数据模型。</p><h5 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h5><ul><li>概念结构根据转换规则生成一般数据模型。</li><li>根据关系数据理论,进行规范化。</li><li>生成特定DBMS支持下的数据模型。</li><li>优化数据模型。</li></ul><h4 id="物理结构设计"><a href="#物理结构设计" class="headerlink" title="物理结构设计"></a>物理结构设计</h4><ul><li>确定存储结构:索引、聚集、hash。</li><li>选择关系的存取方法</li></ul><h2 id="第五章-关系数据理论"><a href="#第五章-关系数据理论" class="headerlink" title="==第五章 关系数据理论=="></a>==第五章 关系数据理论==</h2><h3 id="函数依赖"><a href="#函数依赖" class="headerlink" title="函数依赖"></a>函数依赖</h3><ul><li>数据依赖:属性值之间相互依赖又相互制约的关系。最重要的有两种:函数依赖和多值依赖。</li></ul><h4 id="函数依赖的定义"><a href="#函数依赖的定义" class="headerlink" title="函数依赖的定义"></a>函数依赖的定义</h4><ul><li>定义:对于X的每个具体值,Y有唯一的值与之对应,则称X函数确定Y或Y函数依赖于X。($X\rightarrow Y$)</li></ul><h4 id="相关术语"><a href="#相关术语" class="headerlink" title="相关术语"></a>相关术语</h4><ul><li>平凡函数依赖:$Y\sube X$。</li><li>非平凡函数依赖:不是平凡函数依赖。</li><li>决定因素:$X$是$X\rightarrow Y$的决定因素。</li><li>完全函数依赖:如果有$X\rightarrow Y$且对于任意$X$的真子集$X’$都有$X’\nrightarrow Y$,则是完全函数依赖。</li><li>部分函数依赖:不是完全函数依赖的函数依赖。</li><li>传递函数依赖:$X\rightarrow Y$且$Y\rightarrow Z$,并且$Y \nrightarrow X$,则称$Z$对$X$传递函数依赖。</li></ul><h5 id="补充说明"><a href="#补充说明" class="headerlink" title="补充说明"></a>补充说明</h5><p>函数依赖是语义范畴的概念,不随时间变化。</p><h4 id="与联系的关系"><a href="#与联系的关系" class="headerlink" title="与联系的关系"></a>与联系的关系</h4><ul><li>1对1:有$X\rightarrow Y$和$Y\rightarrow X$。</li><li>1对m:有$Y\rightarrow X$。</li><li>n对m:无函数依赖关系。</li></ul><h4 id="关系键的形式定义"><a href="#关系键的形式定义" class="headerlink" title="关系键的形式定义"></a>关系键的形式定义</h4><ul><li>候选码与主码:<ul><li>候选码:U完全函数依赖于K。</li><li>主码:如果多个候选码,就选一个作为主码。性质有唯一性和最小性。</li></ul></li><li>主属性与非主属性:<ul><li>主属性:包含在任何一个候选码中的属性。</li><li>非主属性:不是主属性。</li></ul></li><li>外部码:R中的属性或属性组X不是R的码但是是另一个关系模式的码,则X是R的外部码。</li></ul><h4 id="函数依赖的逻辑蕴涵"><a href="#函数依赖的逻辑蕴涵" class="headerlink" title="函数依赖的逻辑蕴涵"></a>函数依赖的逻辑蕴涵</h4><ul><li>从$R<U, F>$中可以推出$X \rightarrow Y$则称为$F$逻辑蕴涵$X \rightarrow Y$。</li><li>$F$的闭包:$F$所蕴涵的函数依赖的全体,记作$F^+$。</li></ul><h4 id="Armstrong公理系统"><a href="#Armstrong公理系统" class="headerlink" title="==Armstrong公理系统=="></a>==Armstrong公理系统==</h4><p>对于$R<U, F>$有如下规则:</p><ul><li>A1自反律:若$Y\sube X\sube U$则$X \rightarrow Y$为$F$所蕴涵。</li><li>A2增广律:若$X \rightarrow Y$为$F$所蕴涵,且$Z\sube U$则$XZ\rightarrow YZ$为$F$所蕴涵。</li><li>A3传递律:若$X \rightarrow Y$且$Y \rightarrow Z$为$F$所蕴涵,则$X \rightarrow Z$为$F$所蕴涵。</li></ul><h5 id="推论"><a href="#推论" class="headerlink" title="推论"></a>推论</h5><ul><li>合并规则:由$X \rightarrow Y$,$Y \rightarrow Z$,有$X \rightarrow YZ$。</li><li>伪传递规则:由$X \rightarrow Y$,$WY \rightarrow Z$,有$XW \rightarrow Z$。</li><li>分解规则:由$X \rightarrow Y$和$Z \sube Y$,有$X \rightarrow Z$。</li><li>定理1:$X \rightarrow A_1 A_2 A_3\dots A_k$成立等价于$X\rightarrow A_i$(i = 1, 2, 3…k)成立。</li></ul><h5 id="属性集闭包"><a href="#属性集闭包" class="headerlink" title="属性集闭包"></a>属性集闭包</h5><ul><li>定理:$X \rightarrow Y$可以由$F$根据公理系统导出等价于$Y \sube X_F^+$。</li></ul><h5 id="公理系统的有效性与完备性"><a href="#公理系统的有效性与完备性" class="headerlink" title="公理系统的有效性与完备性"></a>公理系统的有效性与完备性</h5><ul><li>有效性:由F除法根据Armstrong公里推导出来的每一个函数依赖一定在F所蕴涵的函数依赖的全体之中。</li><li>完备性:F所蕴涵的函数依赖的全体中的每一个函数依赖,必定可以由F根据Armstrong公理系统导出。</li></ul><h5 id="求属性闭包的算法"><a href="#求属性闭包的算法" class="headerlink" title="求属性闭包的算法"></a>求属性闭包的算法</h5><ul><li>初始,$X_F^+=X$,然后把$F$中所有$X_F$下属性能推出的属性都加进去,直到不变或者变为属性全集$U$。</li></ul><h5 id="函数依赖集等价"><a href="#函数依赖集等价" class="headerlink" title="函数依赖集等价"></a>函数依赖集等价</h5><ul><li>若函数依赖集$F^+=G^+$,则称F和G等价。</li><li>==最小函数依赖集==条件:<ul><li>$F$中任一函数依赖$X \rightarrow A$,$A$必须是单属性。</li><li>$F$中不存在$X \rightarrow A$使得$F$与$F-{X\rightarrow A}$等价,即不存在多余的依赖。</li><li>$F$中不存在$X \rightarrow A$,在$X$中有真子集$Z$,使得$F$与$F-{X \rightarrow A}∪{Z \rightarrow A}$等价,即左侧不能有多余的属性。</li></ul></li><li>==极小化的算法:==<ul><li>首先将所有$X\rightarrow Y$的$Y$展开。</li><li>逐个检查$F$中的函数依赖的左侧,如果左侧是多属性,且删去一个属性后依然可以推出右侧,则能够删掉。形式化为:对于$X \rightarrow A$,设$X=B_1\dots B_m$,如果$A∈(X-B_i)^+_F$,则以$(X-B_i)$取代$X$直到$F$不再改变。</li><li>逐个检查$F$中的每个函数依赖,如果删掉函数依赖后的$G=F-{X\rightarrow A}$,仍然可以有$A∈(X)_G^+$,就删除该函数依赖。</li></ul></li></ul><h3 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h3><p>如果一个关系满足某个指定的约束集,则称它属于某种特定的范式(Normal Form)。</p><h4 id="1NF"><a href="#1NF" class="headerlink" title="1NF"></a>1NF</h4><p>当一个关系只包含原子值这一约束时,称为1NF。也就是表里每个格只有一个值。满足原子值这一约束条件的关系称为规范化关系简称范式。</p><p>一个低一级范式的关系模式,可以通过<strong>模式分解</strong>转换为若干高级范式的关系模式的集合,这个过程称为<strong>规范化</strong>。</p><h4 id="2NF"><a href="#2NF" class="headerlink" title="2NF"></a>2NF</h4><ul><li>定义:1NF的关系的每个非主属性完全依赖于码,就是2NF。</li><li>弊病:<ul><li>插入异常有所改善但是仍然存在。</li><li>删除异常。</li><li>数据冗余得到了一定的改善。</li></ul></li></ul><h4 id="3NF"><a href="#3NF" class="headerlink" title="3NF"></a>3NF</h4><p>定义:如果不存在码$X$,属性组$Y$和非主属性$Z(Z不是Y的子集)$,使得下式成立,$X\rightarrow Y$,$Y\rightarrow Z$,$Y \nrightarrow X$,则$R∈3NF$。(2NF的关系模式,每个非主属性都不传递依赖于任何码)</p><h4 id="BCNF"><a href="#BCNF" class="headerlink" title="BCNF"></a>BCNF</h4><ul><li>所有非主属性都完全函数依赖于每个候选码。</li><li>所有主属性都完全函数依赖于每个不包含它的候选码。</li><li>没任何属性完全函数依赖于非码的任意一组属性。</li></ul><h4 id="多值依赖与4NF"><a href="#多值依赖与4NF" class="headerlink" title="多值依赖与4NF"></a>多值依赖与4NF</h4><ul><li>多值依赖定义:$Z = U - X - Y$,关系模式$R(U)$中多值依赖$X\rightarrow \rightarrow Y$成立,当且仅当对$R(U)$的任一关系r,给定的一对$(x,z)$值有一组$Y$的值,这组值仅仅取决于x值而与z值无关。</li><li>多值依赖有对称性,若$X\rightarrow \rightarrow Y$则$X\rightarrow \rightarrow (U-X-Y)$。</li><li>$X\rightarrow Y$可以推出$X\rightarrow \rightarrow Y$。</li><li>4NF:对于每个非平凡的多值依赖$X\rightarrow \rightarrow Y$且必须是函数依赖,$X$都含有码。</li></ul><h3 id="规范化目的与基本思想"><a href="#规范化目的与基本思想" class="headerlink" title="规范化目的与基本思想"></a>规范化目的与基本思想</h3><p>在关系数据库中,对关系的最基本要求是满足1NF。</p><p>规范化要逐步消除数据依赖中不合适的部分,使数据库模式中各关系模式达到某种程度的“分离”,使一个关系只描述一个实体或者实体间的一种联系,即<strong>“一事一地”</strong>的设计原则。规范化的实质是<strong>概念的单一化</strong>。</p><h3 id="模式分解理论"><a href="#模式分解理论" class="headerlink" title="模式分解理论"></a>模式分解理论</h3><h4 id="无损连接性分解判定算法"><a href="#无损连接性分解判定算法" class="headerlink" title="无损连接性分解判定算法"></a>无损连接性分解判定算法</h4><p>$F={FD_1,\dots, FD_p}$</p><ul><li>如果将n个属性的关系模式分解为k个,先建立n列k行的表TB:<ul><li>每一列对应一个属性$A_i$。</li><li>每一行对应分解中的一个关系模式$R_i$。</li><li>分量的取值:$C_{ij}=A_j∈U_i?a_j:b_{ij}$。</li></ul></li><li>对$FD_i$中每一个函数依赖$X\rightarrow Y$,若TB中存在元素t1和t2使,t1[X]=t2[X],则对每一个$A_i∈Y$:<ul><li>若$t1[A_i], t2[A_i]$有一个等于ai,则另一个也改为ai。</li><li>若上面不成立,就取$t1[A_i]=t2[A_i]$。(t1行号小于t2)</li></ul></li><li>反复执行上一步直到:<ul><li>TB出现一行为全a,即为无损分解。</li><li>TB不变且没有一行为全a,为有损分解。</li></ul></li></ul><h4 id="无损分解判定准则"><a href="#无损分解判定准则" class="headerlink" title="无损分解判定准则"></a>无损分解判定准则</h4><p>定理:分解$ρ={R_1<U_1,F_1>,R_2<U_2,F_2>}$具有无损连接性的充分必要条件是,$U_1∩U_2\rightarrow U_1-U_2∈F^+$或$U_1∩U_2\rightarrow U_2-U_1∈F^+$。即$R_1, R_2$的共同属性至少构成$R_1,R_2$两者之一的候选码。</p><h4 id="保持函数依赖判定准则"><a href="#保持函数依赖判定准则" class="headerlink" title="保持函数依赖判定准则"></a>保持函数依赖判定准则</h4><p>$R$中的每个函数依赖都能够从$R_1,\dots,R_n$函数依赖的并集中逻辑导出。</p><h4 id="模式分解原则"><a href="#模式分解原则" class="headerlink" title="模式分解原则"></a>模式分解原则</h4><ul><li>投影分解应遵循的原则:<ul><li>具有无损连接性</li><li>保持函数依赖</li></ul></li><li>模式分解能够达到的最高范式等级:<ul><li>要求保持函数依赖,总可以达到3NF,不一定到BCNF。</li><li>要求无损连接,一定可以达到4NF或更高。</li><li>要求两者都保持,可以达到3NF,但不一定到BCNF。</li></ul></li></ul><h4 id="达到3NF的等价模式分解"><a href="#达到3NF的等价模式分解" class="headerlink" title="达到3NF的等价模式分解"></a>达到3NF的等价模式分解</h4><h5 id="保持函数依赖的分解算法"><a href="#保持函数依赖的分解算法" class="headerlink" title="保持函数依赖的分解算法"></a>保持函数依赖的分解算法</h5><ul><li>对F进行极小化。</li><li>找出不在F的属性,将它们构成一个关系模式,并且从U中去掉。</li><li>若有$X\rightarrow A∈F$,且$XA=U$,则$ρ={R}$,算法终止。</li><li>对F按具有相同左部的原则分成k组,每一组函数以阿里所涉及的属性全体记为$U_i$,若有$U_i\sube U_j$则去掉$U_i$。令$F_i$为$F$在$U_i$上的投影,则可以获得一个保持函数依赖的分解$ρ={R_1<U_1,F_1>,\dots,R_k<U_k,F_k>}$。</li></ul><h5 id="同时保持函数依赖和无损连接的分解算法"><a href="#同时保持函数依赖和无损连接的分解算法" class="headerlink" title="同时保持函数依赖和无损连接的分解算法"></a>同时保持函数依赖和无损连接的分解算法</h5><p>设$ρ$是一个保持函数依赖的分解,$X$为$R<U,F>$的码。</p><ul><li>如果有某个$U_i$满足$X\sube U_i$,则ρ即为所求。</li><li>否则令$τ=ρ∪{R*<X,F_X>}$,τ即为所求。</li></ul><h4 id="达到BCNF的无损连接分解算法"><a href="#达到BCNF的无损连接分解算法" class="headerlink" title="达到BCNF的无损连接分解算法"></a>达到BCNF的无损连接分解算法</h4><ul><li>令$ρ=R<U,F>$。</li><li>检查$ρ$中各关系模式是否属于BCNF,若是,则算法终止。</li><li>设ρ中的$R_i<U_i,F_i>$不属于BCNF,则存在函数依赖$X\rightarrow A∈F_i^+$,且$X$不是$R_i$的码,则$XA$是$U_i$的真子集,将$R_i$分解为$\sigma={S_1,S_2}$,其中$U_{S_1}=XA,U_{S_2}=U_i-{A}$,以$\sigma$代替$R_i$返回上一步。</li></ul><h3 id="候选码的求解"><a href="#候选码的求解" class="headerlink" title="候选码的求解"></a>候选码的求解</h3><h4 id="属性分类"><a href="#属性分类" class="headerlink" title="属性分类"></a>属性分类</h4><ul><li>L类:只出现在F函数依赖左侧的属性。</li><li>R类:只出现在F函数依赖右侧的属性。</li><li>N类:没有出现在函数依赖中的属性。</li><li>LR类:在左右均出现的属性。</li></ul><h4 id="定理"><a href="#定理" class="headerlink" title="定理"></a>定理</h4><ul><li>如果X是L类属性,则必是任一候选码的成员。</li><li>如果X是R类属性,则X不在R的任何一个候选码中。</li><li>如果X是N类属性,则X必包含在任一候选码中。</li></ul><h4 id="图论判定法"><a href="#图论判定法" class="headerlink" title="图论判定法"></a>图论判定法</h4><p>将函数依赖关系绘制成有向图。</p><ul><li>入度为0的为原始点,L类。</li><li>出度为0的为终结点,R类。</li><li>入度出度均不为0的为途中点,LR类。</li><li>入度出度均为0的为孤立点,N类。</li><li>关键点:原始点和孤立点。</li><li>独立回路:不能由其他点到达的回路。</li></ul><h4 id="定理-1"><a href="#定理-1" class="headerlink" title="定理"></a>定理</h4><ul><li>关键点必在R的任何候选码中。</li><li>终结点必不在R的任何候选码中。</li><li>R具有唯一候选码的充要条件是G中不存在独立回路。</li><li>若Y是途中点且Y在独立回路,则Y必在某候选码中。</li></ul><h4 id="多属性依赖集候选码求解"><a href="#多属性依赖集候选码求解" class="headerlink" title="多属性依赖集候选码求解"></a>多属性依赖集候选码求解</h4><ul><li>将所有属性分成L、R、LR和N四类,并令X代表L和N类,Y代表LR类。</li><li>求出$X_F^+$,如果是U,则X为唯一候选码,否则继续下一步。</li><li>对于Y中任一一个属性A,求$(XA)_F^+$,若为U,则XA为一个候选码,否则在Y中依次取2个、3个,求属性闭包,直到闭包包含R的全部属性。</li></ul><h3 id="与数据库设计的联系"><a href="#与数据库设计的联系" class="headerlink" title="与数据库设计的联系"></a>与数据库设计的联系</h3><ul><li>求最小依赖集消除冗余联系。</li><li>一般情况下3NF足以满足要求。</li></ul><h2 id="第六章-关系查询处理与查询优化(不是重点)"><a href="#第六章-关系查询处理与查询优化(不是重点)" class="headerlink" title="第六章 关系查询处理与查询优化(不是重点)"></a>第六章 关系查询处理与查询优化(不是重点)</h2><h3 id="关系查询处理步骤——四个阶段"><a href="#关系查询处理步骤——四个阶段" class="headerlink" title="关系查询处理步骤——四个阶段"></a>关系查询处理步骤——四个阶段</h3><ul><li>查询分析:词法分析,语法检查和语法分析。</li><li>查询检查:语义检查,存取权限检查,SQL语句转换为关系代数表达式。</li><li>查询优化:选择一个高效的查询处理策略,按照优化的层次分为代数优化和物理优化。</li><li>查询执行:生成查询计划,生成执行查询计划的代码。</li></ul><h3 id="查询优化"><a href="#查询优化" class="headerlink" title="查询优化"></a>查询优化</h3><ul><li>目标:选择一个高效的执行查询处理策略,使得查询代价最小。</li><li>执行开销:总代价=IO代价+CPU代价+内存代价</li><li>按照优化层次分为代数优化和物理优化:<ul><li>代数优化:改变代数表达式的操作次序和组合。</li><li>物理优化:存取路径和底层操作算法选择。</li></ul></li><li>一般步骤:<ul><li>把查询转换成语法树,如关系代数语法树。</li><li>代数优化语法树。</li><li>物理优化,选择存取路径。</li><li>生成查询计划。</li></ul></li></ul><h3 id="代数优化"><a href="#代数优化" class="headerlink" title="代数优化"></a>代数优化</h3><p>通过对关系代数表达式的等价变化来提高查询效率。</p><p>等价:用相同的关系代替两个表达式中相应的关系所得到的结果是相同的。</p><ul><li>连接和笛卡尔积交换律。</li><li>连接和笛卡尔积结合律。</li><li>投影串接定律。</li><li>选择串接定律。</li><li>选择与投影的交换律。</li><li>选择与笛卡尔积的交换律。</li><li>选择与并的分配律。</li><li>选择与差的分配律。</li><li>选择对自然连接的分配律。</li><li>投影与笛卡尔积的分配律。</li><li>投影与并的分配律。</li></ul><p>查询树的启发式优化:</p><ul><li>减小中间关系——选择运算早做。</li><li>减少扫描关系的次数</li><li>把笛卡尔积与选择转换为连接</li><li>中间结果复用</li></ul><h3 id="物理优化"><a href="#物理优化" class="headerlink" title="物理优化"></a>物理优化</h3><p>常用方法:</p><ul><li>基于规则的启发式优化方法</li><li>基于代价估算的优化方法</li><li>两者结合的优化方法</li></ul><p>基于启发式规则的存取路径选择优化:</p><ul><li>选择操作的启发式规则:<ul><li>小关系使用全表顺序扫描。</li><li>大关系可以使用索引扫描。</li></ul></li><li>连接操作的启发式规则:<ul><li>排序合并</li><li>索引连接</li><li>hash join</li><li>嵌套循环</li></ul></li></ul><h2 id="第七章-事务处理技术"><a href="#第七章-事务处理技术" class="headerlink" title="第七章 事务处理技术"></a>第七章 事务处理技术</h2><h3 id="事务的概念"><a href="#事务的概念" class="headerlink" title="事务的概念"></a>事务的概念</h3><h4 id="事务的定义"><a href="#事务的定义" class="headerlink" title="==事务的定义=="></a>==事务的定义==</h4><p>事务是用户定义的数据库操作序列,这些操作要么都做,要么都不做。</p><ul><li>事务与应用程序是两个概念。</li><li>事务的开始与结束可以由用户显式控制。</li></ul><h4 id="事务的特性"><a href="#事务的特性" class="headerlink" title="==事务的特性=="></a>==事务的特性==</h4><ul><li>原子性:事务中包括的所有操作要么都做,要么都不做。</li><li>一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。</li><li>隔离性:一个事务的执行不能被其他事务干扰,一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的事务之间不能互相干扰。</li><li>持久性:一个事务一旦提交,它对数据库的影响必须是永久的,其他操作或故障不应该对其执行的结果有任何影响。</li></ul><p>ACID特性对于数据库数据的正确有效有重要意义。</p><ul><li>利用数据库并发控制机制以及数据库恢复机制保证事务的特性不被破坏。从而保证数据库数据的正确有效。</li><li><strong>事务是数据库恢复和并发控制的基本单位。</strong></li></ul><h4 id="SQL事务的定义"><a href="#SQL事务的定义" class="headerlink" title="SQL事务的定义"></a>SQL事务的定义</h4><ul><li>开始:<code>BEGIN TRANSACTION</code>。</li><li>结束:<code>COMMIT</code>或<code>ROLLBACK</code>。</li></ul><h3 id="数据库恢复技术"><a href="#数据库恢复技术" class="headerlink" title="数据库恢复技术"></a>数据库恢复技术</h3><h4 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h4><p>把数据库从某一错误状态恢复到某一已知的正确状态。</p><p>通过<strong>数据库管理系统的恢复子系统</strong>完成。</p><h5 id="意义"><a href="#意义" class="headerlink" title="意义"></a>意义</h5><ul><li>保证事务原子性。</li><li>当系统故障后,使数据库恢复正常状态。</li></ul><h4 id="故障种类"><a href="#故障种类" class="headerlink" title="故障种类"></a>故障种类</h4><ul><li>事务内部故障:<ul><li>可预期的:事务根据内部条件来回滚。</li><li>不可预期的:不能由应用程序处理,比如死锁、运算溢出、违反完整性规则等。</li></ul></li><li>系统故障:<ul><li>造成系统停止运行的任何事情。</li><li>使事务都异常终止但不会破坏数据库。</li></ul></li><li>介质故障:<ul><li>外存故障。</li><li>破坏全部或部分数据库,并影响正在存取这部分数据的所有事务。</li></ul></li><li>计算机病毒:<ul><li>数据库主要威胁,人为破坏或故障。</li><li>对数据进行非法修改。</li></ul></li></ul><p>两种影响:</p><ul><li>数据库本身被破坏。</li><li>数据库没有被破坏但数据可能不正确。</li></ul><h4 id="恢复的实现技术"><a href="#恢复的实现技术" class="headerlink" title="==恢复的实现技术=="></a>==恢复的实现技术==</h4><p>基本原理:<strong>冗余</strong>。</p><h5 id="数据转储"><a href="#数据转储" class="headerlink" title="数据转储"></a>数据转储</h5><ul><li>概念:DBA定期将整个数据库复制到磁带或另一个磁盘上保存起来的过程,备用数据称为<strong>后备副本或后援副本</strong>。</li><li>两种转储状态:<ul><li>静态转储:无事务运行时的转储操作。</li><li>动态转储:转储期间允许对数据库进行存取或修改。需要用后援副本加上日志文件恢复。</li></ul></li><li>两种转储方式:<ul><li>海量转储:每次转储全部数据库。</li><li>增量转储:每次只转储上一次转储后更新过的数据。</li></ul></li><li>日志:记录事务对数据库更新操作的文件,分为以记录为单位和以数据块为单位的两种格式。<ul><li>作用:事务故障和系统故障恢复必须使用日志文件。</li><li>写入规则:先写入日志文件,后写数据库。</li></ul></li></ul><h5 id="故障的恢复策略"><a href="#故障的恢复策略" class="headerlink" title="故障的恢复策略"></a>故障的恢复策略</h5><ul><li>事务故障的恢复:UNDO,撤销事务,在不影响其他事务的情况下强行回滚。反向扫描日志,执行所有更新操作的逆操作。</li><li>系统故障:UNDO+REDO,撤销故障发生时未完成的事务,重做已完成但没有写入数据库的事务。</li><li>介质故障:装入最新数据库后备副本,使数据库恢复到最近一次转储时的一致状态。装入转储以后的日志文件副本,重做已经完成的事务。</li></ul><h5 id="检查点技术"><a href="#检查点技术" class="headerlink" title="检查点技术"></a>检查点技术</h5><p>日志文件天啊及检查点记录,要记下所有正在执行的事务清单和这些事务最近一个日志记录的地址。</p><p>增加一个重新开始文件,用来记录各个检查点记录在日志文件中的地址。</p><h5 id="数据库镜像"><a href="#数据库镜像" class="headerlink" title="数据库镜像"></a>数据库镜像</h5><p>把整个DB或关键数据复制到另一个磁盘上,由DBMS自动保证镜像数据库与主数据库的一致性。</p><h3 id="并发控制技术"><a href="#并发控制技术" class="headerlink" title="并发控制技术"></a>并发控制技术</h3><h4 id="并发控制"><a href="#并发控制" class="headerlink" title="并发控制"></a>并发控制</h4><h5 id="事务并发的优点"><a href="#事务并发的优点" class="headerlink" title="事务并发的优点"></a>事务并发的优点</h5><ul><li>一个事务多个步骤并发执行,<strong>提高系统吞吐量</strong>。</li><li>如果各个事务涉及的是数据库的不同部分,采用并发会<strong>减少平均响应时间</strong>。</li></ul><h5 id="带来的问题"><a href="#带来的问题" class="headerlink" title="==带来的问题=="></a>==带来的问题==</h5><ul><li>多个事务同时存取同一数据时,不加以控制会读取或存取不正确的数据,破坏一致性。</li><li><strong>丢失更新</strong>:两个事务同时读入数据并修改,后面的事务会破坏前面事务的结果,导致前面事务的结果丢失。</li><li><strong>脏数据的读出</strong>:先前事务的结果被撤销,后面事务已经读出了错误的数据。</li><li><strong>不能重复读</strong>:一个事务读取后,另一个事务更新了数据,导致第一个事务不能再现结果。</li></ul><h5 id="并发控制的基本思想"><a href="#并发控制的基本思想" class="headerlink" title="并发控制的基本思想"></a>并发控制的基本思想</h5><p>==合理调度并发事务,避免并发事务之间的互相干扰造成数据的不一致性。==</p><p>==主要方法是<strong>封锁机制</strong>==。</p><h4 id="封锁"><a href="#封锁" class="headerlink" title="封锁"></a>封锁</h4><p>事务T在对某个数据如表、记录等操作之前,先向系统发出请求,对其加锁,从而对该数据对象有了一定的控制权。</p><h5 id="封锁的类型"><a href="#封锁的类型" class="headerlink" title="封锁的类型"></a>封锁的类型</h5><ul><li>排它锁(X锁):上锁后,则只允许当前事务对数据对象进行读取和修改,直到释放锁。</li><li>共享锁(S锁):上锁后可以读取但不能修改数据对象,其他事务只能加S锁,也不能加X锁,直到释放S锁。</li></ul><h5 id="封锁协议"><a href="#封锁协议" class="headerlink" title="封锁协议"></a>封锁协议</h5><p>运用两种基本封锁可以建立不同的约定,形成不同级别的封锁协议。</p><ul><li>一级封锁协议:防止丢失修改。在修改数据R之前加X锁,结束才可以释放。</li><li>二级封锁协议:防止读脏数据。一级封锁协议加上在读取R之前必须加S锁,读完释放S锁。</li><li>三级封锁协议:保证数据可以重复读。一级封锁协议加上读取R前必须加S锁,直到事务结束才可以释放。</li></ul><h5 id="封锁粒度"><a href="#封锁粒度" class="headerlink" title="封锁粒度"></a>封锁粒度</h5><p>封锁对象的大小称为封锁的粒度。</p><p>粒度大,则并发度低,封锁机构简单,开销小。</p><p>粒度小,则并发度高,封锁机构复杂,开销高。</p><p><strong>多粒度封锁</strong>:在一个系统中同时支持多种封锁粒度,选择封锁粒度时应同时考虑封锁开销和并发度两个因素。</p><p><strong>多粒度封锁协议</strong>:允许多粒度树中每个结点被单独加锁,对一个结点加锁意味着所有后裔结点也被加以同样类型的锁。</p><p>==<strong>意向锁</strong>==:该结点的下层结点正在被加锁,对任意结点加锁时,必须先对上级结点加意向锁。好处是,对象加锁时,不需要再检查下级结点的封锁。</p><h5 id="三种常用意向锁"><a href="#三种常用意向锁" class="headerlink" title="三种常用意向锁"></a>三种常用意向锁</h5><ul><li>意向共享锁(IS锁):如果要对一个对象加IS锁,表示他的后裔结点拟加S锁。</li><li>意向排它锁(IX锁):如果要对一个数据对象加IX锁,表示他的后裔结点拟加X锁。</li><li>意向共享排它锁(SIX锁):如果要对一个数据对象加SIX锁,表示对它加S锁,再加IX锁。</li></ul><h5 id="活锁与死锁"><a href="#活锁与死锁" class="headerlink" title="==活锁与死锁=="></a>==活锁与死锁==</h5><ul><li>活锁:一个事务一直占用锁,后面可能一直等待,采用先来先服务法。</li><li>死锁:预防死锁,死锁检测与解除。</li><li>死锁预防:<ul><li>一次封锁法:要求每个事务必须一次将其所有要使用的数据全部加锁,否则就不能执行,降低了系统的并发度。</li><li>顺序封锁法:预先对数据对象规定一个封锁顺序,所有事务都按照这个顺序封锁,实现难度大。</li></ul></li><li>死锁检测:<ul><li>超时法:如果等待时间超过时限就认为发生死锁。</li><li>等待图法:图中有回路说明出现了死锁。</li></ul></li><li>死锁恢复:选择一个处理死锁代价最小的事务,将其撤销。</li></ul><h4 id="事务的调度"><a href="#事务的调度" class="headerlink" title="事务的调度"></a>事务的调度</h4><p>N个事务的一个调度S是N个事务所有操作的一个序列S,表示这些操作的执行顺序,并且这个序列满足,对每个事务T,如果操作i在事务T中先于操作k,则在S中i也先于操作k。</p><h4 id="并发调度正确性"><a href="#并发调度正确性" class="headerlink" title="并发调度正确性"></a>并发调度正确性</h4><ul><li>一个事务正常或者预想的结果是没有其他并行事务干扰时得到的结果,因此<strong>一组事务的串行调度策略一定是正确的调度策略</strong>。</li><li>各种结果都将保持数据库数据的一致性,所以都是正确的。</li></ul><h4 id="并发调度的可串行性"><a href="#并发调度的可串行性" class="headerlink" title="并发调度的可串行性"></a>并发调度的可串行性</h4><ul><li>可串行化:多个事务并发执行正确,当且仅当按某一次序串行执行它们时的结果相同,我们称这种调度策略为可串行化调度。</li><li>可串行性是并行事务正确性的准则,一个给定的并发调度,当且仅当它是可串行化的,才认为是正确调度。</li><li>一个调度Sc在保证冲突操作次序不变的情况下,可以通过交换两个事务不冲突操作的次序,得到另一个串行调度Sc’,则调度Sc为冲突可串行化调度。</li><li>两段锁协议可以保证并行事务的可串行性。<ul><li>内容:<ul><li>对任何数据进行读写操作之前,事务首先要获得对该数据的封锁。</li><li>在释放一个封锁之后,事务不再获得任何其他封锁。</li></ul></li><li>含义:事务分为两个阶段,第一个阶段获得封锁称为<strong>扩展阶段</strong>,第二阶段释放封锁,称为<strong>收缩阶段</strong>。</li><li>定理:若所有事务均遵从两段锁协议,则这些事务的所有并发调度都是可串行化的。</li><li>注意:遵守两段锁协议只是充分条件。遵守两段锁的事务仍然可能发生死锁。</li></ul></li></ul><h2 id="第八章-数据库保护"><a href="#第八章-数据库保护" class="headerlink" title="第八章 数据库保护"></a>第八章 数据库保护</h2><h3 id="安全性控制"><a href="#安全性控制" class="headerlink" title="安全性控制"></a>安全性控制</h3><ul><li>安全性:保护数据库以防止不合法的使用所造成的数据泄漏、更改和破坏。<ul><li>向授权用户提供可靠的信息服务。</li><li>拒绝对数据库的非授权存取访问请求,保证数据的可用性、完整性和一致性,进而保护数据库所有者和使用者的合法权益。</li></ul></li><li>安全性控制:包含数据库系统的计算机系统安全模型。<ul><li>用户标识与鉴别:用户标识和认证是系统提供的最外层安全保护措施。<ul><li>标识:系统采用一定的方式标识其用户或应用程序的名字或身份。</li><li>认证:系统在用户或应用程序登录时判断其是否为合法的授权用户。</li></ul></li></ul></li><li>存取控制:确保合法用户按照指定的权限使用DBMS和访问数据。<ul><li>用户权限定义</li><li>合法权限检查</li><li>上述两者一起组成了DBMS的安全子系统。</li></ul></li><li>存取控制方法分类<ul><li>==自主存取控制(DAC)==:用户对于不同数据对象有不同的存取权限,不同用户对同一对象也有不同的权限。<strong>用户还可以将其拥有的权限转授给其他用户</strong>。</li><li>==强制存取控制(MAC)==:对于任意一个对象,只有具有合法许可证的用户才可以存取。</li><li>对于用户存取权限的定义称为<strong>授权</strong>。在授权中应指明用户名、数据对象名、允许的操作对象类型。</li></ul></li><li>SQL可以授予用户的两类权限:<ul><li>用户级权限:DBA为每个用户授予特定权限,是对用户使用整个数据库权限的限定。</li><li>关系级权限:DBA和数据库对象的拥有者为用户授予的与关系或视图有关的权限,这种权限是对用户使用关系的视图权限的限定。</li><li>授权:GRANT option TO user,回收权限:REVOKE option ON user。</li></ul></li><li>角色与用户组<ul><li>角色是一组权限的集合。</li><li>用户组是一组具有相同特性用户的集合,可以在授权或收回权限时以用户组为单位进行。</li></ul></li><li>强制存取方法:MAC中全部实体被分为主体和客体。<ul><li>主体是系统中的活动实体,包括实际用户和代表用户的各进程。</li><li>客体是系统的被动实体,由主体操纵。</li><li>对于主客体,DBMS为每个实例指定一个<strong>敏感度标记(Label)</strong>。<strong>主体的敏感度标记称为许可证级别,客体的敏感度标记称为密级</strong>。</li><li>MAC机制通过对比主体的label和客体的label最终确定主体是否能够存取客体。</li><li>当某一主体以某一许可证级别注册入系统时,系统要求他对任何客体的存取必须遵循如下规则:<ul><li>只有当主体的许可证级别大于等于客体的密级时,主体才能读取相应客体。</li><li>仅当主体许可证级别等于客体的密级时,才可以写相应客体。</li></ul></li></ul></li><li>其他方法:<ul><li>视图机制</li><li>审计</li><li>数据加密</li></ul></li></ul><h3 id="完整性控制"><a href="#完整性控制" class="headerlink" title="完整性控制"></a>完整性控制</h3><ul><li>完整性:数据的正确性和相容性。<ul><li>正确性:数据应该具有合法类型,在有效取值范围内。</li><li>相容性:表示同一个事实的两个数据应该相同。</li><li>数据库是否保持完整性关系到数据库系统是否能真实反映现实世界。</li></ul></li><li>完整性约束条件:施加在数据库数据之上的语义约束条件称为数据库完整性约束条件。作用对象可以是<strong>列、元组和关系</strong>三种。</li><li>完整性约束条件分类:<ul><li><strong>静态约束</strong>:反应数据库状态合理性的约束。</li><li><strong>动态约束</strong>:反应数据库状态变迁的约束。</li></ul></li><li>完整性控制包括三个方面的功能:<ul><li>定义功能</li><li>检查功能</li><li>违约相应</li></ul></li><li>完整性检查时机:<ul><li>立即执行约束:在执行用户事务过程中,在一条语句执行完后立即进行完整性约束的检查。</li><li>延迟执行约束:整个用户事务执行完毕后,在进行完整性约束的检查。</li></ul></li><li>完整性规则表示:五元组<ul><li>D:数据对象。(工资)</li><li>O:触发完整性检查的数据库操作。(插入或修改)</li><li>A:数据库对象必须满足的断言或语义约束。(工资>=500000000)</li><li>C:选择A作用的数据对象值的谓词。(职称=’老八’)</li><li>P:违反完整性规则时触发的过程。(拒绝执行该操作)</li></ul></li><li>SQL完整性:断言ASSERTION,触发器TRIGGER。</li></ul><h2 id="第九章-分布式数据库"><a href="#第九章-分布式数据库" class="headerlink" title="第九章 分布式数据库"></a>第九章 分布式数据库</h2><h3 id="分布式数据库系统"><a href="#分布式数据库系统" class="headerlink" title="分布式数据库系统"></a>分布式数据库系统</h3><ul><li>分布性:数据分布存储在网络的各个节点。</li><li>逻辑上的整体性:数据被一种机制联系在一起,构成一个有机整体。</li><li>分布式数据库定义:由一组分布在计算机网络的不同结点上的数据组成,每个结点具有独立处理的能力,可以执行局部应用,同时每个结点也可以通过网络通信支持全局应用。</li><li>场地自治性:每个场地有自己的数据库,一组终端(局部应用)。</li><li>自治场地之间的协作性:逻辑上如同一个集中式数据库,可以在任何场地执行全局应用。</li></ul><h3 id="分布式数据库系统的特点"><a href="#分布式数据库系统的特点" class="headerlink" title="分布式数据库系统的特点"></a>分布式数据库系统的特点</h3><ul><li>数据独立性:<ul><li>逻辑独立性</li><li>物理独立性</li><li>分布独立性:逻辑分片、数据物理位置的分布细节等与用户无关。</li></ul></li><li>集中与自治相结合的控制结构:<ul><li>数据共享分为局部共享和全局共享。</li><li>分布式数据库有自治功能,系统又设有集中控制结构。</li></ul></li><li>适当增加数据冗余:<ul><li>在不同结点存储同一个数据的多个副本。</li><li>提高系统可靠性、可用性。</li><li>提高系统性能。</li></ul></li><li>全局的一致性、可串行性和可恢复性</li></ul><h3 id="体系结构"><a href="#体系结构" class="headerlink" title="体系结构"></a>体系结构</h3><ul><li>全局外模式</li><li>全局概念模式</li><li>分片模式:<ul><li>分片方式:水平分片、垂直分片、导出分片、混合分片。</li><li>满足完全性、不相交性和可重构性。</li></ul></li><li>分布模式<ul><li>分布透明性:分片透明性、位置透明性、局部数据模型透明性。</li></ul></li><li>局部概念模式</li><li>局部内模式</li></ul><h3 id="DDBMS"><a href="#DDBMS" class="headerlink" title="DDBMS"></a>DDBMS</h3><p>组成</p><ul><li>LDBMS:局部场地上的数据库管理系统。</li><li>GDBMS:全局DBMS。</li><li>GDD:全局数据字典。</li><li>CM:通信管理。</li></ul><h3 id="主要技术"><a href="#主要技术" class="headerlink" title="主要技术"></a>主要技术</h3><h4 id="查询类型"><a href="#查询类型" class="headerlink" title="查询类型"></a>查询类型</h4><ul><li>局部查询:单结点</li><li>远程查询:单结点</li><li>全局查询:多个结点</li></ul><h4 id="处理过程"><a href="#处理过程" class="headerlink" title="处理过程"></a>处理过程</h4><ul><li>查询分解</li><li>选择操作执行的次序</li><li>选择执行操作的方法</li><li>使用半连接缩减关系。</li></ul>]]></content>
<categories>
<category> 数据库 </category>
</categories>
<tags>
<tag> 数据库 </tag>
<tag> SQL </tag>
</tags>
</entry>
<entry>
<title>编译原理 —— 知识摘要</title>
<link href="/2023/12/20/compiler/"/>
<url>/2023/12/20/compiler/</url>
<content type="html"><![CDATA[<p>施工中… (该死的 bh 云盘,这篇文章传输失败了,本地也没有存档,以后有空再补叭</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 编译原理 </tag>
</tags>
</entry>
<entry>
<title>安卓开发</title>
<link href="/2023/12/10/android/"/>
<url>/2023/12/10/android/</url>
<content type="html"><![CDATA[<h1 id="安卓开发——一款更适合你的运动助手"><a href="#安卓开发——一款更适合你的运动助手" class="headerlink" title="安卓开发——一款更适合你的运动助手"></a>安卓开发——一款更适合你的运动助手</h1><ul><li><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/Android/Android_ppt.pdf">项目 ppt 下载链接</a></li><li><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/Android/%E9%A1%B9%E7%9B%AE%E6%8A%A5%E5%91%8A.pdf">项目报告 pdf 链接</a></li><li><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/Android/%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C.pdf">用户手册 pdf 链接</a></li><li><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/Android/SrcCode.zip">源码下载链接</a></li></ul>]]></content>
<categories>
<category> 项目实训 </category>
</categories>
<tags>
<tag> Android </tag>
</tags>
</entry>
<entry>
<title>Ruby on Rails 敏捷开发</title>
<link href="/2023/12/01/ruby/"/>
<url>/2023/12/01/ruby/</url>
<content type="html"><![CDATA[<h1 id="Ruby-on-Rails-敏捷开发——电商平台"><a href="#Ruby-on-Rails-敏捷开发——电商平台" class="headerlink" title="Ruby on Rails 敏捷开发——电商平台"></a>Ruby on Rails 敏捷开发——电商平台</h1><p><a href="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/ruby_project.zip">源码下载链接</a><br><a href="http://21371249.project.rubyapp.act.buaa.edu.cn:9000/users/sign_in">电商平台链接——随时失效</a></p><h2 id="模块设计"><a href="#模块设计" class="headerlink" title="模块设计"></a>模块设计</h2><h3 id="登录注册模块"><a href="#登录注册模块" class="headerlink" title="登录注册模块"></a>登录注册模块</h3><p>使用 devise 插件进行登录注册模块的构建:</p><pre><code>rails generate devise User</code></pre><p>为自动生成的 User 类添加电话号码和角色属性</p><pre class=" language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">AddPhoneAndRoleToUsers</span> <span class="token operator"><</span> <span class="token constant">ActiveRecord</span><span class="token punctuation">:</span><span class="token symbol">:Migration</span><span class="token punctuation">[</span><span class="token number">7.1</span><span class="token punctuation">]</span> <span class="token keyword">def</span> change add_column <span class="token symbol">:users</span><span class="token punctuation">,</span> <span class="token symbol">:phone_number</span><span class="token punctuation">,</span> <span class="token symbol">:string</span> add_column <span class="token symbol">:users</span><span class="token punctuation">,</span> <span class="token symbol">:role</span><span class="token punctuation">,</span> <span class="token symbol">:string</span> <span class="token keyword">end</span><span class="token keyword">end</span></code></pre><p>这样使得用户在登录时能选择注册成为购买者或管理员。</p><h3 id="商品清单模块"><a href="#商品清单模块" class="headerlink" title="商品清单模块"></a>商品清单模块</h3><p>新建商品表:</p><pre class=" language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">CreateProducts</span> <span class="token operator"><</span> <span class="token constant">ActiveRecord</span><span class="token punctuation">:</span><span class="token symbol">:Migration</span><span class="token punctuation">[</span><span class="token number">7.1</span><span class="token punctuation">]</span> <span class="token keyword">def</span> change create_table <span class="token symbol">:products</span> <span class="token keyword">do</span> <span class="token operator">|</span>t<span class="token operator">|</span> t<span class="token punctuation">.</span>string <span class="token symbol">:name</span> t<span class="token punctuation">.</span>text <span class="token symbol">:description</span> t<span class="token punctuation">.</span>decimal <span class="token symbol">:price</span> t<span class="token punctuation">.</span>integer <span class="token symbol">:sales</span> t<span class="token punctuation">.</span>string <span class="token symbol">:image_path</span> t<span class="token punctuation">.</span>string <span class="token symbol">:product_type</span> t<span class="token punctuation">.</span>string <span class="token symbol">:color</span> t<span class="token punctuation">.</span>timestamps <span class="token keyword">end</span> <span class="token keyword">end</span><span class="token keyword">end</span></code></pre><p>在商品类的控制器中,实现添加、删除、展示列表、查看详情的方法。</p><h3 id="收藏栏模块"><a href="#收藏栏模块" class="headerlink" title="收藏栏模块"></a>收藏栏模块</h3><p>新建收藏条目表:</p><pre class=" language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">CreateFavorites</span> <span class="token operator"><</span> <span class="token constant">ActiveRecord</span><span class="token punctuation">:</span><span class="token symbol">:Migration</span><span class="token punctuation">[</span><span class="token number">7.1</span><span class="token punctuation">]</span> <span class="token keyword">def</span> change create_table <span class="token symbol">:favorites</span> <span class="token keyword">do</span> <span class="token operator">|</span>t<span class="token operator">|</span> t<span class="token punctuation">.</span>string <span class="token symbol">:name</span> t<span class="token punctuation">.</span>text <span class="token symbol">:description</span> t<span class="token punctuation">.</span>decimal <span class="token symbol">:price</span> t<span class="token punctuation">.</span>integer <span class="token symbol">:sales_count</span> t<span class="token punctuation">.</span>string <span class="token symbol">:image_url</span> t<span class="token punctuation">.</span>string <span class="token symbol">:product_type</span> t<span class="token punctuation">.</span>string <span class="token symbol">:color</span> t<span class="token punctuation">.</span>references <span class="token symbol">:user</span><span class="token punctuation">,</span> null<span class="token punctuation">:</span> <span class="token keyword">false</span><span class="token punctuation">,</span> foreign_key<span class="token punctuation">:</span> <span class="token keyword">true</span> t<span class="token punctuation">.</span>timestamps <span class="token keyword">end</span> <span class="token keyword">end</span><span class="token keyword">end</span></code></pre><p>该模块仅限身份为购买者的用户访问;<br>在控制器中添加新建、删除、查看详情和展示列表方法;<br>在商品详情页面中添加按钮 Favor this Product 触发一个新建收藏条目动作;<br>考虑到用户可能使用收藏栏来记录自己的喜好和倾向,故没有对 product 添加外键约束,使商品删除后还是可以在收藏栏查看浏览记录。</p><h3 id="购物车模块"><a href="#购物车模块" class="headerlink" title="购物车模块"></a>购物车模块</h3><p>新建购物车条目表</p><pre class=" language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">CreateCartItems</span> <span class="token operator"><</span> <span class="token constant">ActiveRecord</span><span class="token punctuation">:</span><span class="token symbol">:Migration</span><span class="token punctuation">[</span><span class="token number">7.1</span><span class="token punctuation">]</span> <span class="token keyword">def</span> change create_table <span class="token symbol">:cart_items</span> <span class="token keyword">do</span> <span class="token operator">|</span>t<span class="token operator">|</span> t<span class="token punctuation">.</span>references <span class="token symbol">:user</span><span class="token punctuation">,</span> foreign_key<span class="token punctuation">:</span> <span class="token keyword">true</span> t<span class="token punctuation">.</span>references <span class="token symbol">:product</span><span class="token punctuation">,</span> foreign_key<span class="token punctuation">:</span> <span class="token keyword">true</span> t<span class="token punctuation">.</span>string <span class="token symbol">:user_email</span> t<span class="token punctuation">.</span>string <span class="token symbol">:product_name</span> t<span class="token punctuation">.</span>integer <span class="token symbol">:quantity</span> t<span class="token punctuation">.</span>datetime <span class="token symbol">:added_at</span> t<span class="token punctuation">.</span>timestamps <span class="token keyword">end</span> <span class="token keyword">end</span><span class="token keyword">end</span><span class="token keyword">class</span> <span class="token class-name">AddCostToCartItems</span> <span class="token operator"><</span> <span class="token constant">ActiveRecord</span><span class="token punctuation">:</span><span class="token symbol">:Migration</span><span class="token punctuation">[</span><span class="token number">7.1</span><span class="token punctuation">]</span> <span class="token keyword">def</span> change add_column <span class="token symbol">:cart_items</span><span class="token punctuation">,</span> <span class="token symbol">:cost</span><span class="token punctuation">,</span> <span class="token symbol">:decimal</span><span class="token punctuation">,</span> precision<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">,</span> scale<span class="token punctuation">:</span> <span class="token number">2</span> <span class="token keyword">end</span><span class="token keyword">end</span></code></pre><p>该模块仅限身份为购买者的用户访问;<br>在控制器中添加新建、删除、查看详情和展示列表方法;<br>在商品详情页面中添加按钮 Add to My Cart 和一个个数输入栏触发一个新建购物车项的动作;<br>该表的 product 采用外键约束,且级联删除。</p><h3 id="订单模块"><a href="#订单模块" class="headerlink" title="订单模块"></a>订单模块</h3><p>新建订单条目表:</p><pre class=" language-ruby"><code class="language-ruby"><span class="token keyword">class</span> <span class="token class-name">CreateOrderItems</span> <span class="token operator"><</span> <span class="token constant">ActiveRecord</span><span class="token punctuation">:</span><span class="token symbol">:Migration</span><span class="token punctuation">[</span><span class="token number">7.1</span><span class="token punctuation">]</span> <span class="token keyword">def</span> change create_table <span class="token symbol">:order_items</span> <span class="token keyword">do</span> <span class="token operator">|</span>t<span class="token operator">|</span> t<span class="token punctuation">.</span>integer <span class="token symbol">:product_id</span> t<span class="token punctuation">.</span>integer <span class="token symbol">:user_id</span> t<span class="token punctuation">.</span>string <span class="token symbol">:receiver</span> t<span class="token punctuation">.</span>string <span class="token symbol">:shipping_address</span> t<span class="token punctuation">.</span>string <span class="token symbol">:phone_number</span> t<span class="token punctuation">.</span>string <span class="token symbol">:postal_code</span> t<span class="token punctuation">.</span>integer <span class="token symbol">:quantity</span> t<span class="token punctuation">.</span>decimal <span class="token symbol">:total_amount</span> t<span class="token punctuation">.</span>string <span class="token symbol">:order_status</span> t<span class="token punctuation">.</span>timestamps <span class="token keyword">end</span> <span class="token keyword">end</span><span class="token keyword">end</span></code></pre><p>该模块下,购买者只能看到自己的订单,而管理员可以看到所有订单;<br>在控制器中添加新建、删除、查看详情和展示列表方法;<br>在购物车条目列表视图中添加按钮 Order 通过购物车信息生成订单;<br>该表的 order_status 属性指示了订单状态:</p><ol><li>To be paid</li><li>To be sent</li><li>To be received</li><li>Completed</li><li>Cancelled</li><li>Rejected</li></ol><p>购买者可以通过 pay 动作将商品从状态 1 转换到状态 2<br>管理员可以通过 send 动作将商品从状态 2 转换到状态 3<br>购买者可以通过 receive 动作将商品从状态 3 转换到状态 4<br>在状态1, 2, 3购买者可以通过 cancel 动作将状态转换为状态 5<br>在状态 2,管理员可以通过 reject 动作将状态转换为状态 6<br>仅有状态4, 5, 6下的条目可以由 delete 动作删除。<br>考虑到交易的完整性,订单条目模块也没有进行 product 的外键约束。</p><hr><h2 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h2><h3 id="购买者"><a href="#购买者" class="headerlink" title="购买者"></a>购买者</h3><ul><li>注册身份选择 buyer (默认)</li><li>进入主界面(商品列表)<ul><li>可点击 View 查看商品详情<ul><li>可点击 Favor this Product 将商品添加到收藏</li><li>可输入数字到 Quantity,点击 Add to My Cart 将商品添加到购物车(总金额会)同步计算</li></ul></li><li>可点击 My Favorites 查看收藏栏<ul><li>可点击 View 查看收藏项目的具体属性内容</li></ul></li><li>可点击 My Order 查看用户本人的订单<ul><li>可选择订单条目后的 Action 中的按钮对订单进行操作</li></ul></li></ul></li></ul><h3 id="管理员"><a href="#管理员" class="headerlink" title="管理员"></a>管理员</h3><ul><li>注册身份选择 admin</li><li>进入主界面(商品列表)<ul><li>可点击 View 查看商品详情</li><li>可点击 Edit 修改商品属性</li><li>可点击 Delete 删除商品条目</li><li>可点击 Add Product 新建商品条目<ul><li>在新建页面输入相应的商品信息,注意图片的 URL 可以为空,但若填写则一定要合法,否则将无法创建</li></ul></li><li>可点击 All Orders 查看所有待处理的订单,可以选择 Send 或 Reject,处理完毕的订单将自动消除</li></ul></li></ul>]]></content>
<categories>
<category> 项目实训 </category>
</categories>
<tags>
<tag> Ruby </tag>
<tag> Web 开发 </tag>
</tags>
</entry>
<entry>
<title>NISL-lab 实习——文献阅读</title>
<link href="/2023/11/22/NISL_lab1/"/>
<url>/2023/11/22/NISL_lab1/</url>
<content type="html"><![CDATA[<h1 id="NISL-lab-实习——文献阅读"><a href="#NISL-lab-实习——文献阅读" class="headerlink" title="NISL-lab 实习——文献阅读"></a>NISL-lab 实习——文献阅读</h1><p>机缘巧合,获得 NISL 实验室威胁情报分析方向的实习机会,起步阶段当然是一些论文的阅读和复现,现在此做笔记备份。</p><hr><h2 id="RAID’14-Paint-It-Black-Evaluating-the-Effectiveness-of-Malware-Blacklists"><a href="#RAID’14-Paint-It-Black-Evaluating-the-Effectiveness-of-Malware-Blacklists" class="headerlink" title="[RAID’14] Paint It Black: Evaluating the Effectiveness of Malware Blacklists"></a>[RAID’14] Paint It Black: Evaluating the Effectiveness of Malware Blacklists</h2><ul><li>研究目的:对黑名单中的恶意域名和 IP 进行分类以发掘它们的特征</li><li>工作内容:<ul><li>提出一种机制识别应当被列入黑名单的域名</li><li>识别黑名单中的黑洞(安全组织控制的服务器,其中管理了大量恶意域名)</li><li>评估黑名单对恶意域名的覆盖率,从而评估黑名单的有效性</li></ul></li></ul><h3 id="总数据集"><a href="#总数据集" class="headerlink" title="总数据集"></a>总数据集</h3><p>$S_{C&C}$: 与 C&C 服务器(命令和控制服务器)相关的域名(扩展为解析到的 IP)<br>$S_{Mal}$: 在<strong>任意</strong>黑名单中<strong>出现过</strong>的所有 IP 地址<br>$S_{IPs}$: <strong>当前</strong>所有黑名单中列出的所有 IP 地址</p><h3 id="托管域名(广告)的识别"><a href="#托管域名(广告)的识别" class="headerlink" title="托管域名(广告)的识别"></a>托管域名(广告)的识别</h3><ul><li>初始数据集的构建<ul><li>模式识别和人工检查标记 parking NS 和相关厂商,分析域名重定向链确定重定向到的页面的 14 种模式。</li><li>依据这些数据,抽离出托管域名 http 响应中可能包含的 47 个描述性字符串;收集 5000 个触发字符串匹配的域名作为托管域名数据集。</li></ul></li><li>特征选取和分类<ul><li>HTTP-based feature<ul><li>存在重定向时,良性域名通常重定向到通用 www 子域</li><li>托管域倾向在本身或其子域上提供相似的内容</li></ul></li><li>HTML-based feature<ul><li>托管域显示的文本内容比例极小</li><li>托管域 JavaScript 代码比例较高</li><li>托管域 <code><frame></code> 标签的数量相对较多</li><li>托管域 <code><anchor></code> 标签较长</li><li>托管域在 <code><meta></code> 标签中 <code>robots</code> 属性取值为 <code>index + nofollow</code> 或 <code>index + follow</code> 或 <code>index + follow + all</code></li></ul></li><li>识别方法:support vector machines (SVMs) using the Anova kernel</li></ul></li><li>评估和验证<ul><li>标记数据集交叉验证</li><li>真实数据集验证,后手动验证可能存在的错误分类</li><li>确定了识别模型假阳性率和假阴性率</li></ul></li></ul><h3 id="黑洞的识别"><a href="#黑洞的识别" class="headerlink" title="黑洞的识别"></a>黑洞的识别</h3><ul><li>过滤与黑洞行为相似(多个域名解析到一个 IP)的 IP<ul><li>IP 对应的多个域提供内容相似度不高,可过滤</li><li>错误被列入黑名单的良性域名,可过滤</li><li>Fast Flux 域名,可过滤<ul><li>观测时间内,域名被前后解析为多个 IP(> 5)</li><li>这些 IP 中至少一半集中在两周内出现</li></ul></li></ul></li><li>识别——图算法<ul><li>对于 $S_{C&C}$ 和 $S_{Mal}$ 分别建图</li><li>域名 和 IP 为顶点,解析和重定向关系(both current and history)为边</li><li>黑洞 IP 的入度会比平均入度高很多,而出度则相反,故可以取二者之比作为衡量参数(比例越高,是黑洞 IP 的概率也越高)</li><li>其他附加条件:<ul><li>必须响应 ICMP Echo 或 HTTP 请求</li><li>能解析到该 IP 的域高于给定阈值</li><li>关联的域使用同一名称系统</li><li>相邻节点为黑洞 IP 的数量大于 1 的顶点为潜在黑洞</li></ul></li></ul></li><li>评估和验证<ul><li>在 $S_{C&C}$ 和 $S_{Mal}$ 集合上分别验证</li></ul></li></ul><h3 id="黑名单效用评估"><a href="#黑名单效用评估" class="headerlink" title="黑名单效用评估"></a>黑名单效用评估</h3><ul><li>分类:大部分的域名要么不存在,要么为托管域名,要么与黑洞有关,少部分无法被分类</li><li>完备性的上限:利用动态恶意软件分析平台获取多个恶意软件家族的域名集合,大部分恶意域名家族被公共黑名单覆盖的比例较低,而反病毒软件供应商提供的黑名单表现较好</li></ul><h3 id="黑名单反应时间下限"><a href="#黑名单反应时间下限" class="headerlink" title="黑名单反应时间下限"></a>黑名单反应时间下限</h3><h3 id="基于随机生成算法的域名识别"><a href="#基于随机生成算法的域名识别" class="headerlink" title="基于随机生成算法的域名识别"></a>基于随机生成算法的域名识别</h3><ul><li>难点:域名有效期短,活跃度低</li><li>反应时间成为黑名单能否收录此类域名的重要因素</li><li>大部分黑名单都还没有激发收录 DGA 域名的潜力</li></ul><hr><h2 id="USENIX-Securiryt’22-Building-an-Open-Robust-and-Stable-Voting-Based-Domain-Top-List-(secrank)"><a href="#USENIX-Securiryt’22-Building-an-Open-Robust-and-Stable-Voting-Based-Domain-Top-List-(secrank)" class="headerlink" title="[USENIX Securiryt’22] Building an Open, Robust, and Stable Voting-Based Domain Top List (secrank)"></a>[USENIX Securiryt’22] Building an Open, Robust, and Stable Voting-Based Domain Top List (secrank)</h2><ul><li>研究目的:当前域名排名列表构建方法存在缺乏透明度,易受操纵,波动性强的缺陷</li><li>工作内容:从零开始的域名排名系统开发<ul><li>研究不同的排名列表构建所考虑的因素</li><li>产生基于投票的域名排名方法</li><li>评估该方法的稳定性和抗操纵性</li></ul></li></ul><h3 id="现有域名排名列表"><a href="#现有域名排名列表" class="headerlink" title="现有域名排名列表"></a>现有域名排名列表</h3><ul><li>现有域名排名缺乏透明度(数据源 & 排名方法)</li><li>现有域名排名易被操纵<ul><li>Tranco 抵御操纵的方法是依赖现有的多个排名,没有从根源上解决</li><li>通过 Alexa 的认证服务,伪造虚假访问,获得高排名</li><li>Alexa 统计极其偏向已认证的域名</li><li>Umbrella 对于某一域名,关注发起 DNS 请求的地址的数量,而不仅仅是关注总的 DNS 请求量</li></ul></li></ul><h3 id="域名排名的衡量属性"><a href="#域名排名的衡量属性" class="headerlink" title="域名排名的衡量属性"></a>域名排名的衡量属性</h3><ul><li>透明度(数据 & 算法)</li><li>一致性(时间维度上建设方法保持一致,更改需通知)</li><li>操纵抗性(减少有限资源攻击的影响)</li><li>排名稳定性</li></ul><h3 id="构建域名排名"><a href="#构建域名排名" class="headerlink" title="构建域名排名"></a>构建域名排名</h3><ul><li>考虑因素:<ul><li>某域名相关的总查找量</li><li>发起与某域名相关的查找的 IP 多样性</li></ul></li><li>PDNS 数据集,监控 5M 个 IP 每日的 DNS 请求<ul><li>可能存在地域导致的数据偏见</li><li>客户端 DNS 缓存无法被监测到</li></ul></li><li><strong>基于投票的域名排名</strong><ul><li>针对 IP 的域名参数<ul><li>请求量</li><li>请求活跃时段</li><li>IP 的域偏好综合指标:上面二者规范化后的几何平均</li></ul></li><li>IP 贡献赋权<ul><li>根据 IP 请求的 SLD 数量衡量 IP 的域多样性</li><li>对于某一 IP,选取其请求的所有域名的总请求量作为权重依据</li><li>IP 的权重:上面二者归一化后的几何平均 ($^{m+n}\sqrt{a^nb^m}$)</li></ul></li><li>跨 IP 投票<ul><li>投票的三个规定<ul><li>投票允许多选</li><li>避免采取打分制的投票形式</li><li>避免多轮投票</li></ul></li><li>投票的四个方案<ul><li>Approval: 每个域名的得票数为选择该域名的 IP(选民)权重之和(无法表达域偏好)</li><li>Borda: 选民对域名(数量不超过阈值)进行排序,在该选民下,域名得分为排在其后的域名数量</li><li>DowDall: Borda 的变体,该选民下,排名第 $i$ 得 $1/i$ 分</li><li>Bucklin: 依据位次依次选取在该位置上的多数(与 Approval 类似,省略)</li></ul></li></ul></li></ul></li></ul><h3 id="方案评估"><a href="#方案评估" class="headerlink" title="方案评估"></a>方案评估</h3><ul><li>时间成本:计算 IP 的域偏好指标 > 计算 IP 权值 > 投票</li><li>投票方法:阈值越高的 Borda 投票效果越趋向于 Approval,阈值越小则限制 IP 对域偏好的表达,抗操纵性差;统计分析的阈值取 1k</li><li>抗操纵性:<ul><li>攻击手段<ul><li>域偏好增强:向目标域发送大量请求</li><li>地址权重提升:向许多其他域发送请求</li></ul></li><li>IP 加权既提高了对低资源攻击的操纵抗性,又提高了高资源攻击的成功上限</li><li>投票方法的选择:Borda 的抗操纵性优于 DowDall,Borda_1k 的 抗操纵性优于Borda_100 和 Borda_10,稳定性优于 Borda_full</li><li>IP 的域偏好使攻击者不得不长时间投入高资源的访问使目标域名获得较高的偏好排名</li><li>与 A, U, T List 相比均具有优良的抗操纵性</li></ul></li><li>稳定性:<ul><li>量化:第一天在列表上的域名占第二天列表域名的比例</li><li>Borda_1k 稳定性较优</li><li>与 A, U, T List 相比均具有优良的稳定性</li></ul></li><li>列表特征:顶级域名的覆盖率科学,低级域名统计效果显著</li></ul><p>名词标注:</p><ul><li>CDF:累积分布函数(Cumulative Distribution Function)</li><li>SLD:二级域名(Second-Level Domain)”example.com”中的”example”就是二级域名</li><li>FQDN:全限定域名(Fully Qualified Domain Name)全限定域名是一个完整的域名,包括主机名和域名后缀</li></ul><hr><h2 id="RAID’22-Encrypted-Malware-Traffic-Detection-via-Graph-based-Network-Analysis"><a href="#RAID’22-Encrypted-Malware-Traffic-Detection-via-Graph-based-Network-Analysis" class="headerlink" title="[RAID’22] Encrypted Malware Traffic Detection via Graph-based Network Analysis"></a>[RAID’22] Encrypted Malware Traffic Detection via Graph-based Network Analysis</h2><h3 id="时空特征"><a href="#时空特征" class="headerlink" title="时空特征"></a>时空特征</h3><ul><li>恶意软件感染的常见特征<ul><li>空间特征: 指的是主机和目标服务器之间的集中属性,特别是在家族内部。如前所述,由于框架的重复使用,同一家族内的一些恶意软件表现出高度相似性,反映在它们试图连接的目标服务器上。</li><li>连接的时间特征: 主机在一段时间内的连接顺序可以帮助我们重建恶意软件的感染过程,这可以清楚地显示随阶段的变化。此外,由于固定参数的设置,感染主机与控制服务器之间的通信是规律的,特别是数据包长度和数据包间隔时间。</li></ul></li></ul><h2 id="ST-Graph"><a href="#ST-Graph" class="headerlink" title="ST-Graph"></a>ST-Graph</h2><p>首先构建了一个异构图,将主机和服务器之间的所有网络连接相关联。基于图结构,应用随机游走生成每个流的相应连接列表,并使用概率模型优化边表示。</p><h3 id="图的建立"><a href="#图的建立" class="headerlink" title="图的建立"></a>图的建立</h3><ul><li>主机-服务器二分图 𝐺 = (𝐻, 𝐷, 𝐸, 𝑆, 𝐼)<ul><li>𝐻 表示内部主机的顶点集,每个主机由其IP表示为唯一标识符</li><li>𝐷 外部服务器顶点集,由其域名(域名不可用时,使用IP地址)初始化</li><li>𝐸 = {𝑒 | 𝑒 = (ℎ𝑒, 𝑑𝑒), ℎ𝑒 ∈ 𝐻, 𝑑𝑒 ∈ 𝐷} 边集来表示主机和服务器之间的所有连接(即流) </li><li>𝐼 = {𝑖𝑒 | 𝑒 ∈ 𝐸} 表示每个边的时态特征,𝑖𝑒 表示由其主机 ℎ𝑒 连接的边 𝑒 的顺序</li><li>𝑆 = {𝑠𝑒 | 𝑒 ∈ 𝐸} 表示从流中提取的属性<ul><li>内部主机提取的 TLS 握手特征(TLS版本、提供的密码套件和扩展的列表)</li><li>从外部节点提取的域名特征(域名的字符串特征)</li><li>流的侧信道统计特征(流内发送和接收的数据包的数量、长度或时间间隔)</li></ul></li></ul></li></ul><h3 id="边的嵌入"><a href="#边的嵌入" class="headerlink" title="边的嵌入"></a>边的嵌入</h3><p>从起始边 𝑜 开始,我们进行最多 𝑃𝐿 步的随机游走,重复 𝑃𝑁 次,以收集一组边 N𝑜。然后,通过最大化 N𝑜 中边的相似性来优化 𝑜 的时空嵌入</p><ul><li>区间倾斜随机游走<ul><li>从边 𝑜 开始,我们定义选择 𝑜 的邻居中的某条边 𝑥 作为下一步游走的概率公式:<br>[ Pr(𝑤1 = 𝑥 |𝑤0 = 𝑜) = \frac{1}{\text{𝑑 (𝑜,𝑥)}} \Bigg/ \sum_{𝑦 \in 𝐶𝑜} \frac{1}{\text{𝑑 (𝑦,𝑜)}} ]<br>倾向于选择与当前游走具有最小连接顺序距离的边作为下一步(倾向连续游走短时间间隔内的流)。</li><li>下面的游走中,每次选择都基于前两步<br>[ Pr(𝑤𝑖+1 = 𝑥 |𝑤𝑖 = 𝑣, 𝑤𝑖−1 = 𝑢) = \frac{\alpha_{𝑢,𝑥}}{\text{𝑑 (𝑣,𝑥)}} \Bigg/ \sum_{𝑡∈𝐶𝑣} \frac{\alpha_{𝑢,𝑡}}{\text{𝑑 (𝑣,𝑡)}} ]<br>当 𝑥 = 𝑢 时,𝛼𝑢,𝑥 取值为 ( \frac{1}{p} ) ;当 𝑥 是 𝑢 的邻居之一时,𝛼𝑢,𝑥 设为 1;否则,( \alpha_{𝑢,𝑥} = \frac{1}{q} )<br>如果 ( q < 1 ),行走者倾向于访问全局节点(DFS);如果 ( q > 1 ),行走者倾向于访问局部节点(BFS),从而增强周围邻居的覆盖范围。</li><li>对于每个边 𝑒,我们通过 𝑃𝑁 次随机漫步生成一个网络邻域 ( N𝑒 )。</li><li>为每个边建立一个向量 ( 𝑟𝑒 ),并通过其网络邻域 ( N𝑒 ) 中的相似性对向量进行优化。</li><li>对边之间的相关性进行建模,定义每条边的邻域概率,优化全局邻域概率</li><li>将流特征 𝑠𝑒 和向量 𝑟𝑒 进行归一化作为边的值</li></ul></li></ul><hr><h2 id="NDSS’20-BLAG-Improving-the-Accuracy-of-Blacklists"><a href="#NDSS’20-BLAG-Improving-the-Accuracy-of-Blacklists" class="headerlink" title="[NDSS’20] BLAG: Improving the Accuracy of Blacklists"></a>[NDSS’20] BLAG: Improving the Accuracy of Blacklists</h2><ul><li>研究目的:改进现有黑名单可能存在的过度专业化、分类错误、信息陈旧导致的不理想的准确性问题</li><li>工作内容:构建黑名单聚合器 BLAG,对多个黑名单数据进行智能聚合,为客户网络生成定制黑名单<ul><li>对 157 个不同攻击类型的黑名单进行聚合(包括历史),并进行评分</li><li>构建推荐系统,针对客户,将可能导致合法源误报的项剔除</li><li>通过打分的方式,选择性地扩展黑名单到 IP 的 24 位前缀</li></ul></li></ul><h3 id="黑名单的分类"><a href="#黑名单的分类" class="headerlink" title="黑名单的分类"></a>黑名单的分类</h3><ul><li>垃圾邮件黑名单</li><li>恶意软件黑名单</li><li>攻击行为黑名单</li><li>信誉黑名单</li></ul><h3 id="当前黑名单的局限性"><a href="#当前黑名单的局限性" class="headerlink" title="当前黑名单的局限性"></a>当前黑名单的局限性</h3><ul><li>专注于对某一恶意行为集合的检测(一个域名可能在不同时段存在多种恶意行为)</li><li>单个黑名单的数据覆盖范围有限</li><li>是给定时间内恶意来源的快照(可通过休眠来规避检测)</li><li>黑名单历史域名再犯现象频繁</li><li>盲目对某些 IP 前缀进行恶意标记(极大增加了合法域名的错误分类几率)</li><li>过时的信息可能导致分类错误</li></ul><h3 id="BLAG-的设计"><a href="#BLAG-的设计" class="headerlink" title="BLAG 的设计"></a>BLAG 的设计</h3><p>概述:从多个黑名单获取历史记录,当黑名单更新时,BLAG 数据库同步更新;向用户网络发送流量来将合法来源剔除黑名单,从而为用户定制黑名单</p><ul><li><p>数据集合</p><ul><li>B: BLAG 数据库,从多个黑名单获取的历史记录</li><li>A: 向用户发送流量的所有源</li><li>D: 被丢弃或隔离的流量源</li><li>$L_{tr} = A - D$</li><li>F: 不在 $L_{tr}$ 中但也可能是合法的源</li></ul></li><li><p>BLAG 的运行</p><ul><li>评估 B 中每个黑名单上每个地址的相关性</li><li>使用 $L_{tr}$ 中的地址构建推荐系统,构建 F 集合</li><li>基于 F, $L_{tr}$ 使用基于阈值的方式为用户剔除黑名单中的一些地址</li><li>基于 F, $L_{tr}$ 选择性地扩展地址到 24 位前缀</li></ul></li><li><p>相关性评分</p><ul><li>依据再犯特性和记录不同恶意行为的黑名单重叠进行评分<br>$r_{a,b} = 2^{l/(t-t_{out})}$<ul><li>l: 常量</li><li>a: 具体地址</li><li>b: 所属的黑名单</li><li>t: 计算分数所在的时间点</li><li>$t_{out}$: 地址最近一次被移出黑名单的时间点</li><li>若地址在黑名单中,则 $r_{a,b} = 1$</li></ul></li></ul></li><li><p>推荐系统构建</p><ul><li>在 $r_{a,b}$ 矩阵右侧增加一列 MB,其中域名在 $L_{tr}$ 的值置为 1,其余值设为未知</li><li>使用协同过滤:对矩阵进行分解,得到 IP 和潜在特征的关联强度矩阵、黑名单和潜在特征的关联强度矩阵</li><li>将这两个矩阵相乘得到的新矩阵,则未知的值会被填充</li><li>在 MB 列获得较高分数的域名可能是需要被从黑名单中剔除的</li></ul></li><li><p>选择性扩展</p><ul><li>构建黑名单候选项的 IP 的前 24 位集合,从中剔除包含 MB 列中得分较高的部分前缀</li></ul></li></ul><h3 id="数据集"><a href="#数据集" class="headerlink" title="数据集"></a>数据集</h3><ul><li>黑名单数据集:157 个公开的黑名单在 2016.01~2016.11 之间的历史数据</li><li>场景数据集(每个场景包括训练、验证、测试)<ul><li>恶意邮件或垃圾邮件<ul><li>从用户不想接受的邮件集合中,索引到发送的 IP</li></ul></li><li>网络上的 DDoS 攻击<ul><li>Mirai 感染主机的 IP 地址</li></ul></li><li>DNS 根节点上的 DDoS 攻击<ul><li>获取针对 DNS 根节点的 TCP SYN flood 攻击的来源</li></ul></li></ul></li><li>限制性<ul><li>只使用了免费提供的公开黑名单</li><li>场景数据集受到一些限制<ul><li>只捕获在给定时间点在Internet上活跃的合法/恶意IP地址的一小部分样本</li><li>较为过时(2016)</li><li>缺少关于 $DDoS_{DNS}$ 的可靠数据集(攻击被观测到的时间过短)</li></ul></li></ul></li></ul><h3 id="评估"><a href="#评估" class="headerlink" title="评估"></a>评估</h3><ul><li>指标<ul><li>Recall: 被收录进入黑名单的恶意域名占总恶意域名集合的百分比</li><li>Specificity:未被收录进入黑名单的良性域名占总良性域名集合的百分比</li></ul></li><li>BLAG 设法大大提高了公共黑名单的性能,并降低了对合法域名的影响,对恶意域名的反应时间也更快</li></ul><h3 id="敏感性分析"><a href="#敏感性分析" class="headerlink" title="敏感性分析"></a>敏感性分析</h3><ul><li>选择性扩展</li><li>BLAG 的扩展方法能否提高其他黑名单的性能</li><li>不同的前缀扩展方法</li></ul><hr><h2 id="NDSS’23-DOITRUST-Dissecting-On-chain-Compromised-Internet-Domains-via-Graph-Learning"><a href="#NDSS’23-DOITRUST-Dissecting-On-chain-Compromised-Internet-Domains-via-Graph-Learning" class="headerlink" title="[NDSS’23] DOITRUST: Dissecting On-chain Compromised Internet Domains via Graph Learning"></a>[NDSS’23] DOITRUST: Dissecting On-chain Compromised Internet Domains via Graph Learning</h2><ul><li>compromised:缺乏抵抗力的,本文中指一个良性域名的页面上有链接到恶意域名的外链接</li><li>研究目的:探索良性网页如何被入侵,最终链接到恶意源;从允许节点到妥协目标,沿着整个链识别和过滤隐形的可疑节点</li><li>工作内容:<ul><li>构建网络域名图数据集;提出链上妥协;揭示了链上妥协的内容隐蔽性和拓扑隐蔽性</li><li>提出集成方案,利用单个节点特征和网络特征,解决隐蔽性导致的信息匮乏的问题</li><li>提出一种新的节点排序的方法</li><li>针对大型图提出图学习方案,将全局传播和局部预测模型的训练分离</li><li>评估了 DOITRUST 将客观恶意节点分类为可疑节点的性能</li></ul></li></ul><h3 id="预处理"><a href="#预处理" class="headerlink" title="预处理"></a>预处理</h3><ul><li>选取 56805 个可信域名,依据其页面上显示的 url 进行图的扩展,将关联图扩展到 170 万个结点,其中 178 个为恶意节点</li><li>将 web 建模为 G(V, E),目的是对每个节点依据节点特征或网络拓扑结构进行置信度分析,衡量其是恶意域名的可能性</li></ul><h3 id="设计概览"><a href="#设计概览" class="headerlink" title="设计概览"></a>设计概览</h3><ul><li>可疑预测<ul><li>个体特征提取(html, url 的特征)</li><li>局部预测(针对每个节点)</li><li>个性化可疑度排序(Personal PageRank –> Personal IncredulityRank,将其能链接到的子节点的可疑程度也纳入考虑)</li><li>全局传播(基于 PIR 的训练时合并,推理时合并,端到端合并,无合并)</li></ul></li><li>入侵修剪和预警</li></ul><h3 id="个体特征提取和预测"><a href="#个体特征提取和预测" class="headerlink" title="个体特征提取和预测"></a>个体特征提取和预测</h3><ul><li>直接从URL和HTML中提取:<ul><li>统计特征<ul><li>HTML标签数量</li><li>iframes数量</li><li>script标签数量</li><li>href标签数量</li><li>URL中的特殊字符</li><li>URL中是否存在IP地址或重定向</li></ul></li><li>词法特征<ul><li>构建了一个 token 字典,由从 10K 个恶意的网页中总结恶意性的单词或符号,选择 2400 个最频繁的 token</li><li>频率分布矩阵:每个HTML文档是一行,每个恶意性的token是一个列,对应的值是该单词在 html 中的频率</li></ul></li></ul></li><li>局部预测<ul><li>有了嵌入节点特征向量,局部节点预测可以简化为二值分类任务。采用全连接网络(FCN)对节点域进行分类</li></ul></li></ul><h3 id="可疑性排名"><a href="#可疑性排名" class="headerlink" title="可疑性排名"></a>可疑性排名</h3><ul><li>直观的:如果一个页面有到恶意的域的外链接,那么它很可能是 compromised 的节点。距离被拒绝的页面的距离越短,一个页面是 compromised 节点的置信度就越高</li><li>形式上:,如果页面节点 v 的怀疑分数为 cv,并且它有 in(v) 个传入页面,则每个传入页面将从节点 v 获得分数分数 cv/in(v)</li><li>折扣因子:远离恶意节点的步长来分割和抑制怀疑分数</li><li>页面的不可置信等级分数则是通过其外链接收的分数分数的总和,并乘以折扣因子,归一化</li></ul><h3 id="Personal-IncredulityRank-的近似"><a href="#Personal-IncredulityRank-的近似" class="headerlink" title="Personal IncredulityRank 的近似"></a>Personal IncredulityRank 的近似</h3><ul><li>扩充初始非零 PIR 节点的数量:找到图中从种子到恶意节点的所有可疑路径(最短路径),然后根据公式2初始化可疑路径上的PIR值</li><li>PIR 矩阵,(u,q) 位置的值表示 u 收到的 q 的贡献分数</li><li>有效的近似:通过选择 PIR 矩阵的 top-k 元素并将其余元素截断为零</li></ul><h3 id="全局传播和实时推理"><a href="#全局传播和实时推理" class="headerlink" title="全局传播和实时推理"></a>全局传播和实时推理</h3><h3 id="Compromised-剪枝"><a href="#Compromised-剪枝" class="headerlink" title="Compromised 剪枝"></a>Compromised 剪枝</h3><ul><li>删除良性域名到恶意域名最短路径上的节点(隔离可疑域的集群);最后将图中不可达的结点删除</li><li>基于流的剪枝:计算域的流,它被定义为从良性节点到每个恶意域通过给定域的最短路径数。较高的流量意味着更多通往被拒绝域的路径在图中通过该节点,我们在每次迭代中找到流量最高的最深的节点,并将其从图中删除;最后将图中不可达的结点删除</li></ul><hr><h2 id="A-Survey-on-Malicious-Domains-Detection-through-DNS-data"><a href="#A-Survey-on-Malicious-Domains-Detection-through-DNS-data" class="headerlink" title="A Survey on Malicious Domains Detection through DNS data"></a>A Survey on Malicious Domains Detection through DNS data</h2><h3 id="数据获取"><a href="#数据获取" class="headerlink" title="数据获取"></a>数据获取</h3><ul><li>数据来源:<ul><li>Host-Resolver: 可以获取域名解析器的内部接口,而其提供了可能直接与特定恶意行为相关的用户请求和响应的细节信息。</li><li>DNS-DNS: 流量数据获取——授权域名服务器,解析器的外部接口。</li></ul></li><li>获取方法:<ul><li>Active DNS: 采集者有意发送DNS请求并记录相应的应答</li><li>Passive DNS: 在DNS服务器部署相应的数据获取检测器</li></ul></li></ul><h3 id="数据扩充"><a href="#数据扩充" class="headerlink" title="数据扩充"></a>数据扩充</h3><ul><li>地理位置信息</li><li>自治系统号</li><li>注册记录</li><li>黑/白名单</li><li>关联资源记录</li><li>网络、通信数据</li></ul><h3 id="域名标记"><a href="#域名标记" class="headerlink" title="域名标记"></a>域名标记</h3><ul><li>一种域名可能在一个场景下成为恶意域名,但是在分析另一种场景时,它很可能就不属于恶意的了,所以要对具体的恶意行为进行区分</li><li>黑名单可能来源于不同的数据获取方式,因此并不是完全可信的</li><li>恶意域名的子域名也是恶意域名吗?</li><li>子域名中的大多数都是恶意域名的域名也是恶意域名吗?</li></ul><h3 id="算法设计"><a href="#算法设计" class="headerlink" title="算法设计"></a>算法设计</h3><ul><li>特征<ul><li>内部特征和上下文特征</li><li>数据依赖性特征和数据独立性特征 </li><li>单一域名特征和多域名特征</li></ul></li><li>检测方法<ul><li>基于知识总结的方法</li><li>基于机器学习的方法<ul><li>半监督学习算法(<strong>基于图的推断方法和聚类方法</strong>)</li></ul></li></ul></li></ul><hr><h2 id="SP’22-SHADEWATCHER-Recommendation-guided-Cyber-Threat-Analysis-using-System-Audit-Records"><a href="#SP’22-SHADEWATCHER-Recommendation-guided-Cyber-Threat-Analysis-using-System-Audit-Records" class="headerlink" title="[SP’22] SHADEWATCHER: Recommendation-guided Cyber Threat Analysis using System Audit Records"></a>[SP’22] SHADEWATCHER: Recommendation-guided Cyber Threat Analysis using System Audit Records</h2><ul><li>研究目的:在审计记录上应用数据起源分析,以搜索异常(异常行为)或已知攻击的规范来应对高级攻击的方法具有局限性(假警报,粗粒度,依赖专家知识);该项目将系统实体交互的安全概念映射到用户-项目交互的推荐概念,通过预测系统实体对其交互实体的偏好来识别网络威胁</li><li>工作内容:<ul><li>利用上下文信息作为潜在的边信息来分析系统实体,具有相似上下文的系统实体将在语义上相关(系统实体交互和实体上下文信息的网络安全概念映射到用户-项目交互和项目边信息的推荐概念,但威胁检测的目标是系统实体不太可能偏好的交互)</li><li>提出 SHADEWATCHER,不是将历史频率作为估计怀疑程度的度量,而是推断系统实体的内在语义以发现异常交互</li><li>部署 SHADEWATCHER,并对现实生活和模拟攻击场景进行系统评估</li></ul></li></ul><h3 id="基本定义"><a href="#基本定义" class="headerlink" title="基本定义"></a>基本定义</h3><ul><li>审计记录:三元组(src, rel, dst),其中src, dst ∈ E = {进程,文件,套接字},rel ∈ R = {克隆,写入,…}</li><li>溯源图:(src, rel, dst) 形成的有向无环图</li><li>知识图(KG):实体和实体间<strong>有效</strong>交互形成的图</li></ul><h3 id="问题重述"><a href="#问题重述" class="headerlink" title="问题重述"></a>问题重述</h3><ul><li>目标:是训练一个推荐模型,其目标是预测系统实体 h <strong>不会</strong>与另一个实体 t 交互的概率$y_{ht}$</li><li>针对威胁:操纵或窃取系统中存在的信息的攻击者</li></ul><h3 id="SHADEWATCHER-概述"><a href="#SHADEWATCHER-概述" class="headerlink" title="SHADEWATCHER 概述"></a>SHADEWATCHER 概述</h3><ul><li>系统的四个阶段:构建知识图谱(KG)、生成推荐模型、检测网络威胁、调整模型</li><li>关键思想:在KG中使用不同顺序的连接来模拟系统实体交互的<strong>可能性</strong>,将系统执行中的异常识别为网络威胁</li><li>工作流程:为了显式利用一阶和高阶信息,通过上下文感知嵌入模块将系统实体参数化为嵌入(即向量),然后通过图神经网络邻居迭代传播嵌入。通过聚合来自所有传播迭代的嵌入,确定实体-实体交互为对抗性的概率。</li><li>训练和检测:使用无攻击的审计记录进行训练。对于新到达的审计流,SHADEWATCHER 首先提取系统实体交互,并将其输入到训练阶段得到的推荐模型中。然后,如果相互作用的对抗性概率大于预定义的阈值(两个(多个)实体间不太可能存在这样的交互),就将其检测为潜在威胁。</li></ul><h3 id="KG-的构建"><a href="#KG-的构建" class="headerlink" title="KG 的构建"></a>KG 的构建</h3><ul><li>溯源图(PG):节点用一组属性表示系统实体,边描述系统实体之间的因果依赖关系和记录发生的时间戳</li><li>降噪策略</li><li>减少计算量:首先识别PG中的所有数据对象,然后对单个数据对象执行前向深度优先搜索以提取子图;若两子图有包含关系(子集)则合并</li></ul><h3 id="推荐模型"><a href="#推荐模型" class="headerlink" title="推荐模型"></a>推荐模型</h3><ul><li>一阶信息建模<ul><li>将系统实体参数化为向量,两向量间的距离衡量相似性</li><li>使用 TransR 在不同的关系语境下为同一实体分配不同的语义,并得到一些元组衡量两实体间(h, t)可能不具备某种关系(r)的得分 f(h, r, t)</li></ul></li><li>高阶信息建模<ul><li>使用 GNN 将多跳路径集成到系统实体的表示中</li><li>给定一个实体,一个 GNN 模块通过传播和聚合来自邻居的消息递归地更新其表示</li><li>注意力机制来区分实体的邻居的权重</li><li>信息聚合:Graph-Sage 聚合器</li></ul></li><li>威胁检测学习<ul><li>经过信息传播和聚合的多次迭代,我们得到了实体的一系列表示,将这些标识拼接成一个向量表示该实体</li><li>给定交互关系,两实体向量的内积为不具备该关系得分,高于阈值则确定为潜在威胁关系</li></ul></li><li>模型适应<ul><li>可以在假阳性相互作用上给出新的标签,允许使用假警报作为额外的监督</li><li>原本报警 –> 发现是误报 –> 作为负面实例来重新训练它的模型</li></ul></li></ul><h3 id="系统评估"><a href="#系统评估" class="headerlink" title="系统评估"></a>系统评估</h3><hr>]]></content>
<categories>
<category> 计算机网络 </category>
</categories>
<tags>
<tag> 网络安全 </tag>
</tags>
</entry>
<entry>
<title>华为“毕昇”编译器模糊测试——项目一期</title>
<link href="/2023/10/25/pro-exp1/"/>
<url>/2023/10/25/pro-exp1/</url>
<content type="html"><![CDATA[<h1 id="华为“毕昇”编译器模糊测试——项目一期"><a href="#华为“毕昇”编译器模糊测试——项目一期" class="headerlink" title="华为“毕昇”编译器模糊测试——项目一期"></a>华为“毕昇”编译器模糊测试——项目一期</h1><p>暑期“毕昇杯”比赛的获奖经历使本人在课设实验中获得了宝贵的开摆机会,又经机缘巧合,遂加入华为“毕昇”编译器模糊测试联合项目组。<br>我负责的是该编译器优化器模块的模糊测试;在第一阶段的工作中,我们尚无权限接触“毕昇”编译器源码,故在该编译器基于的 llvm 经典编译器源码上进行架构设计和相关实验。</p><h2 id="环境要求"><a href="#环境要求" class="headerlink" title="环境要求"></a>环境要求</h2><ul><li>Ubuntu 20.04 (或一些较新版本的 linux 系统)<ul><li>推荐 4 GB 内存</li><li>预留至少 30 GB 的存储空间</li></ul></li><li>GNU 工具包</li><li>ninja 工具</li><li>集成开发环境(可选)</li></ul><h2 id="源码获取和安装"><a href="#源码获取和安装" class="headerlink" title="源码获取和安装"></a>源码获取和安装</h2><h3 id="源码下载"><a href="#源码下载" class="headerlink" title="源码下载"></a>源码下载</h3><p><a href="https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-15.0.4.tar.gz">下载链接</a></p><p>解压后置于根目录或根目录下的子目录即可(这样保证了磁盘分区足够)</p><h3 id="源码编译和运行"><a href="#源码编译和运行" class="headerlink" title="源码编译和运行"></a>源码编译和运行</h3><p>进入源码根目录,运行:</p><pre class=" language-c"><code class="language-c">cmake <span class="token operator">-</span>S llvm <span class="token operator">-</span>B build <span class="token operator">-</span>G <span class="token string">"Unix Makefiles"</span> <span class="token operator">-</span>DCMAKE_C_COMPILER<span class="token operator">=</span>clang <span class="token operator">-</span>DCMAKE_CXX_COMPILER<span class="token operator">=</span>clang<span class="token operator">++</span> <span class="token operator">-</span>DLLVM_USE_SANITIZER<span class="token operator">=</span>Address <span class="token operator">-</span>DLLVM_USE_SANITIZE_COVERAGE<span class="token operator">=</span>On <span class="token operator">-</span>DLLVM_BUILD_RUNTIME<span class="token operator">=</span>Off <span class="token operator">-</span>DCMAKE_BUILD_TYPE<span class="token operator">=</span>Releasecmake <span class="token operator">--</span>build build</code></pre><p>等待即可(时间较长)</p><p>编译完成后,所有模块的可执行文件位于 build/bin 目录下,查阅相关使用文档,在该目录下执行相关运行指令即可。</p><hr><h2 id="优化器模糊测试设计"><a href="#优化器模糊测试设计" class="headerlink" title="优化器模糊测试设计"></a>优化器模糊测试设计</h2><h3 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h3><p>编译优化器模糊测试的整体架构如图所示,其可以自动生成或由用户指定输入一系列初始输入文件(初始种子)置于输入池中,由变异模块采取不同的变异策略对输入文件进行有针对性的变异,检测分析模块依据编译器优化模块对这些变异文件的执行结果,生成测试报告,并依据 libFuzzer 覆盖率统计导向选取其中对当前测试目标有较新覆盖的变异文件放入输入池中进一步变异以继续测试。</p><p><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/pro-exp1_2.jpg"></p><p>在编译优化器模糊测试架构下,主要可分为4个子模块:<br>(1)输入预处理模块<br>处理用户命令行输入,对用户提供的含有初始输入 llvm 字节码文件的初始种子目录进行扫描,依次读入文件供给变异模块;若用户提供的文件非法或不存在,则调用样例自动生成器。<br>样例自动生成器的初步设计是事先给定一个较大的语料库,当需要调用自动生成模块时,从语料库中随机选出指令文件并进行随机的初步简单变异放入输入池中;值得注意的是,后续优化测试中生成的具有较新覆盖的变异文件也会可能被填充进入语料库中。</p><p>(2)针对优化的变异模块<br>对初始的输入文件进行针对优化导向的变异;具体的,变异模块内部采取多种针对不同优化策略的变异策略(具体变异策略详见变异设计),每个变异策略具有一定的权重,变异时会依据设定的权重随机对每个输入文件进行多次多种变异,生成较多的变异体供给编译器的优化模块执行。</p><p>(3)运行检测分析模块<br>对编译器优化器执行的结果进行评估,若执行时崩溃或执行后得到的优化 IR 无法正常执行,则可以说明在变异模块不引入错误的情况下,变异针对的优化策略的程序中可能存在缺陷,模块会记录优化程序和优化后的 IR 的执行日志信息,结合 Sanitizer 检测,标注可能存在缺陷的编译器优化模块,生成测试报告。</p><p>(4)覆盖率检测模块<br>将 libFuzzer 和待测试的编译器优化模块链接,通过在编译器优化模块代码中插桩,检测优化模块执行变异体的执行路径,从而统计测试的覆盖率,如果覆盖率提高,证明执行的变异体是较优的,将该变异体放入测试输入池中,同时也可选择将其放入语料库中以供随机测试输入的生成。</p><hr><h3 id="变异策略设计"><a href="#变异策略设计" class="headerlink" title="变异策略设计"></a>变异策略设计</h3><h4 id="针对具体优化的设计方法"><a href="#针对具体优化的设计方法" class="headerlink" title="针对具体优化的设计方法"></a>针对具体优化的设计方法</h4><p>下面的内容中,先指出针对的变异策略,代码部分分割线上方是变异前的代码,下方是变异后的代码;可以发现,经过我们的变异设计,代码中产生了更多可触发相关优化的位点,如此增加针对优化的测试强度。</p><p><strong>块内变异算子</strong></p><ul><li>InstrCombine</li></ul><pre class=" language-llvm"><code class="language-llvm"> %a = add i32 %b, constant --------------------------------- %a1 = add i32 %b, constant_0 %a2 = add i32 %a1, constant_1 …… %a = add i32 %an, constant_n // constant = constant_0 + …… + constant_n</code></pre><ul><li>FuncInline</li></ul><pre class=" language-llvm"><code class="language-llvm"> %a = add i32 %b, %c --------------------------------- define dso_local i32 @sum(i32 %d1, i32 %d2){ %d3 = add i32 %d1, %d2 ret i32 %d3 } %a = call i32 @sum(i32 %b, i32 %c)</code></pre><ul><li>DeadCodeEleminate</li></ul><pre class=" language-llvm"><code class="language-llvm"> instr1 instr2 --------------------------------- instr1 DEAD_CODE_UNIT instr2</code></pre><p> DEAD_CODE_UNIT:</p><ul><li><p>通用的:<br>* 新建与程序无关的变量,进行无效计算<br>* 引入对主程序无影响的冗余函数<br>* 构造无意义循环</p></li><li><p>特化的:<br>* 如果 instr1/instr2 为计算类指令,可插入一些互逆的冗余运算,但要保证运算值的一致性<br>* 如果 instr2 为 store/load 类指令,可在其之前插入若干对该指令对象的 store/load 指令</p></li><li><p>CalculateSimplify</p></li></ul><pre class=" language-llvm"><code class="language-llvm"> %a = add i32 %b, constant -------------------------------- %c = ALU_OP i32 constant_1, constant_2 %a = add i32 %b, %c // constant_1 ALU_OP constant_2 = constant</code></pre><ul><li>GlobalValueLocalize</li></ul><pre class=" language-llvm"><code class="language-llvm"> %a = add i32 %b, %c -------------------------------- @GLB_a = dso_local global i32 0 %a = add i32 %b, %c store i32 %a, i32* @GLB_a instr replace all %a with @GLB_a</code></pre><p><strong>函数内变异算子</strong></p><ul><li>GVN & GCM</li></ul><pre class=" language-llvm"><code class="language-llvm"> %a = add %b, %c …… instr use %a ------------------------- %a = add %b, %c …… %d = add %b, %c instr replace all %a with %d // 需保证 %b, %c 的值在中间没有被改变 (store)</code></pre><ul><li>LoopInvariantCodeMotion</li></ul><pre class=" language-llvm"><code class="language-llvm"> BB2: br label %BB3 BB3: %l15 = phi i32 [ 0 , %BB2 ], [ %l9 , %BB4 ] %l4 = icmp slt i32 %l15, 10 br i1 %l4, label %BB4, label %BB5 BB4: call void @putint(i32 %l15) %l9 = add i32 %l15, 1 br label %BB3 BB5: ret i32 0 ------------------------------------------------ @GLB_a = dso_local global [1 x i32] [i32 1] BB2: br label %BB3 BB3: %l23 = phi i32 [ 0 , %BB2 ], [ %l7 , %BB4 ] %l21 = phi i32 [ 0 , %BB2 ], [ %l15 , %BB4 ] %l4 = icmp slt i32 %l21, 10 br i1 %l4, label %BB4, label %BB5 BB5: ret i32 0 BB4: /*----------------------------------------------------*/ %l6 = getelementptr inbounds [1 x i32], [1 x i32]* @GLB_a, i32 0, i32 0 %l7 = load i32, i32* %l6 /*----------------------------------------------------*/ call void @putint(i32 %l7) call void @putint(i32 %l21) %l15 = add i32 %l21, 1 br label %BB3</code></pre><ul><li>LoopFusion</li></ul><pre class=" language-llvm"><code class="language-llvm"> BB2: br label %BB3 BB3: %l20 = phi i32 [ 0 , %BB2 ], [ %l12 , %BB4 ] %l18 = phi i32 [ 0 , %BB2 ], [ %l9 , %BB4 ] %l6 = icmp slt i32 %l20, 10 br i1 %l6, label %BB4, label %BB5 BB5: ret i32 0 BB4: %l9 = add i32 %l18, 1 %l12 = add i32 %l20, 1 br label %BB3 ------------------------------------------------- BB2: br label %BB3 BB3: %l23 = phi i32 [ 0 , %BB2 ], [ %l7 , %BB4 ] %l4 = icmp slt i32 %l23, 10 br i1 %l4, label %BB4, label %BB5 BB5: br label %BB6 BB6: %l25 = phi i32 [ 0 , %BB5 ], [ %l17 , %BB7 ] %l14 = icmp slt i32 %l25, 10 br i1 %l14, label %BB7, label %BB8 BB8: ret i32 0 BB7: %l17 = add i32 %l25, 1 br label %BB6 BB4: %l7 = add i32 %l23, 1 br label %BB3</code></pre><h4 id="策略在-llvm-源码上的添加"><a href="#策略在-llvm-源码上的添加" class="headerlink" title="策略在 llvm 源码上的添加"></a>策略在 llvm 源码上的添加</h4><p>在 llvm 中,模糊测试的框架已经为我们搭建完成,但其中采用的变异策略十分随机,过于简单,我们可以在其源码中添加我们编写的针对优化的变异策略进行效果测试。</p><p>我们以针对 FuncInline 的变异策略为例:</p><p>首先,找到 llvm/include/llvm/FuzzMutate/IRMutator.h 仿照已经建立的变异策略新建变异策略类:</p><pre class=" language-c++"><code class="language-c++">//针对函数内联优化class ForFuncInlineIRStrategy : public IRMutationStrategy {public: uint64_t getWeight(size_t CurrentSize, size_t MaxSize, uint64_t CurrentWeight) override { return 100000; } using IRMutationStrategy::mutate; void mutate(BasicBlock &BB, RandomIRBuilder &IB) override;};</code></pre><p>这里将权重设置为 10000 以确保随机采用变异策略时几乎每次都能触发此策略,这便于我们后续运行查看效果。</p><p>下一步,找到 llvm/lib/FuzzMutate/IRMutator.cpp 添加新建策略类的 mutate 方法的定义:</p><pre class=" language-cpp"><code class="language-cpp"><span class="token comment" spellcheck="true">//针对函数内联</span><span class="token keyword">static</span> <span class="token keyword">int</span> v_block_id <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token keyword">static</span> <span class="token keyword">int</span> v_func_id <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token keyword">void</span> llvm<span class="token operator">::</span>ForFuncInlineIRStrategy<span class="token operator">::</span><span class="token function">mutate</span><span class="token punctuation">(</span>BasicBlock <span class="token operator">&</span>BB<span class="token punctuation">,</span> RandomIRBuilder <span class="token operator">&</span>IB<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&</span>inst <span class="token operator">:</span> BB<span class="token punctuation">.</span><span class="token function">getInstList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>inst<span class="token punctuation">.</span><span class="token function">isBinaryOp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">int</span> opcode <span class="token operator">=</span> inst<span class="token punctuation">.</span><span class="token function">getOpcode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Value <span class="token operator">*</span>val1 <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span> Value <span class="token operator">*</span>val2 <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span> Use <span class="token operator">*</span>oprands <span class="token operator">=</span> inst<span class="token punctuation">.</span><span class="token function">getOperandList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>Use <span class="token operator">*</span>oprand <span class="token operator">=</span> oprands<span class="token punctuation">,</span> <span class="token operator">*</span>E <span class="token operator">=</span> inst<span class="token punctuation">.</span><span class="token function">getNumOperands</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> oprands<span class="token punctuation">;</span> oprand <span class="token operator">!=</span> E<span class="token punctuation">;</span> <span class="token operator">++</span>oprand<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>oprand <span class="token operator">==</span> oprands<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> val1 <span class="token operator">=</span> oprand<span class="token operator">-</span><span class="token operator">></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> val2 <span class="token operator">=</span> oprand<span class="token operator">-</span><span class="token operator">></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>val1 <span class="token operator">==</span> <span class="token constant">NULL</span> <span class="token operator">||</span> val2 <span class="token operator">==</span> <span class="token constant">NULL</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> Type <span class="token operator">*</span>types<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span>val1<span class="token operator">-</span><span class="token operator">></span><span class="token function">getType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> val2<span class="token operator">-</span><span class="token operator">></span><span class="token function">getType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span> FunctionType <span class="token operator">*</span>funcType <span class="token operator">=</span> FunctionType<span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span>inst<span class="token punctuation">.</span><span class="token function">getType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> ArrayRef<span class="token operator"><</span>Type <span class="token operator">*</span><span class="token operator">></span><span class="token punctuation">(</span>types<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Function <span class="token operator">*</span>func <span class="token operator">=</span> Function<span class="token operator">::</span><span class="token function">Create</span><span class="token punctuation">(</span>funcType<span class="token punctuation">,</span> llvm<span class="token operator">::</span>GlobalValue<span class="token operator">::</span>LinkageTypes<span class="token operator">::</span>ExternalLinkage<span class="token punctuation">,</span> <span class="token string">"my_func_"</span> <span class="token operator">+</span> std<span class="token operator">::</span><span class="token function">to_string</span><span class="token punctuation">(</span>v_func_id<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">,</span> inst<span class="token punctuation">.</span><span class="token function">getModule</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> llvm<span class="token operator">::</span>LLVMContext <span class="token operator">&</span>llvmContext <span class="token operator">=</span> inst<span class="token punctuation">.</span><span class="token function">getModule</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> BasicBlock <span class="token operator">*</span>block <span class="token operator">=</span> BasicBlock<span class="token operator">::</span><span class="token function">Create</span><span class="token punctuation">(</span>llvmContext<span class="token punctuation">,</span> <span class="token string">"my_block_"</span> <span class="token operator">+</span> std<span class="token operator">::</span><span class="token function">to_string</span><span class="token punctuation">(</span>v_block_id<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">,</span> func<span class="token punctuation">)</span><span class="token punctuation">;</span> Instruction <span class="token operator">*</span>newInst <span class="token operator">=</span> inst<span class="token punctuation">.</span><span class="token function">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newInst<span class="token operator">-</span><span class="token operator">></span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">"my_new_inst_"</span> <span class="token operator">+</span> std<span class="token operator">::</span><span class="token function">to_string</span><span class="token punctuation">(</span>v_block_id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> block<span class="token operator">-</span><span class="token operator">></span><span class="token function">getInstList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>newInst<span class="token punctuation">)</span><span class="token punctuation">;</span> Function<span class="token operator">::</span>arg_iterator arg_it <span class="token operator">=</span> func<span class="token operator">-</span><span class="token operator">></span><span class="token function">arg_begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> newInst<span class="token operator">-</span><span class="token operator">></span><span class="token function">setOperand</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token punctuation">(</span><span class="token operator">*</span>arg_it<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> arg_it<span class="token operator">++</span><span class="token punctuation">;</span> newInst<span class="token operator">-</span><span class="token operator">></span><span class="token function">setOperand</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token punctuation">(</span><span class="token operator">*</span>arg_it<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> IRBuilder<span class="token operator"><</span><span class="token operator">></span> <span class="token function">builder</span><span class="token punctuation">(</span>llvmContext<span class="token punctuation">)</span><span class="token punctuation">;</span> ReturnInst <span class="token operator">*</span>retInst <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">CreateRet</span><span class="token punctuation">(</span>newInst<span class="token punctuation">)</span><span class="token punctuation">;</span> block<span class="token operator">-</span><span class="token operator">></span><span class="token function">getInstList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>retInst<span class="token punctuation">)</span><span class="token punctuation">;</span> Value <span class="token operator">*</span>params<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span>val1<span class="token punctuation">,</span> val2<span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span> CallInst<span class="token operator">*</span> callInst <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">CreateCall</span><span class="token punctuation">(</span>func<span class="token punctuation">,</span> ArrayRef<span class="token operator"><</span>Value <span class="token operator">*</span><span class="token operator">></span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span> callInst<span class="token operator">-</span><span class="token operator">></span><span class="token function">insertAfter</span><span class="token punctuation">(</span><span class="token operator">&</span>inst<span class="token punctuation">)</span><span class="token punctuation">;</span> inst<span class="token punctuation">.</span><span class="token function">replaceAllUsesWith</span><span class="token punctuation">(</span>callInst<span class="token punctuation">)</span><span class="token punctuation">;</span> inst<span class="token punctuation">.</span><span class="token function">eraseFromParent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//wait to opt, we have to ret here cause erase will damage the iterator!!!</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>这里需要使用很多 llvm 提供的接口来改变 IR 的结构,推荐使用 IDE 进行代码编辑或查阅相关文档。</p><p>最后,找到 llvm/tools/llvm-opt-fuzzer/llvm-opt-fuzzer.cpp 将新建的策略放入策略表中以供测试时选取:</p><pre class=" language-c++"><code class="language-c++">Strategies.push_back(std::make_unique<ForFuncInlineIRStrategy>());</code></pre><p>至此,我们为 llvm 的模糊测试架构添加了一个新的变异策略。</p><h4 id="策略的运行和测试"><a href="#策略的运行和测试" class="headerlink" title="策略的运行和测试"></a>策略的运行和测试</h4><p>我们修改了 llvm 的源码,显然,我们不想再经历一次整个项目的 make;因此,我们可以采用 ninja 工具:</p><ul><li>进入源码根目录,运行:</li></ul><pre class=" language-c"><code class="language-c"> cmake <span class="token operator">-</span>S llvm <span class="token operator">-</span>B buildnin <span class="token operator">-</span>G Ninja <span class="token operator">-</span>DCMAKE_C_COMPILER<span class="token operator">=</span>clang <span class="token operator">-</span>DCMAKE_CXX_COMPILER<span class="token operator">=</span>clang<span class="token operator">++</span> <span class="token operator">-</span>DLLVM_USE_SANITIZER<span class="token operator">=</span>Address <span class="token operator">-</span>DLLVM_USE_SANITIZE_COVERAGE<span class="token operator">=</span>On <span class="token operator">-</span>DLLVM_BUILD_RUNTIME<span class="token operator">=</span>Off <span class="token operator">-</span>DCMAKE_BUILD_TYPE<span class="token operator">=</span>Release</code></pre><ul><li>进入源码根目录下的 buildnin 目录,运行:</li></ul><pre class=" language-c"><code class="language-c"> ninja llvm<span class="token operator">-</span>opt<span class="token operator">-</span>fuzzer</code></pre><ul><li>编译完成后,在 buildnin/bin 下即可找到 llvm-opt-fuzzer 的可执行文件</li></ul><p>至此,我们可以试运行以测试刚刚的变异策略是否有效:</p><ul><li>在 buildnin/bin 下运行:</li></ul><pre class=" language-c"><code class="language-c"> <span class="token punctuation">.</span><span class="token operator">/</span>llvm<span class="token operator">-</span>opt<span class="token operator">-</span>fuzzer test <span class="token operator">-</span>ignore_remaining_args<span class="token operator">=</span><span class="token number">1</span> <span class="token operator">-</span>mtriple x86_64 <span class="token operator">-</span>passes instcombine</code></pre><p> 其中 -passes 后指明了测试针对的优化,也可以更换成其他的来进行测试。<br> 该命令可以手动终止(Ctrl + z)</p><ul><li>此时 buildnin/bin 下生成的 test 文件中包含了一系列字节码文件,使用 build/bin 目录下的 llvm-dis 将其反汇编为 .ll 文件即可查看变异效果:</li></ul><pre class=" language-c"><code class="language-c"> <span class="token punctuation">.</span><span class="token operator">/</span>llvm<span class="token operator">-</span>dis <span class="token operator">~</span><span class="token operator">/</span>LLVM<span class="token operator">/</span>llvm<span class="token operator">-</span>project<span class="token operator">-</span>llvmorg<span class="token number">-15.0</span><span class="token punctuation">.</span><span class="token number">4</span><span class="token operator">/</span>buildnin<span class="token operator">/</span>bin<span class="token operator">/</span>test<span class="token operator">/</span><span class="token operator">*</span></code></pre><p> 其中的 test 目录所在位置依据存放的实际位置来编写。</p><p>针对函数内联的变异测试中,其中一个文件经过多次变异前后的效果如下:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/pro-exp1_3.jpg"></p><hr><h3 id="用户接口设计"><a href="#用户接口设计" class="headerlink" title="用户接口设计"></a>用户接口设计</h3><h4 id="测试器运行接口"><a href="#测试器运行接口" class="headerlink" title="测试器运行接口"></a>测试器运行接口</h4><p>该编译优化器模糊测试工具提供命令行接口供用户进行针对优化测试或全局优化测试,命令行初步设计如下:</p><pre class=" language-c"><code class="language-c">llvm<span class="token operator">-</span>opt<span class="token operator">-</span>test <span class="token punctuation">[</span><span class="token operator">-</span>d DIRECTORY<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token operator">-</span><span class="token function">passes</span> <span class="token punctuation">(</span>OPT_STRATEGY<span class="token punctuation">)</span><span class="token operator">*</span><span class="token punctuation">]</span></code></pre><p>其中 –d DIRECTORY 指示了初始输入文件所在目录的位置,若缺省则默认为当前目录,-passes (OPT_STRATEGY)* 指示了测试针对的若干具体优化策略,若缺省则表示对所有优化策略进行测试,即全局优化测试。</p><p>具体的,OPT_STRATEGY初步设计的部分可选参数如下:</p><table><thead><tr><th>OPT_STRATEGY</th><th>说明</th></tr></thead><tbody><tr><td>缺省</td><td>默认对所有优化策略进行测试</td></tr><tr><td>*</td><td>对所有优化策略进行测试</td></tr><tr><td>dce</td><td>针对死代码删除优化的测试</td></tr><tr><td>cprog</td><td>针对常量传播优化的测试</td></tr><tr><td>gcm</td><td>针对全局代码移动优化的测试</td></tr><tr><td>instcombine</td><td>针对指令合并优化的测试</td></tr><tr><td>funcinline</td><td>针对函数内联优化的测试</td></tr><tr><td>glbopt</td><td>针对全局变量或函数优化集合的测试</td></tr><tr><td>loopopt</td><td>针对循环相关优化的测试</td></tr></tbody></table><h4 id="新增针对测试接口"><a href="#新增针对测试接口" class="headerlink" title="新增针对测试接口"></a>新增针对测试接口</h4><p>在编译器的实际测试中,开发人员也可能新增一些编译优化策略,该编译优化器模糊测试工具也提供了命令行接口使用户可以自定义OPT_STRATEGY选项的内容以针对新增的优化策略进行测试,命令行初步设计如下:</p><pre class=" language-c"><code class="language-c">add<span class="token operator">-</span>test<span class="token operator">-</span>pass –pass NEW_STRATEGY –cmd CMD_TO_OPEN_STRATEGY</code></pre><p>其中,NEW_STRATEGY为用户自定义的新优化策略的字符串表示,由数字、字母和下划线构成,可用于测试命令的OPT_STRATEGY选项,CMD_TO_OPEN_STRATEGY为用户提供的在运行待测试编译器时打开该优化的指令接口(可以理解成编译待测试的编译器时打开相关优化以得到具备这种优化功能的可执行文件的编译选项)。</p><hr><h2 id="后续工作"><a href="#后续工作" class="headerlink" title="后续工作"></a>后续工作</h2><ul><li>继续完成剩余的针对各种优化的测试的变异策略</li><li>着手依照测试架构搭建测试工具的框架</li></ul>]]></content>
<categories>
<category> 项目实训 </category>
</categories>
<tags>
<tag> 软件测试 </tag>
<tag> 编译原理 </tag>
</tags>
</entry>
<entry>
<title>数据库系统——基础篇</title>
<link href="/2023/10/16/db1/"/>
<url>/2023/10/16/db1/</url>
<content type="html"><![CDATA[<h1 id="数据库系统——基础篇"><a href="#数据库系统——基础篇" class="headerlink" title="数据库系统——基础篇"></a>数据库系统——基础篇</h1><h2 id="数据库系统的结构"><a href="#数据库系统的结构" class="headerlink" title="数据库系统的结构"></a>数据库系统的结构</h2><h3 id="数据模型"><a href="#数据模型" class="headerlink" title="数据模型"></a>数据模型</h3><ul><li>概念模型:由工程人员给出的一系列定义来对数据进行信息建模得到的模型。</li><li>逻辑模型:存在某种结构或逻辑关系的数据模型。</li></ul><h3 id="数据模型组成"><a href="#数据模型组成" class="headerlink" title="数据模型组成"></a>数据模型组成</h3><ul><li>数据结构</li><li>数据操作</li><li>数据完整性约束<ul><li>实体完整性:主键不重复且不为空</li><li>参照完整性:与外键相关,不出现不存在的外键</li></ul></li></ul><h3 id="三级模式,两级映像"><a href="#三级模式,两级映像" class="headerlink" title="三级模式,两级映像"></a>三级模式,两级映像</h3><p><strong>三级模式</strong></p><ul><li>内模式:也称为存储模式,一个数据库的内模式唯一,是数据物理结构和存储方式的描述,是数据在数据库内部的组织方式。</li><li>模式:也称为逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。</li><li>外模式:也称为子模式或用户模式,是用户可见和使用的局部数据的逻辑结构和特征的描述,是用户的数据视图,是与某一应用有关的数据的逻辑表示。</li></ul><p><strong>两级映像</strong></p><ul><li>外模式/模式映像:保证了数据与程序的逻辑独立性,即模式改变时,编写的应用程序不变。</li><li>模式/内模式映像:保证了数据与程序的物理独立性,即存储结构改变时,模式保持不变,当然,应用程序也保持不变。</li></ul><h2 id="关系数据模型"><a href="#关系数据模型" class="headerlink" title="关系数据模型"></a>关系数据模型</h2><h3 id="关系代数"><a href="#关系代数" class="headerlink" title="关系代数"></a>关系代数</h3><ul><li>基本关系操作:选择、投影、并、差、笛卡尔积</li><li>传统的集合运算:并、差、交、笛卡尔积</li><li>专门的关系运算:选择、投影、连接、除法</li></ul><p><strong>选择</strong><br>在关系 R 中选择满足给定条件的元组(<strong>行</strong>),返回的是一组元组</p><p><strong>投影</strong><br>从关系 R 中选择出若干<strong>属性列</strong>组成新关系,返回的是一个新的关系</p><p><strong>连接</strong><br>从两个关系的笛卡尔积中选取满足一定条件的元组,返回的事一个新的关系<br>若满足的关系为属性间的<strong>相等关系</strong>,则为等值连接<br>等值连接得到的关系中<strong>去除重复</strong>列得到关系,为自然连接<br>自然连接中保留因为<strong>不存在公共属性上值相等</strong>的悬浮元组的关系,为外连接</p><p><strong>除法</strong><br>T = R/S,则 T 包含所有在 R 但不在 S 中的属性及值,<strong>且 T 的元组与 S 的元组的所有组合都在 R 中</strong></p><h2 id="关系数据库标准语言-SQL"><a href="#关系数据库标准语言-SQL" class="headerlink" title="关系数据库标准语言 SQL"></a>关系数据库标准语言 SQL</h2><h3 id="模式相关语句"><a href="#模式相关语句" class="headerlink" title="模式相关语句"></a>模式相关语句</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> <span class="token keyword">schema</span> <span class="token operator"><</span>模式名<span class="token operator">></span> <span class="token keyword">authorization</span> <span class="token operator"><</span>用户名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token operator"><</span>表定义字句<span class="token operator">></span> <span class="token operator">|</span> <span class="token operator"><</span>视图定义子句<span class="token operator">></span> <span class="token operator">|</span> <span class="token operator"><</span>授权定义子句<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">drop</span> <span class="token keyword">schema</span> <span class="token operator"><</span>模式名<span class="token operator">></span> <span class="token operator"><</span><span class="token keyword">CASCADE</span> <span class="token operator">|</span> <span class="token keyword">RESTRICT</span><span class="token operator">></span><span class="token punctuation">;</span></code></pre><p>MySQL官方文档指出,从概念上讲,模式是一组相互关联的数据库对象,如表,表列,列的数据类型,索引,外键等等。但是<strong>从物理层面上来说,模式与数据库是同义的</strong>。你可以在MySQL的SQL语法中用关键字SCHEMA替代DATABASE,例如使用CREATE SCHEMA来代替CREATE DATABASE。</p><h3 id="基本表相关语句"><a href="#基本表相关语句" class="headerlink" title="基本表相关语句"></a>基本表相关语句</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> <span class="token keyword">table</span> <span class="token operator"><</span>表名<span class="token operator">></span> <span class="token punctuation">(</span><span class="token operator"><</span>列名<span class="token operator">></span> <span class="token operator"><</span>数据类型<span class="token operator">></span> <span class="token punctuation">[</span>列级完整性约束条件<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>列名<span class="token operator">></span> <span class="token operator"><</span>数据类型<span class="token operator">></span> <span class="token punctuation">[</span>列级完整性约束条件<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>表级完整性约束条件<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">alter</span> <span class="token keyword">table</span> <span class="token operator"><</span>表名<span class="token operator">></span><span class="token punctuation">[</span><span class="token keyword">add</span> <span class="token punctuation">[</span><span class="token keyword">column</span><span class="token punctuation">]</span> <span class="token operator"><</span>新列名<span class="token operator">></span> <span class="token operator"><</span>数据类型<span class="token operator">></span> <span class="token punctuation">[</span>列级完整性约束条件<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token keyword">add</span> <span class="token operator"><</span>表级完整性约束条件<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token keyword">drop</span> <span class="token punctuation">[</span><span class="token keyword">column</span><span class="token punctuation">]</span> <span class="token operator"><</span>列名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token keyword">CASCADE</span> <span class="token operator">|</span> <span class="token keyword">RESTRICT</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token keyword">drop</span> <span class="token keyword">constraint</span> <span class="token operator"><</span>完整列约束名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token keyword">CASCADE</span> <span class="token operator">|</span> <span class="token keyword">RESTRICT</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token keyword">alter</span> <span class="token keyword">column</span> <span class="token operator"><</span>列名<span class="token operator">></span> <span class="token operator"><</span>数据类型<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre><h3 id="索引相关语句"><a href="#索引相关语句" class="headerlink" title="索引相关语句"></a>索引相关语句</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> <span class="token punctuation">[</span><span class="token keyword">unique</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>cluster<span class="token punctuation">]</span> <span class="token keyword">index</span> <span class="token operator"><</span>索引名<span class="token operator">></span> <span class="token keyword">on</span> <span class="token operator"><</span>表名<span class="token operator">></span><span class="token punctuation">(</span><span class="token operator"><</span>列名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token operator"><</span>次序<span class="token operator">></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>列名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token operator"><</span>次序<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">alter</span> <span class="token keyword">index</span> <span class="token operator"><</span>旧索引名<span class="token operator">></span> <span class="token keyword">rename</span> <span class="token keyword">to</span> <span class="token operator"><</span>新索引名<span class="token operator">></span><span class="token punctuation">;</span><span class="token keyword">drop</span> <span class="token keyword">index</span> <span class="token operator"><</span>索引名<span class="token operator">></span><span class="token punctuation">;</span></code></pre><p>用户为基本表建立索引后,DBMS 会自动使用索引机制访问元组,具体的映射和访问方法无需用户关心。</p><h3 id="元组操作语句"><a href="#元组操作语句" class="headerlink" title="元组操作语句"></a>元组操作语句</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">select</span> <span class="token punctuation">[</span><span class="token keyword">all</span> <span class="token operator">|</span> <span class="token keyword">distinct</span><span class="token punctuation">]</span> <span class="token operator"><</span>目标列表达式<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>目标列表达式<span class="token operator">></span><span class="token punctuation">]</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">from</span> <span class="token operator"><</span>表名 <span class="token operator">|</span> 视图名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>表名 <span class="token operator">|</span> 视图名<span class="token operator">></span><span class="token punctuation">]</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token operator"><</span><span class="token keyword">select</span> 语句<span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token keyword">as</span><span class="token punctuation">]</span> <span class="token operator"><</span>别名<span class="token operator">></span><span class="token punctuation">[</span><span class="token keyword">where</span> <span class="token operator"><</span>条件表达式<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token keyword">group</span> <span class="token keyword">by</span> <span class="token operator"><</span>列名<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token keyword">having</span> <span class="token operator"><</span>条件表达式<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token keyword">order</span> <span class="token keyword">by</span> <span class="token operator"><</span>列名<span class="token number">2</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token keyword">asc</span> <span class="token operator">|</span> <span class="token keyword">desc</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">insert</span> <span class="token keyword">into</span> <span class="token operator"><</span>表名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token operator"><</span>属性列<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>属性列<span class="token number">2</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token keyword">values</span> <span class="token punctuation">(</span><span class="token operator"><</span>常量<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>常量<span class="token number">2</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">insert</span> <span class="token keyword">into</span> <span class="token operator"><</span>表名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token operator"><</span>属性列<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>属性列<span class="token number">2</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator"><</span>子查询<span class="token operator">></span><span class="token punctuation">;</span><span class="token keyword">update</span> <span class="token operator"><</span>表名<span class="token operator">></span><span class="token keyword">set</span> <span class="token operator"><</span>列名<span class="token number">1</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token operator"><</span>表达式<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span><span class="token operator"><</span>列名<span class="token number">2</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token operator"><</span>表达式<span class="token number">2</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">[</span><span class="token keyword">where</span> <span class="token operator"><</span>条件<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">delete</span> <span class="token keyword">from</span> <span class="token operator"><</span>表名<span class="token operator">></span><span class="token punctuation">[</span><span class="token keyword">where</span> <span class="token operator"><</span>条件<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre><h3 id="视图相关语句"><a href="#视图相关语句" class="headerlink" title="视图相关语句"></a>视图相关语句</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> <span class="token keyword">view</span> <span class="token operator"><</span>视图名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token operator"><</span>列名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>列名<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token keyword">as</span> <span class="token operator"><</span>子查询<span class="token operator">></span><span class="token punctuation">[</span><span class="token keyword">with</span> <span class="token keyword">check</span> <span class="token keyword">option</span><span class="token punctuation">]</span></code></pre><p>with check option 表示对视图进行操作时要满足<strong>视图定义中的子查询的谓词约束</strong></p><p>注意,一个视图被定义时并未执行子查询语句,只有当其被访问时,才执行。<br>更新、查询视图的各个操作和查询基本表相同;注意,数据库管理系统会结合查询语句和视图定义将视图查询转化为基本表的查询来执行。</p><h2 id="数据库的安全性"><a href="#数据库的安全性" class="headerlink" title="数据库的安全性"></a>数据库的安全性</h2><h3 id="授权与收回(自主存取控制方法-DAC)"><a href="#授权与收回(自主存取控制方法-DAC)" class="headerlink" title="授权与收回(自主存取控制方法 DAC)"></a>授权与收回(自主存取控制方法 DAC)</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">grant</span> <span class="token operator"><</span>权限<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>权限<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">on</span> <span class="token operator"><</span>对象类型<span class="token operator">></span> <span class="token operator"><</span>对象名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>对象类型<span class="token operator">></span> <span class="token operator"><</span>对象名<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">to</span> <span class="token operator"><</span>用户<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>用户<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">[</span><span class="token keyword">with</span> <span class="token keyword">grant</span> <span class="token keyword">option</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">revoke</span> <span class="token operator"><</span>权限<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>权限<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">on</span> <span class="token operator"><</span>对象类型<span class="token operator">></span> <span class="token operator"><</span>对象名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>对象类型<span class="token operator">></span> <span class="token operator"><</span>对象名<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">from</span> <span class="token operator"><</span>用户<span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>用户<span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">[</span><span class="token keyword">cascade</span> <span class="token operator">|</span> <span class="token keyword">restrict</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">create</span> <span class="token keyword">user</span> <span class="token operator"><</span>用户名<span class="token operator">></span> <span class="token punctuation">[</span><span class="token keyword">with</span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">dba</span> <span class="token operator">|</span> resource <span class="token operator">|</span> <span class="token keyword">connect</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre><ul><li><权限> 一般为 <对象类型> 的操作名(select, update, delete, all privileges…)</li><li><对象类型> 可以是表、视图等</li><li>with grant option 表示获得该权限组的用户可以将权限转授其他用户</li><li>cascade 或 restrict 表示级联操作,即次第收回唯一从收回操作对象用户处得到该权限的用户的权限</li></ul><table><thead><tr><th>权限</th><th>create user</th><th>create schema</th><th>create table</th><th>登录数据库,查询操作</th></tr></thead><tbody><tr><td>DBA</td><td>√</td><td>√</td><td>√</td><td>√</td></tr><tr><td>RESOURCE</td><td>×</td><td>×</td><td>√</td><td>√</td></tr><tr><td>CONNECT</td><td>×</td><td>×</td><td>×</td><td>√</td></tr></tbody></table><h3 id="角色——用户(自主存取控制方法-DAC)"><a href="#角色——用户(自主存取控制方法-DAC)" class="headerlink" title="角色——用户(自主存取控制方法 DAC)"></a>角色——用户(自主存取控制方法 DAC)</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> role <span class="token operator"><</span>角色名<span class="token operator">></span><span class="token punctuation">;</span><span class="token keyword">grant</span> <span class="token operator"><</span>角色<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">,</span> <span class="token operator"><</span>角色<span class="token number">2</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">to</span> <span class="token operator"><</span>角色<span class="token number">3</span><span class="token operator">|</span>用户<span class="token number">1</span><span class="token operator">></span> <span class="token punctuation">[</span><span class="token punctuation">.</span> <span class="token operator"><</span>角色<span class="token number">4</span><span class="token operator">|</span>用户<span class="token number">2</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">[</span><span class="token keyword">with</span> admin <span class="token keyword">option</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre><p>给角色授权和收回权限的语句与用户类似。<br>with admin option 表示获得某种角色权限的角色或用户还可以将这些权限转授其他角色。<br><strong>数据库角色是一组权限的集合</strong></p><h3 id="强制存取控制方法(MAC)"><a href="#强制存取控制方法(MAC)" class="headerlink" title="强制存取控制方法(MAC)"></a>强制存取控制方法(MAC)</h3><p><strong>敏感度标记</strong></p><ul><li>绝密:TS</li><li>机密:S</li><li>可信:C</li><li>公开:P</li></ul><p><strong>访问规则</strong></p><ul><li>仅当主体的许可证级别大于等于客体的密级时,才可读</li><li>仅当主体的许可证密级小于等于客体的密级时,才可写</li></ul><h3 id="其他安全机制"><a href="#其他安全机制" class="headerlink" title="其他安全机制"></a>其他安全机制</h3><ul><li>视图机制:控制数据对不同对象的可见范围</li><li>审计机制:将用户对数据库的操作记录下来存入日志</li><li>数据加密机制:存储加密,传输加密</li></ul><h2 id="数据库完整性"><a href="#数据库完整性" class="headerlink" title="数据库完整性"></a>数据库完整性</h2><h3 id="完整性分类"><a href="#完整性分类" class="headerlink" title="完整性分类"></a>完整性分类</h3><ul><li>实体完整性:主码唯一且主码中没有属性为空</li><li>参照完整性:外码参照的主码数据应当存在,外码与本关系的主码没有交集时,可以接受空值</li><li>用户定义的完整性:<ul><li>属性约束条件</li><li>约束条件的检查和违约处理</li></ul></li></ul><h3 id="断言"><a href="#断言" class="headerlink" title="断言"></a>断言</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> assertion <span class="token operator"><</span>断言名<span class="token operator">></span> <span class="token operator"><</span><span class="token keyword">check</span> 子句<span class="token operator">></span><span class="token punctuation">;</span><span class="token keyword">drop</span> assertion <span class="token operator"><</span>断言名<span class="token operator">></span><span class="token punctuation">;</span></code></pre><p>任何对断言涉及的关系的操作都会触发 DBMS 检查断言,为假则拒绝执行。<br>check 子句中约束条件和 where 子句中的类似。</p><h3 id="触发器"><a href="#触发器" class="headerlink" title="触发器"></a>触发器</h3><pre class=" language-sql"><code class="language-sql"><span class="token keyword">create</span> <span class="token keyword">trigger</span> <span class="token operator"><</span>触发器名<span class="token operator">></span><span class="token operator">&</span><span class="token comment" spellcheck="true">#123;before | after&#125; <触发事件> on <表名></span>referencing newrow<span class="token operator">|</span>oldrow <span class="token keyword">as</span> <span class="token operator"><</span>变量<span class="token operator">></span><span class="token keyword">for</span> each <span class="token operator">&</span><span class="token comment" spellcheck="true">#123;row | statement&#125;</span><span class="token punctuation">[</span><span class="token keyword">when</span> <span class="token operator"><</span>触发条件<span class="token operator">></span><span class="token punctuation">]</span> <span class="token operator"><</span>触发动作<span class="token operator">></span><span class="token punctuation">;</span><span class="token keyword">drop</span> <span class="token keyword">trigger</span> <span class="token operator"><</span>触发器名<span class="token operator">></span> <span class="token keyword">on</span> <span class="token operator"><</span>表名<span class="token operator">></span></code></pre><ul><li><触发事件> 为一些操作名(insert, update…),也可以指定列(insert of <列, …>)</li><li>row 代表行触发器,对应操作每操作一行触发一次,statement表示语句触发器,执行一条指令触发一次</li><li>when <触发条件> 缺省时默认为真</li><li>运行顺序:before类触发器 –> sql语句 –> after类触发器</li><li>对同一个表上的多个 before(after) 类触发器,先创建的先运行</li></ul>]]></content>
<categories>
<category> 数据库 </category>
</categories>
<tags>
<tag> 数据库 </tag>
<tag> SQL </tag>
</tags>
</entry>
<entry>
<title>算法课程杂记 1</title>
<link href="/2023/10/15/alg1/"/>
<url>/2023/10/15/alg1/</url>
<content type="html"><![CDATA[<h1 id="算法课程杂记-1"><a href="#算法课程杂记-1" class="headerlink" title="算法课程杂记 1"></a>算法课程杂记 1</h1><h2 id="线性时间解决MCS问题"><a href="#线性时间解决MCS问题" class="headerlink" title="线性时间解决MCS问题"></a>线性时间解决MCS问题</h2><p>课堂上的分治算法解决最大子序列问题的时间复杂度为 $O(n*logn)$,然而,这种问题更加优越、更加常见的解决方式是应用动态规划的思想,即 Kadane 算法。</p><h3 id="MCS-问题简述"><a href="#MCS-问题简述" class="headerlink" title="MCS 问题简述"></a>MCS 问题简述</h3><p>即最大子序列问题:在数组的一个维度寻找连续的的子序列,使该子序列的和最大。<br>这种问题经常被包装成一些现实的策略问题,例如:根据股票的涨跌求算哪个时间区间入股赚得最多(当然是事后判断,要是能预测那大家都退学炒股去了hhh</p><h3 id="算法思想"><a href="#算法思想" class="headerlink" title="算法思想"></a>算法思想</h3><p>一开始接触到的是分治算法解决的思想:</p><ul><li>显然,将一个数组从正中间分成两块,则所求序列有三种分布方式:在左块,在右块,横跨两块</li><li>在左或右的情况递归处理即可,横跨两块的情况需要从正中的坐标出发,分别向左右进行移动,找到起点在正中的左右最大子序列(复杂度:$O(n)$),再将左右找到的合并即可。</li><li>对这三种情况求算出的结果区最大值即可</li></ul><p>显然,这种算法不可能是线性复杂度的</p><p>故采用动态规划的思想:</p><ul><li>要利用动态规划,一般情况下需要找到比当前问题规模小 “1” 的子问题</li><li>故该问题转化为,求一系列以<code>array[i], 0 <= i < len</code>结尾的最大子序列,其中这一系列最大子序列中最大的为所求。</li></ul><h3 id="算法实现"><a href="#算法实现" class="headerlink" title="算法实现"></a>算法实现</h3><p>这样,核心代码就非常简单了:</p><pre class=" language-c"><code class="language-c"><span class="token keyword">int</span> <span class="token function">MCSofArray</span><span class="token punctuation">(</span><span class="token keyword">int</span> <span class="token operator">*</span>array<span class="token punctuation">,</span> <span class="token keyword">int</span> len<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> dp<span class="token punctuation">[</span>len<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span>array<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span> <span class="token keyword">int</span> maxdp <span class="token operator">=</span> dp<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><</span> len<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">max</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i<span class="token number">-1</span><span class="token punctuation">]</span> <span class="token operator">+</span> array<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> array<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> maxdp <span class="token operator">=</span> <span class="token function">max</span><span class="token punctuation">(</span>maxdp<span class="token punctuation">,</span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">return</span> maxdp<span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>该算法的时间复杂度为 $O(n)$</p><h3 id="分治和动归的界限"><a href="#分治和动归的界限" class="headerlink" title="分治和动归的界限"></a>分治和动归的界限</h3><p>或许仍有些疑问,如果我拿到一个算法问题,如何确定是用分治还是用动归思想去解决呢?</p><p>我浅薄地认为:</p><ul><li>分治思想适用的问题都可以被分成两个(或者多个)子问题,这些子问题一般是该问题<strong>做除法</strong>得到的,这一点反映在时间复杂度的计算上</li><li>动归思想适用的问题一般可以分为多个子问题,这些子问题是该问题<strong>做减法</strong>得到的</li><li>显然,对于问题规模的下降速度,减法要比除法慢得多,所以“做减法”的问题如果不做转换一般不适用于分治的经典结构——递归</li></ul><h2 id="快速傅里叶变换"><a href="#快速傅里叶变换" class="headerlink" title="快速傅里叶变换"></a>快速傅里叶变换</h2><p>课上学习两个多项式相乘的算法时,我们很别扭地将两个多项式的乘法拆成了3个子问题,然而,最著名的解决该问题的方法则是快速傅里叶变换。</p><h3 id="多项式的表示形式"><a href="#多项式的表示形式" class="headerlink" title="多项式的表示形式"></a>多项式的表示形式</h3><p>不必多说,对于 n 次多项式,其标准型为:</p><p>$A(x) = a_0 + a_1 * x + a_2 * x^2 + \dots + a_n * x^n$</p><p>系数表示法写成:</p><p>$A = (a_0, a_1, a_2, \dots, a_n)$</p><p><strong>点值表示法</strong>则有:</p><p>$A(x) = {(x_0, A(x_0)), (x_1, A(x_1)),\dots,(x_{n-1}, A(x_{n-1})),}$ , $x_k$ 互不相等</p><p>这个表示法是多项式乘法能被傅里叶变换优化的基础。</p><h3 id="多项式相乘问题的-another-approach"><a href="#多项式相乘问题的-another-approach" class="headerlink" title="多项式相乘问题的 another approach"></a>多项式相乘问题的 another approach</h3><p>假设我们需要求的式子为:<br>$C(x) = A(x) * B(x)$</p><p>其中用点值表示法表示 C(x), A(x), B(x)<br>必然有:<br>$C(x) = {(x_0, A(x_0)*B(x_0)), (x_1, A(x_1)*B(x_1)),\dots,(x_{n-1}, A(x_{n-1})*B(x_{n-1})),}$ , $x_k$ 互不相等</p><p>至此,我们只需要根据 C(x) 的点表示式写出其一般多项式形式即可。</p><p>这个问题的关键有两点:</p><ul><li>如何得到一个多项式的点表示式</li><li>如何由一个点表示式推出对应多项式</li></ul><p><strong>如何得到 A(x) 的点表示式</strong></p><ul><li>需要取n个不重复的点,这n个点的取法是复数域上的单位根。复数域上的单位根:将单位圆分成n份,每一份对应的复数即为选择的点:<br>$w_n^k = cos(2k\pi/n) + i * sin(2k\pi/n)$</li><li>现在知道点表示法的横坐标了,需要带入 A(x) 求出对应的纵坐标的值,直接带入计算的话,求解这n个点的时间复杂度是$O(n^2)$的,因此不可取</li><li>现在起要求n是2的整数次幂,如果不足的话,后面补零</li><li>将 A(x) 的奇数项和偶数项分开,设:</li></ul><p>$A_1(x) = a_0 + a_2*x + … + a_{n-2}*x^{n/2-1}$</p><p>$A_2(x) = a_1 + a_3*x + … + a_{n-1}*x^{n/2-1}$</p><p>$A(x) = A_1(x^2) + x*A_2(x^2)$</p><ul><li>当需要求解 $w_n^k$ 对应的纵坐标时,不妨同时关注$w_n^{k + n/2}$:</li></ul><p>$A(w_n^k) = A_1(w_n^{2k}) + w_n^k*A_2(w_n^{2k})$</p><p>由变换可得(转化为三角形式会直观些):</p><p>$A(w_n^k) = A_1(w_{n/2}^{k}) + w_n^k*A_2(w_{n/2}^{k})$</p><p>同样的:</p><p>$A(w_n^{k+n/2}) = A_1(w_n^{2k+n}) + w_n^{k+n/2}*A_2(w_n^{2k+n})$</p><p>变换得:</p><p>$A(w_n^{k+n/2}) = A_1(w_{n/2}^{k}) - w_n^k*A_2(w_{n/2}^{k})$</p><ul><li>注意到$A(w_n^k)$ 和 $A(w_n^{k+n/2})$ 最后分解成的式子中有公共部分,则这二者可一并计算</li><li>故对于计算单个点对应的纵坐标,采用分治算法,时间复杂度 $T(n) = 2*T(n/2)$,为$O(logn)$</li><li>总时间复杂度为 $O(n*logn)$</li></ul><p>关于如何分治:因为我们要求$A(w_n^k)$需要知道$A_1(w_{n/2}^{k})$ 和 $A_2(w_{n/2}^{k})$</p><p>可见,子问题的形式与原问题一样,但规模减半,运用分支的递归策略即可求解</p><p><strong>如何由一个点表示式推出对应多项式</strong><br>结论是:<br>将n个点的每个点$(w_n^k, A(w_n^k))$记作$(x_k, y_k)$,则多项式系数$a_k$为:<br>$a_k = 1/n * \sum(y_i * (w_n^{-k})^i), i \in [0, n-1]$<br>具体推导步骤<a href="http://t.csdnimg.cn/l95Tr">见此</a></p><p>那对于$a_k$的计算,如何分治呢?<br>其实这里是一个小 trick,观察$a_k$可知,我们要计算的是一个以 $w_n^{-k}$ 为参数的多项式,这与刚刚求纵坐标的方式非常类似,做相同的处理即可,在编程上可以用同一个函数实现,总复杂度为 $O(n*logn)$</p><h2 id="背包问题"><a href="#背包问题" class="headerlink" title="背包问题"></a>背包问题</h2><p>背包问题主要有三类:</p><ul><li>0-1背包问题,每个物体数量为1</li><li>完全背包问题,每个物体数量无限</li><li>多重背包问题,每个物体数量有限,为 s[i]</li></ul><p>其中,多重背包问题可通过将同类物体视为不同转变为0-1背包问题,这里不做赘述。</p><h3 id="状态转移方程辨析"><a href="#状态转移方程辨析" class="headerlink" title="状态转移方程辨析"></a>状态转移方程辨析</h3><p>递推式中,i 表示检索第 i 个物体,j表示当前背包重量,v 为物体价值数组,dp 存储检索完第 i 个物体时背包重量为 j 时,对应的背包价值。</p><p>0-1背包问题:</p><pre class=" language-c"><code class="language-c">dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">max</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span> v<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token operator">+</span>dp<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j <span class="token operator">-</span> w<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre><p>完全背包问题:</p><pre class=" language-c"><code class="language-c">dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">max</span><span class="token punctuation">(</span>dp<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span> v<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">+</span> dp<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">[</span>j <span class="token operator">-</span> w<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre><p>可以看到,由于完全背包情况下物体数量无限,故决定是否放入标号为 i 的物体前,可能已放入标号为 i 的物体。</p><h2 id="多项式时间复杂度中的-x-的辨析"><a href="#多项式时间复杂度中的-x-的辨析" class="headerlink" title="多项式时间复杂度中的 x 的辨析"></a>多项式时间复杂度中的 x 的辨析</h2><p>多项式时间算法:在输入规模为x的情况下,算法能够在$O(x^k)$ 时间(k为常数)内解决该问题。</p><p>以一个最简单的问题为例,寻找 $[0, N]$ 区间内所有的素数。<br>大家可能会想到素数筛等算法,或者干脆的直接查表,时间复杂度为O(n),但这个问题的输入只有一个数字 n,换算成输入规模为 $x = logn, n = 2^x$</p><p>显然,该算法的时间复杂度可以表示为 $O(2^x)$,不是多项式时间算法。</p><p>到这,你或许可以理解为什么人们对多项式时间算法如此执着追求,你可以通俗的理解,<strong>这种算法响应一个输入的相对时间代价较小</strong>;毕竟算法都是服务于人的,就像那个素数的例子,没有用户会手动把 0 到 N 全部输入进去哈哈哈~</p>]]></content>
<categories>
<category> 算法 </category>
</categories>
<tags>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title>北航计算机学院面向对象(2023 第四单元)</title>
<link href="/2023/06/01/OO_4/"/>
<url>/2023/06/01/OO_4/</url>
<content type="html"><![CDATA[<h1 id="北航计算机学院面向对象(2023-第四单元)"><a href="#北航计算机学院面向对象(2023-第四单元)" class="headerlink" title="北航计算机学院面向对象(2023 第四单元)"></a>北航计算机学院面向对象(2023 第四单元)</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>本文将以笔者学习过程中的思考感悟为基础,对2023北航计算机学院面向对象课程第四单元(作业13~15)的架构搭建和程序设计思路做简明的描述;如有不同见解,欢迎学习交流。</p><hr><h2 id="正向建模与开发"><a href="#正向建模与开发" class="headerlink" title="正向建模与开发"></a>正向建模与开发</h2><p>本单元可以说是面向对象课程对架构设计考验最严格的一次(之前的三次作业都有固定的架构模板或者根本不需要设计架构)。<br>在实际的开发问题中,问题的逻辑往往一开始是模糊隐蔽且错综复杂的,需要对问题从<strong>现实维度</strong>进行理解,将问题的<strong>逻辑链</strong>和<strong>事件链</strong>抽离出来进行建模,服务与后续架构设计。<br>本节将基于本单元的编程实践讨论正向建模开发的过程。</p><h3 id="一次微型重构"><a href="#一次微型重构" class="headerlink" title="一次微型重构"></a>一次微型重构</h3><p>在第一次作业公布后,给我的最直接的感觉是书的传递规则十分复杂,在那个周二的晚上,我做出了第一版设计,这个设计虽然在后续几天被改得面目全非,但其中一次改动使我对这个单元正向建模的风格(或者完成作业的技巧?)有了一个大概的把握。<br>图书管理系统,本质上是书籍在不同对象间的规则传递,那么<strong>需要为书建立实例化对象吗,或是在各个对象内仅对书进行分类计数?</strong>,弄清这个问题是本单元建模和开发的基础:</p><ul><li>在第一版设计中,我没有为书籍建立专门的类,而是在各个对象内对书籍进行分类计数;书籍的传递也只是简单的数量加减。</li><li>在经过第二天一个上午的思考后,我决定改动这个设计,为书籍建立相应的类,在拥有书籍的对象中建立容器管理书籍;书籍的传递涉及对象在容器中的出入。</li></ul><p>为什么做这样的改动呢,看上去第一版似乎更加简单且易于实现?<br>其实是这样的:第一版设计确实可以完成本单元第一次作业,但这样做的风险很大,因为现实中书籍是有很多维度的性质的,即使完全重名的两本书,也可能有不同的状态,实例化书籍对象在模型构建和后续迭代的过程中都使代码<strong>更加具象且易于管理</strong>。<br>因此,我理解的正向建模实际上就是<strong>使用计算机语言对开发场景下现实世界中的物理对象的实体和行为进行最大贴合的建模</strong>(这样做的性能可能不是最佳,但模型的可读性强,性能可以在代码构建后进行局部优化)。</p><h3 id="逻辑链的抽离"><a href="#逻辑链的抽离" class="headerlink" title="逻辑链的抽离"></a>逻辑链的抽离</h3><p>开发场景下,物理世界实体的行为逻辑往往是十分复杂的,如何剖析入理,明白代码需要遵循哪些场景逻辑是正向建模中十分重要的一步。<br>在本单元作业中,图书馆管理管理系统主要涉及以下几条逻辑链:</p><ul><li>借阅书籍(学生——图书馆)</li><li>预订书籍(学生——图书馆)</li><li>运输书籍(图书馆——图书馆)</li><li>购入书籍(图书馆)</li><li>归还书籍(学生——图书馆)</li><li>馆内分流(图书馆)</li></ul><h2 id="在这些逻辑链中,往往存在行为触发规则和行为进行所需要的信息。对于这两类关键控制因素:-行为触发规则-在各方法的代码实现中体现,多体现为对目标对象状态和自身状态的检测。-行为依赖信息-在各个对象实体中用一定的数据结构进行保存,行为通过检索数据进行执行,执行结果有时也会对其依赖的数据产生影响。"><a href="#在这些逻辑链中,往往存在行为触发规则和行为进行所需要的信息。对于这两类关键控制因素:-行为触发规则-在各方法的代码实现中体现,多体现为对目标对象状态和自身状态的检测。-行为依赖信息-在各个对象实体中用一定的数据结构进行保存,行为通过检索数据进行执行,执行结果有时也会对其依赖的数据产生影响。" class="headerlink" title="在这些逻辑链中,往往存在行为触发规则和行为进行所需要的信息。对于这两类关键控制因素:* 行为触发规则 在各方法的代码实现中体现,多体现为对目标对象状态和自身状态的检测。* 行为依赖信息 在各个对象实体中用一定的数据结构进行保存,行为通过检索数据进行执行,执行结果有时也会对其依赖的数据产生影响。 "></a>在这些逻辑链中,往往存在行为触发规则和行为进行所需要的信息。对于这两类关键控制因素:<br>* 行为触发规则<br> 在各方法的代码实现中体现,多体现为对目标对象状态和自身状态的检测。<br>* 行为依赖信息<br> 在各个对象实体中用一定的数据结构进行保存,行为通过检索数据进行执行,执行结果有时也会对其依赖的数据产生影响。 </h2><h2 id="架构设计和UML图"><a href="#架构设计和UML图" class="headerlink" title="架构设计和UML图"></a>架构设计和UML图</h2><p>本单元的架构设计,我始终遵循一个认知:<br><strong>所有行为对象都是书籍的集合!</strong></p><h3 id="架构的搭建"><a href="#架构的搭建" class="headerlink" title="架构的搭建"></a>架构的搭建</h3><p>在本单元作业的要求中,我们可以发现,所有的行为实体(学生、书架、管理员……)都具有一些共同的功能,例如:</p><ul><li>给出一本书</li><li>接纳一本书</li><li>书籍的成批发出和接受</li></ul><p>但各个实体也有自己独特的功能方法,例如:</p><ul><li>学生可以损坏或丢失书籍</li><li>预订管理员可以记录申请</li><li>后期处可以修复书籍</li></ul><p>这些特征暗示了各个行为对象可以有共同的方法又保持自身一定的独特性,即可以使用继承关系<strong>继承一个“书集合”的父类</strong>。<br>但我在架构设计的时候为了避免继承时子类需要实现过多的额外方法,直接在 BookGroup 类中实现了尽可能多的方法(可能不被全部行为实体共有),后在各个行为实体中<strong>直接实例化该类</strong>,间接调用方法。<br>以本单元第一次作业为例可以形象地感受这个设计思路:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OO4-1.png"></p><p>可以发现:</p><ul><li>bookGroup作为通用类被几个主要行为对象实例化</li><li>行为对象间的交互在 MainClass 中发生</li><li>为学生的申请单独开辟 Requirement 类记录格式化的信息</li><li>使用 DateOpt 类进行日期转换和计算</li></ul><p>这种架构在视觉上十分清晰简洁,对象间的交互统一管理,减少了不必要的参数传递。</p><h3 id="架构的迭代"><a href="#架构的迭代" class="headerlink" title="架构的迭代"></a>架构的迭代</h3><p>本单元迭代工作量较大的一次是第一次到第二次作业的迭代;在本次迭代中由于引入了校际借阅和购入图书等新行为,使得逻辑链更加交错复杂;不过得益于书籍的实例化和通用方法的使用,本次迭代的工作量相比之下没有失控,具体架构如下:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OO4-2.png"></p><p>可以发现有以下变化:</p><ul><li>封装原本的校内交互为 School 类的方法</li><li>在 MainClass 中实例化多个 school,处理校际交互行为</li><li>构建运输类专门处理校际书籍的交接</li><li>图书管理员和采购部分离各司其职</li></ul><p>本架构在最大化维持原本的布局的情况下完成了复杂功能的扩展,可见原本的架构设计是较为合理的。</p><hr><h2 id="架构设计思维的演进"><a href="#架构设计思维的演进" class="headerlink" title="架构设计思维的演进"></a>架构设计思维的演进</h2><p>在面向对象的课程中,虽然老师和助教一直强调架构设计的重要性,但十分惭愧地说:我在最后一单元作业中才真正自主从头到尾设计出一套架构:</p><ul><li>第一单元的表达式解析<ul><li>使用经典的递归下降方法(任务练习作业中已经打好框架)</li><li>使用预处理进行简化,方便后续操作</li><li>各部分功能类相互分离,降低耦合</li></ul></li><li>第二单元多线程电梯模拟<ul><li>参考学长的博客,采用自由竞争的策略,架构较为简单</li><li>主要分为电梯运行部分和开关门动作单独处理部分</li><li>由于没有控制器的加入,各部分独立性强,但性能不顶尖</li></ul></li><li>第三单元 JML 撰写和编程<ul><li>几乎没考虑架构,全部完形填空去了(×</li><li>回看第三单元的作业,实现的是人群间通讯模拟,对性能要求高</li><li>使用实现与设计分离,优化算法提升性能</li></ul></li><li>第四单元图书管理系统<ul><li>实例化书本带来了架构的可靠性和可维护性</li><li>公共类的引入带来了架构的可扩展性和简洁性</li><li>低耦合度的方法使新功能的实现更加便携</li></ul></li></ul><hr><h2 id="测试思维的演进"><a href="#测试思维的演进" class="headerlink" title="测试思维的演进"></a>测试思维的演进</h2><p>在面向对象课程中,测试思维的好坏往往能决定程序的品质<del>和分数</del>,在四个单元的磨炼中,我也形成了一套测试思维:</p><ul><li>第一单元初接触较为庞大的程序,测试抓不住重点,采用随机数据生成的方式进行随机测试,这种测试效率不高且易发生疏漏。</li><li>第二单元中,多线程的引入使对拍和debug不再方便,采用边界条件构造和大数据量测试的方法,集中测试程序在极端情况下的可靠性,效果较为出色。</li><li>第三单元,使用静态分析、OKtest测试和对拍程序相结合的方式,在本单元完成了一个数据生成和自动对拍器,本单元对性能的强调也是突出的,故有针对地构造大量耗时数据十分重要。</li><li>第四单元,测试被淡化,但绝不是不重要,由于充分的考量和架构设计,我们的程序具有较高的起点,犯错概率大大降低;本单元采用对逻辑链依次构造数据的方式,测评程序完备性。</li></ul><hr><h2 id="课程总结与收获"><a href="#课程总结与收获" class="headerlink" title="课程总结与收获"></a>课程总结与收获</h2><p>在 2023北航面向对象 的课程中,我在java基本程序设计、复杂架构搭建、测试策略和程序编写、形式化验证、程序结构建模等方面收获良多,虽然最后取得的成绩并不顶尖,但这些面向对象的思维观念和良好的编程习惯已经牢牢地刻印在脑海中。<br>这门课给我的最直观感受是要求严格但知识密度极大,是教授真正本领的一门课程,我很荣幸能全程参与。<br>最后,希望北航面向对象课程越办越好。</p>]]></content>
<categories>
<category> 面向对象 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> 面向对象 </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab6)</title>
<link href="/2023/05/15/os-lab6/"/>
<url>/2023/05/15/os-lab6/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab6"><a href="#Lab6" class="headerlink" title="Lab6"></a>Lab6</h2><hr><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-6-1"><a href="#Thinking-6-1" class="headerlink" title="Thinking 6.1"></a>Thinking 6.1</h3><p>交换管道操作的顺序即可。</p><pre class=" language-c"><code class="language-c"><span class="token keyword">char</span> buf<span class="token punctuation">[</span><span class="token number">100</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">int</span> status<span class="token punctuation">;</span><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> status <span class="token operator">=</span> <span class="token function">pipe</span><span class="token punctuation">(</span>fildes<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>status <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"error\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span><span class="token function">fork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">:</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token number">0</span><span class="token punctuation">:</span> <span class="token comment" spellcheck="true">/* 子进程 - 作为管道的写者 */</span> <span class="token function">close</span><span class="token punctuation">(</span>fildes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 关闭不用的读端 */</span> <span class="token function">write</span><span class="token punctuation">(</span>fildes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"Hello world\n"</span><span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 向管道中写数据 */</span> <span class="token function">close</span><span class="token punctuation">(</span>fildes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 写入结束,关闭写端 */</span> <span class="token function">exit</span><span class="token punctuation">(</span>EXIT_SUCCESS<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token punctuation">:</span> <span class="token comment" spellcheck="true">/* 父进程 - 作为管道的读者 */</span> <span class="token function">close</span><span class="token punctuation">(</span>fildes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 关闭不用的写端 */</span> <span class="token function">read</span><span class="token punctuation">(</span>fildes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> buf<span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 从管道中读数据 */</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"parent-process read:%s"</span><span class="token punctuation">,</span>buf<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 打印读到的数据 */</span> <span class="token function">close</span><span class="token punctuation">(</span>fildes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">/* 读取结束,关闭读端 */</span> <span class="token function">exit</span><span class="token punctuation">(</span>EXIT_SUCCESS<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><h3 id="Thinking-6-2"><a href="#Thinking-6-2" class="headerlink" title="Thinking 6.2"></a>Thinking 6.2</h3><p>dup 函数的主要工作如下:</p><pre class=" language-c"><code class="language-c"> <span class="token comment" spellcheck="true">//将newfd所在的虚拟页映射到oldfd所在的物理页</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>r <span class="token operator">=</span> <span class="token function">syscall_mem_map</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> oldfd<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> newfd<span class="token punctuation">,</span> vpt<span class="token punctuation">[</span><span class="token function">VPN</span><span class="token punctuation">(</span>oldfd<span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">&</span> <span class="token punctuation">(</span>PTE_D <span class="token operator">|</span> PTE_LIBRARY<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">goto</span> err<span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><pre class=" language-c"><code class="language-c"> <span class="token comment" spellcheck="true">//将newfd的数据所在的虚拟页映射到oldfd的数据所在的物理页</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>vpd<span class="token punctuation">[</span><span class="token function">PDX</span><span class="token punctuation">(</span>ova<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> PDMAP<span class="token punctuation">;</span> i <span class="token operator">+</span><span class="token operator">=</span> BY2PG<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> pte <span class="token operator">=</span> vpt<span class="token punctuation">[</span><span class="token function">VPN</span><span class="token punctuation">(</span>ova <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>pte <span class="token operator">&</span> PTE_V<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// should be no error here -- pd is already allocated</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>r <span class="token operator">=</span> <span class="token function">syscall_mem_map</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span>ova <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">(</span>nva <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">,</span> pte <span class="token operator">&</span> <span class="token punctuation">(</span>PTE_D <span class="token operator">|</span> PTE_LIBRARY<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">goto</span> err<span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>考虑以下情况:</p><pre class=" language-c"><code class="language-c"> <span class="token comment" spellcheck="true">//父进程</span> <span class="token function">dup</span><span class="token punctuation">(</span>p<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> newfd<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">write</span><span class="token punctuation">(</span>p<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">"Hello"</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><pre class=" language-c"><code class="language-c"> <span class="token comment" spellcheck="true">//子进程</span> <span class="token function">read</span><span class="token punctuation">(</span>p<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> buf<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><ul><li>若子进程先执行,还未进入 read 函数时发生进程切换,切换至父进程执行;</li><li>父进程执行 dup 函数时,对 p[0] 进行映射而未来得及对 pipe 进行映射就发生进程切换;</li><li>再次回到子进程时,<code>ref(p[0]) == ref(pipe) == 2</code>,即认为写进程关闭,出错!</li></ul><h3 id="Thinking-6-3"><a href="#Thinking-6-3" class="headerlink" title="Thinking 6.3"></a>Thinking 6.3</h3><p>系统调用一定是原子操作:</p><pre class=" language-c"><code class="language-c"><span class="token comment" spellcheck="true">/* disable interrupts */</span> mtc0 zero<span class="token punctuation">,</span> CP0_STATUS</code></pre><p>因为系统调用时禁用了中断,防止了中途退出该进程。</p><h3 id="Thinking-6-4"><a href="#Thinking-6-4" class="headerlink" title="Thinking 6.4"></a>Thinking 6.4</h3><ul><li>可以解决,因为<code>ref(p[0]) <= ref(pipe)</code>恒成立,交换解除顺序后 ref(p[0]) 在相同时刻要更小,所以一定不会出现这种问题。</li><li>如 Thinking 6.2 中所描述的,先对 p[0] 进行映射再对 pipe 进行映射,若中断条件发生在两类映射之间则存在使得<code>ref(p[0]) == ref(pipe)</code>的情况;也可以通过交换顺序解决。</li></ul><h3 id="Thinking-6-5"><a href="#Thinking-6-5" class="headerlink" title="Thinking 6.5"></a>Thinking 6.5</h3><ul><li>打开文件的过程<ul><li>用户态调用 file.c 下的 open 函数;</li><li>open 函数调用 fsipc.c 下的 fsipc_open 函数;</li><li>fsipc_open 调用 fsipc.c 下的 fsipc 函数向内核态发生请求并接收反馈;</li><li>内核态调用 serv.c 下的 serve_open 函数处理请求;</li><li>serve_open 调用 fs.c 下的 file_open 函数;</li><li>file_open 函数调用 fs.c 下的 walk_path 函数对磁盘块进行检索。</li></ul></li><li>Lab3 中填写的 load_icode 函数,实现了 ELF 可执行<br>文件中读取数据并加载到内存空间,其中通过调用elf_load_seg 函数来加载各个程序段。<br>在 Lab3 中填写的 load_icode_mapper 回调函数,在内核态下加载 ELF 数据到内存空间。</li><li>对于 bss 段中和其他段的数据在一个页面的部分,调用函数进行清零;对于其他部分,在存入内存时仅进行页面分配而不进行页面映射;使得其占据了空间且初值为0。</li></ul><h3 id="Thinking-6-6"><a href="#Thinking-6-6" class="headerlink" title="Thinking 6.6"></a>Thinking 6.6</h3><p>在 user/init.c 的 main 函数中:</p><pre class=" language-c"><code class="language-c"> <span class="token comment" spellcheck="true">// stdin should be 0, because no file descriptors are open yet</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>r <span class="token operator">=</span> <span class="token function">opencons</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">user_panic</span><span class="token punctuation">(</span><span class="token string">"opencons: %d"</span><span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// stdout</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>r <span class="token operator">=</span> <span class="token function">dup</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">user_panic</span><span class="token punctuation">(</span><span class="token string">"dup: %d"</span><span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>将 0 或 1 号文件描述符设置为标准输入或输出。</p><h3 id="Thinking-6-7"><a href="#Thinking-6-7" class="headerlink" title="Thinking 6.7"></a>Thinking 6.7</h3><ul><li>在 MOS 中我们用到的 shell 命令需要 fork 一个子 shell 进行执行,所以是外部命令。</li><li>由于 linux 的 cd 指令的功能是进入目录,需要读取文件,陷入内核,故不需要 fork 一个子 shell,是内部命令。</li></ul><h3 id="Thinking-6-8"><a href="#Thinking-6-8" class="headerlink" title="Thinking 6.8"></a>Thinking 6.8</h3><ul><li>两次 spawn ,对应两次生成的子进程分别用于执行ls.b和cat.b。</li><li>两次销毁,对应销毁生成的两个子进程。</li></ul><hr><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><p>笔者认为本次实验的难点如下:</p><ul><li>判断管道关闭的控制逻辑,涉及多进程执行结果的不确定性,依靠合理安排代码块顺序进行解决,十分巧妙。</li><li>父子进程使用管道时共享内存的细节问题。</li><li>spawn 函数的处理流程和细节。</li></ul><hr><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>lab6 的指导书相比前两个实验要更加明晰易懂,当然这也可能是我们在 lab6 完成了较为完整的操作系统,对其有整体的把控,但一些函数的细节理解还是有一定的挑战性。总之,在课程组的引导下,一步步实现一个可以工作的操作系统是一次难得的学习经历,使我对理论课的知识有了具象化的理解。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>北航计算机学院面向对象(2023 第三单元)</title>
<link href="/2023/05/01/OO_3/"/>
<url>/2023/05/01/OO_3/</url>
<content type="html"><![CDATA[<h1 id="北航计算机学院面向对象(2023-第三单元)"><a href="#北航计算机学院面向对象(2023-第三单元)" class="headerlink" title="北航计算机学院面向对象(2023 第三单元)"></a>北航计算机学院面向对象(2023 第三单元)</h1><h2 id="简介。"><a href="#简介。" class="headerlink" title="简介。"></a>简介。</h2><p>本文将以笔者学习过程中的思考感悟为基础,对2023北航计算机学院面向对象课程第三单元(作业9~11)的架构搭建和程序设计思路做简明的描述;如有不同见解,欢迎学习交流。</p><hr><h2 id="一、作业架构"><a href="#一、作业架构" class="headerlink" title="一、作业架构"></a>一、作业架构</h2><h3 id="1-架构总览"><a href="#1-架构总览" class="headerlink" title="1. 架构总览"></a>1. 架构总览</h3><p>本单元的作业要求实现一个社交网络模拟器,由于规格和部分文件已经给出,故架构较为固定,笔者在设计过程中为了使功能相对关系不大的方法分开,在要求实现的类的基础上添加了一些优化代码可读性的设计。<br>这是本次作业的架构图:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OO3-1.png"></p><p>可见这个系统本质上是一个以人为结点,人与人间关系为边,各种社交行为可以修改边和点的属性的无向图。</p><h3 id="2-图模型的建立和维护"><a href="#2-图模型的建立和维护" class="headerlink" title="2. 图模型的建立和维护`"></a>2. 图模型的建立和维护`</h3><ul><li>在设计中采用 HashMap 存储各个节点下属的边;在总的 MyNetwork 类中采用 ArrayList 存储 person、message 等数据信息。经本地对比测试,在10000条数据内 ArrayList 的性能略优于 HashMap,但30000条数据以上,HashMap 存储的优势显现。</li><li>对于关系的查找,并未采用并查集的策略,而是使用深度优先搜索进行遍历。<br>其实并查集和深搜策略的性能取决于测试数据是读密集型(利好并查集)还是写密集型(利好深搜)。</li><li>将性能纳入考虑,则需要采用缓存策略和一系列图论算法(见第三节优化部分)。</li></ul><hr><h2 id="二、代码测试"><a href="#二、代码测试" class="headerlink" title="二、代码测试"></a>二、代码测试</h2><p>本节中,将对各种测试方式和本单元测试策略做简要说明。</p><h3 id="1-黑箱与白箱测试"><a href="#1-黑箱与白箱测试" class="headerlink" title="1. 黑箱与白箱测试"></a>1. 黑箱与白箱测试</h3><ul><li>白箱测试<br>是测试人员要了解程序结构和处理过程,按照<strong>程序内部逻辑</strong>测试程序,检查程序中的每条通路是否按照预定要求正确工作.它主要的针对被测程序的<strong>源代码</strong>,测试者可以完全不考虑程序的功能.</li><li>黑箱测试<br>是根据功能需求来测试程序是否<strong>按照预期工作</strong>,是要从用户的角度分析,尽量发现代码所表现的<strong>外部行为</strong>的错误。黑盒测试应该是由测试团队来完成的,根据某个给定的输入,应该能够理解并详细说明程序的预期输出。</li></ul><h3 id="2-各种测试策略"><a href="#2-各种测试策略" class="headerlink" title="2. 各种测试策略"></a>2. 各种测试策略</h3><ul><li>单元测试<br>完成最小的软件设计单元(<strong>模块</strong>)的验证工作,目标是确保模块被正确的编码,使用<strong>过程设计描述</strong>作为指南,对重要的控制路径进行测试以发现模块内的错误,通常情况下是<strong>白盒</strong>的,对代码风格和规则、程序设计和结构、业务逻辑等进行<strong>静态测试</strong>,及早的发现和解决不易显现的错误。</li><li>功能测试<br>功能测试也叫<strong>黑盒测试或数据驱动测试</strong>,只需考虑需要测试的各个功能,不需要考虑整个软件的内部结构及代码,一般从软件产品的界面、架构出发,按照<strong>需求</strong>编写出来的测试用例,输入数据在预期结果和实际结果之间进行评测,进而提出更加使产品达到用户使用的要求。</li><li>集成测试<br>通过测试发现与<strong>模块接口</strong>有关的问题。目标是把通过了单元测试的模块拿来,构造一个在设计中所描述的程序结构进行测试。</li><li>压力测试<br>压力测试指一段时间内持续<strong>超过系统规格的负载</strong>进行测试的一种可靠性测试方法。</li><li>回归测试<br>在对软件进行修正后进行的有选择的<strong>重新测试</strong>过程,一般要重复已用的测试用例,目的是检验软件在更改后所引起的错误,验证软件在<strong>修改后</strong>未引起不希望的有害效果。</li></ul><h3 id="3-测试工具"><a href="#3-测试工具" class="headerlink" title="3. 测试工具"></a>3. 测试工具</h3><p>笔者在本单元中对代码的测试主要采用黑盒测试的方式,主要进行功能测试和压力测试,使用的工具是 python 编写的数据生成器和对拍器。测试策略有:</p><ul><li>对指令集进行划分,既可以在全指令集上进行综合测试,也可以对部分指令进行集中的针对测试</li><li>对指令数量做出要求,可一次产生10000条测试数据进行压力测试。</li><li>支持多人对拍,对多个 jar 包进行功能测试,参与的人数越多,结果越准确。</li><li>对于 okTest 方法的测试主要采用灰盒测试的策略,在对代码的各个分支进行分析后针对性构造测试数据,测试输出是否符合预期。</li></ul><h3 id="4-数据构造"><a href="#4-数据构造" class="headerlink" title="4. 数据构造"></a>4. 数据构造</h3><p>依靠数据生成器,可从以下几个角度构造具有一定强度的测试数据:</p><ul><li>大数据量 + 全指令集,生成综合测试数据。</li><li>大数据量 + 针对指令集,生成针对性数据,特别是一些费时的查询指令,这种方法可以测试程序是否具有一定的性能。</li></ul><p>依靠手动构造,可从以下几个角度构造具有一定强度的测试数据:</p><ul><li>边界数据(调用函数作用自身,存在异常等情况)</li><li>异常触发数据,用于覆盖测试异常抛出机制。</li></ul><hr><h2 id="三、规格和实现分离的优化策略"><a href="#三、规格和实现分离的优化策略" class="headerlink" title="三、规格和实现分离的优化策略"></a>三、规格和实现分离的优化策略</h2><p>在第3单元作业的编写中,一些方法的规格十分简单易懂,但完全按照规格编写会导致某些方法的性能较差;具体的:</p><h3 id="1-queryBlockSum-方法"><a href="#1-queryBlockSum-方法" class="headerlink" title="1. queryBlockSum 方法"></a>1. queryBlockSum 方法</h3><p>该方法的目的是求出总人群中互不相连的人群数,规格中描述如下:</p><pre class=" language-java"><code class="language-java"> <span class="token comment" spellcheck="true">/*@ ensures \result == @ (\sum int i; 0 <= i && i < people.length && @ (\forall int j; 0 <= j && j < i; !isCircle(people[i].getId(), people[j].getId())); @ 1); @*/</span> <span class="token keyword">public</span> <span class="token comment" spellcheck="true">/*@ pure @*/</span> <span class="token keyword">int</span> <span class="token function">queryBlockSum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>可以看出,该方法在二重循环中调用了 isCircle 方法,算法复杂度达到 O(n3logn),必须考虑优化:</p><ul><li>优化方法1:<br>为该方法另编写深搜函数,从某个人出发进行深搜,将可以链接到的人标记,在下一次深搜时不予访问;深搜次数即为所求;这种算法的复杂度约为 O(n2)</li><li>优化方法2:<br>对 person 对象构造并查集,在 addPerson、addRelation、modifyRelation 时进行更新,这样在查询时复杂度可以降低到 O(1)<br>但这种方法需要在人或关系变更时对并查集进行维护,其性能优化效果取决于测试数据是<strong>读密集型</strong>还是<strong>写密集型</strong>。</li></ul><h3 id="2-queryTripleSum-方法"><a href="#2-queryTripleSum-方法" class="headerlink" title="2. queryTripleSum 方法"></a>2. queryTripleSum 方法</h3><p>改方法的目的是查询总人群中三角关系的总数,规格中描述如下:</p><pre class=" language-java"><code class="language-java"> <span class="token comment" spellcheck="true">/*@ ensures \result == @ (\sum int i; 0 <= i && i < people.length; @ (\sum int j; i < j && j < people.length; @ (\sum int k; j < k && k < people.length @ && getPerson(people[i].getId()).isLinked(getPerson(people[j].getId())) @ && getPerson(people[j].getId()).isLinked(getPerson(people[k].getId())) @ && getPerson(people[k].getId()).isLinked(getPerson(people[i].getId())); @ 1))); @*/</span> <span class="token keyword">public</span> <span class="token comment" spellcheck="true">/*@ pure @*/</span> <span class="token keyword">int</span> <span class="token function">queryTripleSum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>可以发现,该规格使用三重循环,算法复杂度为 O(n3),需要进行优化。<br>考虑到人与关系的集合本质是无向图,在边的遍历时,相同节点对间的边会被访问两次,故优化策略为<strong>将无向图转化为有向图</strong>:</p><ul><li>若节点 A 与节点 B 间有边,则保留 小id 的指向 大id 的边,以此处理构造有向图。</li><li>寻找三角关系,使用hashmap存储节点对<pre class=" language-java"><code class="language-java"> hashmap<span class="token operator"><</span>idB<span class="token punctuation">,</span> idA<span class="token operator">></span> <span class="token comment" spellcheck="true">//<key, value> </span> <span class="token comment" spellcheck="true">// idB > idA,这表示指向 B 的节点为 A</span></code></pre><pre class=" language-mermaid"><code class="language-mermaid"> graph TD A-->B A-->C B-->C</code></pre>如图每次选取一个节点 A ,在 hashmap 中设置其指向的结点,对每个其指向的结点 B,查询 B 指向的结点 C 的 hashmap值,若 <strong>hashmap.get(idB) == hashmap.get(idC)</strong> 则确认一组三角关系。<br>该算法的复杂度为 O(n1.5)</li></ul><h3 id="3-queryCoupleSum-方法"><a href="#3-queryCoupleSum-方法" class="headerlink" title="3. queryCoupleSum 方法"></a>3. queryCoupleSum 方法</h3><p>该方法寻找总人群中互相关系最好的对数,规格中描述如下:</p><pre class=" language-java"><code class="language-java"> <span class="token comment" spellcheck="true">/*@ ensures \result == @ (\sum int i, j; 0 <= i && i < j && j < people.length @ && people[i].acquaintance.length > 0 && queryBestAcquaintance(people[i].getId()) == people[j].getId() @ && people[j].acquaintance.length > 0 && queryBestAcquaintance(people[j].getId()) == people[i].getId(); @ 1); @*/</span> <span class="token keyword">public</span> <span class="token comment" spellcheck="true">/*@ pure @*/</span> <span class="token keyword">int</span> <span class="token function">queryCoupleSum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>可以发现,该方法使用二重循环,每次调用 queryBestAcquaintance 方法,故算法复杂度为 O(n3),需要优化。</p><p>在该方法内部,调用了许多次 queryBestAcquaintance 方法,若每次进行检索,则做了许多重复计算,故在person类中设置 hisBestAcq 变量保存上一次的计算结果,并设置信号量 ifNeedRenew,在某些操作时发送更新信号,动态维护。<br>优化后复杂度为 O(n2)。</p><p>进一步,无需对每个可能存在的对都遍历一次,可以遍历所有人,对每个人求 bestAcq ,在确认 bestAcq 的 bestAcq 是否是此人,这样结合上一个策略,复杂度降到 O(n)。</p><h3 id="4-queryLeastMoments-方法"><a href="#4-queryLeastMoments-方法" class="headerlink" title="4. queryLeastMoments 方法"></a>4. queryLeastMoments 方法</h3><p>该方法的目的是寻找以结点 id 为出发点的最短回路(回路上包括出发点至少有三个不同的结点),给出的规格只从结果约束的角度对方法进行了描述,未给出可能的实现方法,需要自行设计。</p><p><strong>(1)删边法</strong><br>最直观的,若有满足描述的最短回路,存在与出发点 A 邻接的点 B,使得 A 到 B 的路径不只有 AB 边这一条。<br>故我们每次取一条与 A 邻接的边 AB,删除该边,然后使用 dijstra 算法求出 A 到各个点的最短路径,若 A 到 B 存在最短路径,则存在一个满足题意的回路,长度为:</p><pre><code>AB.length + Path(AB).length</code></pre><p>如此遍历所有与 A,邻接的点后,长度最短的回路则为所求。<br>这种方法虽然简单易于实现,但在最坏情况下复杂度达到了 O(n3),需要进行优化。</p><p><strong>(2)建树法</strong><br>此方法的思想是“寻找最后一条边”,具体的:</p><ul><li>以 A 为出发点,使用 dijstra 算法</li><li>记录 A 到各个点的最短路径上的边,以此构造最短路径树</li><li>选取原图中不在最短路径树上的边 BC</li><li>对每个这样的边的两个端点使用最近公共祖先(LCA)算法</li><li>若最近公共祖先为 A ,则回路上“最后一条边”为 BC</li><li>该回路长度为<pre><code> Path(AC).length + Path(AB).length + BC.length</code></pre></li><li>遍历每个这样的非路径树边记录最短回路长度即可</li></ul><p>这样只进行了一次 dijstra 算法,且由于在使用 dijstra 算法的过程中记录每个点在最短路径树上的深度, 一次LCA 算法的开销为O(n),故总复杂度降到 O(n2)。</p><h3 id="5-缓存策略的推广"><a href="#5-缓存策略的推广" class="headerlink" title="5. 缓存策略的推广"></a>5. 缓存策略的推广</h3><p>记录上一次运算结果的策略也可以推广到其他方法中:</p><table><thead><tr><th>方法</th><th>历史保存变量</th><th>更新信号量</th><th>更新触发方法</th></tr></thead><tbody><tr><td>queryBlockSum</td><td>hisBlockSum</td><td>ifRenewForBlock</td><td>addRelation/addPerson/modifyRelation</td></tr><tr><td>queryTripleSum</td><td>hisTriSum</td><td>ifRenewForTri</td><td>addRelation/modifyRelation</td></tr><tr><td>queryBestAcquaintance</td><td>hisBestValue/hisBestId</td><td>ifBestNeedRenew</td><td>addRelation/modifyRelation</td></tr></tbody></table><p>这种策略可以适用于读密集型的数据,并规避恶意重复访问。</p><hr><h2 id="四、Bug-的发现和修复"><a href="#四、Bug-的发现和修复" class="headerlink" title="四、Bug 的发现和修复"></a>四、Bug 的发现和修复</h2><p>在本单元作业中,笔者在强测出现了一些代码实现和设计上的 bug,并在强测中对他人的 bug 进行了hack。</p><h3 id="1-作业中出现的-bug"><a href="#1-作业中出现的-bug" class="headerlink" title="1. 作业中出现的 bug"></a>1. 作业中出现的 bug</h3><ul><li>在本单元第一次作业中,笔者的 okTest 中出现了访问越界的 bug,在代码设计的时候想当然的认为在该函数中 null 可以用判等符号与另一个非 null 值进行比较,结果课程组提供的 Runner 类中有对访问越界的异常进行捕获的机制,导致还未进行判等就直接抛出异常了。<br>在撰写代码的时候还是应当注意与之关联的部分的实现方式。</li><li>在第二次作业中,对 qcs 的强测出现了 CPU_Time_Limited_Existed 的 bug,这来源于 queryCoupleSum 方法的设计问题,当时仅对照 JML 描述进行了翻译,并未做降低复杂度的优化,导致超时。</li><li>在第三次作业中,对 qlm 的强测中出现了 Memrory_Limited_Existed 的 bug,这来源于 queryLeastMoments 方法的设计问题,当时使用了过大的二维数组,适当减小空间或切换为邻接表表示图即可。</li></ul><p>在撰写代码时还应该注意采用规格和实现分离的优化策略。</p><h3 id="2-Hack-策略"><a href="#2-Hack-策略" class="headerlink" title="2. Hack 策略"></a>2. Hack 策略</h3><p>由于笔者和室友在往届学长的对拍器上进行了扩展,形成了针对本单元作业的对拍器,故 hack 时非常简单直接,对拍器支持大于1的任意人数进行测试,数据在范围内随机生成,检测每个测试对象的每个输出,在不同的位置进行标记报错,定位 bug 十分快捷;主要发现的 bug 有</p><ul><li>MyPerson 中一些函数的处理没有考虑到传入自身的特殊情况。</li><li>qlm 指令计算路径错误(常常表现为找不到路径)</li><li>继承 Messgae 类的类的 equals 方法中直接沿用了Message类的 <code>instanceof Message</code>语句而未做修改。</li></ul><hr><h2 id="五、关于-OK测试"><a href="#五、关于-OK测试" class="headerlink" title="五、关于 OK测试"></a>五、关于 OK测试</h2><h3 id="1-OKTest-检验规格一致性"><a href="#1-OKTest-检验规格一致性" class="headerlink" title="1. OKTest 检验规格一致性"></a>1. OKTest 检验规格一致性</h3><p>在三次作业中,我们对代码中的小部分方法进行了 OK测试,在根据规格编写测试程序时,可以发现:</p><ul><li>OK测试代码严格依附于 JML 规格。</li><li>OK测试代码对方法调用前后数据变化的合理性和一致性都做了测试,这于规格相符。</li><li>OK测试对于方法调用可能作用于数据的各种行为进行了覆盖,较为严密。</li></ul><h3 id="2-改进建议"><a href="#2-改进建议" class="headerlink" title="2. 改进建议"></a>2. 改进建议</h3><p>在完成作业时,笔者有一些感受和建议:</p><ul><li>避免在写完该方法的代码实现后再编写 OKTest,否则易受到代码编写的影响导致 OKTest 失去原本的作用。</li><li>可以尝试为已经提供的方法进行 OKTest,真正体现 OKTest 的作用。</li><li>可以尝试在强测中引入 OKTest 互测机制,为同学的指定方法进行测试。</li></ul><hr><h2 id="写在后面"><a href="#写在后面" class="headerlink" title="写在后面"></a>写在后面</h2><p>本单元的核心是对 JML 规格的理解和撰写能力,在复杂方法中,JML 规格常常通过约束方法前后的变化和定义中间量来对方法的规格进行描述。<br>我们在阅读规格实现方法时,即要充分理解规格,保证完备性,又要不受规格中性能较低的语句约束,采取适当的优化,提升性能。<br>我们在撰写 JML 规格时,要明确该方法的作用是什么,有几种可能出现的情况,对变量修改的完备性如何等问题,并考虑 OKTest 的编写来验证方法是否符合规格的期待。</p>]]></content>
<categories>
<category> 面向对象 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> 面向对象 </tag>
<tag> JML </tag>
<tag> 软件测试 </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab5)</title>
<link href="/2023/04/28/os-lab5/"/>
<url>/2023/04/28/os-lab5/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab5"><a href="#Lab5" class="headerlink" title="Lab5"></a>Lab5</h2><hr><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-5-1"><a href="#Thinking-5-1" class="headerlink" title="Thinking 5.1"></a>Thinking 5.1</h3><p>当外设需要从内存中获取数据时,若数据先保存在 cache 中,则只有该数据在 cache 中的空间被后来的数据申请才会把该数据移到内存中(缓存更新),外设才可以获取这部分数据;会导致不同步或无响应的错误行为。<br>对于不同的外设:</p><ul><li>串口设备:每次读写以字节为单位,传输频繁,如果采用这种方式,极易出错。</li><li>IDE 磁盘:每次读写以磁盘块为单位,传输频率较低,采用这种方式出错概率小于串口设备。</li></ul><h3 id="Thinking-5-2"><a href="#Thinking-5-2" class="headerlink" title="Thinking 5.2"></a>Thinking 5.2</h3><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">define</span> FILE2BLK (BY2BLK / sizeof(struct File))</span></code></pre><p>可知一个磁盘中最多有 16 个文件控制块。</p><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">define</span> NDIRECT 10</span><span class="token macro property">#<span class="token directive keyword">define</span> NINDIRECT (BY2BLK / 4)</span></code></pre><p>因为不使用 INDRECT 部分的前十个指针,则一个目录文件最多可以使用1024个磁盘块存储数据,因此一个目录下最多1024*16 = 16384个文件。</p><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">define</span> MAXFILESIZE (NINDIRECT * BY2BLK)</span></code></pre><p>可知单个文件最大为 4KB * 1K = 4MB</p><h3 id="Thinking-5-3"><a href="#Thinking-5-3" class="headerlink" title="Thinking 5.3"></a>Thinking 5.3</h3><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">define</span> DISKMAX 0x40000000</span></code></pre><p>可知为 1GB</p><h3 id="Thinking-5-4"><a href="#Thinking-5-4" class="headerlink" title="Thinking 5.4"></a>Thinking 5.4</h3><p>fs/serv.h</p><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">define</span> PTE_DIRTY 0x0002 </span><span class="token comment" spellcheck="true">// file system block cache is dirty</span><span class="token comment" spellcheck="true">/* IDE disk number to look on for our file system */</span><span class="token macro property">#<span class="token directive keyword">define</span> DISKNO 1</span><span class="token macro property">#<span class="token directive keyword">define</span> BY2SECT 512 </span><span class="token comment" spellcheck="true">/* Bytes per disk sector */</span><span class="token macro property">#<span class="token directive keyword">define</span> SECT2BLK (BY2BLK / BY2SECT) </span><span class="token comment" spellcheck="true">/* sectors to a block */</span><span class="token comment" spellcheck="true">/* Disk block n, when in memory, is mapped into the file system * server's address space at DISKMAP+(n*BY2BLK). */</span><span class="token macro property">#<span class="token directive keyword">define</span> DISKMAP 0x10000000</span><span class="token comment" spellcheck="true">/* Maximum disk size we can handle (1GB) */</span><span class="token macro property">#<span class="token directive keyword">define</span> DISKMAX 0x40000000</span></code></pre><p>定义了磁盘空间的各个基本单位的参数。</p><p>user/include/fs.h</p><pre class=" language-c"><code class="language-c"><span class="token comment" spellcheck="true">// Bytes per file system block - same as page size</span><span class="token macro property">#<span class="token directive keyword">define</span> BY2BLK BY2PG</span><span class="token macro property">#<span class="token directive keyword">define</span> BIT2BLK (BY2BLK * 8)</span><span class="token comment" spellcheck="true">// Maximum size of a filename (a single path component), including null</span><span class="token macro property">#<span class="token directive keyword">define</span> MAXNAMELEN 128</span><span class="token comment" spellcheck="true">// Maximum size of a complete pathname, including null</span><span class="token macro property">#<span class="token directive keyword">define</span> MAXPATHLEN 1024</span><span class="token comment" spellcheck="true">// Number of (direct) block pointers in a File descriptor</span><span class="token comment" spellcheck="true">// Number of (indirect) block pointers in a File descriptor</span><span class="token macro property">#<span class="token directive keyword">define</span> NDIRECT 10</span><span class="token macro property">#<span class="token directive keyword">define</span> NINDIRECT (BY2BLK / 4)</span><span class="token comment" spellcheck="true">//Maximum size ofa file</span><span class="token macro property">#<span class="token directive keyword">define</span> MAXFILESIZE (NINDIRECT * BY2BLK)</span><span class="token comment" spellcheck="true">//Size of a file control block</span><span class="token macro property">#<span class="token directive keyword">define</span> BY2FILE 256</span></code></pre><p>定义了文件控制块和文件本身的限制和参数。</p><h3 id="Thinking-5-5"><a href="#Thinking-5-5" class="headerlink" title="Thinking 5.5"></a>Thinking 5.5</h3><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><stdio.h></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><unistd.h></span></span><span class="token keyword">int</span> <span class="token function">main</span> <span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">long</span> pid<span class="token punctuation">;</span> pid <span class="token operator">=</span> <span class="token function">fork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>pid <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span> FILE<span class="token operator">*</span> f0 <span class="token operator">=</span> <span class="token function">fopen</span><span class="token punctuation">(</span><span class="token string">"/newmotd"</span><span class="token punctuation">,</span> <span class="token string">"r"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"child open file's code is %d\n"</span><span class="token punctuation">,</span> f0<span class="token operator">-></span>_flags<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> FILE<span class="token operator">*</span> f1 <span class="token operator">=</span> <span class="token function">fopen</span><span class="token punctuation">(</span><span class="token string">"/newmotd"</span><span class="token punctuation">,</span> <span class="token string">"r"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"parent open file's code is %d\n"</span><span class="token punctuation">,</span> f1<span class="token operator">-></span>_flags<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>仅平台测试发现,父子进程共享文件描述符和定位指针。</p><h3 id="Thinking-5-6"><a href="#Thinking-5-6" class="headerlink" title="Thinking 5.6"></a>Thinking 5.6</h3><pre class=" language-c"><code class="language-c"><span class="token keyword">struct</span> File <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">char</span> f_name<span class="token punctuation">[</span>MAXNAMELEN<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// filename</span> uint32_t f_size<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// file size in bytes</span> uint32_t f_type<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// file type</span> uint32_t f_direct<span class="token punctuation">[</span>NDIRECT<span class="token punctuation">]</span><span class="token punctuation">;</span> uint32_t f_indirect<span class="token punctuation">;</span> <span class="token keyword">struct</span> File <span class="token operator">*</span>f_dir<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// the pointer to the dir where this file is in, valid only in memory.</span> <span class="token keyword">char</span> f_pad<span class="token punctuation">[</span>BY2FILE <span class="token operator">-</span> MAXNAMELEN <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">+</span> NDIRECT<span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">4</span> <span class="token operator">-</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">void</span> <span class="token operator">*</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token function">__attribute__</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token function">aligned</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">,</span> packed<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// file descriptor</span><span class="token keyword">struct</span> Fd <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> u_int fd_dev_id<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//文件对应的设备id</span> u_int fd_offset<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//文件指针所指向的位置</span> u_int fd_omode<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//文件打开模式</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">// file descriptor + file</span><span class="token keyword">struct</span> Filefd <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">struct</span> Fd f_fd<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//文件描述符结构体</span> u_int f_fileid<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//文件id</span> <span class="token keyword">struct</span> File f_file<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//文件控制块</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span></code></pre><table><thead><tr><th>结构体名称</th><th>使用域</th></tr></thead><tbody><tr><td>Fd</td><td>记录已打开文件的状态,用户可以直接使用文件描述符对文件进行操作,该结构体对应磁盘上的物理实体</td></tr><tr><td>File</td><td>记录文件中的详细信息,包括文件名、文件类型、磁盘位置等</td></tr><tr><td>Filefd</td><td>是以上两种结构体的组合包,将 Fd* 强制转换为 Filefd* 从而获取到文件控制块中更详细的信息</td></tr></tbody></table><h3 id="Thinking-5-7"><a href="#Thinking-5-7" class="headerlink" title="Thinking 5.7"></a>Thinking 5.7</h3><ul><li>实线箭头为同步消息</li><li>虚线箭头为返回消息</li><li>通信时,消息接收方进入可接收状态并通知发送方发送数据,进行进程切换;发送方发送完毕后等待接收方接收完毕的信号;收到信号后通知接收方继续运行。</li><li>ipc 机制保证了用户、内核、文件进程间的正常通信。</li></ul><hr><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><p>在完成作业时,主要的难点如下:</p><ul><li>内核态读写驱动读写缓冲区和设置操作值的顺序易出错;</li><li>文件体系结构的管理数据结构较为多样</li><li>文件系统服务的通信机制较为复杂</li></ul><hr><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>本次实验系统介绍了文件系统,按照 外设–接口–驱动–文件系统管理–用户接口构造 的顺序逐步构建文件系统。<br>安照指导书和代码注释补全代码难度不大,但要完整的把握整个文件系统的运行流程还需对fs文件夹以及user文件夹下的相关代码做仔细的阅读。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab4)</title>
<link href="/2023/04/14/os-lab4/"/>
<url>/2023/04/14/os-lab4/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab4"><a href="#Lab4" class="headerlink" title="Lab4"></a>Lab4</h2><hr><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-4-1"><a href="#Thinking-4-1" class="headerlink" title="Thinking 4.1"></a>Thinking 4.1</h3><ul><li>系统从用户态切换到内核态后,内核首先需要将原用户进程的运行现场保存到内核空间(在 kern/entry.S 中通过 SAVE_ALL 宏完成),其中保存的信息包括通用寄存器的值。</li><li>可以,操作系统在陷入内核的过程中并未对寄存器 a0 ~ a3 存储的值作修改。</li><li>传入 msyscall 函数的参数被保存在寄存器 a0 ~ a3 中和栈中,从用户态转移到内核态调用 sys 开头的参数时,用户态的运行现场保存在 Trapframe 中被传递给内核,其中包含寄存器的值和栈帧,sys 开头的函数可根据这些信息确定传入的参数,与传入 msyscall 函数的参数相同。</li><li>对 EPC 的值做了处理,将函数返回值填入 v0 寄存器中,这样使得返回用户态后程序能从正确的位置正常运行下去。</li></ul><h3 id="Thinking-4-2"><a href="#Thinking-4-2" class="headerlink" title="Thinking 4.2"></a>Thinking 4.2</h3><p>判断 e->env_id != envid 的情况时为了防止取到一个未经 env_alloc 的空进程。如果没有这步判断,可能会在 env 数组中取到一个未经初始化分配的进程。</p><h3 id="Thinking-4-3"><a href="#Thinking-4-3" class="headerlink" title="Thinking 4.3"></a>Thinking 4.3</h3><p>kern/env.c 文件中 mkenvid() 不会返回 0:</p><pre class=" language-c"><code class="language-c">u_int <span class="token function">mkenvid</span><span class="token punctuation">(</span><span class="token keyword">struct</span> Env <span class="token operator">*</span>e<span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">static</span> u_int i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">+</span> LOG2NENV<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token punctuation">(</span>e <span class="token operator">-</span> envs<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><p>其中 ++i 保证了 env_id 不会是0。<br>在 envid2env() 函数中:</p><pre class=" language-c"><code class="language-c"><span class="token keyword">if</span><span class="token punctuation">(</span>envid <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token operator">*</span>penv <span class="token operator">=</span> curenv<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> </code></pre><p>可见,当envid的值是0时,函数会直接返回指向当前进程控制块的指针;因此,将 0 传入函数可以方便地访问当前进程的控制块。</p><h3 id="Thinking-4-4"><a href="#Thinking-4-4" class="headerlink" title="Thinking 4.4"></a>Thinking 4.4</h3><p><strong>C</strong><br>由代码顺序执行特征和实验结果可知,fork() 函数在父进程中被调用了一次,创建子进程后在两个进程中分别返回。</p><h3 id="Thinking-4-5"><a href="#Thinking-4-5" class="headerlink" title="Thinking 4.5"></a>Thinking 4.5</h3><ul><li>ULIM 和 UTOP 之间存储的是内核页表和进程控制快等信息,这部分在 env_init 中通过 map_segment 函数初始化了,不必复制。</li><li>UTOP 和 USTACKTOP 之间是为异常处理预留的空间,不必复制。</li><li>USTACKTOP 之下为用户常规使用空间,需要复制。</li></ul><h3 id="Thinking-4-6"><a href="#Thinking-4-6" class="headerlink" title="Thinking 4.6"></a>Thinking 4.6</h3><pre class=" language-c"><code class="language-c"><span class="token macro property">#<span class="token directive keyword">define</span> vpt ((volatile Pte *)UVPT)</span><span class="token macro property">#<span class="token directive keyword">define</span> vpd ((volatile Pde *)(UVPT + (PDX(UVPT) << PGSHIFT)))</span></code></pre><ul><li>vpt 是指向页表地址的指针,vpd 是指向页目录的指针。需要访问页表或页目录中第 n 项时,只需使用 vpt[n] 或 vpd[n] 即可。</li><li>由宏定义知 vpt 和 vpd 都对应了相应区域的首地址,且有强制转换为其赋予种类,则进程可以十分方便的将其视作数组首地址来访问。</li><li>观察知 vpd 的值是在 vpt 与 vpt + 4MB 之间的,即页目录首地址通过自映射(计算 vpd 之前的页数进行转换加和)映射到页表中的一页。</li><li>不能;页表需在内核态维护,用户态只读。</li></ul><h3 id="Thinking-4-7"><a href="#Thinking-4-7" class="headerlink" title="Thinking 4.7"></a>Thinking 4.7</h3><ul><li>syscall_set_tlb_mod_entry 函数可被传入用户定义的异常处理函数指针,若自定义的异常处理函数在运行时又对一个 COW 页进行写入,则需要采用异常重入策略。<br>支持异常重入增强了程序的扩展性,保证用户自定义异常处理函数的安全性。</li><li>因为指导书中说明异常处理在用户态进行,若需要访问内核态的现场,则需通过复制 Trapframe 访问。</li></ul><h3 id="Thinking-4-8"><a href="#Thinking-4-8" class="headerlink" title="Thinking 4.8"></a>Thinking 4.8</h3><p>微内核体系下,用户态进行页面处理更加方便。减下了内核出错的概率,提高系统执行效率和稳定性。</p><h3 id="Thinking-4-9"><a href="#Thinking-4-9" class="headerlink" title="Thinking 4.9"></a>Thinking 4.9</h3><ul><li>将 syscall_set_tlb_mod_entry 的调用放置在 syscall_exofork 之前充分保证了写时复制机制建立之前就存在写入异常处理机制,保证了系统的安全性。</li><li>如果放置在写时复制保护机制完成之后,此时异常处理函数未被制定,异常处理机制无法使用。</li></ul><hr><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><p>本次实验的难点主要有以下几个方面:</p><ul><li>理解系统调用的过程,理清系统调用间的函数关系和内存保护注意事项。</li><li>理清 fork 机制建立的过程:<ul><li>申请进程空间</li><li>拷贝父子进程数据</li><li>对 COW 的处理</li><li>对进程运行队列的维护</li></ul></li><li>理清异常处理机制的建立与写时复制机制间的关系。</li></ul><hr><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>本次作业模块间的耦合度要比以往高出许多,特别是 fork 模块的实现,需要考虑到父子进程地址空间间的关系和一系列异常处理措施。<br>本次作业对 bug 的查找也十分有挑战性,笔者采取的方法是使用之前实现的 printk 函数对进程的运行情况进行监测。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>北航计算机学院面向对象(2023 第二单元)</title>
<link href="/2023/04/01/OO_2/"/>
<url>/2023/04/01/OO_2/</url>
<content type="html"><![CDATA[<h1 id="北航计算机学院面向对象(2023-第二单元)"><a href="#北航计算机学院面向对象(2023-第二单元)" class="headerlink" title="北航计算机学院面向对象(2023 第二单元)"></a>北航计算机学院面向对象(2023 第二单元)</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>本文将以笔者学习过程中的思考感悟为基础,对2023北航计算机学院面向对象课程第二单元(作业5~7)的架构搭建和程序设计思路做简明的描述;如有不同见解,欢迎学习交流。</p><hr><h2 id="一、同步与锁"><a href="#一、同步与锁" class="headerlink" title="一、同步与锁"></a>一、同步与锁</h2><p>在该节,将对三次作业中线程互斥和安全问题进行系统性分析。</p><h3 id="1-共享资源的确定"><a href="#1-共享资源的确定" class="headerlink" title="1.共享资源的确定"></a>1.共享资源的确定</h3><p>在多线程开发的工程中,多个线程常常需要访问同一个区域的资源,这表明我们需要确定多个线程可以访问的类、变量、方法等来选取<strong>共享资源</strong>。<br>在我们的作业中:</p><ul><li>输入线程将输入置于请求队列中</li><li>电梯线程从队列中获取乘客</li><li>需要换乘时电梯线程将乘客写入请求队列中</li><li>调度模块检索请求队列为各电梯提供决策<br>可见<strong>该队列及其行为</strong>即为该系统的共享资源,我们将其命名为<strong>请求表(RequestTable)</strong>,并将其封装成一个专门的类便于后续线程互斥的操作。</li></ul><h3 id="2-线程互斥的判定"><a href="#2-线程互斥的判定" class="headerlink" title="2.线程互斥的判定"></a>2.线程互斥的判定</h3><p>线程互斥的“锁程度”(笔者杜撰,即被资源加锁的代码块长度)是个微妙的话题:<br>过高的锁程度为编程人员带来很强的安全感,但多线程程序的执行效率可能受到影响,甚至趋近于单线程。<br>在未保证线程安全的情况下过低的锁程度可能导致线程对同一资源的访问冲突,导致线程安全问题。</p><p>故决定何处的代码块应该被加锁,不加不必要的线程锁是十分重要的。</p><p>根据<strong>Bernstein条件</strong>:<br>两个线程在某区域可并发执行,当且仅当对于该区域:</p><ul><li>R(S1) & W(S2) = ∅</li><li>R(S2) & W(S1) = ∅</li><li>W(S1) & W(S2) = ∅</li></ul><p>其中 R 表示读行为,W 表示写行为。<br>故当资源不可被多个线程访问(线程不可在该区域并行,即需要加锁),以上三个条件至少有一个无法满足。</p><p>基于此,在三次作业的代码中,与 RequestTable 相关的读写代码块都应该被加锁;这样处理可以保证共享资源不被同时读写,保证了共享资源的线程互斥和安全。</p><hr><h2 id="二、线程协作和调度"><a href="#二、线程协作和调度" class="headerlink" title="二、线程协作和调度"></a>二、线程协作和调度</h2><p>在本节中,将介绍三次作业的架构和线程协作模式,分析调度策略的更迭。</p><h3 id="1-代码架构"><a href="#1-代码架构" class="headerlink" title="1.代码架构"></a>1.代码架构</h3><p>以下是本实验的UML架构,三次作业差别不大,故取第三次作业的架构进行分析:</p><p><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OO2-1.png"></p><p>系统架构分为6个大类,简要功能如下:</p><table><thead><tr><th>类名称</th><th>功能</th></tr></thead><tbody><tr><td>MainClass</td><td>主类,接受输入包的输入,负责开启电梯线程</td></tr><tr><td>Elevator</td><td>电梯类,是唯一的继承Thread的类,包含电梯的各个行为方法,和状态函数</td></tr><tr><td>Person</td><td>请求单元类,存放并维护请求单元</td></tr><tr><td>RequestTable</td><td>请求表类,该类为各个电梯线程共享,提供请求表的信息和维护方法</td></tr><tr><td>Dispatch</td><td>决策类,根据电梯和请求表的状态为电梯提供下一步行为的决策</td></tr><tr><td>ArrangePath</td><td>寻路类,仅在第三次作业中使用,解决人员的必要的换乘需求</td></tr></tbody></table><p>以下是三次作业的架构变化分析:</p><table><thead><tr><th>作业序号</th><th>功能更迭</th></tr></thead><tbody><tr><td>1</td><td>通过电梯线程的模拟,实现人员在楼层间的一次传输</td></tr><tr><td>2</td><td>增加电梯的增减功能,只需维护一个Elevator类数组即可,但线程终止条件需要进行修改</td></tr><tr><td>3</td><td>增加换乘、电梯楼层限制、同时服务限制;为此,添加寻路类和服务数、服务楼层的特判</td></tr></tbody></table><h3 id="2-调度和决策"><a href="#2-调度和决策" class="headerlink" title="2.调度和决策"></a>2.调度和决策</h3><p>在三次作业中,均采用<strong>自由竞争</strong>的策略;前两次作业电梯类间无约束,最后一次作业为此策略添加了控制和规划的元素。</p><p><strong>(1)纯粹自由竞争</strong><br>该策略十分容易实现,且可实现人员输送的速度最大化,但对于耗电量的处理在人员流量下的情况下可能效果不佳。<br>该策略具体如下:</p><ul><li>电梯内为空时,向着 RequestTable 内有请求的方向移动,否则原地待命。</li><li>电梯内有人时,到相应楼层,相应楼层请求若与电梯行进方向相同,则开门捎带。</li><li>电梯在 1层 和 顶层 自动切换运行方向。</li></ul><p>可见该策略逻辑简单,在做好线程安全和同步的前提下,电梯线程间互不干扰,速度性能和安全性能较佳,但耗电量不可控。</p><p><strong>(2)规划自由竞争</strong><br>在第三次作业中,电梯的达到楼层和同时服务数限制,自由竞争策略在这种条件下需要进行改进,具体改进思路如下:</p><ul><li>引入 ArrangePath 类,使用 Djstra 算法进行寻路,具体处理如下:<ul><li>将电梯的可达楼层掩码转化为楼层可达矩阵</li><li>将各个电梯的可达性矩阵加和得到总图</li><li>对总图应用 Djstra 算法,依据人员始末楼层规划最短换乘路径</li><li>维护或添加电梯时只需使用总图减去或加上可达矩阵即可。</li></ul></li><li>在每次维护、增加电梯时更新总图和 RequestTable 中的人员路径;在每次人出电梯时更新出电梯需换乘的人员路径。</li><li>在电梯到某一楼层时,依次检索电梯外的人员,若其下一个到达楼层该电梯可达且电梯容量未达到上限,则开门接人。</li><li>在电梯到某一楼层时,依次检索电梯内的人员,若人员当前需到达楼层为该层,则开门放人,若该人员的终止楼层为该楼,则释放该请求,否则将该人员的起点楼层和下一到达楼层修改,重新放入RequestTable 中。</li><li>在共享的空间中添加“正服务”和“只开门”数组记录楼层的服务信息,当电梯在某楼层确需开门中先结合该数组进行判断,再决定是否开门。</li></ul><p>该策略中,保留了自由竞争的成分,但使用了共享资源作为限制条件,并针对人员使用路径规划,在保证整体架构不变的前提下实现了功能的迭代。</p><p>该策略中,电梯线程间不直接相互影响,而是通过共享资源进行间接限制,在不引入调度线程的前提下,实现了电梯准确性、速度和耗电量的权衡。</p><p><strong>(3)线程时序分析</strong><br>以下是主线程和电梯线程的时序图:</p><p><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OO2-2.png"></p><p>可见该系统的时序调用十分简单,电梯线程仅仅由主线程创建,线程间的关系较为单一,便于代码的编写和分块调试。</p><h3 id="3-易变分析"><a href="#3-易变分析" class="headerlink" title="3.易变分析"></a>3.易变分析</h3><p>在三次作业中,迭代开发的需求较为显著,可分为稳定和易变两个方面:</p><ul><li>稳定部分<ul><li>电梯的行为:移动、等待、开关门、结束运行</li><li>人员的起始终止楼层信息</li><li>RequestTable 的结构</li></ul></li><li>易变部分<ul><li>电梯的容量、可达性、速度等参数</li><li>楼层的同时服务限制</li><li>电梯的终止条件限制</li><li>电梯数量的变化</li></ul></li></ul><p>其中稳定性部分多是对象的基本行为属性,这也在意料之中,因为现实中电梯可执行的动作也基本上在第一次作业就被涵盖了。</p><p>易变的是电梯的性质和运行规则,为适用与不同的应用场景,这些参数是可以被频繁修改的。</p><hr><h2 id="三、多线程Debug策略"><a href="#三、多线程Debug策略" class="headerlink" title="三、多线程Debug策略"></a>三、多线程Debug策略</h2><p>对于多线程程序,debug 无法使用单步调试工具,故在 debug 和 hack 过程中,需要采取一些特殊的策略;虽然这一单元笔者在强测和互测中均为出现 bug,也为发现 bug,但在课下的调试过程中,笔者收获了一些调试技巧和感悟。</p><h3 id="1-Debug-策略"><a href="#1-Debug-策略" class="headerlink" title="1.Debug 策略"></a>1.Debug 策略</h3><ul><li>CPU_Time_Limited_Exited<br>出现该 bug 的原因一般是代码中产生了轮询(频繁地访问或修改一个量),定位该 bug 可选择在含有循环的结构中打印一些信息,若运行时某一信息出现次数过多即该处很可能发生了轮询。<br>例如笔者第三次作业的课下,由于决策类的设计笔误,电梯在本该停下的时候发生了不间断的转向,导致方向信号量杯反复修改,通过打印电梯的行为可以直接定位 bug。</li><li>Running_Time_Limited_Exited<br>出现该 bug 的原因可能是调度策略问题(完成得太慢),但这种情况可能性很小;更多的是电梯线程未正常结束,大多是人员未完全送到电梯就都停下了。<br>避免该 bug 的机制也比较简单,可以在输入结束后维护一个信号,在电梯运行时维护剩余未完成请求的变量,当结束信号产生、变量归零时即可结束进程。</li><li>Runtime Error<br>该 bug 在本次作业中大多由于遍历结构时对结构进行修改产生(遍历和修改可能是两个不同的线程),故在同一线程中注意缓冲区的构建,在线程间协调好安全问题即可。</li><li>Wrong Anwser<br>该 bug 的原因十分多样,可能有人员送错楼层,行为时间间隔有误,电梯到达不可到达的楼层等,但评测机的出现使这一类 bug 的定位解决较为简单。</li></ul><h3 id="2-Hack策略"><a href="#2-Hack策略" class="headerlink" title="2.Hack策略"></a>2.Hack策略</h3><p>在三次 hack 中,笔者未能命中(<del>可能是大伙都用评测机跑了</del>),但还是有一些数据构造策略:</p><ul><li>短时间,大流量,长跨度数据的投放</li><li>边界数据(增减电梯在边界层)</li><li>极端条件(废除尽可能多的电梯)</li><li>换乘构造(构造可能需要多次换乘的数据)</li></ul><hr><h2 id="四、写在后面"><a href="#四、写在后面" class="headerlink" title="四、写在后面"></a>四、写在后面</h2><p>在本单元的练习中,笔者对多线程编程有了大概的理解和掌握,并初步进行应用。</p><p>对于线程安全问题,笔者采用同步代码块的方式,将主类中声明的 RequestTable 对象作为共享对象,实现了线程访问的互斥;在线程通信方面,由于本架构线程间耦合性低,故采用 sleep() 方法代替 wait-notify 机制进行必要的等待,这种方式降低了进程间通信的性能消耗,但线程间的关系不易看出,实在算不上好的策略。</p><p>对于调度器的编写,笔者三次作业坚持延续自由调度的核心,以耗电量的增加换取代码的简洁和输送速度的提高,虽说任何调度策略都需要在这两个方面做权衡,但自由调度的策略还是太偏向于速度,忽略耗电量了(太极端,易被样例针对);虽然最后的性能得分都在95左右,但要将该系统部署在现实中还需要调度策略的优化。</p><p>总之,笔者认为自身对安全性和代码简洁性的考虑有些过头,策略选取和类构造都尽可能简单,这是之后的作业中需要权衡改进的。</p>]]></content>
<categories>
<category> 面向对象 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> 面向对象 </tag>
<tag> 并发程序设计 </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab3)</title>
<link href="/2023/03/29/os-lab3/"/>
<url>/2023/03/29/os-lab3/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab3"><a href="#Lab3" class="headerlink" title="Lab3"></a>Lab3</h2><hr><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-3-1"><a href="#Thinking-3-1" class="headerlink" title="Thinking 3.1"></a>Thinking 3.1</h3><pre class=" language-C"><code class="language-C">e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V;</code></pre><p>大小为4MB(0x7fc000000 - 0x80000000)是保存该进程页表项的区域,其中 UVPT = 0x7fc00000。<br>采用页表自映射的方式:页目录的 4KB 空间在这 4MB 空间之中,该页目录中有一项指向的空间是<strong>页目录的头地址</strong>,该项即为第PDX(UVPT) 项,将页目录本身的物理地址映射给这一页目录项实现自映射。</p><h3 id="Thinking-3-2"><a href="#Thinking-3-2" class="headerlink" title="Thinking 3.2"></a>Thinking 3.2</h3><p>在 env.c 文件的 load_icode 函数中,调用了 elf_load_seg 函数,形参 map_page 和 data 对应的实参分别是 load_icode_mapper函数和 e(进程控制块)。<br>不可以没有该参数,因为该参数的作用是作为回调函数的参数传入,函数会对其进行分配物理页面建立映射的操作。</p><h3 id="Thinking-3-3"><a href="#Thinking-3-3" class="headerlink" title="Thinking 3.3"></a>Thinking 3.3</h3><p>va 和 va + bin_size 的关系可能有:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OS3_1.png"><br>va + bin_size 和 va + sig_size 的关系可能有:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/OS3_2.png"></p><h3 id="Thinking-3-4"><a href="#Thinking-3-4" class="headerlink" title="Thinking 3.4"></a>Thinking 3.4</h3><p>env_tf.cp0_epc 存储的是程序入口,而各个进程的程序入口相同,所以这是虚拟地址。</p><h3 id="Thinking-3-5"><a href="#Thinking-3-5" class="headerlink" title="Thinking 3.5"></a>Thinking 3.5</h3><p>handle_int (kern/genex.S)</p><pre><code>NESTED(handle_int, TF_SIZE, zero) mfc0 t0, CP0_CAUSE mfc0 t2, CP0_STATUS and t0, t2 andi t1, t0, STATUS_IM4 bnez t1, timer_irq // TODO: handle other irqstimer_irq: sw zero, (KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_INTERRUPT_ACK) li a0, 0 j scheduleEND(handle_int)</code></pre><p>handle_mod、handle_tlb、handle_sys通过genex.S文件中的宏函数BUILD_HANDLER实现:</p><pre><code>BUILD_HANDLER tlb do_tlb_refill#if !defined(LAB) || LAB >= 4BUILD_HANDLER mod do_tlb_modBUILD_HANDLER sys do_syscall#endif</code></pre><h3 id="Thinking-3-6"><a href="#Thinking-3-6" class="headerlink" title="Thinking 3.6"></a>Thinking 3.6</h3><pre><code>LEAF(enable_irq) li t0, (STATUS_CU0 | STATUS_IM4 | STATUS_IEc) //赋值 t0 = 0x10001001 mtc0 t0, CP0_STATUS //#将 CP0 的 SR 寄存器中第1、12、28位 置为1,作用是开启全局中断使能和始终中断使能,并允许用户态使用CP0 jr ra //返回END(enable_irq)</code></pre><pre><code>timer_irq: sw zero, (KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_INTERRUPT_ACK) //写入0,响应时钟中断 li a0, 0 //向 schedule 中传入 0 j schedule //跳转到 schedule 函数</code></pre><h3 id="Thinking-3-7"><a href="#Thinking-3-7" class="headerlink" title="Thinking 3.7"></a>Thinking 3.7</h3><ul><li>当线程被创建并置为 RUNNABLE 时,将其插入到 env_sched_list 的头部。</li><li>每次运行前检查正需要运行的进程时间片是否用完。</li><li>用完若状态仍为 RUNNABLE 则将其插入到 env_sched_list 的尾部,否则直接移出可执行线程队列。继续运行队列头部的线程。</li><li>若未用完则继续执行。</li></ul><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><ul><li>页表自映射的机制较为抽象,在 lab2 的扩展部分,第一次接触到了页表自映射的概念,由于对二级页表的处理较为生疏,理解该映射机制存在一定难度;该机制实际上是将<strong>页目录、页表、其他虚拟页</strong>一视同仁,都采用相同的映射机制进行访问,唯一需要注意的是为了实现该机制,各个页表占用的总 4MB 空间要求<strong>连续存储</strong>。</li><li>对中断处理函数的理解有一定难度,主要操作位,结合中断允许控制位和中断标志位对是否中断及中断类型进行判断,通过<strong>进程调度</strong>的方式来处理中断。</li><li>调度函数的编写容易出错,由于进程是可以创建进程的,故一个进程需要执行时,需先将其从可执行线程链表中<strong>立即取出</strong>,若执行后再取出,可能会导致其他进程获取到相同的子进程。</li></ul><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>本次作业要求填补的函数难度不高,但透彻理解线程的创建过程和中断的处理机制还是有一定挑战的;经历 lab2 对内存管理的熟悉后,完成 lab3 实验的压力降低了很多;后续需要加强对进程在内存中执行的细节的了解和理解。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab2)</title>
<link href="/2023/03/15/os-lab2/"/>
<url>/2023/03/15/os-lab2/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab2"><a href="#Lab2" class="headerlink" title="Lab2"></a>Lab2</h2><hr><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-2-1"><a href="#Thinking-2-1" class="headerlink" title="Thinking 2.1"></a>Thinking 2.1</h3><p>由于而在实际程序中,访存、跳转等指令以及用于取指的 PC 寄存器中的访存目标地址都是虚拟地址,所以 C 程序和 MIPS 程序中使用的都是虚拟地址。</p><h3 id="Thinking-2-2"><a href="#Thinking-2-2" class="headerlink" title="Thinking 2.2"></a>Thinking 2.2</h3><p>(1)<br>用宏实现链表的相关操作有以下优点:</p><ul><li>重用性和可移植性好,代码简洁;宏定义的使用避免了重复冗余代码在程序中的出现。</li><li>代码执行效率高;预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的CALL调用、 返回参数、执行return等过程,从而提高了速度。</li></ul><p>(2)<br>实验环境中定义了单向链表、双向链表、单向队列、双向队列、循环队列。</p><ul><li>插入操作:<br>单向链表和循环链表的插入只需维护两个指针,双向链表的插入需要维护四个指针;对于在头节点插入,三种实现方式的开销相似;对于在尾节点插入,单向链表和双向链表均需要遍历整个链表,二循环链表可直接定位插入。</li><li>删除操作:<br>单向链表和循环链表的删除性能接近(均需遍历以找到删除节点的上一个节点),双向链表删除性能较好;对于在头结点进行删除,三种实现方式的开销相似。</li></ul><h3 id="Thinking-2-3"><a href="#Thinking-2-3" class="headerlink" title="Thinking 2.3"></a>Thinking 2.3</h3><pre class=" language-C"><code class="language-C">#define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ }</code></pre><pre class=" language-C"><code class="language-C">#define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ }</code></pre><pre class=" language-C"><code class="language-C">LIST_HEAD(Page_list, Page);typedef LIST_ENTRY(Page) Page_LIST_entry_t;struct Page { Page_LIST_entry_t pp_link; /* free list link */ // Ref is the count of pointers (usually in page table entries) // to this page. This only holds for pages allocated using // page_alloc. Pages allocated at boot time using pmap.c's "alloc" // do not have valid reference count fields. u_short pp_ref;};</code></pre><p>联系以上三段代码,显然选择 <strong>C</strong>。<br>Page_list 是 Page类型的头指针,是查询各页信息的入口,Page类型内含有双向指针和此页引用次数的数据。</p><h3 id="Thinking-2-4"><a href="#Thinking-2-4" class="headerlink" title="Thinking 2.4"></a>Thinking 2.4</h3><p>由于操作系统将进程作为处理任务的单元,故不同进程可能使用相同的虚拟地址,但若此地址不是共享的(Global = 0)则映射到的物理地址是不同的,这里使用 ASID 来标注引导取不同的物理地址,防止混淆。<br>结合原文和 ASID 6位的事实, R3000 中可容纳不同的地址空间的最大数量为 64。</p><h3 id="Thinking-2-5"><a href="#Thinking-2-5" class="headerlink" title="Thinking 2.5"></a>Thinking 2.5</h3><ul><li>tlb_invalidate 调用 tlb_out。</li><li>tlb_invalidate将释放快表中地址空间为 ASID,虚拟地址为 va的项。</li></ul><pre class=" language-C"><code class="language-C">LEAF(tlb_out).set noreorder mfc0 t0, CP0_ENTRYHI //保存原本EntryHi中具有的值 mtc0 a0, CP0_ENTRYHI //将待查询信息(ASID 和 虚页号组合)写入EntryHi nop /* Step 1: Use 'tlbp' to probe TLB entry */ /* Exercise 2.8: Your code here. (1/2) */ nop tlbp //根据探查信息获取页表项索引 nop nop nop //等待cpu执行完毕tlbp nop /* Step 2: Fetch the probe result from CP0.Index */ mfc0 t1, CP0_INDEX //取页表项索引 Index.set reorder bltz t1, NO_SUCH_ENTRY //索引小于0,则没有对应页表项.set noreorder mtc0 zero, CP0_ENTRYHI //清空 EntryHi mtc0 zero, CP0_ENTRYLO0 //清空 EntryLo nop /* Step 3: Use 'tlbwi' to write CP0.EntryHi/Lo into TLB at CP0.Index */ /* Exercise 2.8: Your code here. (2/2) */ tlbwi //将清零后的Hi/Lo写入TLB的项.set reorderNO_SUCH_ENTRY: mtc0 t0, CP0_ENTRYHI //恢复EntryHi中原来的值 j ra //返回END(tlb_out)</code></pre><h3 id="Thinking-2-6"><a href="#Thinking-2-6" class="headerlink" title="Thinking 2.6"></a>Thinking 2.6</h3><p>X86 和 MIPS 在内存管理上的区别主要有:</p><ul><li>MIPS 采用的是页式管理系统,X86 采用的是页式段式内存管理结构;</li><li>TLB 不命中时:MIPS 会触发TLB Refill 异常,内核的 tlb_refill_handler 会以 pgd_current 为当前进程的 PGD 基址,索引获得转换失败的虚址对应的 PTE,并将其填入 TLB;X86 是由硬件 MMU 以 CR3 为当前进程的 PGD 基址,索引获得 PFN 后,直接输出 PA。同时 MMU 会填充 TLB 以加快下次转换的速度。</li><li>转换失败的虚拟地址:MIPS 使用 BadVAddr 寄存器存放,X86 使用 CR2 存放。</li></ul><h3 id="Thinking-A-1"><a href="#Thinking-A-1" class="headerlink" title="Thinking A.1"></a>Thinking A.1</h3><p>(1)<br>PTbase + PTbase << 9 + PTbase << 18<br>(2)<br>PTbase + PTbase << 9 + PTbase << 18 + PTbase << 27</p><hr><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><p>个人感觉这次实验的难度上了一个台阶,主要有以下几点:</p><ul><li>搞清楚 Page_list 的指针结构,其中定义<code>struct type **le_prev;</code>为指向前一个结点的指针让我很迷惑,后来自习阅读示例才发现此指针指向的是上一个结点指向下一个结点的指针。</li><li>弄清楚 <strong>虚拟地址(va)<strong>,</strong>物理地址(pa)</strong>,<strong>页控制块地址(pp)</strong> 的关系和转化函数;在pamap.c中,我们需要时刻记清楚现在操作的是什么类型的地址,必要时灵活使用转化函数。</li><li>对于两级页表的处理,考验对页表结构的熟悉程度,由于给了结构图,这里只需理清地址之间的关系即可。</li><li>TLB部分任务虽然简单,但是封装好的函数内部较为复杂,需要仔细体会。</li></ul><hr><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>本次实验为初步构建操作系统内存管理体系,可分为两个部分,即内核对内存相关的地址空间的初始化和用户访存过程中页面控制、页表和快表的行为处理。<br>个人感觉本次作业子刚上手的时候较为困难,常常记不住一些函数和宏的作用,不知道自己写的函数功能是什么,混淆三种地址导致bug。但对内存管理相关的文件(pmap.c pmap.h mmu.h queue.h tlbex.c tlb_asm.S)熟悉后再结合教程的图文,绝大部分的问题还是不难解决的。<br>总的来说,这次作业使我在理论课中学到的内存管理知识得以应用,让我从更加具象的层面观察操作系统的内存管理机制。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab1)</title>
<link href="/2023/03/08/os-lab1/"/>
<url>/2023/03/08/os-lab1/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab1"><a href="#Lab1" class="headerlink" title="Lab1"></a>Lab1</h2><hr><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-1-1"><a href="#Thinking-1-1" class="headerlink" title="Thinking 1.1"></a>Thinking 1.1</h3><p><strong>(1)编译工具使用</strong><br>使用实验环境中的原生 x86 工具<br>链(gcc、ld、readelf、objdump)等对 hello.c 进行处理可观察到 <strong>预处理,编译,链接</strong> 的全过程,最后生成的 hello 文件可使用<code>./hello</code>执行。</p><p>使用MIPS 交叉编译工具链(带有 mips-linux-gnu 的前缀)对 hello.c进行处理,预处理生成的文件与使用 x86 工具处理的几乎一样,但其生成的目标文件和可执行文件无法使用 x86 架构下的 objdump 反编译,且最终的可执行文件无法通过<code>./hello</code>执行,这是由于 <strong>x86 和 mips 架构存在差异</strong>。</p><p><strong>(2)objdump的参数意义</strong></p><ul><li>objdump -D <file(s)>: 将代码段反汇编;</li><li>objdump -S <file(s)>: 将代码段反汇编的同时,将反汇编代码与源代码交替显示,编译时需要使用-g参数,即需要调试信息;</li><li>objdump -C <file(s)>: 将C++符号名逆向解析;</li><li>objdump -l <file(s)>: 反汇编代码中插入文件名和行号;</li><li>objdump -j section <file(s)>: 仅反汇编指定的section。</li></ul><h3 id="Thinking-1-2"><a href="#Thinking-1-2" class="headerlink" title="Thinking 1.2"></a>Thinking 1.2</h3><p><strong>(1) readelf 对 mos 的解析结果</strong></p><pre><code>0:0x01:0x800100002:0x800121a03:0x800121b84:0x800121d05:0x06:0x07:0x08:0x09:0x010:0x011:0x012:0x013:0x014:0x015:0x016:0x017:0x0</code></pre><p><strong>(2)对实验中 readelf 的探究</strong><br>hello.c的编译链接选项:</p><ul><li>-m32:编译出来的是32位程序,既可以在32位操作系统运行,又可以在64位操作系统运行。</li><li>-static: 选择静态库链接。</li><li>-g: 支持调试</li></ul><p>官方的 readelf 工具和我们在实验中的 readelf 程序较大的不同是**官方 readelf 工具支持解析64位 ELF 文件,而我们实验的 readelf 只可解析32位 ELF 文件;<br>编译选项控制生成 hello 为 <strong>32位 ELF 文件</strong>,我们实验编译产生的 readelf 为 <strong>64位 ELF 文件</strong>,自然的,我们编写的 readelf 程序是不能解析 readelf 文件本身的,而系统工具 readelf 则可以解析。</p><h3 id="Thinking-1-3"><a href="#Thinking-1-3" class="headerlink" title="Thinking 1.3"></a>Thinking 1.3</h3><p><strong>答:</strong><br>在实验中,GXemul 仿真器支持直接加载 ELF 格式的内核,也<br>就是说,<strong>GXemul 已经提供了 bootloader 的引导(启动)功能</strong>;MOS 操作系统不需要再实现 bootloader 的功能。在 MOS 操作系统的运行第一行代码前,我们就已经拥有一个正常的程序运行环境,内存和一些外围设备都可以正常使用。<br>GXemul 支持加载 ELF 格式内核,所以启动流程被简化为加载内核到内存,之后<strong>跳转</strong>到内核的入口,启动就完成了。</p><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><p>在 lab1 中,我认为难度较大的实验操作如下:</p><ul><li>理清操作系统启动的全过程,找到不同操作系统启动间的共性,生成启动流程图。</li><li>较大型程序体系的把控和复杂 Makefile 程序的解析。</li><li>最后的 print.c 函数的补全,考查了对 c 语言指针和变长类型的掌握能力,编程中需考虑的细节情况较多。</li></ul><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>本次实验中,我从课程组提供的教程和简易操作系统的代码出发,学习了操作系统启动的全过程,对操作系统的启动流程,可执行文件的编译,Makefile 的编写有了更加深入的理解。<br>对于实验最后要求我们编写的 print.c 程序以支持 C 标准中的 printf 函数这一部分,目前的 print.c 还不支持长型、浮点、非十进制的读入,仍需进一步完善。<br>在附录中,我对于实验中出现的一些陌生的宏定义有了大致的了解,对代码的理解加深了一些。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>北航计算机学院面向对象(2023 第一单元)</title>
<link href="/2023/03/01/OO_1/"/>
<url>/2023/03/01/OO_1/</url>
<content type="html"><![CDATA[<h1 id="北航计算机学院面向对象(2023-第一单元)"><a href="#北航计算机学院面向对象(2023-第一单元)" class="headerlink" title="北航计算机学院面向对象(2023 第一单元)"></a>北航计算机学院面向对象(2023 第一单元)</h1><p>本文将以笔者学习过程中的思考感悟为基础,对2023北航计算机学院面向对象课程第一单元(作业1~3)的架构搭建和程序设计思路做简明的描述;如有不同见解,欢迎学习交流。</p><hr><h2 id="一、架构的搭建和迭代"><a href="#一、架构的搭建和迭代" class="headerlink" title="一、架构的搭建和迭代"></a>一、架构的搭建和迭代</h2><p>在面向对象(OO)这门课程中,每个单元的作业采取增量开发的模式,需求随着时间的推进变得更加复杂、丰富;这需要我们在编程过程中尽量构建可扩展性强的架构。</p><h3 id="1-第一次作业"><a href="#1-第一次作业" class="headerlink" title="1.第一次作业"></a>1.第一次作业</h3><p>第一单元第一次作业是我们建构面向对象思维很好的起点,我们在这次作业构建的架构的科学性很大程度上决定了后两次作业的工作量。</p><p><strong>(1)需求概述</strong><br>本次作业的目标可以概述为:编写一个可以化简由数字(支持前导零),变量(x,y,z),指数,括号(暂不考虑嵌套)构成的表达式的程序,去除所有括号,结果短则性能佳。</p><p><strong>(2)基本思路</strong><br><del>由于本人上学期没有选上 oopre,故</del>仔细学习了课程组提供的练习题的代码,将其思想推广到本次作业的情形:</p><ul><li>不要妄图靠特判和顺序循环把本次作业搞成字符串的 tirck,为了方便后两次作业的迭代,基于表达式文法的递归下降方法需要被采用。</li><li>作业需求中对待化简表达式的递归定义十分严谨,简单来看可以分为三个层次:<pre class=" language-mermaid"><code class="language-mermaid">graph TDA[常数因子]--->B[因子]C[变量因子]--->BD[表达式因子]-->BB-->|*|E[项]E-->|+|F[表达式]D------F</code></pre></li><li>我们的精力集中在对表达式的解析上,所以表达式形制越简单,我们在编写文法和词法解析器时的思考量也越小;<strong>预处理</strong>是一种较好的策略(将空格全部去除,将幂全部转为乘积,将相连的正负号等价缩短)。</li></ul><p><strong>(3)架构搭建</strong></p><pre class=" language-mermaid"><code class="language-mermaid">graph LRA[预处理]-->B[文法词法解析]-->C[后处理]-->D[合并同类项]</code></pre><ul><li>预处理上文已经交代;</li><li>文法词法解析主要包括两个重要的类:<br><strong>Lexer</strong><br> 词法解析器,指示目前程序读到的关键字段,如数字,括号,正负号等,使顺序遍历字符串的工具。<br><strong>Parser</strong><br> 语法解析器,遇到标志符号则调用相应的解析器,简要规则:<ol><li>入口为表达式解析器;</li><li>遇到加减切换至项解析器;</li><li>遇到乘法切换到因子解析器;</li><li>遇到括号切换到表达式解析器。<br> 这里为了方便描述一些细节处理没有完全写出。</li></ol></li><li>后处理主要包括将连乘恢复为幂,根据项内各因子的符号决定项的符号(exp: -x*+y*-z –> +x*y*z);</li><li>合并同类项只需检查幂次的对应匹配即可。</li></ul><p><strong>(4)可拓展性</strong><br>本次作业虽然需求较为单一,但考虑到后两次作业不可避免的增量开发,故提前支持了括号的嵌套功能;其实这也是十分自然的设计,因为层次化的递归下降法就是为了解析这种嵌套次数不定,字词出现概率不定但递归定义十分明朗的语言而设计的。</p><h3 id="2-第二次作业"><a href="#2-第二次作业" class="headerlink" title="2.第二次作业"></a>2.第二次作业</h3><p><strong>(1)新增需求</strong><br>本次作业支持括号嵌套(上一次已实现),三角函数(函数内容为任意<strong>因子</strong>),自定义函数。</p><p><strong>(2)扩展思路</strong></p><ul><li><p>处理三角函数<br>由于三角函数无法在预处理中消除,我们必须对 Lexer 和 Parser 做适当的扩展。<br>扩展时可参考的层次结构如下:</p><pre class=" language-mermaid"><code class="language-mermaid"> graph TD G[三角函数因子]--->B[因子] I[三角函数内容]-->G H[三角函数名]-->G A[常数因子]--->B C[变量因子]--->B D[表达式因子]-->B B-->|*|E[项] E-->|+|F[表达式] D------F I------B</code></pre><p>主要的工作是扩展 Lexer 使其支持 sin/cos 的识别;扩展 Parser 使其读到 sin/cos 时再次进入因子解析器。</p></li><li><p>处理自定义函数<br>为了降低解析的复杂度,考虑在预处理中消除自定义函数,则这个过程分为两步:</p><ol><li>读取用户自定义的函数,做法是建立自定义函数类,包含<strong>函数名</strong>、<strong>形参列表</strong>、<strong>函数体</strong>三个关键参数。</li><li>依据定义的函数名识别带化简字符串中调用的函数,进行简单的字符串替换和拼接(注意括号);笔者开始时尝试使用递归的方法从内到外对调用的函数进行解析,无奈方法复杂度较高,故采用了<strong>循环化简</strong>直至式子中不出现函数名为止的较为朴素的方法。</li></ol></li></ul><p><strong>(3)架构搭建</strong><br>基于第一次作业的架构,在文法词法解析前加入了自定义函数处理的环节,扩展了文法词法解析对三角函数的支持,结构如下:</p><pre class=" language-mermaid"><code class="language-mermaid">graph LRA[预处理]-->E[函数处理]-->B[文法词法解析]-->C[后处理]-->D[合并同类项]</code></pre><h3 id="3-第三次作业"><a href="#3-第三次作业" class="headerlink" title="3.第三次作业"></a>3.第三次作业</h3><p><strong>(1)新增要求</strong><br>自定义函数定义时可以使用已定义的自定义函数;加入求导算子(一组输入中只出现一次)。</p><p><strong>(2)扩展思路</strong><br>根据笔者前两次作业调试 Bug 的经验,文法词法解析和后处理的步骤最容易出现错误,故考虑将新增功能的扩展尽量前移;</p><ol><li><p>其中支持使用现有函数定义函数的处理较为简单,只需动态维护一个现有函数库,将第二次作业的<strong>函数处理类</strong>对<strong>每个函数在定义时解析出的函数体</strong>使用即可,只不过传入的参数不是完全的函数库而是目前为止已定义的函数的集合。</p></li><li><p>对于导数的处理,要尽可能简化我们求导的流程,则又可以采用预处理的策略;可以先对求导对象(d[xyz](content) 的 content)使用第二次作业的程序对其进行全过程解析化简,最后的通式为:</p></li></ol><pre><code>Constant * x**a * y**b * z**c * sin(A)**d * cos(B)**f [+-] ···</code></pre><p>则基于此通式,采用递归下降的思路,可构建一个类专门用于求导,构造的三个函数调用关系如下:</p><pre class=" language-mermaid"><code class="language-mermaid">graph TDA[表达式求导]--->|加法法则|B[项求导]B--->|乘方求导公式|AB--->|乘法法则|AB--->|不含括号外的乘和乘方|C[基元求导]C-->D[常数求导]C-->E[单个一次变量求导]C-->F[三角函数求导]F-->|三角求导公式|A</code></pre><p>其中调用的衔接是根据求导公式的十分简单的字符串拼接。</p><p><strong>(3)架构搭建</strong></p><pre class=" language-mermaid"><code class="language-mermaid">graph LRE[函数处理]-->F[导数处理]-->A[预处理]--> B[文法词法解析]-->C[后处理]-->D[合并同类项]</code></pre><p>值得注意的是,将预处理放在了函数、导数处理之后;这是因为预处理中包含了乘方转化为乘法的步骤,若放在第一步,会大大降低求导的效率。<br>这个架构的优点是我们可以完全复用上一次作业的文法词法解析器、后处理、合并同类项的函数和类,<strong>无需任何改动</strong>。</p><hr><h2 id="二、模块化重构策略"><a href="#二、模块化重构策略" class="headerlink" title="二、模块化重构策略"></a>二、模块化重构策略</h2><p>虽然三次作业是迭代开发的逻辑关系,但由于架构和需求的原因,难免会出现<strong>重构</strong>的情况;重构常常是必要的,但我们可以采取一些策略以降低我们的工作量。笔者认为,主要有以下两点:</p><ul><li>非必要不改动核心架构,而是通过添加<strong>预/后处理</strong>操作使现有的核心架构能够处理新增的需求。</li><li>开始一个项目时遵循模块化策略(将问题的处理按流程划分),面对新的需求时仅重构其中一个流程的操作,避免修改较多的文件。</li></ul><p>具体来说,以第一单元的作业为例:</p><h3 id="1-三角函数导致的部分重构"><a href="#1-三角函数导致的部分重构" class="headerlink" title="1.三角函数导致的部分重构"></a>1.三角函数导致的部分重构</h3><p>在第二次作业中,支持三角函数的需求的加入使笔者不得不对代码作出一些修改:</p><ul><li>在词法文法解析模块加入识别三角函数的判定,并为三角函数新建一个类以存储函数名和函数体;这部分的工作量并不大,因为三角函数括号内部可以看做因子处理,总的来看,<strong>三角函数符号可以看作一个无法被消除的括号</strong>。</li><li>对于化简和合并同类项的部分:<br>由于第一次作业在此部分的函数默认了表达式中已经没有括号了,故采用切割表达式录入项的通式,最后匹配幂次进行合并的方式。<br>但第二次作业存在三角函数这种“无法被消去的括号”,故笔者的化简部分需要重构。<ul><li>考虑到思路的连贯性,还是采取拆字符串的方式,但分隔符是表达式不被在括号中的加减号。</li><li>重新构造项类,将三角函数纳入,并使用 hashset 记录因子,方便后续的合并操作。</li><li>对于三角函数内的式子,递归调用此化简和合并方法。</li></ul></li></ul><p>可见这次重构涉及了四个文件,并未进行全局性的大改。</p><h3 id="2-“懒惰”地处理求导"><a href="#2-“懒惰”地处理求导" class="headerlink" title="2.“懒惰”地处理求导"></a>2.“懒惰”地处理求导</h3><p>第三次作业的一个要求看起来十分得复杂:<br><strong>加入求导算子</strong><br>但我们可以这样理解:<br><strong>只加入求导算子,不引入新的变量或常量</strong></p><p>因此我们只要在词法文法分析之前将求导算子计算完毕,则后续的操作可以直接复用第二次作业的代码;故我们将求导操作放在预处理之前。</p><ul><li>那如何尽量简化求导的操作呢,基本思想是将待求导的式子<strong>规范化</strong>;这里笔者采取的方式是复用第二次作业对表达式处理的全程代码,最后生成的式子较为规整,格式如下:<pre><code>Constant * x**a * y**b * z**c * sin(A)**d * cos(B)**f [+-] ···</code></pre></li><li>有了规整的式子,我们的求导操作可以由三个基本的操作构成:常数求导,一次变量求导,三角函数求导,具体逻辑可参照第一节相关内容;在此基础上进行层次化的递归下降,不难构造出求导类。</li></ul><p>将求导操作集中在一个类里,避免了在文法词法分析时进行求导操作,直接避免了在各个因子的类中构造求导函数;虽然这样安排有些面向过程的嫌疑,但集中在一个类中极大方便了代码的维护,提高了代码的复用率,降低了编程思维量。</p><p>通过这两个例子,可以看出模块化重构和添加功能的优势。</p><hr><h2 id="三、Bug-的查找、修复和编程习惯"><a href="#三、Bug-的查找、修复和编程习惯" class="headerlink" title="三、Bug 的查找、修复和编程习惯"></a>三、Bug 的查找、修复和编程习惯</h2><p>在此节,笔者将以反思的态度总结在第一单元作业编程过程中的疏漏,并记录一些实用技巧。</p><h3 id="1-Bug-的定位"><a href="#1-Bug-的定位" class="headerlink" title="1.Bug 的定位"></a>1.Bug 的定位</h3><p>从接触编程到现在,其实每次程序运行结果出错,定位一个 Bug 比改好一个 Bug 花费的时间多得多。<br>在维护一个较大的项目时,这种问题尤为突出,笔者认为可以从两个方面入手改善 debug 的体验感:</p><ul><li>利用好程序模块化的特点,在主程序各个阶段使用打印的方式定位 Bug 出现在哪个流程中,在相应的流程中再次利用此方法,定位 Bug 在哪个函数中;这样下来 Bug 的出现范围就大大缩小了。</li><li>利用好报错信息和编辑器的调试功能;得到大致范围后,根据 IDEA 详细的报错信息和自己具备的调试经验,不难精准定位 Bug。</li></ul><h3 id="2-Bug-的修复"><a href="#2-Bug-的修复" class="headerlink" title="2.Bug 的修复"></a>2.Bug 的修复</h3><p>对于 Bug 的修复,大抵可以遵循重构一节的策略,即非必要不要做影响基本架构的改动,非必要不要做跨文件的修改。</p><h3 id="3-作业中的-Bug"><a href="#3-作业中的-Bug" class="headerlink" title="3. 作业中的 Bug"></a>3. 作业中的 Bug</h3><p>笔者在第一次作业和第三次作业中各出现了一个 Bug。<br><strong>(1)字符串处理的 Trick</strong><br>在第一次作业中,笔者在乘方转化为乘法的函数中,画蛇添足地记录了每一次乘方符号的位置,在下一次从该位置开始继续找,但忽视了展开操作对字符串长度的影响,导致有时展开不完全,出现错误,在互测中被测出2次。<br><strong>(2)危险的思维定势</strong><br>在第三次作业中指导书有这样一句话:<strong>在输入中,求导算子最多只能出现一次</strong>,然而,由于求导算子可以作为函数的参数,展开后可以出现多次,故需要循环处理求导因子,笔者仅仅处理了一次,直接导致强测爆炸呜呜呜。</p><p>反思:<strong>多做测试,多做测试,多做测试!</strong><br>中测的数据不强,在今后的作业中还是要仔细考虑可能出现的情况,对代码进行针对性测试。</p><h3 id="4-Hack-数据的构造"><a href="#4-Hack-数据的构造" class="headerlink" title="4.Hack 数据的构造"></a>4.Hack 数据的构造</h3><p>面向对象课程独特的互测机制极大地考验构造数据的能力;笔者认为构造数据的技巧有以下几点:</p><ul><li>考虑边界条件和简单的样例(大数字,0,1,x**0,sin(0)**0 ……)<del>笔者的室友第一次作业就靠捏0收获6分</del></li><li>考虑正负号的连续和与数字的特殊组合</li><li>考虑函数调用的特殊情况</li><li>考虑字符串处理中可能的疏漏</li><li>考虑从易误读的定义入手</li><li>考虑自己编程的易错点(同一个房间的水平相差不大)</li><li>认真阅读他人代码</li></ul><p>在互测中,笔者一般先采取<strong>盲狙</strong>的策略,之后再对房间内的代码进行<strong>针对性检查</strong>。关于手写评测机,由于数据的随机性,可能没有针对性构造效率高,但也不失为一种省心省力的办法。</p><p>ps: 个人体验是中测的强度不是很高,所以 强测前的自查是必要的,群里和讨论区的优秀样例都可以拿来测试。</p><h3 id="4-编程习惯"><a href="#4-编程习惯" class="headerlink" title="4.编程习惯"></a>4.编程习惯</h3><p>面向对象课程作业的规模直接决定了我们需要改变以往面向过程的编程习惯,笔者到目前为止粗浅地总结了几点:</p><ul><li><strong>架构极其重要</strong>,刚接触一个作业时,我们既要根据已有需求选择合理的安排,又要“脑补”下后续可能的需求,给架构留足拓展空间。</li><li>巧用递归和层次分析可以大大减少编程的思维量和复杂度。</li><li>面向过程地安排模块(这也是自然的,做任何事总会有个先后和流程),在模块内利用面向对象的思想构造类,巧用继承和接口降低代码重复率。</li><li>善于利用 java 的数据类型、库和函数大大降低代码量。</li><li>摒弃过多的字符串循环检查和读取操作,利用解析器结合构造的类更科学地获取数据。</li></ul><hr><h2 id="四、-心得体会"><a href="#四、-心得体会" class="headerlink" title="四、 心得体会"></a>四、 心得体会</h2><p>第一单元的作业让我真正踏入了面向对象编程的大门;在编写程序的过程中,我熟悉了许多 java 的语法和工具,能较灵活地应用递归下降等经典方法,学会了如何科学地维护自己的程序。<br>但我也暴露出一些不足,包括没有完全利用 java 的继承属性导致寻找合法符号的函数在不同类中出现多次;为保证低耦合度每个流程对字符串处理一遍导致效率不高;构造 hack 数据经验尚少等。<br>总的来说,这次迭代开发的作业让我收获许多,也为后续的任务打下了一定的基础。</p>]]></content>
<categories>
<category> 面向对象 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> 面向对象 </tag>
</tags>
</entry>
<entry>
<title>操作系统实验报告(lab0)</title>
<link href="/2023/03/01/os-lab0/"/>
<url>/2023/03/01/os-lab0/</url>
<content type="html"><![CDATA[<h1 id="操作系统实验"><a href="#操作系统实验" class="headerlink" title="操作系统实验"></a>操作系统实验</h1><h2 id="Lab0"><a href="#Lab0" class="headerlink" title="Lab0"></a>Lab0</h2><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p><strong>1.思考题解答</strong><br><strong>2.难点分析</strong><br><strong>3.思考体会</strong></p><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><h3 id="Thinking-0-1"><a href="#Thinking-0-1" class="headerlink" title="Thinking 0.1"></a>Thinking 0.1</h3><p>以下为Thinking 0.1要求得到的所有文件内容:</p><pre><code>Untracked.txt未跟踪的文件: (使用 "git add <文件>..." 以包含要提交的内容) README.txt Untracked.txt 提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)</code></pre><pre><code>Stage.txt要提交的变更: (使用 "git restore --staged <文件>..." 以取消暂存) 新文件: README.txt 未跟踪的文件: (使用 "git add <文件>..." 以包含要提交的内容) Stage.txt Untracked.txt</code></pre><pre><code>Modified.txt尚未暂存以备提交的变更: (使用 "git add <文件>..." 更新要提交的内容) (使用 "git restore <文件>..." 丢弃工作区的改动) 修改: README.txt 未跟踪的文件: (使用 "git add <文件>..." 以包含要提交的内容) Modified.txt Stage.txt Untracked.txt 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")</code></pre><p>开始时创建了 README.txt,Git 状态为<strong>未跟踪</strong>,对应 Untracked.txt 显示的状态。</p><p>输入命令<code>git add README.txt</code>;</p><p>README.txt 的 Git 状态为<strong>已跟踪,未暂存</strong>,对应 Stage.txt 显示的状态。</p><p>输入命令<code>git commit README.txt</code>;</p><p>README.txt 的 Git 状态为<strong>已暂存</strong>。</p><p>修改 README.txt 的内容;</p><p>README.txt状态为<strong>已变更,变更未暂存</strong>,对应 Modified.txt 显示的状态。</p><p><code>git add</code>使 README.txt 被 git 仓库跟踪,其修改状态可被 git 仓库感知,若未使用此指令,则状态一直未 <strong>未跟踪</strong>。</p><h3 id="Thinking-0-2"><a href="#Thinking-0-2" class="headerlink" title="Thinking 0.2"></a>Thinking 0.2</h3><p><em>add the file</em> : <code>git add filename</code><br><em>stage the file</em> : <code>git add filename</code><br><em>commit</em> : <code>git commit filename</code></p><h3 id="Thinking-0-3"><a href="#Thinking-0-3" class="headerlink" title="Thinking 0.3"></a>Thinking 0.3</h3><ol><li><p><code>git checkout -- print.c</code></p></li><li><p><code>git reset HEAD print.c</code><br><code>git checkout -- print.c</code></p></li><li><p><code>git clean hello.txt -f</code></p></li></ol><h3 id="Thinking-0-4"><a href="#Thinking-0-4" class="headerlink" title="Thinking 0.4"></a>Thinking 0.4</h3><p>三次提交后:</p><table><thead><tr><th>提交序号</th><th>哈希值</th></tr></thead><tbody><tr><td>1</td><td>0fb5628c1a0c6da35386b494fa821201be1001bd</td></tr><tr><td>2</td><td>f6c6c7b6a22c5b31eda77caa497ba8296371c35b</td></tr><tr><td>3</td><td>393b36b7ffcf9a798682817d5e662d24b7fc6e3b</td></tr></tbody></table><p>执行<code>git reset --hard HEAD^</code>后,gitlog 中仅存在前两次提交记录,第3次(最近一次)被撤销了。</p><p>执行<code>git reset --hard 0fb5628c1a0c6da35386b494fa821201be1001bd</code>后,gitlog 中仅存在第1次提交记录,回到提交说明为1的版本。</p><p>执行<code> git reset --hard 393b36b7ffcf9a798682817d5e662d24b7fc6e3b</code>后,回到版本3,gilog中存在3次记录。</p><h3 id="Thinking-0-5"><a href="#Thinking-0-5" class="headerlink" title="Thinking 0.5"></a>Thinking 0.5</h3><p>执行<code>echo first</code><br>输出 first 到屏幕(标准输出)上。<br>执行<code>echo second > output.txt</code><br>重定向输入到 output.txt, output.txt内容:</p><pre><code>second</code></pre><p>执行<code>echo third > output.txt</code><br>重定向输入到 output.txt, output.txt被覆写:</p><pre><code>third</code></pre><p>执行<code>echo forth >> output.txt</code><br>重定向输入到 output.txt的文末, output.txt内容:</p><pre><code>thirdforth</code></pre><h3 id="Thinking-0-6"><a href="#Thinking-0-6" class="headerlink" title="Thinking 0.6"></a>Thinking 0.6</h3><p>command.sh 文件内容:</p><pre><code> 1 #!/bin/bash 2 touch test 3 echo 'echo Shell Start...' > test 4 echo 'echo set a = 1' >> test 5 echo 'a=1' >> test 6 echo 'echo set b = 2' >> test 7 echo 'b=2' >> test 8 echo 'echo set c = a+b' >> test 9 echo 'c=$[$a+$b]' >> test10 echo 'echo c = $c' >> test11 echo 'echo save c to ./filel' >> test12 echo 'echo $c>file1' >> test13 echo 'echo save b to ./file2' >> test14 echo 'echo $b>file2' >> test15 echo 'echo save a to ./file3' >> test16 echo 'echo $a>file3' >> test17 echo 'echo save filel file2 file3 to file4' >> test18 echo 'cat filel>file4' >> test19 echo 'cat file2>>file4' >> test20 echo 'cat file3>>file4' >> test21 echo 'echo save file4 to ./result' >> test22 echo 'cat file4>>result' >> test</code></pre><p> result文件内容:</p><pre><code>321</code></pre><p>(随着执行次数增加result内的 3 2 1 序列数目也增加)</p><p>test 文件实现了</p><ul><li>为变量 a b c 赋值</li><li>将变量分别写入三个文件</li><li>将三个文件的内容合并</li><li>将合并后的文件内容输出到result文件的文末</li></ul><p>故可以解释上述输出。</p><table><thead><tr><th>指令</th><th>执行结果</th></tr></thead><tbody><tr><td>echo echo Shell Start</td><td>屏幕上显示 echo Shell Start</td></tr><tr><td>echo `echo Shell Start`</td><td>屏幕上显示 Shell Start</td></tr><tr><td>echo echo $c>file1</td><td>file1 被写入 echo</td></tr><tr><td>echo `echo $c>file1`</td><td>file1 被写入 空字符串,屏幕上输出空行</td></tr></tbody></table><hr><h2 id="难点分析"><a href="#难点分析" class="headerlink" title="难点分析"></a>难点分析</h2><p>在 lab0 中,我认为难度较大的实验操作如下:</p><ul><li>Makefile文件的编写,由于从未接触过此类程序编译执行方式,编写过程中特殊的语法和跨文件夹链接的操作具有较大难度。</li><li>脚本文件的语法,在 .sh 文件中,变量和基本程序结构的使用方法与之前使用的编程语言有所不同,需要尽快掌握。</li><li>awk 和 sed 高效处理字符串,这两类指令集批量处理字符串十分便携,但指令格式也相对复杂,可能需要查询文档才能准确使用。</li></ul><hr><h2 id="思考体会"><a href="#思考体会" class="headerlink" title="思考体会"></a>思考体会</h2><p>在 lab0 中,我熟悉了课上实验的评测流程;在所有题目中最让我感到困难的是 Exercise 0.4 的 Makefile 的编写,由于以往编写过的 Makefile 编译链接的都是同一个文件夹下的库和文件,导致不熟悉如何制定链接文件的位置来实现跨文件夹的编译;在课下的练习中,应该加强对 Makefile 的语法和功能的理解实践。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> linux </tag>
</tags>
</entry>
<entry>
<title>2022北航计算机组成原理 Project 8</title>
<link href="/2022/12/10/CO_P8/"/>
<url>/2022/12/10/CO_P8/</url>
<content type="html"><![CDATA[<h1 id="MIPS微系统设计文档"><a href="#MIPS微系统设计文档" class="headerlink" title="MIPS微系统设计文档"></a>MIPS微系统设计文档</h1><p>如果你能看到并用到这篇文章,证明你已经是一个成熟的6系计组人了(笑<br>但我还是要说<strong>最后一次实验难度较大且考期紧张</strong>,适当的取舍也并非不可;如果你下决心要做,就不要被最后一次实验的困难打倒。</p><hr><h2 id="模块概览"><a href="#模块概览" class="headerlink" title="模块概览"></a>模块概览</h2><h3 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h3><blockquote><p>mips</p><blockquote><p>TC0<br>Bridge<br>Key<br>Switch<br>LED<br>DTube<br>IM<br>DM</p></blockquote></blockquote><blockquote><blockquote><p>mips_uart</p><blockquote><p>uart_rx<br>uart_rd</p></blockquote></blockquote></blockquote><blockquote><blockquote><p>CPU</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller<br>W_Controller</p></blockquote></blockquote></blockquote><blockquote><blockquote><blockquote><p>Blocker</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller</p></blockquote></blockquote></blockquote></blockquote><blockquote><blockquote><blockquote><p>E_MDU</p><blockquote><p>MulDivUnit</p><blockquote><p>MulUnit<br>DivUnit</p></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote><blockquote><blockquote><p>F_PC<br>FD_REG<br>D_GRF<br>D_ext<br>D_cmp<br>D_NPC<br>DE_REG<br>E_ALU<br>EM_REG<br>M_DM_IN<br>M_DM_OUT<br>CP0<br>MW_REG</p></blockquote></blockquote></blockquote><h3 id="部分新增模块实现"><a href="#部分新增模块实现" class="headerlink" title="部分新增模块实现"></a>部分新增模块实现</h3><p><strong>TC0</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>Addr</td><td>30</td><td>in</td><td>地址输入</td></tr><tr><td>WE</td><td>1</td><td>in</td><td>写使能信号</td></tr><tr><td>Din</td><td>32</td><td>in</td><td>数据输入</td></tr><tr><td>Dout</td><td>32</td><td>out</td><td>数据输出</td></tr><tr><td>IRQ</td><td>1</td><td>out</td><td>中断请求信号</td></tr></tbody></table><p>TC0即系统计时器,可使用写入指令控制计时模式和计时起点,在到达特定时间时,将置高 IRQ 向系统发出中断信号。</p><p><strong>Bridge</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>m_data_addr</td><td>32</td><td>out</td><td>DM或外设的读写地址</td></tr><tr><td>m_data_rdata</td><td>32</td><td>in</td><td>从外置DM直接读取的待选用的数据</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>写入DM或外设的数据</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>经处理的字节使能信号</td></tr><tr><td>temp_m_data_addr</td><td>32</td><td>in</td><td>DM或TC的读写地址</td></tr><tr><td>temp_m_data_rdata</td><td>32</td><td>out</td><td>经过选择从DM或外设中读出的数据</td></tr><tr><td>temp_m_data_wdata</td><td>32</td><td>in</td><td>写入DM或外设的数据</td></tr><tr><td>temp_m_data_byteen</td><td>4</td><td>in</td><td>未经处理的字节使能信号</td></tr><tr><td>TC0_WE</td><td>1</td><td>out</td><td>TC0写使能信号</td></tr><tr><td>TC0_Addr</td><td>32</td><td>out</td><td>TC0读写地址</td></tr><tr><td>TC0_Din</td><td>32</td><td>out</td><td>可能写入TC0的数据</td></tr><tr><td>TC0_Dout</td><td>32</td><td>in</td><td>根据地址从TC0中直接读出的数据</td></tr><tr><td>UART_WE</td><td>1</td><td>out</td><td>UART写使能信号</td></tr><tr><td>UART_Addr</td><td>32</td><td>out</td><td>UART读写地址</td></tr><tr><td>UART_Din</td><td>32</td><td>out</td><td>可能写入UART的数据</td></tr><tr><td>UART_Dout</td><td>32</td><td>in</td><td>根据地址从UART中直接读出的数据</td></tr><tr><td>DTube_data_byteen</td><td>4</td><td>out</td><td>数码管写字节使能信号</td></tr><tr><td>DTube_Addr</td><td>32</td><td>out</td><td>数码管读写地址</td></tr><tr><td>DTube_Din</td><td>32</td><td>out</td><td>可能写入数码管的数据</td></tr><tr><td>DTube_Dout</td><td>32</td><td>in</td><td>根据地址从数码管中直接读出的数据</td></tr><tr><td>Switch_Addr</td><td>1</td><td>out</td><td>两组拨码开关的选择信号</td></tr><tr><td>Switch_Dout</td><td>32</td><td>in</td><td>从拨码开关读出的数据</td></tr><tr><td>Key_Dout</td><td>32</td><td>in</td><td>从按键开关读出的数据</td></tr><tr><td>LED_data_byteen</td><td>4</td><td>out</td><td>LED输出字节使能信号</td></tr><tr><td>LED_Din</td><td>32</td><td>out</td><td>可能写入LED的数据</td></tr></tbody></table><p>Bridge 即系统桥,其功能是根据读写地址在 CPU 和各项外设之间选择性开关数据通路。</p><p><strong>Key</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>KeyInput</td><td>8</td><td>in</td><td>按键的输入数据(外设按键信号)</td></tr><tr><td>KeyResult</td><td>32</td><td>out</td><td>按键输出数据</td></tr></tbody></table><p>Key 即按键开关,输出数据仅有低8位有效。</p><p><strong>Switch</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>Addr</td><td>1</td><td>in</td><td>两组拨码开关的选择信号</td></tr><tr><td>swift1</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift2</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift3</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift4</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift5</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift6</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift7</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>swift8</td><td>8</td><td>in</td><td>拨码开关输入数据</td></tr><tr><td>SwitchResult</td><td>32</td><td>out</td><td>拨码开关输出数据</td></tr></tbody></table><p>Switch 即拨码开关,共64个,分为2个大组,8个小组,通过Addr 来选择从哪个大组中读出数据。</p><p><strong>LED</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>LED_data_byteen</td><td>4</td><td>in</td><td>LED字节使能信号</td></tr><tr><td>LEDInput</td><td>32</td><td>in</td><td>输入LED的数据</td></tr><tr><td>LEDResult</td><td>32</td><td>out</td><td>LED输出数据</td></tr></tbody></table><p>LED 即控制开发板上 LED 灯的模块。</p><p><strong>DTube</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>Addr</td><td>1</td><td>in</td><td>数码管组选择信号</td></tr><tr><td>DTube_data_byteen</td><td>4</td><td>in</td><td>数码管字节使能信号</td></tr><tr><td>DTubeInput</td><td>32</td><td>in</td><td>待输入数码管的数据</td></tr><tr><td>DTubeResult</td><td>32</td><td>out</td><td>经Addr选择输入外置数码管的数据</td></tr><tr><td>DTube0</td><td>8</td><td>out</td><td>可能输入1-4号外置数码管的数据</td></tr><tr><td>DTube_sel0</td><td>4</td><td>out</td><td>1-4号外置数码管选择信号</td></tr><tr><td>DTube1</td><td>8</td><td>out</td><td>可能输入5-8号外置数码管的数据</td></tr><tr><td>DTube_sel1</td><td>4</td><td>out</td><td>5-8号外置数码管选择信号</td></tr><tr><td>DTube2</td><td>8</td><td>out</td><td>可能输入最高位外置数码管的数据</td></tr><tr><td>DTube_sel2</td><td>1</td><td>out</td><td>最高位外置数码管选择信号</td></tr></tbody></table><p>DTube 即外置数码管的控制模块,主要通过写入的值更改数码管的输出,并以固定的时间间隔轮询刷新各个数码管。</p><p><strong>IM/DM</strong><br>按照教程的说法这两个模块是使用 ip_core 生成的,由于其同步读的特性,应该对流水线中的线路连通进行修改,大致工作如下:</p><ul><li>对于 DM 只需在 MW_REG 中将 W_dataOut 和 M_dataOut 短接并辅助特判即可:<pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> W_dataOut <span class="token operator">=</span> <span class="token punctuation">(</span>reset <span class="token operator">||</span> flush <span class="token operator">||</span> Req<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> M_dataOut<span class="token punctuation">;</span></code></pre></li><li>对于 IM 如法炮制,需要注意阻塞时的行为。<pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">reg</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> last_instr<span class="token punctuation">;</span> <span class="token keyword">assign</span> D_instr <span class="token operator">=</span> <span class="token punctuation">(</span>reset <span class="token operator">||</span> flush <span class="token operator">||</span> Req<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token operator">!</span>en<span class="token punctuation">)</span> <span class="token operator">?</span> last_instr <span class="token punctuation">:</span> F_instr<span class="token punctuation">;</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">posedge</span> clk<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>reset <span class="token operator">|</span> flush <span class="token operator">|</span> Req<span class="token punctuation">)</span><span class="token keyword">begin</span> last_instr <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> D_pc <span class="token operator"><=</span> Req <span class="token operator">?</span> <span class="token number">32'h00004180</span> <span class="token punctuation">:</span> <span class="token number">32'h00003000</span><span class="token punctuation">;</span> D_ExcCode <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> D_BD <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token function">if</span><span class="token punctuation">(</span>en<span class="token punctuation">)</span><span class="token keyword">begin</span> last_instr <span class="token operator"><=</span> F_instr<span class="token punctuation">;</span> D_pc <span class="token operator"><=</span> F_pc<span class="token punctuation">;</span> D_ExcCode <span class="token operator"><=</span> F_ExcCode<span class="token punctuation">;</span> D_BD <span class="token operator"><=</span> F_BD<span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span></code></pre></li></ul><p><strong>mips_uart</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>dataIn</td><td>32</td><td>in</td><td>CPU 发往 UART 的数据</td></tr><tr><td>dataOut</td><td>32</td><td>out</td><td>UART 发往 CPU 的数据</td></tr><tr><td>Addr</td><td>2</td><td>in</td><td>读写数据地址</td></tr><tr><td>WE</td><td>1</td><td>in</td><td>UART写使能信号</td></tr><tr><td>rxd</td><td>1</td><td>in</td><td>外界发往UART的一字节数据</td></tr><tr><td>txd</td><td>1</td><td>out</td><td>UART发往外界的一字节数据</td></tr><tr><td>UART_Int</td><td>1</td><td>out</td><td>外界发送数据待接收的中断信号</td></tr></tbody></table><p>mips_uart 即 uart_rx, uart_rd 的封装模块,主要维护 UART 的寄存器读写和rx, rd间的数据流和控制逻辑。重要控制信号和数据处理如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> UART_Int <span class="token operator">=</span> rx_ready<span class="token punctuation">;</span> <span class="token keyword">assign</span> LSR <span class="token operator">=</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span><span class="token number">26'b0</span><span class="token punctuation">,</span> tx_avai<span class="token punctuation">,</span> <span class="token number">4'b0</span><span class="token punctuation">,</span> rx_ready<span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> rx_clear <span class="token operator">=</span> WE<span class="token punctuation">;</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">posedge</span> clk <span class="token keyword">or</span> <span class="token keyword">posedge</span> reset<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>reset<span class="token punctuation">)</span> tx_start <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">else</span> tx_start <span class="token operator"><=</span> <span class="token operator">!</span>tx_start <span class="token operator">&&</span> WE <span class="token operator">&&</span> <span class="token punctuation">(</span>Addr <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">end</span></code></pre><hr><h2 id="可综合性的实现"><a href="#可综合性的实现" class="headerlink" title="可综合性的实现"></a>可综合性的实现</h2><p>由于本次实验需要生成可烧录的 .bit 文件,故 verilog 代码必须是可综合的;主要有两方面的工作,一时处理 IM、DM 的可综合性,二是优化乘除模块的可综合性。前者在上节已经介绍完毕,现介绍 MDU 模块的改进。</p><p>笔者将课程组提供的乘除模块封装入 P6 中自己构造的乘除模块中以减少主电路的改动。</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>Req<span class="token punctuation">)</span> in_valid <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">begin</span> <span class="token comment" spellcheck="true">//译码阶段,根据不同的运算赋值控制信号。</span> <span class="token keyword">case</span> <span class="token punctuation">(</span>MDUCtrl<span class="token punctuation">)</span> <span class="token constant">`MDUCtrl_mult</span><span class="token punctuation">:</span><span class="token keyword">begin</span> in_op <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> in_sign <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> in_valid <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token constant">`MDUCtrl_multu</span><span class="token punctuation">:</span><span class="token keyword">begin</span> in_op <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> in_sign <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> in_valid <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token constant">`MDUCtrl_div</span><span class="token punctuation">:</span><span class="token keyword">begin</span> in_op <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> in_sign <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> in_valid <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token constant">`MDUCtrl_divu</span><span class="token punctuation">:</span><span class="token keyword">begin</span> in_op <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> in_sign <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> in_valid <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">default</span><span class="token punctuation">:</span><span class="token keyword">begin</span> in_op <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> in_sign <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> in_valid <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">endcase</span> <span class="token keyword">end</span> <span class="token keyword">end</span> MulDivUnit <span class="token function">m_MulDivUnit</span><span class="token punctuation">(</span> <span class="token punctuation">.</span><span class="token function">clk</span><span class="token punctuation">(</span>clk<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span>reset<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">in_src0</span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">in_src1</span><span class="token punctuation">(</span>B<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">in_op</span><span class="token punctuation">(</span>in_op<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">in_sign</span><span class="token punctuation">(</span>in_sign<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">in_ready</span><span class="token punctuation">(</span>in_ready<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">in_valid</span><span class="token punctuation">(</span>in_valid<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">out_ready</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">out_valid</span><span class="token punctuation">(</span>out_valid<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">out_res0</span><span class="token punctuation">(</span>lo<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">out_res1</span><span class="token punctuation">(</span>hi<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">posedge</span> clk <span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>reset<span class="token punctuation">)</span><span class="token keyword">begin</span> HI <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> LO <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> Busy <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token function">if</span><span class="token punctuation">(</span><span class="token operator">!</span>Req<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>MDUCtrl <span class="token operator">==</span> <span class="token constant">`MDUCtrl_mthi</span><span class="token punctuation">)</span> HI <span class="token operator"><=</span> A<span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token function">if</span><span class="token punctuation">(</span>MDUCtrl <span class="token operator">==</span> <span class="token constant">`MDUCtrl_mtlo</span><span class="token punctuation">)</span> LO <span class="token operator"><=</span> A<span class="token punctuation">;</span> <span class="token function">if</span><span class="token punctuation">(</span>out_valid<span class="token punctuation">)</span><span class="token keyword">begin</span> <span class="token comment" spellcheck="true">//计算完毕将子模块的结果返回主乘除模块</span> LO <span class="token operator"><=</span> lo<span class="token punctuation">;</span> HI <span class="token operator"><=</span> HI<span class="token punctuation">;</span> <span class="token keyword">end</span> Busy <span class="token operator"><=</span> <span class="token operator">~</span>in_ready<span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span></code></pre><h2 id="汇编程序的编写及思路"><a href="#汇编程序的编写及思路" class="headerlink" title="汇编程序的编写及思路"></a>汇编程序的编写及思路</h2><p>根据教程的提交要求,需要在我们编写的 CPU 上运行 mips 汇编程序以完成相应的任务;笔者把任务划分为三步:</p><ul><li>实现最基本的选择操作、计算、数码管及LED显示的控制。</li><li>实现计时器功能。</li><li>实现串口显示计算结果或计时时间,完善回写功能。</li></ul><p>代码如下:<br><strong>code_main</strong></p><pre class=" language-python"><code class="language-python"><span class="token comment" spellcheck="true"># Data Memory 0x0000_0000 - 0x0000_2fff</span><span class="token comment" spellcheck="true"># Instr Memory0x0000_3000 - 0x0000_6fff</span><span class="token comment" spellcheck="true"># Timer0 0x0000_7f00 - 0x0000_7f0b</span><span class="token comment" spellcheck="true"># UART 0x0000_7f30 - 0x0000_7f3f</span><span class="token comment" spellcheck="true"># Digital Tube 0x0000_7f50 - 0x0000_7f57</span><span class="token comment" spellcheck="true"># Dip Switch 0x0000_7f60 - 0x0000_7f67</span><span class="token comment" spellcheck="true"># Button Key 0x0000_7f68 - 0x0000_7f6b</span><span class="token comment" spellcheck="true"># LED 0x0000_7f70 - 0x0000_7f73</span><span class="token punctuation">.</span>text <span class="token number">0x3000</span>ori $t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0xfc01</span>mtc0 $t0<span class="token punctuation">,</span> $<span class="token number">12</span>loop<span class="token punctuation">:</span>lbu $t0<span class="token punctuation">,</span> <span class="token number">0x7f68</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>lw $s0<span class="token punctuation">,</span> <span class="token number">0x7f60</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#B / preset</span>lw $s1<span class="token punctuation">,</span> <span class="token number">0x7f64</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#A</span><span class="token comment" spellcheck="true"># 操作识别阶段</span>beq $t0<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> TimerLEDPlusnopbeq $t0<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> TimerUARTPlusnopbeq $t0<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> TimerLEDMinusnopbeq $t0<span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> TimerUARTMinusnopbeq $t0<span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> AddLEDnopbeq $t0<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> AddUARTnopbeq $t0<span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> SubLEDnopbeq $t0<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> SubUARTnopbeq $t0<span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">,</span> MultLEDnopbeq $t0<span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> MultUARTnopbeq $t0<span class="token punctuation">,</span> <span class="token number">32</span><span class="token punctuation">,</span> DivLEDnopbeq $t0<span class="token punctuation">,</span> <span class="token number">34</span><span class="token punctuation">,</span> DivUARTnopbeq $t0<span class="token punctuation">,</span> <span class="token number">64</span><span class="token punctuation">,</span> AndLEDnopbeq $t0<span class="token punctuation">,</span> <span class="token number">66</span><span class="token punctuation">,</span> AndUARTnopbeq $t0<span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">,</span> OrLEDnopbeq $t0<span class="token punctuation">,</span> <span class="token number">130</span><span class="token punctuation">,</span> OrUARTnopj End<span class="token comment" spellcheck="true">#计时器指令</span>TimerLEDPlus<span class="token punctuation">:</span> ori $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> li $t2<span class="token punctuation">,</span> <span class="token number">25000000</span> sw $t2<span class="token punctuation">,</span> <span class="token number">0x7f04</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> li $t1<span class="token punctuation">,</span> <span class="token number">11</span> sw $t1<span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> li $t3<span class="token punctuation">,</span> <span class="token number">0</span><span class="token comment" spellcheck="true">#count from 0</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> wait1<span class="token punctuation">:</span> lbu $s3<span class="token punctuation">,</span> <span class="token number">0x7f68</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $s4<span class="token punctuation">,</span> <span class="token number">0x7f60</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#B / preset</span> bne $s3<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> end1 nop bne $s4<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> end1 nop blt $t3<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> wait1 nop end1<span class="token punctuation">:</span> sw $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> j End nopTimerUARTPlus<span class="token punctuation">:</span> ori $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> li $t2<span class="token punctuation">,</span> <span class="token number">25000000</span> sw $t2<span class="token punctuation">,</span> <span class="token number">0x7f04</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> li $t1<span class="token punctuation">,</span> <span class="token number">11</span> sw $t1<span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t3<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token comment" spellcheck="true">#count from 0</span> <span class="token operator">or</span> $t9<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> wait3<span class="token punctuation">:</span> lbu $s3<span class="token punctuation">,</span> <span class="token number">0x7f68</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $s4<span class="token punctuation">,</span> <span class="token number">0x7f60</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#B / preset</span> bne $t3<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> Timer_UART nop return_TimerUARTPlus<span class="token punctuation">:</span> add $t9<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> $<span class="token number">0</span> bne $s3<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> end3 nop bne $s4<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> end3 nop blt $t3<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> wait3 nop end3<span class="token punctuation">:</span> sw $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> j End nopTimerLEDMinus<span class="token punctuation">:</span> ori $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> li $t2<span class="token punctuation">,</span> <span class="token number">25000000</span> sw $t2<span class="token punctuation">,</span> <span class="token number">0x7f04</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> li $t1<span class="token punctuation">,</span> <span class="token number">11</span> sw $t1<span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t3<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> $zero<span class="token comment" spellcheck="true">#count from preset</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> wait2<span class="token punctuation">:</span> lbu $s3<span class="token punctuation">,</span> <span class="token number">0x7f68</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $s4<span class="token punctuation">,</span> <span class="token number">0x7f60</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#B / preset</span> bne $s3<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> end2 nop bne $s4<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> end2 nop bnez $t3<span class="token punctuation">,</span> wait2 nop end2<span class="token punctuation">:</span> sw $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> j End nopTimerUARTMinus<span class="token punctuation">:</span> ori $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> li $t2<span class="token punctuation">,</span> <span class="token number">25000000</span> sw $t2<span class="token punctuation">,</span> <span class="token number">0x7f04</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> li $t1<span class="token punctuation">,</span> <span class="token number">11</span> sw $t1<span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t3<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token comment" spellcheck="true">#count from preset</span> <span class="token operator">or</span> $t9<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> $<span class="token number">0</span> wait4<span class="token punctuation">:</span> lbu $s3<span class="token punctuation">,</span> <span class="token number">0x7f68</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $s4<span class="token punctuation">,</span> <span class="token number">0x7f60</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#B / preset</span> bne $t3<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> Timer_UART nop return_TimerUARTMinus<span class="token punctuation">:</span> add $t9<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> $<span class="token number">0</span> bne $s3<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> end4 nop bne $s4<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> end4 nop bnez $t3<span class="token punctuation">,</span> wait4 nop end4<span class="token punctuation">:</span> sw $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x7f00</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">or</span> $t6<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span> j End nop<span class="token comment" spellcheck="true">#计算指令</span>AddLED<span class="token punctuation">:</span> addu $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j End nopAddUART<span class="token punctuation">:</span> addu $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 j Cal_UART nopSubLED<span class="token punctuation">:</span> subu $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j End nopSubUART<span class="token punctuation">:</span> subu $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 j Cal_UART nopMultLED<span class="token punctuation">:</span> mult $s1<span class="token punctuation">,</span> $s0 mflo $t3 sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j End nopMultUART<span class="token punctuation">:</span> mult $s1<span class="token punctuation">,</span> $s0 mflo $t3 j Cal_UART nopDivLED<span class="token punctuation">:</span> div $s1<span class="token punctuation">,</span> $s0 mflo $t3 sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j End nopDivUART<span class="token punctuation">:</span> div $s1<span class="token punctuation">,</span> $s0 mflo $t3 j Cal_UART nopAndLED<span class="token punctuation">:</span> <span class="token operator">and</span> $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j End nopAndUART<span class="token punctuation">:</span> <span class="token operator">and</span> $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 j Cal_UART nopOrLED<span class="token punctuation">:</span> <span class="token operator">or</span> $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j End nopOrUART<span class="token punctuation">:</span> <span class="token operator">or</span> $t3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s0 j Cal_UART nop<span class="token comment" spellcheck="true">#针对计算指令的串口显示处理</span>Cal_UART<span class="token punctuation">:</span> num3<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num3 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">24</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num32<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num32 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">16</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num2<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num2 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">16</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num21<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num21 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">8</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num1<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num1 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">8</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num10<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num10 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">0</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num0<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> num0 nop srl $t5<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">0</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> num_loop<span class="token punctuation">:</span> lbu $s3<span class="token punctuation">,</span> <span class="token number">0x7f68</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $s4<span class="token punctuation">,</span> <span class="token number">0x7f60</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">#B / preset</span> lw $s5<span class="token punctuation">,</span> <span class="token number">0x7f64</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> bne $s3<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> End nop bne $s4<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> End nop bne $s5<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> End nop j num_loop nop<span class="token comment" spellcheck="true">#针对计时指令的串口显示处理</span>Timer_UART<span class="token punctuation">:</span> time3<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time3 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">24</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> time32<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time32 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">16</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> time2<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time2 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">16</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> time21<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time21 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">8</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> time1<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time1 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">8</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> time10<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time10 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">0</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> time0<span class="token punctuation">:</span> lw $t4<span class="token punctuation">,</span> <span class="token number">0x7f34</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span><span class="token comment" spellcheck="true">#LSR</span> andi $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">32</span> beqz $t4<span class="token punctuation">,</span> time0 nop srl $t5<span class="token punctuation">,</span> $t9<span class="token punctuation">,</span> <span class="token number">0</span> sw $t5<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> beq $t0<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> return_TimerUARTPlus nop beq $t0<span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> return_TimerUARTMinus nopEnd<span class="token punctuation">:</span> j loop nop</code></pre><p><strong>code_handle</strong></p><pre class=" language-python"><code class="language-python"><span class="token punctuation">.</span>ktext <span class="token number">0x4180</span>nopnopnopmfc0 $t7<span class="token punctuation">,</span> $<span class="token number">13</span>andi $t7<span class="token punctuation">,</span> $t7<span class="token punctuation">,</span> <span class="token number">4096</span> <span class="token comment" spellcheck="true">#判断是否为UART中断</span>check_tc0<span class="token punctuation">:</span>beqz $t6<span class="token punctuation">,</span> check_uart <span class="token comment" spellcheck="true">#判断是否为计时指令引起的中断</span>nop beq $t0<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> plus nop beq $t0<span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> plus nop <span class="token comment" spellcheck="true">#更新时间并显示</span> minus<span class="token punctuation">:</span> subi $t3<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">1</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> j check_uart nop plus<span class="token punctuation">:</span> addi $t3<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">1</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f50</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t3<span class="token punctuation">,</span> <span class="token number">0x7f70</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> check_uart<span class="token punctuation">:</span> beqz $t7<span class="token punctuation">,</span> back_to_mainnop <span class="token comment" spellcheck="true">#回显功能的实现</span> lw $a0<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $a0<span class="token punctuation">,</span> <span class="token number">0x7f30</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> back_to_main<span class="token punctuation">:</span>eret</code></pre><hr><h2 id="问题与解决"><a href="#问题与解决" class="headerlink" title="问题与解决"></a>问题与解决</h2><p>就我本人来看,本次实验是我最为吃力的一次,遇到的主要问题和解决如下。</p><p><strong>1.如何改动使ip核生成的 IM/DM 融入CPU?</strong><br>一开始采用了简单的倍频方式,其后发现该方式存在一些难以理解的行为,且工程设计中并不会采用,故转用更加合理的修改数据通路的方式。</p><p><strong>2.如何封装教程提供的UART子模块代码?</strong><br>其实弄清楚这个草图可以应对本实验的要求:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/CO8-2.png"></p><p><strong>3.如何实现串口发生一个字的数据?</strong><br>串口以一个字节为一个单位发送数据,故可以在 mips 汇编代码中编写程序,对于一个字共发送4次,每次使用位移指令选择相应的位进行发送,在这期间要不断从 UART 的 LSR 中获取 UART 的工作状态,在上一个字节已经发送完毕后再进行发送。</p><p><strong>4.如何实现回显功能?</strong><br>为了不影响其他功能的实现,我采用的中断的方式进行处理,当UART接收到一个字节的数据后产生中断,进入 handle 程序执行回显指令。</p><p><strong>5.如何实现计时器?</strong><br>同样的,也采用 timer 提供中断信号的方式,用软件控制将 timer 设置成约1秒产生一次中断的工作模式,在中断中更新计时器的值即可。</p><hr><p>最后的最后<br>一点感受:计组给我的锻炼到目前为止都是北航其他课程无法比拟的。<br>虽然每次课上实验都像一次“冒险”,但最终贯通整个架构,在 FPGA 上实现自己的 CPU 是一次十分难得的经历。<br>希望你也能体会到其中的乐趣 :-)</p><p>彩蛋:<br><img src="https://argithun-blog-1321510384.cos.ap-beijing.myqcloud.com/CO8-1.png"></p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 计算机组成 </tag>
<tag> Verilog </tag>
<tag> 嵌入式 </tag>
<tag> FPGA </tag>
</tags>
</entry>
<entry>
<title>2022北航计算机组成原理 Project 7</title>
<link href="/2022/11/22/CO_P7/"/>
<url>/2022/11/22/CO_P7/</url>
<content type="html"><![CDATA[<h1 id="流水线CPU(支持异常处理)设计文档"><a href="#流水线CPU(支持异常处理)设计文档" class="headerlink" title="流水线CPU(支持异常处理)设计文档"></a>流水线CPU(支持异常处理)设计文档</h1><hr><h2 id="设计草稿及模块安排"><a href="#设计草稿及模块安排" class="headerlink" title="设计草稿及模块安排"></a>设计草稿及模块安排</h2><h3 id="整体模块架构"><a href="#整体模块架构" class="headerlink" title="整体模块架构"></a>整体模块架构</h3><blockquote><p>mips</p><blockquote><p>TC0<br>TC1<br>Bridge</p></blockquote></blockquote><blockquote><blockquote><p>CPU</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller<br>W_Controller</p></blockquote></blockquote></blockquote><blockquote><blockquote><blockquote><p>Blocker</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller</p></blockquote></blockquote></blockquote></blockquote><blockquote><blockquote><blockquote><p>F_PC<br>FD_REG<br>D_GRF<br>D_ext<br>D_cmp<br>D_NPC<br>DE_REG<br>E_ALU<br>EM_REG<br>M_DM_IN<br>M_DM_OUT<br>CP0<br>MW_REG</p></blockquote></blockquote></blockquote><hr><h3 id="模块安排"><a href="#模块安排" class="headerlink" title="模块安排"></a>模块安排</h3><p><strong>mips</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>interrupt</td><td>1</td><td>in</td><td>外部中断信号</td></tr><tr><td>macroscopic_pc</td><td>32</td><td>out</td><td>宏观pc</td></tr><tr><td>i_inst_rdata</td><td>32</td><td>in</td><td>i_inst_addr 对应的 32 位指令</td></tr><tr><td>i_inst_addr</td><td>32</td><td>out</td><td>F级的pc</td></tr><tr><td>m_data_addr</td><td>32</td><td>out</td><td>DM或TC读写地址</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>DM或TC待写入数据</td></tr><tr><td>m_data_rdata</td><td>32</td><td>in</td><td>m_data_addr 对应的 32 位数据</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>写DM的字节使能信号</td></tr><tr><td>m_inst_addr</td><td>32</td><td>out</td><td>M级的pc</td></tr><tr><td>m_int_addr</td><td>32</td><td>out</td><td>中断发生器待写入地址</td></tr><tr><td>m_int_byteen</td><td>4</td><td>out</td><td>中断发生器字节使能信号</td></tr><tr><td>w_grf_we</td><td>1</td><td>out</td><td>GRF 写使能信号</td></tr><tr><td>w_grf_addr</td><td>5</td><td>out</td><td>GRF 中待写入寄存器编号</td></tr><tr><td>w_grf_wdata</td><td>32</td><td>out</td><td>GRF 中待写入数据</td></tr><tr><td>w_inst_addr</td><td>32</td><td>out</td><td>W级pc</td></tr></tbody></table><p>mips模块是整个系统的主模块,其主要承担整体架构中CPU,TC0,TC1,Bridge以及<strong>外置指令、数据存储器</strong>的线路连接任务。</p><p><strong>TC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>Addr</td><td>30</td><td>in</td><td>地址输入</td></tr><tr><td>WE</td><td>1</td><td>in</td><td>写使能信号</td></tr><tr><td>Din</td><td>32</td><td>in</td><td>数据输入</td></tr><tr><td>Dout</td><td>32</td><td>out</td><td>数据输出</td></tr><tr><td>IRQ</td><td>1</td><td>out</td><td>中断请求信号</td></tr></tbody></table><p>TC是一种外部设备,其主要功能就是根据设定的时间来定时产生中断信号,是我们系统的中断来源之一;其内置3个32位寄存器,对于TC0,寄存器地址范围为0x0000_7F00∼0x0000_7F0B,对于TC1,寄存器地址范围为0x0000_7F10∼0x0000_7F1B,具体读写和控制特性可见:COCO定时器设计规范-1.0.0.4.pdf。</p><p><strong>Bridge</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>m_data_addr</td><td>32</td><td>out</td><td>DM或TC的读写地址</td></tr><tr><td>m_data_rdata</td><td>32</td><td>in</td><td>从外置DM直接读取的待选用的数据</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>写入DM或TC的数据</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>经处理的DM字节使能信号,若读写TC则置0</td></tr><tr><td>temp_m_data_addr</td><td>32</td><td>in</td><td>DM或TC的读写地址</td></tr><tr><td>temp_m_data_rdata</td><td>32</td><td>out</td><td>经过选择从DM或TC中读出的数据</td></tr><tr><td>temp_m_data_wdata</td><td>32</td><td>in</td><td>写入DM或TC的数据</td></tr><tr><td>temp_m_data_byteen</td><td>4</td><td>in</td><td>未经处理的DM字节使能信号</td></tr><tr><td>TC0_WE</td><td>1</td><td>out</td><td>TC0写使能信号</td></tr><tr><td>TC0_Addr</td><td>32</td><td>out</td><td>TC0读写地址</td></tr><tr><td>TC0_Din</td><td>32</td><td>out</td><td>可能写入TC0的数据</td></tr><tr><td>TC0_Dout</td><td>32</td><td>in</td><td>根据地址从TC0中直接读出的数据</td></tr><tr><td>TC1_WE</td><td>1</td><td>out</td><td>TC1写使能信号</td></tr><tr><td>TC1_Addr</td><td>32</td><td>out</td><td>TC1读写地址</td></tr><tr><td>TC1_Din</td><td>32</td><td>out</td><td>可能写入TC1的数据</td></tr><tr><td>TC1_Dout</td><td>32</td><td>in</td><td>根据地址从TC1中直接读出的数据</td></tr></tbody></table><p>Bridge可以理解为一个大型的多路选择器,根据地址信息来判断读写目标是外置DM、TC0 或 TC1 ;CPU通过 lw , sw 指令对特定地址的读写来与TC交互。</p><p><strong>CPU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>HWInt</td><td>5</td><td>in</td><td>外部中断信号</td></tr><tr><td>macroscopic_pc</td><td>32</td><td>out</td><td>宏观pc</td></tr><tr><td>i_inst_rdata</td><td>32</td><td>in</td><td>i_inst_addr 对应的 32 位指令</td></tr><tr><td>i_inst_addr</td><td>32</td><td>out</td><td>F级的pc</td></tr><tr><td>m_data_addr</td><td>32</td><td>out</td><td>DM或TC读写地址</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>DM或TC待写入数据</td></tr><tr><td>m_data_rdata</td><td>32</td><td>in</td><td>m_data_addr 对应的 32 位数据</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>未经Bridge处理的写数据存储器的字节使能信号</td></tr><tr><td>m_inst_addr</td><td>32</td><td>out</td><td>M级的pc</td></tr><tr><td>w_grf_we</td><td>1</td><td>out</td><td>GRF 写使能信号</td></tr><tr><td>w_grf_addr</td><td>5</td><td>out</td><td>GRF 中待写入寄存器编号</td></tr><tr><td>w_grf_wdata</td><td>32</td><td>out</td><td>GRF 中待写入数据</td></tr><tr><td>w_inst_addr</td><td>32</td><td>out</td><td>W级pc</td></tr></tbody></table><p>CPU即该系统的主处理器,承担各个子模块的线路连接,数据阻塞、转发,异常和中断识别和控制、程序在异常处理和正常工作模式下转换等功能的核心模块。</p><p><strong>F_PC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>Req</td><td>1</td><td>in</td><td>异常或中断识别信号</td></tr><tr><td>next_pc</td><td>32</td><td>in</td><td>下一条执行指令地址</td></tr><tr><td>pc</td><td>32</td><td>out</td><td>当前执行指令地址</td></tr></tbody></table><p>F_PC即F级的指令取址器,定位执行指令的地址;由于流水线CPU可能存在的<strong>阻塞处理,这里使用en端实现,需阻塞则置为0,暂停更新pc值</strong>,对于可能存在的<strong>异常情况,即Req为1时,pc也进行更新,但跳转到异常处理程序的地址,注意阻塞时异常亦跳转</strong>。</p><p><strong>FD_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>Req</td><td>1</td><td>in</td><td>异常或中断识别信号</td></tr><tr><td>F_pc</td><td>32</td><td>in</td><td>F级当前执行指令的地址</td></tr><tr><td>F_instr</td><td>32</td><td>in</td><td>F级当前的执行指令</td></tr><tr><td>F_ExcCode</td><td>5</td><td>in</td><td>F级异常码</td></tr><tr><td>F_BD</td><td>1</td><td>in</td><td>F级指令是否是延迟槽指令</td></tr><tr><td>D_pc</td><td>32</td><td>out</td><td>D级当前需执行指令的地址</td></tr><tr><td>D_instr</td><td>32</td><td>out</td><td>D级当前需执行的指令</td></tr><tr><td>D_ExcCode</td><td>5</td><td>out</td><td>D级从F级接收的异常码</td></tr><tr><td>D_BD</td><td>1</td><td>out</td><td>D级指令是否是延迟槽指令</td></tr></tbody></table><p>FD_REG即保存前一周期F级得到的指令及状态并在本周期将其传送到D级的寄存器,其中引入flush即刷新信号也是为了服务于阻塞机制,但在目前的指令集下,其在FD_REG中无作用,将在DE_REG中介绍;需要注意的是,<strong>阻塞发生时,该寄存器的en也应置为0</strong>;引入Req信号,<strong>在异常发生时,刷新输出,并将D_pc置为异常处理指令地址</strong>。</p><p><strong>D_GRF</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>W级指令地址</td></tr><tr><td>A1</td><td>5</td><td>in</td><td>读取的寄存器1编号</td></tr><tr><td>A2</td><td>5</td><td>in</td><td>读取的寄存器2编号</td></tr><tr><td>A3</td><td>5</td><td>in</td><td>需写入的寄存器编号</td></tr><tr><td>WD</td><td>32</td><td>in</td><td>需写入寄存器的数据</td></tr><tr><td>RD1</td><td>32</td><td>out</td><td>从寄存器1读出的数据</td></tr><tr><td>RD2</td><td>32</td><td>out</td><td>从寄存器2读出的数据</td></tr></tbody></table><p>D_GRF即D级的寄存器文件,值得注意的是其中pc、A3和WD来自W级,且可能产生冒险行为,这里采用<strong>寄存器内部转发</strong>来解决W级的回写与D级读寄存器地址冲突的情况,采用<strong>外部转发</strong>解决E,M与D级产生的数据冲突;具体操作见<strong>冲突处理</strong>一节。</p><p><strong>D_ext</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>imm16</td><td>16</td><td>in</td><td>16位立即数输入</td></tr><tr><td>extop</td><td>1</td><td>in</td><td>扩展方式控制:0:0扩展;1:符号扩展</td></tr><tr><td>imm32</td><td>32</td><td>out</td><td>扩展后的32位立即数</td></tr></tbody></table><p>D_ext即安排在D级的立即数扩展模块</p><p><strong>D_cmp</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>rt_data</td><td>32</td><td>in</td><td>从寄存器2读出的数据(可能是转发过来的)</td></tr><tr><td>cmpop</td><td>3</td><td>in</td><td>选择比较方式,对应beq、bne等指令</td></tr><tr><td>jump</td><td>1</td><td>out</td><td>根据指令比较方式和比较结果决定是否跳转,跳转则置1</td></tr></tbody></table><p>D_cmp即D级的比较器,为了减少判断跳转指令可能带来的流水线上的无效指令,将分支判断提前到D级,那么即使发生跳转,需要作废的指令只有F级,此时若跳转也约定F级指令不作废,即得到<strong>延时槽</strong>。</p><p><strong>D_NPC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>NPCop</td><td>3</td><td>in</td><td>根据指令选择的下一条指令地址的操作选择信号</td></tr><tr><td>F_pc</td><td>32</td><td>in</td><td>当前F级的指令地址</td></tr><tr><td>D_pc</td><td>32</td><td>in</td><td>当前D级的指令地址</td></tr><tr><td>b_jump</td><td>1</td><td>in</td><td>来自D_cmp的跳转判断信号</td></tr><tr><td>imm16</td><td>16</td><td>in</td><td>16位地址偏移量</td></tr><tr><td>imm26</td><td>26</td><td>in</td><td>26位伪直接寻址的指令地址</td></tr><tr><td>rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>next_pc</td><td>32</td><td>out</td><td>经判断计算得到的下一条执行指令的地址</td></tr><tr><td>Req</td><td>1</td><td>in</td><td>异常或中断识别信号</td></tr><tr><td>eret</td><td>1</td><td>in</td><td>从异常处理程序返回信号</td></tr><tr><td>EPC</td><td>32</td><td>in</td><td>从异常处理程序返回地址的上一条指令地址</td></tr><tr><td>F_BD</td><td>1</td><td>out</td><td>F级指令是否是延迟槽指令</td></tr></tbody></table><p>D_NPC即D级的指令更新器,注意若处理b这一类指令满足条件应在跳转至<code>D_pc + 4 + {{14{imm16[15]}},imm16,2'b00}</code>,而若不需要跳转则下一条指令地址为<code>F_pc+4</code>;若Req有效则跳转至异常处理程序的地址;若eret有效则返回<code>EPC+4</code>。值得注意的一点是若imm16 = 0则由于延时槽的存在且D_pc+4 = F_pc该跳转指令的下一条指令会被执行<strong>两次</strong>。<br>另设延时槽识别信号F_BD,若D级指令的下一条指令(即在F级的指令)地址关系不满足<code>F_pc == D_pc + 4</code>,则F级指令为延时槽指令。</p><p><strong>DE_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>ifBlock</td><td>1</td><td>in</td><td>阻塞信号</td></tr><tr><td>Req</td><td>1</td><td>in</td><td>异常信号</td></tr><tr><td>D_pc</td><td>32</td><td>in</td><td>D级正在执行的指令地址</td></tr><tr><td>D_instr</td><td>32</td><td>in</td><td>D级正在执行的指令</td></tr><tr><td>D_rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>D_rt_data</td><td>32</td><td>in</td><td>从寄存器2读出的数据(可能是转发过来的)</td></tr><tr><td>D_imm32</td><td>32</td><td>in</td><td>在D级被扩展得到的32位立即数</td></tr><tr><td>D_b_jump</td><td>1</td><td>in</td><td>在D级经判断得到的b指令跳转信号</td></tr><tr><td>D_ExcCode</td><td>5</td><td>in</td><td>D级指令的异常码</td></tr><tr><td>D_BD</td><td>1</td><td>in</td><td>D级指令是否是延迟槽指令</td></tr><tr><td>E_pc</td><td>32</td><td>out</td><td>E级需执行的指令地址</td></tr><tr><td>E_instr</td><td>32</td><td>out</td><td>E级需执行的指令</td></tr><tr><td>E_rs_data</td><td>32</td><td>out</td><td>传递到E级的寄存器1数据</td></tr><tr><td>E_rt_data</td><td>32</td><td>out</td><td>传递到E级的寄存器2数据</td></tr><tr><td>E_imm32</td><td>32</td><td>out</td><td>传递到E级的32位立即数</td></tr><tr><td>E_b_jump</td><td>1</td><td>out</td><td>传递到E级的b指令跳转信号</td></tr><tr><td>E_ExcCode</td><td>5</td><td>out</td><td>E级接收的D级指令的异常码</td></tr><tr><td>E_BD</td><td>1</td><td>out</td><td>E级指令是否是延迟槽指令</td></tr></tbody></table><p>DE_REG即保存前一周期D级得到的指令及状态并在本周期将其传送到E级的寄存器,需要注意的是 <strong>异常的优先级高于阻塞</strong>,<strong>只要处于阻塞状态,该寄存器的flush置1,清空除了E_pc,E_BD,E_ExcCode的其他E级信号,这主要是为了保证异常信号不丢失,保证流水线的“单周期化”</strong>,即在流水线中产生“气泡”,“气泡”随流水线传递,达到等待直至阻塞状态解除的目的。</p><p><strong>E_ALU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>A</td><td>32</td><td>in</td><td>操作数1</td></tr><tr><td>B</td><td>32</td><td>in</td><td>操作数2</td></tr><tr><td>ALUCtrl</td><td>4</td><td>in</td><td>ALU运算控制信号</td></tr><tr><td>possible_CalOv</td><td>1</td><td>in</td><td>计算类指令可能溢出信号</td></tr><tr><td>possible_AddrOv</td><td>1</td><td>in</td><td>访存类指令地址可能溢出信号</td></tr><tr><td>ALUResult</td><td>32</td><td>out</td><td>运算结果</td></tr><tr><td>E_Exc_CalOv</td><td>1</td><td>out</td><td>E级计算类指令溢出信号</td></tr><tr><td>E_Exc_AddrOv</td><td>1</td><td>out</td><td>E级访存类指令地址溢出信号</td></tr></tbody></table><p>E_ALU即安排在E级的运算单元,在P7中新增了判断特定指令数据溢出的功能。</p><p><strong>E_MDU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>A</td><td>32</td><td>in</td><td>操作数1</td></tr><tr><td>B</td><td>32</td><td>in</td><td>操作数2</td></tr><tr><td>Start</td><td>1</td><td>in</td><td>乘除运算开始信号</td></tr><tr><td>Busy</td><td>1</td><td>out</td><td>乘除运算正在进行信号</td></tr><tr><td>HI</td><td>32</td><td>out</td><td>高位寄存器</td></tr><tr><td>LO</td><td>32</td><td>out</td><td>低位寄存器</td></tr></tbody></table><p>E_MDU即安排在E级的乘除相关指令(<code>mult, multu, div, divu, mfhi, mflo, mthi, mtlo</code>)处理单元。乘除法部件的执行乘法的时间为 5 个时钟周期,执行除法的时间为 10 个时钟周期(包含写入内部的 HI 和 LO 寄存器);通过只能有效 1 个时钟周期的 Start 信号来启动乘除法运算,通过 Busy 输出标志来反映这个延迟。</p><p><strong>EM_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>E_pc</td><td>32</td><td>in</td><td>E级正在执行的指令地址</td></tr><tr><td>E_instr</td><td>32</td><td>in</td><td>E级正在执行的指令</td></tr><tr><td>E_ALUResult</td><td>32</td><td>in</td><td>E级ALU的运算结果</td></tr><tr><td>E_MDUResult</td><td>32</td><td>in</td><td>E级MDU的运算结果(HI/LO)</td></tr><tr><td>E_rt_data</td><td>32</td><td>in</td><td>E级保存的寄存器2数据</td></tr><tr><td>E_imm32</td><td>32</td><td>in</td><td>E级保存的32位立即数</td></tr><tr><td>E_b_jump</td><td>1</td><td>in</td><td>E级保存的b指令跳转信号</td></tr><tr><td>E_BD</td><td>1</td><td>in</td><td>E级指令是否为延迟槽指令</td></tr><tr><td>E_Exc_AddrOv</td><td>1</td><td>in</td><td>E级访存类指令地址溢出信号</td></tr><tr><td>E_ExcCode</td><td>5</td><td>in</td><td>E级异常码</td></tr><tr><td>M_pc</td><td>32</td><td>out</td><td>M级需执行的指令地址</td></tr><tr><td>M_instr</td><td>32</td><td>out</td><td>M级需执行的指令</td></tr><tr><td>M_ALUResult</td><td>32</td><td>out</td><td>传递到M级的ALU的运算结果</td></tr><tr><td>M_MDUResult</td><td>32</td><td>out</td><td>传递到M级的MDU的运算结果</td></tr><tr><td>M_rt_data</td><td>32</td><td>out</td><td>传递到M级的寄存器2数据</td></tr><tr><td>M_imm32</td><td>32</td><td>out</td><td>传递到M级的32位立即数</td></tr><tr><td>M_b_jump</td><td>1</td><td>out</td><td>传递到M级的b指令跳转信号</td></tr><tr><td>M_BD</td><td>1</td><td>out</td><td>M级指令是否为延迟槽指令</td></tr><tr><td>M_Exc_AddrOv</td><td>1</td><td>out</td><td>M级访存类指令地址溢出信号</td></tr><tr><td>M_ExcCode</td><td>5</td><td>out</td><td>M级从E级接收的异常码</td></tr></tbody></table><p>EM_REG即保存前一周期E级得到的指令及状态并在本周期将其传送到M级的寄存器,不同于DE_REG,这里EM_REG不会刷新,若Req有效则清空除M_pc以外的M级所有信息,M_pc置为异常处理程序地址,因为CP0在M级,宏观pc就是M_pc。</p><p><strong>M_DM_IN</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>instr</td><td>32</td><td>in</td><td>M级指令</td></tr><tr><td>DMop</td><td>3</td><td>in</td><td>存取数据存储器方式选择信号</td></tr><tr><td>MemAddr</td><td>32</td><td>in</td><td>存取数据存储器地址</td></tr><tr><td>dataIn</td><td>32</td><td>in</td><td>待处理的写入外置存储器的数据</td></tr><tr><td>WriteEnable</td><td>1</td><td>in</td><td>写存储器使能信号</td></tr><tr><td>store</td><td>1</td><td>in</td><td>存储指令识别</td></tr><tr><td>M_Exc_AddrOv</td><td>1</td><td>in</td><td>M级访存指令地址溢出信号</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>写数据存储器的字节使能信号</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>写入外置存储器的数据</td></tr><tr><td>M_Exc_AdEs</td><td>1</td><td>out</td><td>存储指令异常信号</td></tr></tbody></table><p>M_DM_IN即安排再M级的外置DM和TC写入数据的预处理器。</p><p><strong>M_DM_OUT</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>instr</td><td>32</td><td>in</td><td>M级指令</td></tr><tr><td>DMop</td><td>3</td><td>in</td><td>存取数据存储器方式选择信号</td></tr><tr><td>MemAddr</td><td>32</td><td>in</td><td>存取数据存储器地址</td></tr><tr><td>m_data_rdata</td><td>32</td><td>in</td><td>从外置存储器读出的数据</td></tr><tr><td>M_Exc_AddrOv</td><td>1</td><td>in</td><td>M级访存指令地址溢出信号</td></tr><tr><td>load</td><td>1</td><td>in</td><td>读取指令识别</td></tr><tr><td>dataOut</td><td>32</td><td>out</td><td>处理后的读出数据</td></tr><tr><td>M_Exc_AdEl</td><td>1</td><td>out</td><td>读取指令异常信号</td></tr></tbody></table><p>M_DM_OUT即安排再M级的外置DM和TC读出的数据的处理器。</p><p><strong>CP0</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>WriteEnable</td><td>1</td><td>in</td><td>写使能信号</td></tr><tr><td>CP0Addr</td><td>5</td><td>in</td><td>读写CP0内置寄存器编号</td></tr><tr><td>CP0In</td><td>32</td><td>in</td><td>写入数据</td></tr><tr><td>CP0Out</td><td>32</td><td>out</td><td>读出数据</td></tr><tr><td>VPC</td><td>32</td><td>in</td><td>受害pc</td></tr><tr><td>BDIn</td><td>1</td><td>in</td><td>是否为延迟槽指令</td></tr><tr><td>ExcCodeIn</td><td>5</td><td>in</td><td>异常码,记录异常类型</td></tr><tr><td>HWInt</td><td>5</td><td>in</td><td>输入的异常信号</td></tr><tr><td>EXLClr</td><td>1</td><td>in</td><td>exl置0信号,此时允许中断</td></tr><tr><td>EPCOut</td><td>32</td><td>out</td><td>异常处理结束后返回的pc</td></tr><tr><td>Req</td><td>1</td><td>out</td><td>异常信号</td></tr></tbody></table><p>CP0即处理异常和中断的协处理器,承担保存、识别异常信号,在异常处理程序和主程序间控制跳转的任务。</p><p><strong>MW_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>Req</td><td>1</td><td>in</td><td>异常信号</td></tr><tr><td>M_pc</td><td>32</td><td>in</td><td>M级正在执行的指令地址</td></tr><tr><td>M_instr</td><td>32</td><td>in</td><td>M级正在执行的指令</td></tr><tr><td>M_ALUResult</td><td>32</td><td>in</td><td>M级保存的ALU的运算结果</td></tr><tr><td>M_MDUResult</td><td>32</td><td>in</td><td>M级保存的MDU的运算结果</td></tr><tr><td>M_dataOut</td><td>32</td><td>in</td><td>M级读出的存储器数据</td></tr><tr><td>M_CP0Out</td><td>32</td><td>in</td><td>M级CP0读出的数据</td></tr><tr><td>M_b_jump</td><td>1</td><td>in</td><td>M级保存的b指令跳转信号</td></tr><tr><td>W_pc</td><td>32</td><td>out</td><td>W级需执行的指令地址</td></tr><tr><td>W_instr</td><td>32</td><td>out</td><td>W级需执行的指令</td></tr><tr><td>W_ALUResult</td><td>32</td><td>out</td><td>传递到W级的ALU的运算结果</td></tr><tr><td>W_MDUResult</td><td>32</td><td>out</td><td>传递到W级的MDU的运算结果</td></tr><tr><td>W_dataOut</td><td>32</td><td>out</td><td>传递到W级的存储器读出数据</td></tr><tr><td>W_CP0Out</td><td>32</td><td>out</td><td>传递到W级的CP0读出的数据</td></tr><tr><td>W_b_jump</td><td>1</td><td>out</td><td>传递到W级的b指令跳转信号</td></tr></tbody></table><p>MW_REG即保存前一周期M级得到的指令及状态并在本周期将其传送到W级的寄存器。</p><p><strong>Controller</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>instr</td><td>32</td><td>in</td><td>32位指令</td></tr><tr><td>b_jump</td><td>1</td><td>in</td><td>b指令跳转信号</td></tr><tr><td>rs</td><td>5</td><td>out</td><td>指令的21-25位,寄存器1编号</td></tr><tr><td>rt</td><td>5</td><td>out</td><td>指令的16-20位,寄存器2编号</td></tr><tr><td>rd</td><td>5</td><td>out</td><td>指令的11-15位,寄存器3编号</td></tr><tr><td>shamt</td><td>5</td><td>out</td><td>指令的6-10位,多用于移位指令的位移量</td></tr><tr><td>imm16</td><td>16</td><td>out</td><td>指令的0-15位,16位立即数</td></tr><tr><td>imm26</td><td>26</td><td>out</td><td>指令的0-25位,26位立即数</td></tr><tr><td>ALUCtrl</td><td>4</td><td>out</td><td>ALU运算操作选择信号</td></tr><tr><td>ALU_Asel</td><td>2</td><td>out</td><td>ALU操作数1选择信号</td></tr><tr><td>ALU_Bsel</td><td>2</td><td>out</td><td>ALU操作数2选择信号</td></tr><tr><td>MDUCtrl</td><td>3</td><td>out</td><td>MDU运算选择信号</td></tr><tr><td>MDU_Start</td><td>1</td><td>out</td><td>乘除运算开始信号</td></tr><tr><td>cmpop</td><td>3</td><td>out</td><td>比较操作选择信号</td></tr><tr><td>extop</td><td>1</td><td>out</td><td>位拓展操作选择信号</td></tr><tr><td>NPCop</td><td>3</td><td>out</td><td>指令地址更新操作选择信号</td></tr><tr><td>DMop</td><td>3</td><td>out</td><td>存储器读/写数据操作选择信号:字/半字/字节</td></tr><tr><td>DM_WriteEnable</td><td>1</td><td>out</td><td>外置数据存储器写使能信号</td></tr><tr><td>GRF_WriteEnable</td><td>1</td><td>out</td><td>寄存器文件写使能信号</td></tr><tr><td>GRF_A3</td><td>5</td><td>out</td><td>寄存器文件写数据地址</td></tr><tr><td>WDSel</td><td>2</td><td>out</td><td>寄存器写入数据选择信号</td></tr><tr><td>CP0_WriteEnable</td><td>1</td><td>out</td><td>CP0写使能信号</td></tr><tr><td>load</td><td>1</td><td>out</td><td>读取数据存储器指令识别信号</td></tr><tr><td>store</td><td>1</td><td>out</td><td>写入数据存储器型指令识别信号</td></tr><tr><td>cal_r</td><td>1</td><td>out</td><td>寄存器操作计算指令识别信号</td></tr><tr><td>cal_i</td><td>1</td><td>out</td><td>立即数操作计算指令识别信号</td></tr><tr><td>shift_s</td><td>1</td><td>out</td><td>固定位移指令识别信号</td></tr><tr><td>shift_v</td><td>1</td><td>out</td><td>可变位移指令识别信号</td></tr><tr><td>branch</td><td>1</td><td>out</td><td>b型跳转指令识别信号</td></tr><tr><td>j_reg</td><td>1</td><td>out</td><td>从寄存器获取跳转地址的跳转指令识别信号</td></tr><tr><td>j_imm</td><td>1</td><td>out</td><td>以立即数为跳转地址的跳转指令识别信号</td></tr><tr><td>j_link</td><td>1</td><td>out</td><td>跳转并链接指令识别信号</td></tr><tr><td>mul_div</td><td>1</td><td>out</td><td>乘除指令识别信号</td></tr><tr><td>mt</td><td>1</td><td>out</td><td>向 HI/LO 寄存器写入指令信号</td></tr><tr><td>mf</td><td>1</td><td>out</td><td>从 HI/LO 寄存器读出数据写入寄存器文件指令识别信号</td></tr><tr><td>mfc0</td><td>1</td><td>out</td><td>mfc0识别信号</td></tr><tr><td>mtc0</td><td>1</td><td>out</td><td>mtc0识别信号</td></tr><tr><td>eret</td><td>1</td><td>out</td><td>eret识别信号</td></tr><tr><td>D_Exc_Syscall</td><td>1</td><td>out</td><td>syscall引起的异常识别信号</td></tr><tr><td>D_Exc_RI</td><td>1</td><td>out</td><td>未识别指令引起的异常识别信号</td></tr><tr><td>possible_CalOv</td><td>1</td><td>out</td><td>可能发生计算类指令溢出</td></tr><tr><td>possible_AddrOv</td><td>1</td><td>out</td><td>可能发生访存类指令地址溢出</td></tr></tbody></table><p>Controller即通用控制器,在mips模块中,在D,E,M,W每一级被调用,接收在相应级所需的状态信息,达到分布式译码的目的,以但前级的指令和状态为依据,发出控制信号,操作数据通路,控制转发操作;在Blocker模块中,在D,E,M级调用,发出指令识别信号以计算 Tuse 和 Tnew ,为是否阻塞提供依据;并对在译码过程中就可以发生的异常给出识别信号。</p><p><strong>Blocker</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>D_instr</td><td>32</td><td>in</td><td>D级正在执行的指令</td></tr><tr><td>E_instr</td><td>32</td><td>in</td><td>E级正在执行的指令</td></tr><tr><td>M_instr</td><td>32</td><td>in</td><td>M级正在执行的指令</td></tr><tr><td>E_MDU_Start</td><td>1</td><td>in</td><td>MDU开始执行乘除指令信号</td></tr><tr><td>E_MDU_Busy</td><td>1</td><td>in</td><td>MDU正在执行乘除指令信号</td></tr><tr><td>ifBlock</td><td>1</td><td>out</td><td>阻塞操作使能信号,需阻塞置1</td></tr></tbody></table><p>Blocker即阻塞控制器,根据Controller的译码结果,计算D_Tuse_rs,D_Tuse_rt,E_Tnew,M_Tnew(由于当前指令集W_Tnew恒为0故先不作计算),再结合寄存器读写信息使用AT模型控制输出的阻塞信号。<strong>注意新增的冲突是,eret读取CP0的EPC时之前指令对CP0的EPC的写</strong>。</p><hr><h2 id="冲突处理"><a href="#冲突处理" class="headerlink" title="冲突处理"></a>冲突处理</h2><p>在流水线CPU中,由于多条指令同时存在于流水线上,且在同一周期内执行不同的指令操作,这可能引发由于硬件资源重叠和指令间依赖性而导致的冲突问题;当前指令集下冲突有以下2种可能:</p><ul><li><strong>寄存器文件中的寄存器被同时读写</strong></li><li><strong>后面指令在需要使用数据时,前面供给的数据还没有存入寄存器堆</strong></li></ul><p>本节主要讨论阻塞和转发处理冲突的情况判断和实现方式。</p><hr><h3 id="阻塞操作"><a href="#阻塞操作" class="headerlink" title="阻塞操作"></a>阻塞操作</h3><p>阻塞,顾名思义使流水线停在某一指令,需等待某种条件解除阻塞状态。</p><p><strong>何时阻塞</strong><br>后面指令(记为B)在需要使用数据时,前面指令(记为A)供给的数据还没有<strong>产生并写入流水级寄存器</strong>,这时转发无源头 <strong>(转发的源头都是流水级寄存器存储的数据,故不能认为数据产生后可被立即转发)</strong> ,唯一的方法是让B等待,直到A在流水线某一级产生所需数据时解除,再考虑转发或直接使用。<br>这里采用Tuse–Tnew模型判断。</p><ul><li>Tuse:某指令位于 <strong>D</strong> 级的时候,再经过多少个时钟周期就必须要使用相应的数据。</li><li>Tnew:位于某个流水级的某个指令,它经过多少个时钟周期可以<strong>算出结果</strong>并且<strong>存储到流水级寄存器</strong>里。</li></ul><p>具体各指令的Tuse,Tnew参见文件夹内表格Tuse&&Tnew。</p><p>由此,可以得到结论 <strong>Tuse < Tnew 且读写地址重叠(均不为$0)</strong> 时必须进行相应阻塞操作。</p><p>加入乘除指令后,由于乘除槽的存在,MDU在进行运算时,后续的乘除相关指令应被阻塞在D级,故需要额外为此添加一个阻塞信号。</p><p>加入异常处理机制后,由于<code>eret</code>指令读取CP0存储EPC的寄存器,而<code>mtc0</code>可能写此寄存器,故额外为此添加一个阻塞信号。</p><p>当前指令集需阻塞的情况代码表示如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">wire</span> E_ifBlock_rs <span class="token operator">=</span> <span class="token punctuation">(</span>E_GRF_A3 <span class="token operator">==</span> D_rs <span class="token operator">&&</span> D_rs <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rs <span class="token operator"><</span> E_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> E_ifBlock_rt <span class="token operator">=</span> <span class="token punctuation">(</span>E_GRF_A3 <span class="token operator">==</span> D_rt <span class="token operator">&&</span> D_rt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rt <span class="token operator"><</span> E_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_rs <span class="token operator">=</span> <span class="token punctuation">(</span>M_GRF_A3 <span class="token operator">==</span> D_rs <span class="token operator">&&</span> D_rs <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rs <span class="token operator"><</span> M_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_rt <span class="token operator">=</span> <span class="token punctuation">(</span>M_GRF_A3 <span class="token operator">==</span> D_rt <span class="token operator">&&</span> D_rt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rt <span class="token operator"><</span> M_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> E_ifBlock_MDU <span class="token operator">=</span> <span class="token punctuation">(</span>D_mul_div <span class="token operator">|</span> D_mf <span class="token operator">|</span> D_mt<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>E_MDU_Busy <span class="token operator">|</span> E_MDU_Start<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_eret <span class="token operator">=</span> <span class="token punctuation">(</span>D_eret<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>E_mtc0 <span class="token operator">&&</span> E_rd <span class="token operator">==</span> <span class="token number">14</span> <span class="token operator">||</span> M_mtc0 <span class="token operator">&&</span> M_rd <span class="token operator">==</span> <span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> ifBlock <span class="token operator">=</span> E_ifBlock_rs <span class="token operator">|</span> E_ifBlock_rt <span class="token operator">|</span> M_ifBlock_rs <span class="token operator">|</span> M_ifBlock_rt <span class="token operator">|</span> E_ifBlock_MDU <span class="token operator">|</span> M_ifBlock_eret<span class="token punctuation">;</span></code></pre><p><strong>如何阻塞</strong><br>自此,我们得到了阻塞信号<code>ifBlock</code><br>以此为依据操作阻塞情况的数据通路(这里先不考虑异常):</p><ul><li>将F_IFU和FD_REG的使能信号(en)置为0,不再更新并发送新的指令信号,达到使进入流水线的指令滞留在<strong>D级</strong>的目的。</li><li>将DE_REG的刷新信号(flush)置为1,使向E级发送的指令为nop,<strong>而发送的指令地址为D_pc</strong>,这主要是为了使保证<strong>宏观pc的单周期特性</strong>,即产生“合理气泡”填充流水线;注意,仅需在此寄存器刷新,因为只要处于阻塞状态,该寄存器不断产生“气泡”,而这些“气泡”随时钟周期向后移动填充流水线各级。</li><li>对于不同指令,当 <strong>Tuse >= Tnew</strong> 或 <strong>E_MDU_Busy = 0, E_MDU_Start = 0</strong>时解除阻塞状态,使能信号置为1,刷新信号置为0,开始考虑转发,继续流水。</li></ul><p>具体代码实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> PC_en <span class="token operator">=</span> <span class="token operator">!</span>ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> FD_REG_en <span class="token operator">=</span> <span class="token operator">!</span>ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> DE_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> EM_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> MW_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> FD_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> DE_REG_flush <span class="token operator">=</span> ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> EM_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> MW_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></code></pre><hr><h3 id="转发操作"><a href="#转发操作" class="headerlink" title="转发操作"></a>转发操作</h3><p>转发,即将先进入流水线的指令产生的数据根据条件发送给后进入的指令。</p><p><strong>何时转发</strong><br>前面指令供给的数据,而后面指令在需要使用数据时,前面供给的数据<strong>已经产生且写入流水级寄存器但还没有存入寄存器堆</strong>,导致后面的指令在GRF中取不到正确的值,故当两个流水级出现读写寄存器的重叠时,(在无需阻塞或阻塞完成时)应考虑转发。</p><p><strong>如何转发</strong><br>在当前指令级下,仅存在:</p><ul><li>W向D级转发(寄存器内自转发)</li><li>E,M向D级转发</li><li>M,W向E级转发</li><li>W向M级转发<br>具体转发关系见文件夹下表格 hazard_and_relocate</li></ul><p>具体代码实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token comment" spellcheck="true">//寄存器内自转发</span> <span class="token keyword">assign</span> RD1 <span class="token operator">=</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span>A3 <span class="token operator">&&</span> A1<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> regFile<span class="token punctuation">[</span>A1<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> RD2 <span class="token operator">=</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span>A3 <span class="token operator">&&</span> A2<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> regFile<span class="token punctuation">[</span>A2<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向D级转发</span> <span class="token keyword">assign</span> D_Forward_rs_data <span class="token operator">=</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> E_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> E_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> D_rs_data<span class="token punctuation">;</span> <span class="token keyword">assign</span> D_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> E_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> E_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> D_rt_data<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向E级转发</span> <span class="token keyword">assign</span> E_Forward_rs_data <span class="token operator">=</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> E_rs_data<span class="token punctuation">;</span> <span class="token keyword">assign</span> E_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> E_rt_data<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向M级转发</span> <span class="token keyword">assign</span> M_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>M_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>M_rt <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> M_rt_data<span class="token punctuation">;</span></code></pre><p>值得注意的是,这种转发方式的正确性是由<strong>阻塞机制</strong>和<strong>转发优先级</strong>决定的。<br>所谓优先级即向每一级转发时,依次沿流水线检索此级的下级,满足条件即转发,若都无需转发,则采用本级读出的寄存器值,这在代码中有所体现。<br>但可能存在这样两个问题<br>1.如需要向D级转发某数据,此数据在E级产生但未写入流水级寄存器,直至下个时钟上升沿才写入EM_REG(M级),则按优先级优先转发了DE_REG(E级)保存的数据,这是否会导致错误?<br><strong>答</strong>:实际上不会,由于阻塞机制的存在,当数据在E级产生但未写入流水级寄存器时,流水线被阻塞,指令停滞,此时转发的数据也起不到作用,待到下个时钟上升沿才写入EM_REG(M级),转发来自M级的数据会直接将错误值<strong>覆盖</strong>,阻塞状态解除,流水线正常执行。</p><p>2.如果转发到的寄存器在此指令期间不被读(可以不转发)将一个值存入其中会不会有影响?<br><strong>答</strong>:不会,若该寄存器不被读,则其要么被写,要么不参与本指令的执行,那么对于第一种情况,该指令写入时会将原本转发的值覆盖;对于第二种情况,该寄存器在流水级中的表现实际是相当于提前被写入了(实际上写入还是要到转发的源头指令的W级)。</p><hr><h2 id="异常和中断处理"><a href="#异常和中断处理" class="headerlink" title="异常和中断处理"></a>异常和中断处理</h2><h3 id="异常概览"><a href="#异常概览" class="headerlink" title="异常概览"></a>异常概览</h3><pre class=" language-mermaid"><code class="language-mermaid">graph TDA[异常]-->B[内部异常]A-->C[外部中断]B-->G[F级]G-->D[pc取址异常:F_Exc_AdEl]D-->H[D级]H-->E[无法识别指令:D_Exc_RI]H-->F[syscall调用:D_Exc_Syscall]E-->I[E级]F-->II-->J[计算类指令数据溢出:E_Exc_CalOv]I-->K[访存类指令地址溢出:E_Exc_AddrOv]J-->L[M级]K-->L[M级]L-->M[存储指令异常:M_Exc_AdEs]L-->N[读取指令异常:M_Exc_AdEl]C-->O[来自TC的中断信号]C-->P[来自tb的中断信号]</code></pre><p><strong>优先级</strong></p><ul><li>同时发生时:外部中断 > 内部异常 > 阻塞转发等行为</li><li>对于流水线上的多条指令都发生异常的情况,优先处理先进入流水线的。</li><li>对于同一条指令在不同流水级可能发生的异常,优先处理最先出现的。</li></ul><h3 id="异常的收集"><a href="#异常的收集" class="headerlink" title="异常的收集"></a>异常的收集</h3><p><strong>外部中断</strong><br>外部中断有两种来源:一是测试模块通过手动设置的发出interrupt,二是TC0和TC1计时结束所发出的IRQ。<br>P要求用一个 HWInt 来记录中断,具体如下:</p><pre class=" language-verilog"><code class="language-verilog"><span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">5</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> HWInt <span class="token operator">=</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span><span class="token number">3'b000</span><span class="token punctuation">,</span> interrupt<span class="token punctuation">,</span> TC1_IRQ<span class="token punctuation">,</span> TC0_IRQ<span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span><span class="token punctuation">;</span></code></pre><p><strong>内部异常</strong><br>如异常概览中所述,指令在不同流水级可能产生不同的异常,而又根据优先级的要求,我们将异常进行流水,每个流水级进行更新,更新方式如下:</p><pre class=" language-verilog"><code class="language-verilog"><span class="token keyword">assign</span> F_ExcCode <span class="token operator">=</span> F_Exc_AdEl <span class="token operator">?</span> <span class="token constant">`Exc_AdEl</span> <span class="token punctuation">:</span> <span class="token constant">`Exc_NULL</span><span class="token punctuation">;</span><span class="token keyword">assign</span> D_ExcCode <span class="token operator">=</span> temp_D_ExcCode <span class="token operator">!=</span> <span class="token number">0</span> <span class="token operator">?</span> temp_D_ExcCode <span class="token punctuation">:</span> D_Exc_RI <span class="token operator">?</span> <span class="token constant">`Exc_RI</span> <span class="token punctuation">:</span> D_Exc_Syscall <span class="token operator">?</span> <span class="token constant">`Exc_Syscall</span> <span class="token punctuation">:</span> <span class="token constant">`Exc_NULL</span><span class="token punctuation">;</span><span class="token keyword">assign</span> E_ExcCode <span class="token operator">=</span> <span class="token punctuation">(</span>temp_E_ExcCode <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> temp_E_ExcCode <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_Exc_CalOv<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token constant">`Exc_Ov</span> <span class="token punctuation">:</span> <span class="token constant">`Exc_NULL</span><span class="token punctuation">;</span><span class="token keyword">assign</span> M_ExcCode <span class="token operator">=</span> <span class="token punctuation">(</span>temp_M_ExcCode <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> temp_M_ExcCode <span class="token punctuation">:</span> <span class="token punctuation">(</span>M_Exc_AdEl<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token constant">`Exc_AdEl</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>M_Exc_AdEs<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token constant">`Exc_AdEs</span> <span class="token punctuation">:</span> <span class="token constant">`Exc_NULL</span><span class="token punctuation">;</span></code></pre><p>注意这里有 temp 前缀的异常码是通过流水级寄存器从上一级直接获取的。</p><p><strong>综合异常</strong></p><p>对于某一条指令,当其到达M级时,所有可能的异常都已经收集完毕,下一步则是交由CP0综合处理并将Req信号发送到各流水级进行相应的处理操作。</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">wire</span> interuption <span class="token operator">=</span> <span class="token operator">!</span><span class="token constant">`exl</span> <span class="token operator">&&</span> <span class="token constant">`ie</span> <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token constant">`im</span> <span class="token operator">&</span> HWInt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> exception <span class="token operator">=</span> <span class="token operator">!</span><span class="token constant">`exl</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>ExcCodeIn <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> Req <span class="token operator">=</span> interuption <span class="token operator">|</span> exception<span class="token punctuation">;</span></code></pre><h3 id="异常的处理"><a href="#异常的处理" class="headerlink" title="异常的处理"></a>异常的处理</h3><p>对异常的处理可以分为三步:</p><ul><li>由于封装要求的单周期性,在M级CP0产生异常信号时,需对各流水级寄存器做一些数据更新操作,并记录受害pc(即 M_pc);具体如下:<pre class=" language-verilog"><code class="language-verilog"> <span class="token comment" spellcheck="true">// FD_REG</span> <span class="token function">if</span><span class="token punctuation">(</span>reset <span class="token operator">|</span> flush <span class="token operator">|</span> Req<span class="token punctuation">)</span><span class="token keyword">begin</span> D_instr <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> D_pc <span class="token operator"><=</span> Req <span class="token operator">?</span> <span class="token number">32'h00004180</span> <span class="token punctuation">:</span> <span class="token number">32'h00003000</span><span class="token punctuation">;</span> D_ExcCode <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//32'h00004180 为异常处理程序首地址</span> D_BD <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token comment" spellcheck="true">// DE_REG</span> <span class="token function">if</span><span class="token punctuation">(</span>reset <span class="token operator">||</span> flush <span class="token operator">||</span> Req <span class="token operator">||</span> ifBlock<span class="token punctuation">)</span><span class="token keyword">begin</span> E_pc <span class="token operator"><=</span> Req <span class="token operator">?</span> <span class="token number">32'h00004180</span> <span class="token punctuation">:</span> ifBlock <span class="token operator">?</span> D_pc <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//服务于“单周期化”</span> E_instr <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> E_rs_data <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> E_rt_data <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> E_imm32 <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> E_b_jump <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> E_BD <span class="token operator"><=</span> ifBlock <span class="token operator">?</span> D_BD <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> E_ExcCode <span class="token operator"><=</span> ifBlock <span class="token operator">?</span> D_ExcCode <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token comment" spellcheck="true">//EM_REG</span> <span class="token function">if</span><span class="token punctuation">(</span>reset <span class="token operator">||</span> flush <span class="token operator">||</span> Req<span class="token punctuation">)</span><span class="token keyword">begin</span> M_pc <span class="token operator"><=</span> Req <span class="token operator">?</span> <span class="token number">32'h00004180</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> M_instr <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_ALUResult <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_MDUResult <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_rt_data <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_imm32 <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_b_jump <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_BD <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_ExcCode <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> M_Exc_AddrOv <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span></code></pre></li><li>跳转进入异常处理程序;我们的任务在上一步更新pc时已经完成了,异常处理程序并不需要我们维护。</li><li>检测到<code>eret</code>指令,根据先前记录的EPC从异常处理程序返回,具体实现如下:<pre class=" language-verilog"><code class="language-verilog"> <span class="token comment" spellcheck="true">//CP0 中更新EPC</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> temp_EPC <span class="token operator">=</span> Req <span class="token operator">?</span> <span class="token punctuation">(</span>BDIn <span class="token operator">?</span> VPC<span class="token operator">-</span><span class="token number">32'h00000004</span> <span class="token punctuation">:</span> VPC<span class="token punctuation">)</span> <span class="token punctuation">:</span> EPC<span class="token punctuation">;</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">posedge</span> clk<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>Req<span class="token punctuation">)</span> <span class="token keyword">begin</span> EPC <span class="token operator"><=</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span>temp_EPC<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token number">2'b00</span><span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token comment" spellcheck="true">//F级中更新pc</span> <span class="token keyword">assign</span> F_pc <span class="token operator">=</span> D_eret <span class="token operator">?</span> EPC <span class="token punctuation">:</span> temp_F_pc<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//D_NPC 中更新next_pc</span> <span class="token keyword">assign</span> next_pc <span class="token operator">=</span> <span class="token punctuation">(</span>Req<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">32'h00004180</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>eret<span class="token punctuation">)</span> <span class="token operator">?</span> EPC <span class="token operator">+</span> <span class="token number">4</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>b_jump <span class="token operator">&&</span> NPCop <span class="token operator">==</span> <span class="token constant">`NPCop_b</span><span class="token punctuation">)</span> <span class="token operator">?</span> D_pc <span class="token operator">+</span> <span class="token number">4</span> <span class="token operator">+</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span><span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span><span class="token number">14</span><span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span>imm16<span class="token punctuation">[</span><span class="token number">15</span><span class="token punctuation">]</span><span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span><span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span><span class="token punctuation">,</span>imm16<span class="token punctuation">,</span><span class="token number">2'b00</span><span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>NPCop <span class="token operator">==</span> <span class="token constant">`NPCop_jr_jalr</span><span class="token punctuation">)</span> <span class="token operator">?</span> rs_data <span class="token punctuation">:</span> <span class="token punctuation">(</span>NPCop <span class="token operator">==</span> <span class="token constant">`NPCop_j_jal</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span>D_pc<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">28</span><span class="token punctuation">]</span><span class="token punctuation">,</span>imm26<span class="token punctuation">,</span><span class="token number">2'b00</span><span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span> <span class="token punctuation">:</span> F_pc<span class="token operator">+</span><span class="token number">4</span> <span class="token punctuation">;</span></code></pre></li></ul><p>最后值得注意的一点是,对于来自tb的中断信号,即 mips 模块的 interrupt 信号,另需要响应方法,即向中断发生器写入:</p><pre class=" language-verilog"><code class="language-verilog"><span class="token comment" spellcheck="true">//DM/TC 写入地址</span> <span class="token keyword">assign</span> m_data_addr <span class="token operator">=</span> bridge_m_data_addr<span class="token punctuation">;</span> <span class="token keyword">assign</span> m_data_byteen <span class="token operator">=</span> bridge_m_byteen<span class="token punctuation">;</span><span class="token comment" spellcheck="true">//中断响应写入地址</span> <span class="token keyword">assign</span> m_int_addr <span class="token operator">=</span> bridge_m_data_addr<span class="token punctuation">;</span> <span class="token keyword">assign</span> m_int_byteen <span class="token operator">=</span> bridge_m_byteen<span class="token punctuation">;</span></code></pre><p>因为 CP0 模块安排在 M 级,故以上两类地址在系统桥的保障下可以直接与系统桥处理后的地址相连。</p><hr><h2 id="测试方案"><a href="#测试方案" class="headerlink" title="测试方案"></a>测试方案</h2><p><strong>异常处理程序</strong></p><pre class=" language-c"><code class="language-c"><span class="token punctuation">.</span>ktext <span class="token number">0x4180</span>_entry<span class="token punctuation">:</span> mfc0$k0<span class="token punctuation">,</span> $<span class="token number">14</span> mfc0$k1<span class="token punctuation">,</span> $<span class="token number">13</span> ori$k0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x1000</span> sw$sp<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token function">4</span><span class="token punctuation">(</span>$k0<span class="token punctuation">)</span> addiu$k0<span class="token punctuation">,</span> $k0<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">256</span> move$sp<span class="token punctuation">,</span> $k0 j_save_context nop _main_handler<span class="token punctuation">:</span> mfc0 $k0<span class="token punctuation">,</span> $<span class="token number">13</span> ori $k1<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x007c</span> and$k0<span class="token punctuation">,</span> $k1<span class="token punctuation">,</span> $k0 beq $<span class="token number">0</span><span class="token punctuation">,</span> $k0<span class="token punctuation">,</span> _restore_context nop mfc0$k0<span class="token punctuation">,</span> $<span class="token number">14</span> addu$k0<span class="token punctuation">,</span> $k0<span class="token punctuation">,</span> <span class="token number">4</span> mtc0$k0<span class="token punctuation">,</span> $<span class="token number">14</span> j_restore_context nop _restore<span class="token punctuation">:</span> eret _save_context<span class="token punctuation">:</span> sw $<span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">2</span><span class="token punctuation">,</span> <span class="token function">8</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">3</span><span class="token punctuation">,</span> <span class="token function">12</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">4</span><span class="token punctuation">,</span> <span class="token function">16</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">5</span><span class="token punctuation">,</span> <span class="token function">20</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">6</span><span class="token punctuation">,</span> <span class="token function">24</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">7</span><span class="token punctuation">,</span> <span class="token function">28</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">8</span><span class="token punctuation">,</span> <span class="token function">32</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">9</span><span class="token punctuation">,</span> <span class="token function">36</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">10</span><span class="token punctuation">,</span> <span class="token function">40</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">11</span><span class="token punctuation">,</span> <span class="token function">44</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">12</span><span class="token punctuation">,</span> <span class="token function">48</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">13</span><span class="token punctuation">,</span> <span class="token function">52</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">14</span><span class="token punctuation">,</span> <span class="token function">56</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">15</span><span class="token punctuation">,</span> <span class="token function">60</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">16</span><span class="token punctuation">,</span> <span class="token function">64</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">17</span><span class="token punctuation">,</span> <span class="token function">68</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">18</span><span class="token punctuation">,</span> <span class="token function">72</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">19</span><span class="token punctuation">,</span> <span class="token function">76</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">20</span><span class="token punctuation">,</span> <span class="token function">80</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">21</span><span class="token punctuation">,</span> <span class="token function">84</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">22</span><span class="token punctuation">,</span> <span class="token function">88</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">23</span><span class="token punctuation">,</span> <span class="token function">92</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">24</span><span class="token punctuation">,</span> <span class="token function">96</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">25</span><span class="token punctuation">,</span> <span class="token function">100</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">26</span><span class="token punctuation">,</span> <span class="token function">104</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">27</span><span class="token punctuation">,</span> <span class="token function">108</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">28</span><span class="token punctuation">,</span> <span class="token function">112</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">29</span><span class="token punctuation">,</span> <span class="token function">116</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">30</span><span class="token punctuation">,</span> <span class="token function">120</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> sw $<span class="token number">31</span><span class="token punctuation">,</span> <span class="token function">124</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> mfhi $k0 sw $k0<span class="token punctuation">,</span> <span class="token function">128</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> mflo $k0 sw $k0<span class="token punctuation">,</span> <span class="token function">132</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> j_main_handler nop _restore_context<span class="token punctuation">:</span> lw $<span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">2</span><span class="token punctuation">,</span> <span class="token function">8</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">3</span><span class="token punctuation">,</span> <span class="token function">12</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">4</span><span class="token punctuation">,</span> <span class="token function">16</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">5</span><span class="token punctuation">,</span> <span class="token function">20</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">6</span><span class="token punctuation">,</span> <span class="token function">24</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">7</span><span class="token punctuation">,</span> <span class="token function">28</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">8</span><span class="token punctuation">,</span> <span class="token function">32</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">9</span><span class="token punctuation">,</span> <span class="token function">36</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">10</span><span class="token punctuation">,</span> <span class="token function">40</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">11</span><span class="token punctuation">,</span> <span class="token function">44</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">12</span><span class="token punctuation">,</span> <span class="token function">48</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">13</span><span class="token punctuation">,</span> <span class="token function">52</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">14</span><span class="token punctuation">,</span> <span class="token function">56</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">15</span><span class="token punctuation">,</span> <span class="token function">60</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">16</span><span class="token punctuation">,</span> <span class="token function">64</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">17</span><span class="token punctuation">,</span> <span class="token function">68</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">18</span><span class="token punctuation">,</span> <span class="token function">72</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">19</span><span class="token punctuation">,</span> <span class="token function">76</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">20</span><span class="token punctuation">,</span> <span class="token function">80</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">21</span><span class="token punctuation">,</span> <span class="token function">84</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">22</span><span class="token punctuation">,</span> <span class="token function">88</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">23</span><span class="token punctuation">,</span> <span class="token function">92</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">24</span><span class="token punctuation">,</span> <span class="token function">96</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">25</span><span class="token punctuation">,</span> <span class="token function">100</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">26</span><span class="token punctuation">,</span> <span class="token function">104</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">27</span><span class="token punctuation">,</span> <span class="token function">108</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">28</span><span class="token punctuation">,</span> <span class="token function">112</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">29</span><span class="token punctuation">,</span> <span class="token function">116</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">30</span><span class="token punctuation">,</span> <span class="token function">120</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $<span class="token number">31</span><span class="token punctuation">,</span> <span class="token function">124</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> lw $k0<span class="token punctuation">,</span> <span class="token function">128</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> mthi $k0 lw $k0<span class="token punctuation">,</span> <span class="token function">132</span><span class="token punctuation">(</span>$sp<span class="token punctuation">)</span> mtlo $k0 j _restore nop <span class="token punctuation">.</span>text ori $<span class="token number">2</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x1001</span> mtc0 $<span class="token number">2</span><span class="token punctuation">,</span> $<span class="token number">12</span> ori$<span class="token number">28</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0000</span> ori$<span class="token number">29</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0000</span> lui$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> lui$<span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> add$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span> or$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span>end<span class="token punctuation">:</span> beq $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> end nop</code></pre><p><strong>testbench</strong></p><pre class=" language-verilog"><code class="language-verilog"><span class="token constant">`timescale</span> <span class="token number">1</span>ns<span class="token operator">/</span><span class="token number">1</span>ps<span class="token keyword">module</span> mips_txt<span class="token punctuation">;</span> <span class="token keyword">reg</span> clk<span class="token punctuation">;</span> <span class="token keyword">reg</span> reset<span class="token punctuation">;</span> <span class="token keyword">reg</span> interrupt<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> macroscopic_pc<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> i_inst_addr<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> i_inst_rdata<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> m_data_addr<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> m_data_rdata<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> m_data_wdata<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">3</span> <span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> m_data_byteen<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> m_inst_addr<span class="token punctuation">;</span> <span class="token keyword">wire</span>w_grf_we<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">4</span> <span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> w_grf_addr<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> w_grf_wdata<span class="token punctuation">;</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> w_inst_addr<span class="token punctuation">;</span> mips <span class="token function">uut</span><span class="token punctuation">(</span> <span class="token punctuation">.</span><span class="token function">clk</span><span class="token punctuation">(</span>clk<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span>reset<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span>interrupt<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">macroscopic_pc</span><span class="token punctuation">(</span>macroscopic_pc<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">i_inst_addr</span><span class="token punctuation">(</span>i_inst_addr<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">i_inst_rdata</span><span class="token punctuation">(</span>i_inst_rdata<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">m_data_addr</span><span class="token punctuation">(</span>m_data_addr<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">m_data_rdata</span><span class="token punctuation">(</span>m_data_rdata<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">m_data_wdata</span><span class="token punctuation">(</span>m_data_wdata<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">m_data_byteen</span><span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">m_inst_addr</span><span class="token punctuation">(</span>m_inst_addr<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">w_grf_we</span><span class="token punctuation">(</span>w_grf_we<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">w_grf_addr</span><span class="token punctuation">(</span>w_grf_addr<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">w_grf_wdata</span><span class="token punctuation">(</span>w_grf_wdata<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">w_inst_addr</span><span class="token punctuation">(</span>w_inst_addr<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">initial</span> <span class="token keyword">begin</span> clk <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> reset <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">;</span> interrupt <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token number">#20</span> reset <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">integer</span> i<span class="token punctuation">;</span> <span class="token keyword">reg</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> fixed_addr<span class="token punctuation">;</span> <span class="token keyword">reg</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> fixed_wdata<span class="token punctuation">;</span> <span class="token keyword">reg</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span><span class="token number">4095</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">reg</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> inst<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span><span class="token number">5119</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// ----------- For Instructions -----------</span> <span class="token keyword">assign</span> m_data_rdata <span class="token operator">=</span> data<span class="token punctuation">[</span><span class="token punctuation">(</span>m_data_addr <span class="token operator">>></span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">5120</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> i_inst_rdata <span class="token operator">=</span> inst<span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i_inst_addr <span class="token operator">-</span> <span class="token number">32'h3000</span><span class="token punctuation">)</span> <span class="token operator">>></span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">5120</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">initial</span> <span class="token keyword">begin</span> <span class="token property">$readmemh</span><span class="token punctuation">(</span><span class="token string">"code.txt"</span><span class="token punctuation">,</span> inst<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5120</span><span class="token punctuation">;</span> i <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> data<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token comment" spellcheck="true">// ----------- For Data Memory -----------</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> fixed_wdata <span class="token operator">=</span> data<span class="token punctuation">[</span><span class="token punctuation">(</span>m_data_addr <span class="token operator">>></span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">&</span> <span class="token number">4095</span><span class="token punctuation">]</span><span class="token punctuation">;</span> fixed_addr <span class="token operator">=</span> m_data_addr <span class="token operator">&</span> <span class="token number">32'hfffffffc</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">24</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">24</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">23</span><span class="token punctuation">:</span><span class="token number">16</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">23</span><span class="token punctuation">:</span><span class="token number">16</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">15</span><span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">15</span><span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">7</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">7</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">posedge</span> clk<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>reset<span class="token punctuation">)</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">4096</span><span class="token punctuation">;</span> i <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> data<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">|</span>m_data_byteen <span class="token operator">&&</span> fixed_addr <span class="token operator">>></span> <span class="token number">2</span> <span class="token operator"><</span> <span class="token number">4096</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> data<span class="token punctuation">[</span>fixed_addr <span class="token operator">>></span> <span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator"><=</span> fixed_wdata<span class="token punctuation">;</span> <span class="token property">$display</span><span class="token punctuation">(</span><span class="token string">"%d@%h: *%h <= %h"</span><span class="token punctuation">,</span> <span class="token property">$time</span><span class="token punctuation">,</span> m_inst_addr<span class="token punctuation">,</span> fixed_addr<span class="token punctuation">,</span> fixed_wdata<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token comment" spellcheck="true">// ----------- For Registers -----------</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">posedge</span> clk<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">~</span>reset<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>w_grf_we <span class="token operator">&&</span> <span class="token punctuation">(</span>w_grf_addr <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token property">$display</span><span class="token punctuation">(</span><span class="token string">"%d@%h: $%d <= %h"</span><span class="token punctuation">,</span> <span class="token property">$time</span><span class="token punctuation">,</span> w_inst_addr<span class="token punctuation">,</span> w_grf_addr<span class="token punctuation">,</span> w_grf_wdata<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token comment" spellcheck="true">// ----------- For Interrupt -----------</span> <span class="token keyword">wire</span> <span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">0</span><span class="token punctuation">]</span> fixed_macroscopic_pc<span class="token punctuation">;</span> <span class="token keyword">assign</span> fixed_macroscopic_pc <span class="token operator">=</span> macroscopic_pc <span class="token operator">&</span> <span class="token number">32'hfffffffc</span><span class="token punctuation">;</span> <span class="token keyword">parameter</span> exception_pc <span class="token operator">=</span> <span class="token number">32'h00003018</span><span class="token punctuation">;</span> <span class="token keyword">integer</span> exception_count<span class="token punctuation">;</span> <span class="token keyword">integer</span> needInterrupt<span class="token punctuation">;</span> <span class="token keyword">initial</span> <span class="token keyword">begin</span> needInterrupt <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> exception_count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token property">$display</span><span class="token punctuation">(</span><span class="token string">"#exception@%h"</span><span class="token punctuation">,</span>exception_pc<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">$display</span><span class="token punctuation">(</span><span class="token string">"#interrupt@1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">$display</span><span class="token punctuation">(</span><span class="token string">"#end@"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token number">#20</span> reset <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token keyword">negedge</span> clk<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>reset<span class="token punctuation">)</span> <span class="token keyword">begin</span> needInterrupt <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> interrupt <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>interrupt<span class="token punctuation">)</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">|</span>m_data_byteen <span class="token operator">&&</span> fixed_addr <span class="token operator">==</span> <span class="token number">32'h7F20</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> interrupt <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>needInterrupt<span class="token punctuation">)</span> <span class="token keyword">begin</span> needInterrupt <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> interrupt <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token keyword">begin</span> <span class="token keyword">case</span> <span class="token punctuation">(</span>fixed_macroscopic_pc<span class="token punctuation">)</span> exception_pc<span class="token punctuation">:</span> <span class="token keyword">begin</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>exception_count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> exception_count <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> interrupt <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">endcase</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token important">always </span><span class="token number">#2</span> clk <span class="token operator"><=</span> <span class="token operator">~</span>clk<span class="token punctuation">;</span><span class="token keyword">endmodule</span></code></pre><p><strong>测试数据</strong></p><pre class=" language-c"><code class="language-c"><span class="token punctuation">.</span>data<span class="token punctuation">.</span>globl TC0_BASE TC1_BASE cnt0 cnt1 cnt0_double cnt1_doubleTC0_BASE<span class="token punctuation">:</span> <span class="token punctuation">.</span>word <span class="token number">0x7f00</span>TC1_BASE<span class="token punctuation">:</span> <span class="token punctuation">.</span>word <span class="token number">0x7f10</span>cnt0<span class="token punctuation">:</span> <span class="token punctuation">.</span>word <span class="token number">1</span>cnt1<span class="token punctuation">:</span> <span class="token punctuation">.</span>word <span class="token number">1</span>cnt0_double<span class="token punctuation">:</span> <span class="token punctuation">.</span>word <span class="token number">0</span>cnt1_double<span class="token punctuation">:</span> <span class="token punctuation">.</span>word <span class="token number">0</span> <span class="token punctuation">.</span>text ori$<span class="token number">28</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0000</span> ori$<span class="token number">29</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0f00</span> mtc0$<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">12</span> <span class="token macro property">#save start address </span> ori $t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x7f00</span> sw $t0<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> ori $t1<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x7f10</span> sw $t1<span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> <span class="token macro property">#set SR included IM, IE, EXL</span> ori $t0<span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0c01</span> mtc0 $t0<span class="token punctuation">,</span>$<span class="token number">12</span> <span class="token macro property">#set Timer0</span> la $t1<span class="token punctuation">,</span> TC0_BASE lw $t1<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span> sw $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span># disable Timer0<span class="token punctuation">.</span>CTRL addiu $t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x80</span># set Timer0<span class="token punctuation">.</span>PRESET sw $t0<span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span> addiu $t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">9</span># set Timer0<span class="token punctuation">.</span>CTRL sw $t0<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span> <span class="token macro property">#set Timer1</span> la $t1<span class="token punctuation">,</span> TC1_BASE lw $t1<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span> sw $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span># disable Timer1<span class="token punctuation">.</span>CTRL addiu $t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x40</span># set Timer1<span class="token punctuation">.</span>PRESET sw $t0<span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span> addiu $t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">9</span># set Timer1<span class="token punctuation">.</span>CTRL sw $t0<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t1<span class="token punctuation">)</span> lui$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> lui$<span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> ori$<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0xffff</span> jslot_ov1 add$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span>slot_ov1<span class="token punctuation">:</span> lui $t0<span class="token punctuation">,</span><span class="token number">0x8000</span> jalslot_ov2 addi$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span>slot_ov2<span class="token punctuation">:</span> ori$t1<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0ba0</span> lui$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x8000</span> lui$<span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0x1000</span> jslot_ov3 sub$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span>slot_ov3<span class="token punctuation">:</span> ori$t2<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x93ac</span> lui$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> lui$<span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> j slot_ov4 add $<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span>slot_ov4<span class="token punctuation">:</span> ori $t2<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x5daa</span> lui$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x7fff</span> lui$<span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0x8000</span> sub$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span> lui$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x8111</span> lui$<span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">0x8111</span> add $<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span> addi $<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">2</span> beq $<span class="token number">0</span><span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span>slot_adel1 addi $<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">3</span> add $<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span> sub$<span class="token number">10</span><span class="token punctuation">,</span> $<span class="token number">8</span><span class="token punctuation">,</span> $<span class="token number">9</span>slot_adel1<span class="token punctuation">:</span>slot_adel2<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x801</span> li $<span class="token number">9</span><span class="token punctuation">,</span><span class="token number">0x800</span> sw $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">9</span><span class="token punctuation">)</span> lh $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_adel3 nop slot_adel3<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x802</span> lw $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_adel4 nop slot_adel4<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x803</span> lhu $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_adel5 nop slot_adel5<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x803</span> lw $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_ades1 nop slot_ades1<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x801</span> sh $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_ades2 nop slot_ades2<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x802</span> sw $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_ades3 nopslot_ades3<span class="token punctuation">:</span> li$<span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">0x801</span> sw $<span class="token number">9</span><span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">8</span><span class="token punctuation">)</span> j slot_combination nop slot_combination<span class="token punctuation">:</span> lui $s0<span class="token punctuation">,</span><span class="token number">0x8000</span> lui $s1<span class="token punctuation">,</span><span class="token number">0x7fff</span> ori $s1<span class="token punctuation">,</span>$s1<span class="token punctuation">,</span><span class="token number">0xffff</span> add $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s0 sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1 addi $<span class="token number">10</span><span class="token punctuation">,</span>$s1<span class="token punctuation">,</span><span class="token number">10</span> sw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> lw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> lhu $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1 addi $<span class="token number">10</span><span class="token punctuation">,</span>$s1<span class="token punctuation">,</span><span class="token number">10</span> sw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> sw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> add $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s0 sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1 mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> add $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s0 sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1 j label_1 add $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s0 sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1label_1<span class="token punctuation">:</span> mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> add $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s0 sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1 mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> add $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s0 bne $<span class="token number">0</span><span class="token punctuation">,</span>$<span class="token number">10</span><span class="token punctuation">,</span>label_2 lw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>label_2<span class="token punctuation">:</span> sub $<span class="token number">10</span><span class="token punctuation">,</span>$s0<span class="token punctuation">,</span>$s1 mult $<span class="token number">10</span><span class="token punctuation">,</span>$<span class="token number">10</span> sh $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1001</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $<span class="token number">10</span><span class="token punctuation">,</span><span class="token function">0x1002</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> nop ori$t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0x0001</span>wait<span class="token punctuation">:</span> lw$k0<span class="token punctuation">,</span> <span class="token function">8</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw$k1<span class="token punctuation">,</span><span class="token function">12</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> bne$k0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> wait nop bne$k1<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> wait nop ori$t0<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0xffff</span> ori$t1<span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0xffff</span>dead_loop<span class="token punctuation">:</span> jdead_loop nop</code></pre><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><p><strong>1、请查阅相关资料,说明鼠标和键盘的输入信号是如何被 CPU 知晓的?</strong><br><strong>答:</strong><br>键盘是常用的输入设备,它是由一组开关矩阵组成,包括数字键、字母键、符号键、功能键及控制键等。每一个按键在计算机中都有它的惟一代码。当按下某个键时,键盘接口将该键的二进制代码送入计算机处理器中,并将按键字符显示在显示器上。当快速大量输入字符,主机来不及处理时,先将这些字符的代码送往内存的键盘缓冲区,然后再从该缓冲区中取出进行分析处理。键盘接口电路多采用单片微处理器,由它控制整个键盘的工作,如上电时对键盘的自检、键盘扫描、按键代码的产生、发送及与主机的通讯等。</p><p>鼠标是输入设备,鼠标通过南桥将位置位移及点击信息传送给cpu,cpu计算后再将结果等一堆信息传送给显卡,显卡生成图像通过dp、dvi、hdmi等接口输出到显示器。</p><p>总的来说:鼠标和键盘产生中断信号,进入中断处理区的对应位置,将输入信号从鼠标和键盘中读入寄存器。</p><p><strong>2、请思考为什么我们的 CPU 处理中断异常必须是已经指定好的地址?如果你的 CPU 支持用户自定义入口地址,即处理中断异常的程序由用户提供,其还能提供我们所希望的功能吗?如果可以,请说明这样可能会出现什么问题?否则举例说明。(假设用户提供的中断处理程序合法)</strong><br><strong>答:</strong><br>可以,但若用户操作不当可能会对存储有 CPU 初始数据和命令的地址区域进行读写,或将连续的地址空间分割,增加了数据丢失和指令处理混乱的风险,并大大增加了硬件设计的难度。</p><p><strong>3、为何与外设通信需要 Bridge?</strong><br><strong>答:</strong><br>Bridge 实际上是一个大型的多路选择器,其可以使 CPU 以相对固定的方式读取或写入不同的外设,并且在系统需要增添外设时,只需要添加相应的读写地址的映射,可拓展性良好。</p><p><strong>4、请阅读官方提供的定时器源代码,阐述两种中断模式的异同,并分别针对每一种模式绘制状态移图。</strong><br><strong>答:</strong></p><ul><li>模式0:<br>当计数器倒计数为 0 后,计数器停止计数,此时控制寄存器中的使能 Enable 自动变为 0。当使能 Enable 被设置为 1 后,初值寄存器值再次被加载至计数器,计数器重新启动倒计数。通常用于产生定时中断。</li><li>模式1:<br>当计数器倒计数为 0 后,初值寄存器值被自动加载至计数器,计数器继续倒计数。常用于产生周期性脉冲。</li></ul><p><strong>5、倘若中断信号流入的时候,在检测宏观 PC 的一级如果是一条空泡(你的 CPU 该级所有信息均为空)指令,此时会发生什么问题?在此例基础上请思考:在 P7 中,清空流水线产生的空泡指令应该保留原指令的哪些信息?</strong><br><strong>答:</strong><br>会丢失上一级指令的延迟槽信息、可能记录的错误信息;这样处理也与“单周期的封装”的目的相违背,因为可能会凭空生成 nop 指令。详细处理见<strong>异常的处理</strong>一节。</p><p><strong>6、为什么 jalr 指令为什么不能写成 jalr $31, $31?</strong><br><strong>答:</strong><br>若读写同一寄存器,则当前pc的值加4会被再次写入该寄存器,若产生异常,则当前CPU结构无法消除其已经改变的值,造成错误的指令行为。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 计算机组成 </tag>
<tag> Verilog </tag>
</tags>
</entry>
<entry>
<title>2022北航计算机组成原理 Project 6</title>
<link href="/2022/11/15/CO_P6/"/>
<url>/2022/11/15/CO_P6/</url>
<content type="html"><![CDATA[<h1 id="流水线CPU(存储器外置)设计文档"><a href="#流水线CPU(存储器外置)设计文档" class="headerlink" title="流水线CPU(存储器外置)设计文档"></a>流水线CPU(存储器外置)设计文档</h1><hr><h2 id="设计草稿及模块安排"><a href="#设计草稿及模块安排" class="headerlink" title="设计草稿及模块安排"></a>设计草稿及模块安排</h2><h3 id="整体模块架构"><a href="#整体模块架构" class="headerlink" title="整体模块架构"></a>整体模块架构</h3><blockquote><p>mips</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller<br>W_Controller</p></blockquote></blockquote><blockquote><blockquote><p>Blocker</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller</p></blockquote></blockquote></blockquote><blockquote><blockquote><p>F_PC<br>FD_REG<br>D_GRF<br>D_ext<br>D_cmp<br>D_NPC<br>DE_REG<br>E_ALU<br>EM_REG<br>M_DM_IN<br>M_DM_OUT<br>MW_REG</p></blockquote></blockquote><hr><h3 id="模块安排"><a href="#模块安排" class="headerlink" title="模块安排"></a>模块安排</h3><p><strong>mips</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>i_inst_rdata</td><td>32</td><td>out</td><td>i_inst_addr 对应的 32 位指令</td></tr><tr><td>m_data_rdata</td><td>32</td><td>out</td><td>m_data_addr 对应的 32 位数据</td></tr><tr><td>i_inst_addr</td><td>32</td><td>out</td><td>F级的pc</td></tr><tr><td>m_data_addr</td><td>32</td><td>out</td><td>数据存储器读写地址</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>数据存储器待写入数据</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>写数据存储器的字节使能信号</td></tr><tr><td>m_inst_addr</td><td>32</td><td>out</td><td>M级的pc</td></tr><tr><td>w_grf_we</td><td>1</td><td>out</td><td>GRF 写使能信号</td></tr><tr><td>w_grf_addr</td><td>5</td><td>out</td><td>GRF 中待写入寄存器编号</td></tr><tr><td>w_grf_wdata</td><td>32</td><td>out</td><td>GRF 中待写入数据</td></tr><tr><td>w_inst_addr</td><td>32</td><td>out</td><td>W级pc</td></tr></tbody></table><p>mips模块是整个系统的主模块,其主要承担整体架构中各分模块以及cpu与<strong>外置指令、数据存储器</strong>的线路连接任务,其中对流水线D,E,M,W每一级调用模块Controller来输出控制信号并以此为依据控制转发,并调用模块Blocker处理阻塞情况。</p><p><strong>F_PC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>next_pc</td><td>32</td><td>in</td><td>下一条执行指令地址</td></tr><tr><td>pc</td><td>32</td><td>out</td><td>当前执行指令地址</td></tr></tbody></table><p>F_PC即F级的指令取址器,定位执行指令的地址;由于流水线CPU可能存在的<strong>阻塞处理,这里使用en端实现,需阻塞则置为0,暂停更新pc值</strong>。</p><p><strong>FD_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>F_pc</td><td>32</td><td>in</td><td>F级当前执行指令的地址</td></tr><tr><td>F_instr</td><td>32</td><td>in</td><td>F级当前的执行指令</td></tr><tr><td>D_pc</td><td>32</td><td>out</td><td>D级当前需执行指令的地址</td></tr><tr><td>D_instr</td><td>32</td><td>out</td><td>D级当前需执行的指令</td></tr></tbody></table><p>FD_REG即保存前一周期F级得到的指令及状态并在本周期将其传送到D级的寄存器,其中引入flush即刷新信号也是为了服务于阻塞机制,但在目前的指令集下,其在FD_REG中无作用,将在DE_REG中介绍;需要注意的是,<strong>阻塞发生时,该寄存器的en也应置为0</strong>。</p><p><strong>D_GRF</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>W级指令地址</td></tr><tr><td>A1</td><td>5</td><td>in</td><td>读取的寄存器1编号</td></tr><tr><td>A2</td><td>5</td><td>in</td><td>读取的寄存器2编号</td></tr><tr><td>A3</td><td>5</td><td>in</td><td>需写入的寄存器编号</td></tr><tr><td>WD</td><td>32</td><td>in</td><td>需写入寄存器的数据</td></tr><tr><td>RD1</td><td>32</td><td>out</td><td>从寄存器1读出的数据</td></tr><tr><td>RD2</td><td>32</td><td>out</td><td>从寄存器2读出的数据</td></tr></tbody></table><p>D_GRF即D级的寄存器文件,值得注意的是其中pc、A3和WD来自W级,且可能产生冒险行为,这里采用<strong>寄存器内部转发</strong>来解决W级的回写与D级读寄存器地址冲突的情况,采用<strong>外部转发</strong>解决E,M与D级产生的数据冲突;具体操作见<strong>冲突处理</strong>一节。</p><p><strong>D_ext</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>imm16</td><td>16</td><td>in</td><td>16位立即数输入</td></tr><tr><td>extop</td><td>1</td><td>in</td><td>扩展方式控制:0:0扩展;1:符号扩展</td></tr><tr><td>imm32</td><td>32</td><td>out</td><td>扩展后的32位立即数</td></tr></tbody></table><p>D_ext即安排在D级的立即数扩展模块</p><p><strong>D_cmp</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>rt_data</td><td>32</td><td>in</td><td>从寄存器2读出的数据(可能是转发过来的)</td></tr><tr><td>cmpop</td><td>3</td><td>in</td><td>选择比较方式,对应beq、bne等指令</td></tr><tr><td>jump</td><td>1</td><td>out</td><td>根据指令比较方式和比较结果决定是否跳转,跳转则置1</td></tr></tbody></table><p>D_cmp即D级的比较器,为了减少判断跳转指令可能带来的流水线上的无效指令,将分支判断提前到D级,那么即使发生跳转,需要作废的指令只有F级,此时若跳转也约定F级指令不作废,即得到<strong>延时槽</strong>。</p><p><strong>D_NPC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>NPCop</td><td>3</td><td>in</td><td>根据指令选择的下一条指令地址的操作选择信号</td></tr><tr><td>F_pc</td><td>32</td><td>in</td><td>当前F级的指令地址</td></tr><tr><td>D_pc</td><td>32</td><td>in</td><td>当前D级的指令地址</td></tr><tr><td>b_jump</td><td>1</td><td>in</td><td>来自D_cmp的跳转判断信号</td></tr><tr><td>imm16</td><td>16</td><td>in</td><td>16位地址偏移量</td></tr><tr><td>imm26</td><td>26</td><td>in</td><td>26位伪直接寻址的指令地址</td></tr><tr><td>rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>next_pc</td><td>32</td><td>out</td><td>经判断计算得到的下一条执行指令的地址</td></tr></tbody></table><p>D_NPC即D级的指令更新器,值得注意的是若处理b这一类指令满足条件应在跳转至<code>D_pc + 4 + {{14{imm16[15]}},imm16,2'b00}</code>,而若不需要跳转则下一条指令地址为<code>F_pc+4</code>。值得注意的一点是若imm16 = 0则由于延时槽的存在且D_pc+4 = F_pc该跳转指令的下一条指令会被执行<strong>两次</strong>。</p><p><strong>DE_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>D_pc</td><td>32</td><td>in</td><td>D级正在执行的指令地址</td></tr><tr><td>D_instr</td><td>32</td><td>in</td><td>D级正在执行的指令</td></tr><tr><td>D_rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>D_rt_data</td><td>32</td><td>in</td><td>从寄存器2读出的数据(可能是转发过来的)</td></tr><tr><td>D_imm32</td><td>32</td><td>in</td><td>在D级被扩展得到的32位立即数</td></tr><tr><td>D_b_jump</td><td>1</td><td>in</td><td>在D级经判断得到的b指令跳转信号</td></tr><tr><td>E_pc</td><td>32</td><td>out</td><td>E级需执行的指令地址</td></tr><tr><td>E_instr</td><td>32</td><td>out</td><td>E级需执行的指令</td></tr><tr><td>E_rs_data</td><td>32</td><td>out</td><td>传递到E级的寄存器1数据</td></tr><tr><td>E_rt_data</td><td>32</td><td>out</td><td>传递到E级的寄存器2数据</td></tr><tr><td>E_imm32</td><td>32</td><td>out</td><td>传递到E级的32位立即数</td></tr><tr><td>E_b_jump</td><td>1</td><td>out</td><td>传递到E级的b指令跳转信号</td></tr></tbody></table><p>DE_REG即保存前一周期D级得到的指令及状态并在本周期将其传送到E级的寄存器,需要注意的是<strong>只要处于阻塞状态,该寄存器的flush置1</strong>,即在流水线中产生“气泡”,“气泡”随流水线传递,达到等待直至阻塞状态解除的目的。</p><p><strong>E_ALU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>A</td><td>32</td><td>in</td><td>操作数1</td></tr><tr><td>B</td><td>32</td><td>in</td><td>操作数2</td></tr><tr><td>ALUCtrl</td><td>4</td><td>in</td><td>ALU运算控制信号</td></tr><tr><td>ALUResult</td><td>32</td><td>out</td><td>运算结果</td></tr></tbody></table><p>E_ALU即安排在E级的运算单元。</p><p><strong>E_MDU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>A</td><td>32</td><td>in</td><td>操作数1</td></tr><tr><td>B</td><td>32</td><td>in</td><td>操作数2</td></tr><tr><td>Start</td><td>1</td><td>in</td><td>乘除运算开始信号</td></tr><tr><td>Busy</td><td>1</td><td>out</td><td>乘除运算正在进行信号</td></tr><tr><td>HI</td><td>32</td><td>out</td><td>高位寄存器</td></tr><tr><td>LO</td><td>32</td><td>out</td><td>低位寄存器</td></tr></tbody></table><p>E_MDU即安排在E级的乘除相关指令(<code>mult, multu, div, divu, mfhi, mflo, mthi, mtlo</code>)处理单元。乘除法部件的执行乘法的时间为 5 个时钟周期,执行除法的时间为 10 个时钟周期(包含写入内部的 HI 和 LO 寄存器);通过只能有效 1 个时钟周期的 Start 信号来启动乘除法运算,通过 Busy 输出标志来反映这个延迟。</p><p><strong>EM_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>E_pc</td><td>32</td><td>in</td><td>E级正在执行的指令地址</td></tr><tr><td>E_instr</td><td>32</td><td>in</td><td>E级正在执行的指令</td></tr><tr><td>E_ALUResult</td><td>32</td><td>in</td><td>E级ALU的运算结果</td></tr><tr><td>E_MDUResult</td><td>32</td><td>in</td><td>E级MDU的运算结果(HI/LO)</td></tr><tr><td>E_rt_data</td><td>32</td><td>in</td><td>E级保存的寄存器2数据</td></tr><tr><td>E_imm32</td><td>32</td><td>in</td><td>E级保存的32位立即数</td></tr><tr><td>E_b_jump</td><td>1</td><td>in</td><td>E级保存的b指令跳转信号</td></tr><tr><td>M_pc</td><td>32</td><td>out</td><td>M级需执行的指令地址</td></tr><tr><td>M_instr</td><td>32</td><td>out</td><td>M级需执行的指令</td></tr><tr><td>M_ALUResult</td><td>32</td><td>out</td><td>传递到M级的ALU的运算结果</td></tr><tr><td>M_MDUResult</td><td>32</td><td>out</td><td>传递到M级的MDU的运算结果</td></tr><tr><td>M_rt_data</td><td>32</td><td>out</td><td>传递到M级的寄存器2数据</td></tr><tr><td>M_imm32</td><td>32</td><td>out</td><td>传递到M级的32位立即数</td></tr><tr><td>M_b_jump</td><td>1</td><td>out</td><td>传递到M级的b指令跳转信号</td></tr></tbody></table><p>EM_REG即保存前一周期E级得到的指令及状态并在本周期将其传送到M级的寄存器。</p><p><strong>M_DM_IN</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>DMop</td><td>3</td><td>in</td><td>存取数据存储器方式选择信号</td></tr><tr><td>MemAddr</td><td>32</td><td>in</td><td>存取数据存储器地址</td></tr><tr><td>dataIn</td><td>32</td><td>in</td><td>待处理的写入外置存储器的数据</td></tr><tr><td>WriteEnable</td><td>1</td><td>in</td><td>写存储器使能信号</td></tr><tr><td>m_data_byteen</td><td>4</td><td>out</td><td>写数据存储器的字节使能信号</td></tr><tr><td>m_data_wdata</td><td>32</td><td>out</td><td>写入外置存储器的数据</td></tr></tbody></table><p>M_DM_IN即安排再M级的外置数据存储器写入数据的预处理器。</p><p><strong>M_DM_OUT</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>DMop</td><td>3</td><td>in</td><td>存取数据存储器方式选择信号</td></tr><tr><td>MemAddr</td><td>32</td><td>in</td><td>存取数据存储器地址</td></tr><tr><td>m_data_rdata</td><td>32</td><td>in</td><td>从外置存储器读出的数据</td></tr><tr><td>dataOut</td><td>32</td><td>out</td><td>处理后的读出数据</td></tr></tbody></table><p>M_DM_OUT即安排再M级的外置数据存储器读出的数据的处理器。</p><p><strong>MW_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>M_pc</td><td>32</td><td>in</td><td>M级正在执行的指令地址</td></tr><tr><td>M_instr</td><td>32</td><td>in</td><td>M级正在执行的指令</td></tr><tr><td>M_ALUResult</td><td>32</td><td>in</td><td>M级保存的ALU的运算结果</td></tr><tr><td>M_MDUResult</td><td>32</td><td>in</td><td>M级保存的MDU的运算结果</td></tr><tr><td>M_dataOut</td><td>32</td><td>in</td><td>M级读出的存储器数据</td></tr><tr><td>M_b_jump</td><td>1</td><td>in</td><td>M级保存的b指令跳转信号</td></tr><tr><td>W_pc</td><td>32</td><td>out</td><td>W级需执行的指令地址</td></tr><tr><td>W_instr</td><td>32</td><td>out</td><td>W级需执行的指令</td></tr><tr><td>W_ALUResult</td><td>32</td><td>out</td><td>传递到W级的ALU的运算结果</td></tr><tr><td>W_MDUResult</td><td>32</td><td>out</td><td>传递到W级的MDU的运算结果</td></tr><tr><td>W_dataOut</td><td>32</td><td>out</td><td>传递到W级的存储器读出数据</td></tr><tr><td>W_b_jump</td><td>1</td><td>out</td><td>传递到W级的b指令跳转信号</td></tr></tbody></table><p>MW_REG即保存前一周期M级得到的指令及状态并在本周期将其传送到W级的寄存器。</p><p><strong>Controller</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>instr</td><td>32</td><td>in</td><td>32位指令</td></tr><tr><td>b_jump</td><td>1</td><td>in</td><td>b指令跳转信号</td></tr><tr><td>rs</td><td>5</td><td>out</td><td>指令的21-25位,寄存器1编号</td></tr><tr><td>rt</td><td>5</td><td>out</td><td>指令的16-20位,寄存器2编号</td></tr><tr><td>rd</td><td>5</td><td>out</td><td>指令的11-15位,寄存器3编号</td></tr><tr><td>shamt</td><td>5</td><td>out</td><td>指令的6-10位,多用于移位指令的位移量</td></tr><tr><td>imm16</td><td>16</td><td>out</td><td>指令的0-15位,16位立即数</td></tr><tr><td>imm26</td><td>26</td><td>out</td><td>指令的0-25位,26位立即数</td></tr><tr><td>ALUCtrl</td><td>4</td><td>out</td><td>ALU运算操作选择信号</td></tr><tr><td>ALU_Asel</td><td>2</td><td>out</td><td>ALU操作数1选择信号</td></tr><tr><td>ALU_Bsel</td><td>2</td><td>out</td><td>ALU操作数2选择信号</td></tr><tr><td>MDUCtrl</td><td>3</td><td>out</td><td>MDU运算选择信号</td></tr><tr><td>MDU_Start</td><td>1</td><td>out</td><td>乘除运算开始信号</td></tr><tr><td>cmpop</td><td>3</td><td>out</td><td>比较操作选择信号</td></tr><tr><td>extop</td><td>1</td><td>out</td><td>位拓展操作选择信号</td></tr><tr><td>NPCop</td><td>3</td><td>out</td><td>指令地址更新操作选择信号</td></tr><tr><td>DMop</td><td>3</td><td>out</td><td>存储器读/写数据操作选择信号:字/半字/字节</td></tr><tr><td>DM_WriteEnable</td><td>1</td><td>out</td><td>外置数据存储器写使能信号</td></tr><tr><td>GRF_WriteEnable</td><td>1</td><td>out</td><td>寄存器文件写使能信号</td></tr><tr><td>GRF_A3</td><td>5</td><td>out</td><td>寄存器文件写数据地址</td></tr><tr><td>WDSel</td><td>2</td><td>out</td><td>寄存器写入数据选择信号</td></tr><tr><td>load</td><td>1</td><td>out</td><td>读取数据存储器指令识别信号</td></tr><tr><td>store</td><td>1</td><td>out</td><td>写入数据存储器型指令识别信号</td></tr><tr><td>cal_r</td><td>1</td><td>out</td><td>寄存器操作计算指令识别信号</td></tr><tr><td>cal_i</td><td>1</td><td>out</td><td>立即数操作计算指令识别信号</td></tr><tr><td>shift_s</td><td>1</td><td>out</td><td>固定位移指令识别信号</td></tr><tr><td>shift_v</td><td>1</td><td>out</td><td>可变位移指令识别信号</td></tr><tr><td>branch</td><td>1</td><td>out</td><td>b型跳转指令识别信号</td></tr><tr><td>j_reg</td><td>1</td><td>out</td><td>从寄存器获取跳转地址的跳转指令识别信号</td></tr><tr><td>j_imm</td><td>1</td><td>out</td><td>以立即数为跳转地址的跳转指令识别信号</td></tr><tr><td>j_link</td><td>1</td><td>out</td><td>跳转并链接指令识别信号</td></tr><tr><td>mul_div</td><td>1</td><td>out</td><td>乘除指令识别信号</td></tr><tr><td>mt</td><td>1</td><td>out</td><td>向 HI/LO 寄存器写入指令信号</td></tr><tr><td>mf</td><td>1</td><td>out</td><td>从 HI/LO 寄存器读出数据写入寄存器文件指令识别信号</td></tr></tbody></table><p>Controller即通用控制器,在mips模块中,在D,E,M,W每一级被调用,接收在相应级所需的状态信息,达到分布式译码的目的,以但前级的指令和状态为依据,发出控制信号,操作数据通路,控制转发操作;在Blocker模块中,在D,E,M级调用,发出指令识别信号以计算 Tuse 和 Tnew ,为是否阻塞提供依据。</p><p><strong>Blocker</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>D_instr</td><td>32</td><td>in</td><td>D级正在执行的指令</td></tr><tr><td>E_instr</td><td>32</td><td>in</td><td>E级正在执行的指令</td></tr><tr><td>M_instr</td><td>32</td><td>in</td><td>M级正在执行的指令</td></tr><tr><td>E_MDU_Start</td><td>1</td><td>in</td><td>MDU开始执行乘除指令信号</td></tr><tr><td>E_MDU_Busy</td><td>1</td><td>in</td><td>MDU正在执行乘除指令信号</td></tr><tr><td>ifBlock</td><td>1</td><td>out</td><td>阻塞操作使能信号,需阻塞置1</td></tr></tbody></table><p>Blocker即阻塞控制器,根据Controller的译码结果,计算D_Tuse_rs,D_Tuse_rt,E_Tnew,M_Tnew(由于当前指令集W_Tnew恒为0故先不作计算),再结合寄存器读写信息使用AT模型控制输出的阻塞信号。</p><hr><h2 id="冲突处理"><a href="#冲突处理" class="headerlink" title="冲突处理"></a>冲突处理</h2><p>在流水线CPU中,由于多条指令同时存在于流水线上,且在同一周期内执行不同的指令操作,这可能引发由于硬件资源重叠和指令间依赖性而导致的冲突问题;当前指令集下冲突有以下2种可能:</p><ul><li><strong>寄存器文件中的寄存器被同时读写</strong></li><li><strong>后面指令在需要使用数据时,前面供给的数据还没有存入寄存器堆</strong></li></ul><p>本节主要讨论阻塞和转发处理冲突的情况判断和实现方式。</p><hr><h3 id="阻塞操作"><a href="#阻塞操作" class="headerlink" title="阻塞操作"></a>阻塞操作</h3><p>阻塞,顾名思义使流水线停在某一指令,需等待某种条件解除阻塞状态。</p><p><strong>何时阻塞</strong><br>后面指令(记为B)在需要使用数据时,前面指令(记为A)供给的数据还没有<strong>产生并写入流水级寄存器</strong>,这时转发无源头 <strong>(转发的源头都是流水级寄存器存储的数据,故不能认为数据产生后可被立即转发)</strong> ,唯一的方法是让B等待,直到A在流水线某一级产生所需数据时解除,再考虑转发或直接使用。<br>这里采用Tuse–Tnew模型判断。</p><ul><li>Tuse:某指令位于 <strong>D</strong> 级的时候,再经过多少个时钟周期就必须要使用相应的数据。</li><li>Tnew:位于某个流水级的某个指令,它经过多少个时钟周期可以<strong>算出结果</strong>并且<strong>存储到流水级寄存器</strong>里。</li></ul><p>具体各指令的Tuse,Tnew参见文件夹内表格Tuse&&Tnew。</p><p>由此,可以得到结论 <strong>Tuse < Tnew 且读写地址重叠(均不为$0)</strong> 时必须进行相应阻塞操作。</p><p>加入乘除指令后,由于乘除槽的存在,MDU在进行运算时,后续的乘除相关指令应被阻塞在D级,故需要额外为此添加一个阻塞信号。</p><p>当前指令集需阻塞的情况代码表示如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">wire</span> E_ifBlock_rs <span class="token operator">=</span> <span class="token punctuation">(</span>E_GRF_A3 <span class="token operator">==</span> D_rs <span class="token operator">&&</span> D_rs <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rs <span class="token operator"><</span> E_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> E_ifBlock_rt <span class="token operator">=</span> <span class="token punctuation">(</span>E_GRF_A3 <span class="token operator">==</span> D_rt <span class="token operator">&&</span> D_rt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rt <span class="token operator"><</span> E_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_rs <span class="token operator">=</span> <span class="token punctuation">(</span>M_GRF_A3 <span class="token operator">==</span> D_rs <span class="token operator">&&</span> D_rs <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rs <span class="token operator"><</span> M_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_rt <span class="token operator">=</span> <span class="token punctuation">(</span>M_GRF_A3 <span class="token operator">==</span> D_rt <span class="token operator">&&</span> D_rt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rt <span class="token operator"><</span> M_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> E_ifBlock_MDU <span class="token operator">=</span> <span class="token punctuation">(</span>D_mul_div <span class="token operator">|</span> D_mf <span class="token operator">|</span> D_mt<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>E_MDU_Busy <span class="token operator">|</span> E_MDU_Start<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> ifBlock <span class="token operator">=</span> E_ifBlock_rs <span class="token operator">|</span> E_ifBlock_rt <span class="token operator">|</span> M_ifBlock_rs <span class="token operator">|</span> M_ifBlock_rt <span class="token operator">|</span> E_ifBlock_MDU<span class="token punctuation">;</span></code></pre><p><strong>如何阻塞</strong><br>自此,我们得到了阻塞信号<code>ifBlock</code><br>以此为依据操作阻塞情况的数据通路:</p><ul><li>将F_IFU和FD_REG的使能信号(en)置为0,不再更新并发送新的指令信号,达到使进入流水线的指令滞留在<strong>D级</strong>的目的。</li><li>将DE_REG的刷新信号(flush)置为1,使向E级发送的指令为nop,即产生“气泡”填充流水线;注意,仅需在此寄存器刷新,因为只要处于阻塞状态,该寄存器不断产生“气泡”,而这些“气泡”随时钟周期向后移动填充流水线各级。</li><li>对于不同指令,当 <strong>Tuse >= Tnew</strong> 或 <strong>E_MDU_Busy = 0, E_MDU_Start = 0</strong>时解除阻塞状态,使能信号置为1,刷新信号置为0,开始考虑转发,继续流水。</li></ul><p>具体代码实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> PC_en <span class="token operator">=</span> <span class="token operator">!</span>ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> FD_REG_en <span class="token operator">=</span> <span class="token operator">!</span>ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> DE_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> EM_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> MW_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> FD_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> DE_REG_flush <span class="token operator">=</span> ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> EM_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> MW_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></code></pre><hr><h3 id="转发操作"><a href="#转发操作" class="headerlink" title="转发操作"></a>转发操作</h3><p>转发,即将先进入流水线的指令产生的数据根据条件发送给后进入的指令。</p><p><strong>何时转发</strong><br>前面指令供给的数据,而后面指令在需要使用数据时,前面供给的数据<strong>已经产生且写入流水级寄存器但还没有存入寄存器堆</strong>,导致后面的指令在GRF中取不到正确的值,故当两个流水级出现读写寄存器的重叠时,(在无需阻塞或阻塞完成时)应考虑转发。</p><p><strong>如何转发</strong><br>在当前指令级下,仅存在:</p><ul><li>W向D级转发(寄存器内自转发)</li><li>E,M向D级转发</li><li>M,W向E级转发</li><li>W向M级转发<br>具体转发关系见文件夹下表格 hazard_and_relocate</li></ul><p>具体代码实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token comment" spellcheck="true">//寄存器内自转发</span> <span class="token keyword">assign</span> RD1 <span class="token operator">=</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span>A3 <span class="token operator">&&</span> A1<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> regFile<span class="token punctuation">[</span>A1<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> RD2 <span class="token operator">=</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span>A3 <span class="token operator">&&</span> A2<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> regFile<span class="token punctuation">[</span>A2<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向D级转发</span> <span class="token keyword">assign</span> D_Forward_rs_data <span class="token operator">=</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> E_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> E_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> D_rs_data<span class="token punctuation">;</span> <span class="token keyword">assign</span> D_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> E_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> E_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> D_rt_data<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向E级转发</span> <span class="token keyword">assign</span> E_Forward_rs_data <span class="token operator">=</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> E_rs_data<span class="token punctuation">;</span> <span class="token keyword">assign</span> E_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> E_rt_data<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向M级转发</span> <span class="token keyword">assign</span> M_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>M_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>M_rt <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> M_rt_data<span class="token punctuation">;</span></code></pre><p>值得注意的是,这种转发方式的正确性是由<strong>阻塞机制</strong>和<strong>转发优先级</strong>决定的。<br>所谓优先级即向每一级转发时,依次沿流水线检索此级的下级,满足条件即转发,若都无需转发,则采用本级读出的寄存器值,这在代码中有所体现。<br>但可能存在这样两个问题<br>1.如需要向D级转发某数据,此数据在E级产生但未写入流水级寄存器,直至下个时钟上升沿才写入EM_REG(M级),则按优先级优先转发了DE_REG(E级)保存的数据,这是否会导致错误?<br><strong>答</strong>:实际上不会,由于阻塞机制的存在,当数据在E级产生但未写入流水级寄存器时,流水线被阻塞,指令停滞,此时转发的数据也起不到作用,待到下个时钟上升沿才写入EM_REG(M级),转发来自M级的数据会直接将错误值<strong>覆盖</strong>,阻塞状态解除,流水线正常执行。</p><p>2.如果转发到的寄存器在此指令期间不被读(可以不转发)将一个值存入其中会不会有影响?<br><strong>答</strong>:不会,若该寄存器不被读,则其要么被写,要么不参与本指令的执行,那么对于第一种情况,该指令写入时会将原本转发的值覆盖;对于第二种情况,该寄存器在流水级中的表现实际是相当于提前被写入了(实际上写入还是要到转发的源头指令的W级)。</p><hr><h2 id="测试方案"><a href="#测试方案" class="headerlink" title="测试方案"></a>测试方案</h2><p><strong>自动随机生成测试程序</strong></p><pre class=" language-cpp"><code class="language-cpp"><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><cstdio></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><algorithm></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><queue></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><map></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><cstring></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><cmath></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><cstdlib></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><set></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><unordered_map></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><vector></span></span><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><ctime></span></span><span class="token keyword">typedef</span> <span class="token keyword">long</span> <span class="token keyword">long</span> ll<span class="token punctuation">;</span><span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span> grf<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span><span class="token number">0</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token keyword">int</span> reg<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">31</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">31</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">31</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token keyword">int</span> hi<span class="token punctuation">,</span> lo<span class="token punctuation">;</span><span class="token keyword">int</span> dm<span class="token punctuation">[</span><span class="token number">3075</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token macro property">#<span class="token directive keyword">define</span> R reg[rand() % 16]</span><span class="token macro property">#<span class="token directive keyword">define</span> R_nz reg[rand() % 16+1]</span><span class="token macro property">#<span class="token directive keyword">define</span> I ((rand() + rand()) % 40) * 4</span><span class="token macro property">#<span class="token directive keyword">define</span> B (rand() % 650)</span><span class="token macro property">#<span class="token directive keyword">define</span> TYPE rand()%10 + 1</span><span class="token keyword">void</span> <span class="token function">Div</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"div $%d,$%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rt<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">divu</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"divu $%d,$%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rt<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">mult</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"mult $%d,$%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rt<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">multu</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"multu $%d,$%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rt<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">mfhi</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"mfhi $%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">mflo</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"mflo $%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">mthi</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"mthi $%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">mtlo</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"mtlo $%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">addu</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">,</span> <span class="token keyword">int</span> rd<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"addu $%d,$%d,$%d\n"</span><span class="token punctuation">,</span> rd<span class="token punctuation">,</span> rt<span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>rd<span class="token punctuation">)</span> grf<span class="token punctuation">[</span>rd<span class="token punctuation">]</span> <span class="token operator">=</span> grf<span class="token punctuation">[</span>rs<span class="token punctuation">]</span> <span class="token operator">+</span> grf<span class="token punctuation">[</span>rt<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">subu</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">,</span> <span class="token keyword">int</span> rd<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"subu $%d,$%d,$%d\n"</span><span class="token punctuation">,</span> rd<span class="token punctuation">,</span> rt<span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>rd<span class="token punctuation">)</span> grf<span class="token punctuation">[</span>rd<span class="token punctuation">]</span> <span class="token operator">=</span> grf<span class="token punctuation">[</span>rs<span class="token punctuation">]</span> <span class="token operator">-</span> grf<span class="token punctuation">[</span>rt<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">ori</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">,</span> <span class="token keyword">int</span> imm<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ori $%d,$%d,%d\n"</span><span class="token punctuation">,</span> rt<span class="token punctuation">,</span> rs<span class="token punctuation">,</span> imm<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>rt<span class="token punctuation">)</span> grf<span class="token punctuation">[</span>rt<span class="token punctuation">]</span> <span class="token operator">=</span> grf<span class="token punctuation">[</span>rs<span class="token punctuation">]</span> <span class="token operator">|</span> imm<span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">lui</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">,</span> <span class="token keyword">int</span> imm<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"lui $%d,%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">,</span> imm<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>rs<span class="token punctuation">)</span> grf<span class="token punctuation">[</span>rs<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">1u</span> <span class="token operator">*</span> imm <span class="token operator"><<</span> <span class="token number">16</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">lw</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> imm <span class="token operator">=</span> I<span class="token punctuation">;</span> <span class="token function">subu</span><span class="token punctuation">(</span>rs<span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"lw $%d,%d($%d)\n"</span><span class="token punctuation">,</span> rt<span class="token punctuation">,</span> imm<span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span> grf<span class="token punctuation">[</span>rt<span class="token punctuation">]</span> <span class="token operator">=</span> dm<span class="token punctuation">[</span>imm <span class="token operator">/</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">sw</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> imm <span class="token operator">=</span> I<span class="token punctuation">;</span> <span class="token function">subu</span><span class="token punctuation">(</span>rs<span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"sw $%d,%d($%d)\n"</span><span class="token punctuation">,</span> rt<span class="token punctuation">,</span> imm<span class="token punctuation">,</span> rs<span class="token punctuation">)</span><span class="token punctuation">;</span> dm<span class="token punctuation">[</span>imm <span class="token operator">/</span> <span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">=</span> grf<span class="token punctuation">[</span>rt<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">int</span> jump<span class="token punctuation">[</span><span class="token number">1010</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">beq</span><span class="token punctuation">(</span><span class="token keyword">int</span> rs<span class="token punctuation">,</span> <span class="token keyword">int</span> rt<span class="token punctuation">,</span> <span class="token keyword">int</span> casenum<span class="token punctuation">)</span><span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> jaddr <span class="token operator">=</span> B<span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>jump<span class="token punctuation">[</span>jaddr<span class="token punctuation">]</span><span class="token punctuation">)</span> jaddr <span class="token operator">=</span> B<span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"beq $%d,$%d,endsubtest%d\n"</span><span class="token punctuation">,</span> rs<span class="token punctuation">,</span> rt<span class="token punctuation">,</span> casenum<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"nop\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">srand</span><span class="token punctuation">(</span><span class="token function">time</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">freopen</span><span class="token punctuation">(</span><span class="token string">"mips_code.asm"</span><span class="token punctuation">,</span> <span class="token string">"w"</span><span class="token punctuation">,</span> <span class="token constant">stdout</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ori $1, $0, %d\n"</span><span class="token punctuation">,</span> I<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//printf("lui $1, %d\n", I);</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ori $2, $0, %d\n"</span><span class="token punctuation">,</span> I<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//printf("lui $2, %d\n", I);</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ori $3, $0, %d\n"</span><span class="token punctuation">,</span> I<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//printf("lui $3, %d\n", I);</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ori $31, $0, %d\n"</span><span class="token punctuation">,</span> I<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> T <span class="token operator">=</span> <span class="token number">15</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> T<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">addu</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span> R<span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"jal subtest%d\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"nop\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"back%d:\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"endtest:\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"beq $0, $0, endtest\nnop\n\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> T<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"subtest%d:\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> last_k<span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> j <span class="token operator"><=</span> <span class="token number">15</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> grf<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">int</span> k <span class="token operator">=</span> TYPE<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">||</span> k <span class="token operator">==</span> <span class="token number">4</span> <span class="token operator">||</span> k <span class="token operator">==</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> r <span class="token operator">=</span> <span class="token function">rand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">%</span><span class="token number">4</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">addu</span><span class="token punctuation">(</span>R<span class="token punctuation">,</span> R<span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token function">subu</span><span class="token punctuation">(</span>R<span class="token punctuation">,</span> R<span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token function">ori</span><span class="token punctuation">(</span>R<span class="token punctuation">,</span> R<span class="token punctuation">,</span> I<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//else if(r == 4) lui(R, R, I);</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">||</span> k <span class="token operator">==</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> r <span class="token operator">=</span> <span class="token function">rand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">%</span><span class="token number">2</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">lw</span><span class="token punctuation">(</span>R<span class="token operator">%</span><span class="token number">4</span><span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token function">sw</span><span class="token punctuation">(</span>R<span class="token operator">%</span><span class="token number">4</span><span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token number">3</span> <span class="token operator">||</span> k <span class="token operator">==</span> <span class="token number">7</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>last_k <span class="token operator">!=</span> <span class="token number">3</span> <span class="token operator">||</span> last_k <span class="token operator">!=</span> <span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token function">beq</span><span class="token punctuation">(</span>R<span class="token punctuation">,</span> R<span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>k <span class="token operator">==</span> <span class="token number">8</span> <span class="token operator">||</span> k <span class="token operator">==</span> <span class="token number">9</span> <span class="token operator">||</span> k <span class="token operator">==</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">&</span>#<span class="token number">123</span><span class="token punctuation">;</span> <span class="token keyword">int</span> r <span class="token operator">=</span> <span class="token function">rand</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">%</span><span class="token number">5</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">mult</span><span class="token punctuation">(</span>R<span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token function">multu</span><span class="token punctuation">(</span>R<span class="token punctuation">,</span> R<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token function">Div</span><span class="token punctuation">(</span>R_nz<span class="token punctuation">,</span> R_nz<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token function">divu</span><span class="token punctuation">(</span>R_nz<span class="token punctuation">,</span> R_nz<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token function">mfhi</span><span class="token punctuation">(</span>R_nz<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">6</span><span class="token punctuation">)</span> <span class="token function">mflo</span><span class="token punctuation">(</span>R_nz<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">7</span><span class="token punctuation">)</span> <span class="token function">mthi</span><span class="token punctuation">(</span>R_nz<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>r <span class="token operator">==</span> <span class="token number">8</span><span class="token punctuation">)</span> <span class="token function">mtlo</span><span class="token punctuation">(</span>R_nz<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> last_k <span class="token operator">=</span> k<span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"endsubtest%d:\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"la $ra, back%d\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"jr $ra\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"nop\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"\n\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token operator">&</span>#<span class="token number">125</span><span class="token punctuation">;</span></code></pre><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><p><strong>1、为什么需要有单独的乘除法部件而不是整合进 ALU?为何需要有独立的 HI、LO 寄存器?</strong><br><strong>答:</strong><br>乘除法的运算时间远大于其他运算,若将其整合进ALU,则需要在一个周期内支持包括乘除运算在内的所有运算,整个CPU的时钟周期大大延长;将其独立出来可使用多个时钟周期进行乘除运算。<br>独立的HI,LO寄存器便于存放可能产生的64位数据或商和余数,简化了CPU的数据通路,便于并行指令。</p><p><strong>2、真实的流水线 CPU 是如何使用实现乘除法的?请查阅相关资料进行简单说明。</strong><br><strong>答:</strong><br>乘法:首先CPU会初始化三个通用寄存器用来存放被乘数,乘数,部分积的二进制数,部分积寄存器初始化为0,然后在判断乘数寄存器的低位是低电平还是高电平(0/1):如果为0则将乘数寄存器右移一位,同时将部分积寄存器也右移一位,在位移时遵循计算机位移规则,乘数寄存器低位溢出的一位丢弃,部分积寄存器低位溢出的一位填充到乘数寄存器的高位,同时部分积寄存器高位补0,如果为1则将部分积寄存器加上被乘数寄存器,再进行移位操作。 当所有乘数位处理完成后部分积寄存器做高位乘数寄存器做低位就是最终乘法结果。</p><p>除法:首先CPU会初始化三个寄存器,用来存放被除数,除数,部分商。余数(被除数与除数比较的结果)放到被除数的有效高位上。CPU做除法时和做乘法时是相反的,乘法是右移,除法是左移,乘法做的是加法,除法做的是减法。 首先CPU会把被除数bit位与除数bit位对齐,然后在让对齐的被除数与除数比较(双符号位判断)。 这里说一下什么是双符号位判断: 比如01-10=11(前面的1是符号位) 1-2=-1 计算机通过符号位和后一位的bit位来判断大于和小于,那么01-10=11 就说明01小于10,如果得数为01就代表大于,如果得数为00代表等于。 如果得数大于或等于则将比较的结果放到被除数的有效高位上然后在商寄存器上商:1 并向后多看一位 (上商就是将商的最低位左移1位腾出商寄存器最低位上新的商) 如果得数小于则上商:0 并向后多看一位 然后循环做以上操作当所有的被除数都处理完后,商做结果被除数里面的值就是余数。</p><p><strong>3、请结合自己的实现分析,你是如何处理 Busy 信号带来的周期阻塞的?</strong><br><strong>答:</strong><br>由于乘除槽的存在,MDU在进行运算时,后续的乘除相关指令应被阻塞在D级,故需要额外为此添加一个阻塞信号。</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">wire</span> E_ifBlock_MDU <span class="token operator">=</span> <span class="token punctuation">(</span>D_mul_div <span class="token operator">|</span> D_mf <span class="token operator">|</span> D_mt<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>E_MDU_Busy <span class="token operator">|</span> E_MDU_Start<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>在MDU中设置周期计数变量 cnt ,乘除运算开始则进行计数,通过对cnt的值的判断来判定MDU的工作状态,具体实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token function">if</span><span class="token punctuation">(</span>cnt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token keyword">begin</span> <span class="token function">if</span><span class="token punctuation">(</span>Start<span class="token punctuation">)</span><span class="token keyword">begin</span> Busy <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">// 根据指令类型设定cnt 并执行相应的运算操作</span> <span class="token keyword">case</span> <span class="token punctuation">(</span>MDUCtrl<span class="token punctuation">)</span> <span class="token constant">`MDUCtrl_mult</span><span class="token punctuation">:</span><span class="token keyword">begin</span> cnt <span class="token operator"><=</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span>hi<span class="token punctuation">,</span>lo<span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span> <span class="token operator"><=</span> <span class="token property">$signed</span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token operator">*</span><span class="token property">$signed</span><span class="token punctuation">(</span>B<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token constant">`MDUCtrl_multu</span><span class="token punctuation">:</span><span class="token keyword">begin</span> cnt <span class="token operator"><=</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token operator">&</span><span class="token number">#123</span><span class="token punctuation">;</span>hi<span class="token punctuation">,</span>lo<span class="token operator">&</span><span class="token number">#125</span><span class="token punctuation">;</span> <span class="token operator"><=</span> A<span class="token operator">*</span>B<span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token constant">`MDUCtrl_div</span><span class="token punctuation">:</span><span class="token keyword">begin</span> cnt <span class="token operator"><=</span> <span class="token number">10</span><span class="token punctuation">;</span> lo <span class="token operator"><=</span> <span class="token property">$signed</span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token operator">/</span><span class="token property">$signed</span><span class="token punctuation">(</span>B<span class="token punctuation">)</span><span class="token punctuation">;</span> hi <span class="token operator"><=</span> <span class="token property">$signed</span><span class="token punctuation">(</span>A<span class="token punctuation">)</span><span class="token operator">%</span><span class="token property">$signed</span><span class="token punctuation">(</span>B<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token constant">`MDUCtrl_divu</span><span class="token punctuation">:</span><span class="token keyword">begin</span> cnt <span class="token operator"><=</span> <span class="token number">10</span><span class="token punctuation">;</span> lo <span class="token operator"><=</span> A<span class="token operator">/</span>B<span class="token punctuation">;</span> hi <span class="token operator"><=</span> A<span class="token operator">%</span>B<span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">endcase</span> <span class="token keyword">end</span> <span class="token keyword">else</span> cnt <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token function">if</span><span class="token punctuation">(</span>cnt <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> HI <span class="token operator"><=</span> hi<span class="token punctuation">;</span> LO <span class="token operator"><=</span> lo<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//将运算结果写入HI/LO</span> Busy <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> cnt <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">end</span> <span class="token keyword">else</span> <span class="token keyword">begin</span> cnt <span class="token operator"><=</span> cnt<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//更新cnt</span> <span class="token keyword">end</span></code></pre><p><strong>4、请问采用字节使能信号的方式处理写指令有什么好处?(提示:从清晰性、统一性等角度考虑)</strong><br><strong>答:</strong><br>以 mips_tb 中这段对数据存储器的写入处理为例:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token important">always @</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token keyword">begin</span> fixed_wdata <span class="token operator">=</span> data<span class="token punctuation">[</span>m_data_addr <span class="token operator">>></span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span> fixed_addr <span class="token operator">=</span> m_data_addr <span class="token operator">&</span> <span class="token number">32'hfffffffc</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">24</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">31</span><span class="token punctuation">:</span><span class="token number">24</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">23</span><span class="token punctuation">:</span><span class="token number">16</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">23</span><span class="token punctuation">:</span><span class="token number">16</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">15</span><span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">15</span><span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>m_data_byteen<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span> fixed_wdata<span class="token punctuation">[</span><span class="token number">7</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> m_data_wdata<span class="token punctuation">[</span><span class="token number">7</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">end</span></code></pre><p>可见字节使能信号处理写指令实现十分得清晰,避免了大量的位拼接和分条件写入的情况,对于按字、半字、字节写入的实现通用,统一性好。</p><p><strong>5、请思考,我们在按字节读和按字节写时,实际从 DM 获得的数据和向 DM 写入的数据是否是一字节?在什么情况下我们按字节读和按字节写的效率会高于按字读和按字写呢?</strong><br><strong>答:</strong><br>不是,是一字,然后再依据字节使能信号做处理。处理大量单字节数据,如字符串中的字符时按字节读和按字节写的效率会高于按字读和按字写。</p><p><strong>6、为了对抗复杂性你采取了哪些抽象和规范手段?这些手段在译码和处理数据冲突的时候有什么样的特点与帮助?</strong><br><strong>答:</strong></p><ul><li>指令分类</li></ul><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> load <span class="token operator">=</span> lw <span class="token operator">|</span> lb <span class="token operator">|</span> lbu <span class="token operator">|</span> lh <span class="token operator">|</span> lhu<span class="token punctuation">;</span> <span class="token keyword">assign</span> store <span class="token operator">=</span> sw <span class="token operator">|</span> sb <span class="token operator">|</span> sh<span class="token punctuation">;</span> <span class="token keyword">assign</span> cal_r <span class="token operator">=</span> add <span class="token operator">|</span> sub <span class="token operator">|</span> addu <span class="token operator">|</span> subu <span class="token operator">|</span> _and <span class="token operator">|</span> _or <span class="token operator">|</span> _xor <span class="token operator">|</span> _nor <span class="token operator">|</span> sll <span class="token operator">|</span> srl <span class="token operator">|</span> sra <span class="token operator">|</span> sllv <span class="token operator">|</span> srlv <span class="token operator">|</span> srav <span class="token operator">|</span> slt <span class="token operator">|</span> sltu<span class="token punctuation">;</span> <span class="token keyword">assign</span> cal_i <span class="token operator">=</span> lui <span class="token operator">|</span> ori <span class="token operator">|</span> addi <span class="token operator">|</span> addiu <span class="token operator">|</span> andi <span class="token operator">|</span> xori <span class="token operator">|</span> slti <span class="token operator">|</span> sltiu<span class="token punctuation">;</span> <span class="token keyword">assign</span> shift_s <span class="token operator">=</span> sll <span class="token operator">|</span> srl <span class="token operator">|</span> sra<span class="token punctuation">;</span> <span class="token keyword">assign</span> shift_v <span class="token operator">=</span> sllv <span class="token operator">|</span> srlv <span class="token operator">|</span> srav<span class="token punctuation">;</span> <span class="token keyword">assign</span> branch <span class="token operator">=</span> beq <span class="token operator">|</span> bne <span class="token operator">|</span> blez <span class="token operator">|</span> bgtz <span class="token operator">|</span> bltz <span class="token operator">|</span> bgez<span class="token punctuation">;</span> <span class="token keyword">assign</span> j_imm <span class="token operator">=</span> j <span class="token operator">|</span> jal<span class="token punctuation">;</span> <span class="token keyword">assign</span> j_link <span class="token operator">=</span> jal <span class="token operator">|</span> jalr<span class="token punctuation">;</span> <span class="token keyword">assign</span> j_reg <span class="token operator">=</span> jr <span class="token operator">|</span> jalr<span class="token punctuation">;</span> <span class="token keyword">assign</span> mul_div <span class="token operator">=</span> mult <span class="token operator">|</span> multu <span class="token operator">|</span> div <span class="token operator">|</span> divu<span class="token punctuation">;</span> <span class="token keyword">assign</span> mt <span class="token operator">=</span> mthi <span class="token operator">|</span> mtlo<span class="token punctuation">;</span> <span class="token keyword">assign</span> mf <span class="token operator">=</span> mfhi <span class="token operator">|</span> mflo<span class="token punctuation">;</span></code></pre><p>在Controller模块中对指令进行特性划分以简化译码操作。</p><ul><li>解耦合<br>将数据通路的阻塞,转发分离;将数据通路中零散的选择信号规整到mips主模块中。降低模块间的耦合度,详见整体模块架构。</li></ul><p><strong>7、在本实验中你遇到了哪些不同指令类型组合产生的冲突?你又是如何解决的?相应的测试样例是什么样的?</strong><br><strong>答:</strong><br>数据冲突情况主要沿用P5的情况分析,因为做了指令的归类,故未做太大的修改。需要注意的是乘除指令的加入:<br>在Blocker中需将乘除指令的Tuse,Tnew纳入考虑;<br>在mips中需要添加MDUResult(HI/LO)对写入寄存器以及转发的影响。<br>解决方法即扩展P5的阻塞和转发模块。<br>乘除指令相关的测试:</p><pre class=" language-c"><code class="language-c"><span class="token comment" spellcheck="true">//(1) busy</span>ori $t0<span class="token punctuation">,</span><span class="token number">11</span>ori $t1<span class="token punctuation">,</span><span class="token number">12</span>multu $t0<span class="token punctuation">,</span>$t1nopmflo $t1mfhi $t2mtlo $t2mthi $t1<span class="token comment" spellcheck="true">//(2)start</span>ori $t0<span class="token punctuation">,</span><span class="token number">11</span>ori $t1<span class="token punctuation">,</span><span class="token number">12</span>divu $t0<span class="token punctuation">,</span>$t1mflo $t1mfhi $t2mtlo $t2mthi $t1<span class="token comment" spellcheck="true">//(3)测试乘除法</span>ori $t0<span class="token punctuation">,</span><span class="token number">2</span>ori $t1<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">3</span>mult $t0<span class="token punctuation">,</span>$t1mfhi $a0mflo $a1multu $t0<span class="token punctuation">,</span>$t1mthi $t0mfhi $a2mflo $a3sw $a2<span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>sb $a3<span class="token punctuation">,</span><span class="token function">2</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>ori $t0<span class="token punctuation">,</span><span class="token number">4</span>ori $t1<span class="token punctuation">,</span><span class="token number">5</span>mtlo $t0mult $t0<span class="token punctuation">,</span>$t1mfhi $a0mflo $a1multu $t0<span class="token punctuation">,</span>$t1mfhi $a2mflo $a3sh $a2<span class="token punctuation">,</span><span class="token function">2</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>sb $a3<span class="token punctuation">,</span><span class="token function">13</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>ori $t0<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">3</span>ori $t1<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">5</span>mult $t0<span class="token punctuation">,</span>$t1mfhi $a0mflo $a1multu $t0<span class="token punctuation">,</span>$t1mfhi $a2mflo $a3sw $a2<span class="token punctuation">,</span><span class="token function">16</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>sb $a3<span class="token punctuation">,</span><span class="token function">15</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>ori $t0<span class="token punctuation">,</span><span class="token number">25</span>ori $t1<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">5</span>div $t0<span class="token punctuation">,</span>$t1mfhi $a0mflo $a1divu $t0<span class="token punctuation">,</span>$t1mfhi $a2mflo $a3mthi $a3sw $a2<span class="token punctuation">,</span><span class="token function">4</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>sw $a3<span class="token punctuation">,</span><span class="token function">8</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>ori $t0<span class="token punctuation">,</span><span class="token number">2</span>ori $t1<span class="token punctuation">,</span><span class="token number">5</span>div $t0<span class="token punctuation">,</span>$t1mfhi $a0mflo $a1divu $t0<span class="token punctuation">,</span>$t1mthi $a1mtlo $a2mfhi $a2mflo $a3sb $a2<span class="token punctuation">,</span><span class="token function">1</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>sw $a3<span class="token punctuation">,</span><span class="token function">12</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>ori $t0<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">999</span>ori $t1<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">5</span>div $t0<span class="token punctuation">,</span>$t1mfhi $a0mthi $a0mflo $a1mtlo $a0divu $t0<span class="token punctuation">,</span>$t1mfhi $a2mflo $a3sw $a2<span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span>sb $a3<span class="token punctuation">,</span><span class="token function">4</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span></code></pre><p><strong>8、如果你是手动构造的样例,请说明构造策略,说明你的测试程序如何保证覆盖了所有需要测试的情况;如果你是完全随机生成的测试样例,请思考完全随机的测试程序有何不足之处;如果你在生成测试样例时采用了特殊的策略,比如构造连续数据冒险序列,请你描述一下你使用的策略如何结合了随机性达到强测的效果。</strong><br><strong>答:</strong><br>生成随机样例的同时使用了特殊的策略:</p><ul><li>限制使用寄存器,仅使用$0,$1,$2,$3,$31,以提高数据冲突的频率。</li><li>将test分为几个subtest,用jal,beq指令将其串联,避免了跳转指令地址不合理的情况</li><li>指令绝对数目多,在长时间内多组指令轮测可覆盖绝大部分情况。</li></ul>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 计算机组成 </tag>
<tag> Verilog </tag>
</tags>
</entry>
<entry>
<title>2022北航计算机组成原理 Project 5</title>
<link href="/2022/11/08/CO_P5/"/>
<url>/2022/11/08/CO_P5/</url>
<content type="html"><![CDATA[<h1 id="流水线CPU设计文档"><a href="#流水线CPU设计文档" class="headerlink" title="流水线CPU设计文档"></a>流水线CPU设计文档</h1><hr><h2 id="设计草稿及模块安排"><a href="#设计草稿及模块安排" class="headerlink" title="设计草稿及模块安排"></a>设计草稿及模块安排</h2><h3 id="整体模块架构"><a href="#整体模块架构" class="headerlink" title="整体模块架构"></a>整体模块架构</h3><blockquote><p>mips</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller<br>W_Controller</p></blockquote></blockquote><blockquote><blockquote><p>Blocker</p><blockquote><p>D_Controller<br>E_Controller<br>M_Controller</p></blockquote></blockquote></blockquote><blockquote><blockquote><p>F_IFU<br>FD_REG<br>D_GRF<br>D_ext<br>D_cmp<br>D_NPC<br>DE_REG<br>E_ALU<br>EM_REG<br>M_DM<br>MW_REG</p></blockquote></blockquote><hr><h3 id="模块安排"><a href="#模块安排" class="headerlink" title="模块安排"></a>模块安排</h3><p><strong>mips</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>mips模块是整个系统的主模块,其主要承担整体架构中各分模块的线路连接任务,其中对流水线D,E,M,W每一级调用模块Controller来输出控制信号并以此为依据控制转发,并调用模块Blocker处理阻塞情况。</td><td></td><td></td><td></td></tr></tbody></table><p><strong>F_IFU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>next_pc</td><td>32</td><td>in</td><td>下一条执行指令地址</td></tr><tr><td>pc</td><td>32</td><td>out</td><td>当前执行指令地址</td></tr><tr><td>instr</td><td>32</td><td>out</td><td>当前32位指令</td></tr></tbody></table><p>F_IFU即F级的取指令器,根据指令地址在指令存储器中取指令;由于流水线CPU可能存在的<strong>阻塞处理,这里使用en端实现,需阻塞则置为0,暂停更新pc值</strong>。</p><p><strong>FD_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>F_pc</td><td>32</td><td>in</td><td>F级当前执行指令的地址</td></tr><tr><td>F_instr</td><td>32</td><td>in</td><td>F级当前的执行指令</td></tr><tr><td>D_pc</td><td>32</td><td>out</td><td>D级当前需执行指令的地址</td></tr><tr><td>D_instr</td><td>32</td><td>out</td><td>D级当前需执行的指令</td></tr></tbody></table><p>FD_REG即保存前一周期F级得到的指令及状态并在本周期将其传送到D级的寄存器,其中引入flush即刷新信号也是为了服务于阻塞机制,但在目前的指令集下,其在FD_REG中无作用,将在DE_REG中介绍;需要注意的是,<strong>阻塞发生时,该寄存器的en也应置为0</strong>。</p><p><strong>D_GRF</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>W级指令地址</td></tr><tr><td>A1</td><td>5</td><td>in</td><td>读取的寄存器1编号</td></tr><tr><td>A2</td><td>5</td><td>in</td><td>读取的寄存器2编号</td></tr><tr><td>A3</td><td>5</td><td>in</td><td>需写入的寄存器编号</td></tr><tr><td>WD</td><td>32</td><td>in</td><td>需写入寄存器的数据</td></tr><tr><td>RD1</td><td>32</td><td>out</td><td>从寄存器1读出的数据</td></tr><tr><td>RD2</td><td>32</td><td>out</td><td>从寄存器2读出的数据</td></tr></tbody></table><p>D_GRF即D级的寄存器文件,值得注意的是其中pc、A3和WD来自W级,且可能产生冒险行为,这里采用<strong>寄存器内部转发</strong>来解决W级的回写与D级读寄存器地址冲突的情况,采用<strong>外部转发</strong>解决E,M与D级产生的数据冲突;具体操作见<strong>冲突处理</strong>一节。</p><p><strong>D_ext</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>imm16</td><td>16</td><td>in</td><td>16位立即数输入</td></tr><tr><td>extop</td><td>1</td><td>in</td><td>扩展方式控制:0:0扩展;1:符号扩展</td></tr><tr><td>imm32</td><td>32</td><td>out</td><td>扩展后的32位立即数</td></tr></tbody></table><p>D_ext即安排在D级的立即数扩展模块</p><p><strong>D_cmp</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>rt_data</td><td>32</td><td>in</td><td>从寄存器2读出的数据(可能是转发过来的)</td></tr><tr><td>cmpop</td><td>3</td><td>in</td><td>选择比较方式,对应beq、bne等指令</td></tr><tr><td>jump</td><td>1</td><td>out</td><td>根据指令比较方式和比较结果决定是否跳转,跳转则置1</td></tr></tbody></table><p>D_cmp即D级的比较器,为了减少判断跳转指令可能带来的流水线上的无效指令,将分支判断提前到D级,那么即使发生跳转,需要作废的指令只有F级,此时若跳转也约定F级指令不作废,即得到<strong>延时槽</strong>。</p><p><strong>D_NPC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>NPCop</td><td>3</td><td>in</td><td>根据指令选择的下一条指令地址的操作选择信号</td></tr><tr><td>F_pc</td><td>32</td><td>in</td><td>当前F级的指令地址</td></tr><tr><td>D_pc</td><td>32</td><td>in</td><td>当前D级的指令地址</td></tr><tr><td>b_jump</td><td>1</td><td>in</td><td>来自D_cmp的跳转判断信号</td></tr><tr><td>imm16</td><td>16</td><td>in</td><td>16位地址偏移量</td></tr><tr><td>imm26</td><td>26</td><td>in</td><td>26位伪直接寻址的指令地址</td></tr><tr><td>rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>next_pc</td><td>32</td><td>out</td><td>经判断计算得到的下一条执行指令的地址</td></tr></tbody></table><p>D_NPC即D级的指令更新器,值得注意的是若处理b这一类指令满足条件应在跳转至<code>D_pc + 4 + {{14{imm16[15]}},imm16,2'b00}</code>,而若不需要跳转则下一条指令地址为<code>F_pc+4</code>。值得注意的一点是若imm16 = 0则由于延时槽的存在且D_pc+4 = F_pc该跳转指令的下一条指令会被执行<strong>两次</strong>。</p><p><strong>DE_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>D_pc</td><td>32</td><td>in</td><td>D级正在执行的指令地址</td></tr><tr><td>D_instr</td><td>32</td><td>in</td><td>D级正在执行的指令</td></tr><tr><td>D_rs_data</td><td>32</td><td>in</td><td>从寄存器1读出的数据(可能是转发过来的)</td></tr><tr><td>D_rt_data</td><td>32</td><td>in</td><td>从寄存器2读出的数据(可能是转发过来的)</td></tr><tr><td>D_imm32</td><td>32</td><td>in</td><td>在D级被扩展得到的32位立即数</td></tr><tr><td>D_b_jump</td><td>1</td><td>in</td><td>在D级经判断得到的b指令跳转信号</td></tr><tr><td>E_pc</td><td>32</td><td>out</td><td>E级需执行的指令地址</td></tr><tr><td>E_instr</td><td>32</td><td>out</td><td>E级需执行的指令</td></tr><tr><td>E_rs_data</td><td>32</td><td>out</td><td>传递到E级的寄存器1数据</td></tr><tr><td>E_rt_data</td><td>32</td><td>out</td><td>传递到E级的寄存器2数据</td></tr><tr><td>E_imm32</td><td>32</td><td>out</td><td>传递到E级的32位立即数</td></tr><tr><td>E_b_jump</td><td>1</td><td>out</td><td>传递到E级的b指令跳转信号</td></tr></tbody></table><p>DE_REG即保存前一周期D级得到的指令及状态并在本周期将其传送到E级的寄存器,需要注意的是<strong>只要处于阻塞状态,该寄存器的flush置1</strong>,即在流水线中产生“气泡”,“气泡”随流水线传递,达到等待直至阻塞状态解除的目的。</p><p><strong>E_ALU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>A</td><td>32</td><td>in</td><td>操作数1</td></tr><tr><td>B</td><td>32</td><td>in</td><td>操作数2</td></tr><tr><td>ALUCtrl</td><td>4</td><td>in</td><td>ALU运算控制信号</td></tr><tr><td>ALUResult</td><td>32</td><td>out</td><td>运算结果</td></tr></tbody></table><p>E_ALU即安排在E级的运算单元。</p><p><strong>EM_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>E_pc</td><td>32</td><td>in</td><td>E级正在执行的指令地址</td></tr><tr><td>E_instr</td><td>32</td><td>in</td><td>E级正在执行的指令</td></tr><tr><td>E_ALUResult</td><td>32</td><td>in</td><td>E级ALU的运算结果</td></tr><tr><td>E_rt_data</td><td>32</td><td>in</td><td>E级保存的寄存器2数据</td></tr><tr><td>E_imm32</td><td>32</td><td>in</td><td>E级保存的32位立即数</td></tr><tr><td>E_b_jump</td><td>1</td><td>in</td><td>E级保存的b指令跳转信号</td></tr><tr><td>M_pc</td><td>32</td><td>out</td><td>M级需执行的指令地址</td></tr><tr><td>M_instr</td><td>32</td><td>out</td><td>M级需执行的指令</td></tr><tr><td>M_ALUResult</td><td>32</td><td>out</td><td>传递到M级的ALU的运算结果</td></tr><tr><td>M_rt_data</td><td>32</td><td>out</td><td>传递到M级的寄存器2数据</td></tr><tr><td>M_imm32</td><td>32</td><td>out</td><td>传递到M级的32位立即数</td></tr><tr><td>M_b_jump</td><td>1</td><td>out</td><td>传递到M级的b指令跳转信号</td></tr></tbody></table><p>EM_REG即保存前一周期E级得到的指令及状态并在本周期将其传送到M级的寄存器。</p><p><strong>M_DM</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>M级执行指令地址</td></tr><tr><td>MemAddr</td><td>32</td><td>in</td><td>写/读数据存储器的地址</td></tr><tr><td>dataIn</td><td>32</td><td>in</td><td>写入存储器的数据</td></tr><tr><td>DMop</td><td>3</td><td>in</td><td>存储器读/写数据操作选择信号:字/半字/字节</td></tr><tr><td>WriteEnable</td><td>1</td><td>in</td><td>写使能</td></tr><tr><td>dataOut</td><td>32</td><td>out</td><td>从存储器中读出的数据</td></tr></tbody></table><p>M_DM安排在M级的数据存储器。</p><p><strong>MW_REG</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr><tr><td>flush</td><td>1</td><td>in</td><td>刷新信号,置1则输出全0</td></tr><tr><td>en</td><td>1</td><td>in</td><td>使能信号</td></tr><tr><td>M_pc</td><td>32</td><td>in</td><td>M级正在执行的指令地址</td></tr><tr><td>M_instr</td><td>32</td><td>in</td><td>M级正在执行的指令</td></tr><tr><td>M_ALUResult</td><td>32</td><td>in</td><td>M级保存的ALU的运算结果</td></tr><tr><td>M_dataOut</td><td>32</td><td>in</td><td>M级读出的存储器数据</td></tr><tr><td>M_b_jump</td><td>1</td><td>in</td><td>M级保存的b指令跳转信号</td></tr><tr><td>W_pc</td><td>32</td><td>out</td><td>W级需执行的指令地址</td></tr><tr><td>W_instr</td><td>32</td><td>out</td><td>W级需执行的指令</td></tr><tr><td>W_ALUResult</td><td>32</td><td>out</td><td>传递到W级的ALU的运算结果</td></tr><tr><td>W_dataOut</td><td>32</td><td>out</td><td>传递到W级的存储器读出数据</td></tr><tr><td>W_b_jump</td><td>1</td><td>out</td><td>传递到W级的b指令跳转信号</td></tr></tbody></table><p>MW_REG即保存前一周期M级得到的指令及状态并在本周期将其传送到W级的寄存器。</p><p><strong>Controller</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>instr</td><td>32</td><td>in</td><td>32位指令</td></tr><tr><td>b_jump</td><td>1</td><td>in</td><td>b指令跳转信号</td></tr><tr><td>rs</td><td>5</td><td>out</td><td>指令的21-25位,寄存器1编号</td></tr><tr><td>rt</td><td>5</td><td>out</td><td>指令的16-20位,寄存器2编号</td></tr><tr><td>rd</td><td>5</td><td>out</td><td>指令的11-15位,寄存器3编号</td></tr><tr><td>shamt</td><td>5</td><td>out</td><td>指令的6-10位,多用于移位指令的位移量</td></tr><tr><td>imm16</td><td>16</td><td>out</td><td>指令的0-15位,16位立即数</td></tr><tr><td>imm26</td><td>26</td><td>out</td><td>指令的0-25位,26位立即数</td></tr><tr><td>ALUCtrl</td><td>4</td><td>out</td><td>ALU运算操作选择信号</td></tr><tr><td>ALU_Asel</td><td>2</td><td>out</td><td>ALU操作数1选择信号</td></tr><tr><td>ALU_Bsel</td><td>2</td><td>out</td><td>ALU操作数2选择信号</td></tr><tr><td>cmpop</td><td>3</td><td>out</td><td>比较操作选择信号</td></tr><tr><td>extop</td><td>1</td><td>out</td><td>位拓展操作选择信号</td></tr><tr><td>NPCop</td><td>3</td><td>out</td><td>指令地址更新操作选择信号</td></tr><tr><td>DMop</td><td>3</td><td>out</td><td>存储器读/写数据操作选择信号:字/半字/字节</td></tr><tr><td>DM_WriteEnable</td><td>1</td><td>out</td><td>数据存储器写使能</td></tr><tr><td>GRF_A3</td><td>5</td><td>out</td><td>寄存器文件写数据地址</td></tr><tr><td>WDSel</td><td>2</td><td>out</td><td>寄存器写入数据选择信号</td></tr><tr><td>load</td><td>1</td><td>out</td><td>读取数据存储器指令识别信号</td></tr><tr><td>store</td><td>1</td><td>out</td><td>写入数据存储器型指令识别信号</td></tr><tr><td>cal_r</td><td>1</td><td>out</td><td>寄存器操作计算指令识别信号</td></tr><tr><td>cal_i</td><td>1</td><td>out</td><td>立即数操作计算指令识别信号</td></tr><tr><td>branch</td><td>1</td><td>out</td><td>b型跳转指令识别信号</td></tr><tr><td>j_reg</td><td>1</td><td>out</td><td>从寄存器获取跳转地址的跳转指令识别信号</td></tr><tr><td>j_imm</td><td>1</td><td>out</td><td>以立即数为跳转地址的跳转指令识别信号</td></tr><tr><td>j_link</td><td>1</td><td>out</td><td>跳转并链接指令识别信号</td></tr></tbody></table><p>Controller即通用控制器,在mips模块中,在D,E,M,W每一级被调用,接收在相应级所需的状态信息,达到分布式译码的目的,以但前级的指令和状态为依据,发出控制信号,操作数据通路,控制转发操作;在Blocker模块中,在D,E,M级调用,发出指令识别信号以计算 Tuse 和 Tnew ,为是否阻塞提供依据。</p><p><strong>Blocker</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>D_instr</td><td>32</td><td>in</td><td>D级正在执行的指令</td></tr><tr><td>E_instr</td><td>32</td><td>in</td><td>E级正在执行的指令</td></tr><tr><td>M_instr</td><td>32</td><td>in</td><td>M级正在执行的指令</td></tr><tr><td>ifBlock</td><td>1</td><td>out</td><td>阻塞操作使能信号,需阻塞置1</td></tr></tbody></table><p>Blocker即阻塞控制器,根据Controller的译码结果,计算D_Tuse_rs,D_Tuse_rt,E_Tnew,M_Tnew(由于当前指令集W_Tnew恒为0故先不作计算),再结合寄存器读写信息使用AT模型控制输出的阻塞信号。</p><hr><h2 id="冲突处理"><a href="#冲突处理" class="headerlink" title="冲突处理"></a>冲突处理</h2><p>在流水线CPU中,由于多条指令同时存在于流水线上,且在同一周期内执行不同的指令操作,这可能引发由于硬件资源重叠和指令间依赖性而导致的冲突问题;当前指令集下冲突有以下2种可能:</p><ul><li><strong>寄存器文件中的寄存器被同时读写</strong></li><li><strong>后面指令在需要使用数据时,前面供给的数据还没有存入寄存器堆</strong></li></ul><p>本节主要讨论阻塞和转发处理冲突的情况判断和实现方式。</p><hr><h3 id="阻塞操作"><a href="#阻塞操作" class="headerlink" title="阻塞操作"></a>阻塞操作</h3><p>阻塞,顾名思义使流水线停在某一指令,需等待某种条件解除阻塞状态。</p><p><strong>何时阻塞</strong><br>后面指令(记为B)在需要使用数据时,前面指令(记为A)供给的数据还没有<strong>产生并写入流水级寄存器</strong>,这时转发无源头 <strong>(转发的源头都是流水级寄存器存储的数据,故不能认为数据产生后可被立即转发)</strong> ,唯一的方法是让B等待,直到A在流水线某一级产生所需数据时解除,再考虑转发或直接使用。<br>这里采用Tuse–Tnew模型判断。</p><ul><li>Tuse:某指令位于 <strong>D</strong> 级的时候,再经过多少个时钟周期就必须要使用相应的数据。</li><li>Tnew:位于某个流水级的某个指令,它经过多少个时钟周期可以<strong>算出结果</strong>并且<strong>存储到流水级寄存器</strong>里。</li></ul><p>具体各指令的Tuse,Tnew参见文件夹内表格Tuse&&Tnew。</p><p>由此,可以得到结论 <strong>Tuse < Tnew 且读写地址重叠(均不为$0)</strong> 时必须进行相应阻塞操作。<br>当前指令集需阻塞的情况代码表示如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">wire</span> E_ifBlock_rs <span class="token operator">=</span> <span class="token punctuation">(</span>E_GRF_A3 <span class="token operator">==</span> D_rs <span class="token operator">&&</span> D_rs <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rs <span class="token operator"><</span> E_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> E_ifBlock_rt <span class="token operator">=</span> <span class="token punctuation">(</span>E_GRF_A3 <span class="token operator">==</span> D_rt <span class="token operator">&&</span> D_rt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rt <span class="token operator"><</span> E_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_rs <span class="token operator">=</span> <span class="token punctuation">(</span>M_GRF_A3 <span class="token operator">==</span> D_rs <span class="token operator">&&</span> D_rs <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rs <span class="token operator"><</span> M_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">wire</span> M_ifBlock_rt <span class="token operator">=</span> <span class="token punctuation">(</span>M_GRF_A3 <span class="token operator">==</span> D_rt <span class="token operator">&&</span> D_rt <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>D_Tuse_rt <span class="token operator"><</span> M_Tnew<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> ifBlock <span class="token operator">=</span> E_ifBlock_rs <span class="token operator">|</span> E_ifBlock_rt <span class="token operator">|</span> M_ifBlock_rs <span class="token operator">|</span> M_ifBlock_rt<span class="token punctuation">;</span></code></pre><p><strong>如何阻塞</strong><br>自此,我们得到了阻塞信号<code>ifBlock</code><br>以此为依据操作阻塞情况的数据通路:</p><ul><li>将F_IFU和FD_REG的使能信号(en)置为0,不再更新并发送新的指令信号,达到使进入流水线的指令滞留在<strong>D级</strong>的目的。</li><li>将DE_REG的刷新信号(flush)置为1,使向E级发送的指令为nop,即产生“气泡”填充流水线;注意,仅需在此寄存器刷新,因为只要处于阻塞状态,该寄存器不断产生“气泡”,而这些“气泡”随时钟周期向后移动填充流水线各级。</li><li>当 <strong>Tuse >= Tnew</strong> 时解除阻塞状态,使能信号置为1,刷新信号置为0,开始考虑转发,继续流水。<br>具体代码实现如下:</li></ul><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> PC_en <span class="token operator">=</span> <span class="token operator">!</span>ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> FD_REG_en <span class="token operator">=</span> <span class="token operator">!</span>ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> DE_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> EM_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> MW_REG_en <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> FD_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> DE_REG_flush <span class="token operator">=</span> ifBlock<span class="token punctuation">;</span> <span class="token keyword">assign</span> EM_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> MW_REG_flush <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span></code></pre><hr><h3 id="转发操作"><a href="#转发操作" class="headerlink" title="转发操作"></a>转发操作</h3><p>转发,即将先进入流水线的指令产生的数据根据条件发送给后进入的指令。</p><p><strong>何时转发</strong><br>前面指令供给的数据,而后面指令在需要使用数据时,前面供给的数据<strong>已经产生且写入流水级寄存器但还没有存入寄存器堆</strong>,导致后面的指令在GRF中取不到正确的值,故当两个流水级出现读写寄存器的重叠时,(在无需阻塞或阻塞完成时)应考虑转发。</p><p><strong>如何转发</strong><br>在当前指令级下,仅存在:</p><ul><li>W向D级转发(寄存器内自转发)</li><li>E,M向D级转发</li><li>M,W向E级转发</li><li>W向M级转发<br>具体转发关系见文件夹下表格 hazard_and_relocate</li></ul><p>具体代码实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token comment" spellcheck="true">//寄存器内自转发</span> <span class="token keyword">assign</span> RD1 <span class="token operator">=</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span>A3 <span class="token operator">&&</span> A1<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> regFile<span class="token punctuation">[</span>A1<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> RD2 <span class="token operator">=</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span>A3 <span class="token operator">&&</span> A2<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> regFile<span class="token punctuation">[</span>A2<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向D级转发</span> <span class="token keyword">assign</span> D_Forward_rs_data <span class="token operator">=</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> E_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> E_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rs <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> D_rs_data<span class="token punctuation">;</span> <span class="token keyword">assign</span> D_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> E_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> E_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>D_rt <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> D_rt_data<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向E级转发</span> <span class="token keyword">assign</span> E_Forward_rs_data <span class="token operator">=</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rs <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> E_rs_data<span class="token punctuation">;</span> <span class="token keyword">assign</span> E_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> M_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> M_WD <span class="token punctuation">:</span> <span class="token punctuation">(</span>E_rt <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> E_rt_data<span class="token punctuation">;</span> <span class="token comment" spellcheck="true">//向M级转发</span> <span class="token keyword">assign</span> M_Forward_rt_data <span class="token operator">=</span> <span class="token punctuation">(</span>M_rt <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>M_rt <span class="token operator">==</span> W_GRF_A3<span class="token punctuation">)</span> <span class="token operator">?</span> W_WD <span class="token punctuation">:</span> M_rt_data<span class="token punctuation">;</span></code></pre><p>值得注意的是,这种转发方式的正确性是由<strong>阻塞机制</strong>和<strong>转发优先级</strong>决定的。<br>所谓优先级即向每一级转发时,依次沿流水线检索此级的下级,满足条件即转发,若都无需转发,则采用本级读出的寄存器值,这在代码中有所体现。<br>但可能存在这样两个问题<br>1.如需要向D级转发某数据,此数据在E级产生但未写入流水级寄存器,直至下个时钟上升沿才写入EM_REG(M级),则按优先级优先转发了DE_REG(E级)保存的数据,这是否会导致错误?<br><strong>答</strong>:实际上不会,由于阻塞机制的存在,当数据在E级产生但未写入流水级寄存器时,流水线被阻塞,指令停滞,此时转发的数据也起不到作用,待到下个时钟上升沿才写入EM_REG(M级),转发来自M级的数据会直接将错误值<strong>覆盖</strong>,阻塞状态解除,流水线正常执行。</p><p>2.如果转发到的寄存器在此指令期间不被读(可以不转发)将一个值存入其中会不会有影响?<br><strong>答</strong>:不会,若该寄存器不被读,则其要么被写,要么不参与本指令的执行,那么对于第一种情况,该指令写入时会将原本转发的值覆盖;对于第二种情况,该寄存器在流水级中的表现实际是相当于提前被写入了(实际上写入还是要到转发的源头指令的W级)。</p><hr><h2 id="测试方案"><a href="#测试方案" class="headerlink" title="测试方案"></a>测试方案</h2><p><strong>综合测试</strong><br>mips指令代码:</p><pre class=" language-c"><code class="language-c">ori $a0<span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1999</span> ori $a1<span class="token punctuation">,</span>$a0<span class="token punctuation">,</span><span class="token number">111</span> lui $a2<span class="token punctuation">,</span><span class="token number">12345</span>lui $a3<span class="token punctuation">,</span><span class="token number">0xffff</span>lui $t0<span class="token punctuation">,</span><span class="token number">0xffff</span>beq $a3<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span>eeeadd $s7<span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span>$a0nopori $a3<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span><span class="token number">0xffff</span>add $s0<span class="token punctuation">,</span>$a0<span class="token punctuation">,</span>$a1 add $s1<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$a3add $s2<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$s0beq $s2<span class="token punctuation">,</span>$s3<span class="token punctuation">,</span>eeesub $s0<span class="token punctuation">,</span>$a0<span class="token punctuation">,</span>$s2 sub $s1<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$a3eee<span class="token punctuation">:</span>sub $s2<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$a0sub $s3<span class="token punctuation">,</span>$s2<span class="token punctuation">,</span>$s1ori $t0<span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0x0000</span>sw $a0<span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>nopsw $a1<span class="token punctuation">,</span><span class="token function">4</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s0<span class="token punctuation">,</span><span class="token function">8</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s1<span class="token punctuation">,</span><span class="token function">12</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s2<span class="token punctuation">,</span><span class="token function">16</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s5<span class="token punctuation">,</span><span class="token function">20</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t1<span class="token punctuation">,</span><span class="token function">20</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t7<span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t6<span class="token punctuation">,</span><span class="token function">20</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $t6<span class="token punctuation">,</span><span class="token function">24</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t5<span class="token punctuation">,</span><span class="token function">12</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>jal endori $t0<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span><span class="token number">1</span>ori $t1<span class="token punctuation">,</span>$t1<span class="token punctuation">,</span><span class="token number">1</span>ori $t2<span class="token punctuation">,</span>$t2<span class="token punctuation">,</span><span class="token number">2</span>beq $t0<span class="token punctuation">,</span>$t2<span class="token punctuation">,</span>eeelui $t3<span class="token punctuation">,</span><span class="token number">1111</span>jal outend<span class="token punctuation">:</span>add $t0<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span>$t7jr $raout<span class="token punctuation">:</span>add $t0<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span>$t3ori $t2<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span><span class="token number">0</span>beq $t0<span class="token punctuation">,</span>$t2<span class="token punctuation">,</span>qqqlui $v0<span class="token punctuation">,</span><span class="token number">10</span>qqq<span class="token punctuation">:</span>lui $v0<span class="token punctuation">,</span><span class="token number">11</span>j wwwnopwww<span class="token punctuation">:</span>lui $ra<span class="token punctuation">,</span><span class="token number">100</span></code></pre><p>机器码:</p><pre class=" language-c"><code class="language-c">340407cf<span class="token number">3485006f</span>3c0630393c07ffff3c08ffff<span class="token number">10e80009</span>0004b820<span class="token number">00000000</span><span class="token number">34e7ffff</span><span class="token number">00858020</span><span class="token number">00e78820</span>00f09020<span class="token number">12530002</span><span class="token number">00928022</span><span class="token number">00e78822</span><span class="token number">00e49022</span><span class="token number">02519822</span><span class="token number">34080000</span>ad040000<span class="token number">00000000</span>ad050004ad100008ad11000cad120010ad1500148d0900148d0f00008d0e0014ad0e00188d0d000c0c000c25<span class="token number">35080001</span><span class="token number">35290001</span>354a0002110affec3c0b04570c000c27010f4020<span class="token number">03e00008</span>010b4020350a0000110a00013c02000a3c02000b08000c2e<span class="token number">00000000</span>3c1f0064</code></pre><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><p><strong>1、我们使用提前分支判断的方法尽早产生结果来减少因不确定而带来的开销,但实际上这种方法并非总能提高效率,请从流水线冒险的角度思考其原因并给出一个指令序列的例子。</strong><br>答:<br>以beq指令为例,我们为了减少不确定带来的开销将比较操作提前到了D级,这直接导致beq指令的D_Tuse_rt和D_Tuse_rs为0,又因为Tuse < Tnew 时需阻塞流水线,则beq指令被阻塞的概率较大(阻塞情况参加表格hazard_and_relocate),可能会在效率方面与提前判断分支带来的提升抵消,甚至降低效率。<br>示例如下:</p><pre class=" language-verilog"><code class="language-verilog"> beq <span class="token property">$t1</span><span class="token punctuation">,</span> <span class="token property">$t2</span><span class="token punctuation">,</span> tag1 add <span class="token property">$t1</span><span class="token punctuation">,</span> <span class="token property">$s1</span><span class="token punctuation">,</span> <span class="token property">$s2</span> <span class="token comment" spellcheck="true">// lw $t1, 0($s1)</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> tag1<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span></code></pre><p><strong>2、因为延迟槽的存在,对于 jal 等需要将指令地址写入寄存器的指令,要写回 PC + 8,请思考为什么这样设计?</strong><br>答:<br>因为存在延时槽,在跳转指令执行之后,下一条指令(地址为pc + 4)执行,执行完毕后再跳转至目标指令,故若需返回时,应返回 pc + 8 ,否则位于 pc + 4 的指令又会被执行一次,则会产生错误。</p><p><strong>3、我们要求大家所有转发数据都来源于流水寄存器而不能是功能部件(如 DM 、 ALU ),请思考为什么?</strong><br>答:<br>如果从功能部件转发,那么某一级的执行总延迟就会增加,从而影响整条流水线的时序设计,不得不延长时钟周期,总效率反而降低,得不偿失。</p><p><strong>4、我们为什么要使用 GPR 内部转发?该如何实现?</strong><br>答:<br>主要是为了处理W级和D级可能产生的寄存器重叠的冲突而进行的转发;实现方式即直接将WD端口的输入赋值到相应输出端口。<br>代码实现如下:</p><pre class=" language-verilog"><code class="language-verilog"> <span class="token keyword">assign</span> RD1 <span class="token operator">=</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A1<span class="token operator">==</span>A3 <span class="token operator">&&</span> A1<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> <span class="token comment" spellcheck="true">//内部转发</span> regFile<span class="token punctuation">[</span>A1<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">assign</span> RD2 <span class="token operator">=</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>A2<span class="token operator">==</span>A3 <span class="token operator">&&</span> A2<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">?</span> WD <span class="token punctuation">:</span> <span class="token comment" spellcheck="true">//内部转发</span> regFile<span class="token punctuation">[</span>A2<span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre><p><strong>5、我们转发时数据的需求者和供给者可能来源于哪些位置?共有哪些转发数据通路?</strong><br>答:<br>参见冲突处理一节的转发操作和表格hazard_and_relocate。</p><p><strong>6、在课上测试时,我们需要你现场实现新的指令,对于这些新的指令,你可能需要在原有的数据通路上做哪些扩展或修改?提示:你可以对指令进行分类,思考每一类指令可能修改或扩展哪些位置。</strong><br>答:<br>扩展指令的思路:</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>明确扩展指令的所属类型,在Controller中添加该指令的识别操作,并将该指令归类(load,store…),并以此为依据修改(或增添)控制信号的选择逻辑。</li><li>根据扩展指令需执行的操作在各个操作模块中添加相应的操作(和控制指令)。</li><li>若扩展指令存在跨级的操作,还要添加相应的流水级寄存器中添加传递的数据和控制信号。</li><li>最后考虑阻塞和转发信号的修改。</li></ul><p>寄存器计算指令(cal_r):</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>在Controller中添加相应的识别和控制操作(主要有ALU的运算选择信号,ALU的操作数选择信号,GRF的写入选择信号)。</li><li>根据在Controller中新增的信号索引到流水级的各个模块(ALU、GRF)进行操作和控制信号的添加。</li><li>与add等指令形制相同则阻塞转发一般无需修改。</li></ul><p>立即数运算指令(cal_i):</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>在Controller中添加相应的识别和控制操作(主要有ext的立即数扩展信号,ALU的运算选择信号,ALU的操作数选择信号,GRF的写入选择信号)。</li><li>根据在Controller中新增的信号索引到流水级的各个模块(ext、ALU、GRF)进行操作和控制信号的添加。</li><li>与ori指令形制相同则阻塞转发一般无需修改。</li></ul><p>写数据存储器指令(store):</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>在Controller中添加相应的识别和控制操作(主要有DM的读写模式信号)。</li><li>修改DM模块的读写操作。</li><li>与sw指令形制相同则阻塞转发一般无需修改。</li></ul><p>读数据存储器指令(load):</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>在Controller中添加相应的识别和控制操作(主要有DM的读写模式信号,GRF的写入数据选择和写入地址选择信号)。</li><li>修改DM模块的读写操作。</li><li>与lw指令形制相同则阻塞转发一般无需修改。</li></ul><p>j类型跳转指令(j_imm,j_reg,j_link):</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>在Controller中添加相应的识别和控制操作(主要有NPC的指令地址更新信号,GRF的写入数据选择和写入地址选择信号)。</li><li>增添NPC模块的地址更新操作和GRF模块的写入操作。</li><li>阻塞转发一般无需修改。(注意j_reg的Tuse_rs = 0)</li></ul><p>b类型跳转指令(branch)</p><ul><li>在defination中添加指令的识别和控制信号的宏定义。</li><li>在Controller中添加相应的识别和控制操作(主要有cmp的比较选择操作,NPC的指令地址更新选择操作)。</li><li>在cmp模块中添加比较操作,NPC模块中添加指令地址更新操作。</li><li>阻塞转发一般无需修改。(注意branch的Tuse_rs = Tuse_rt = 0)</li></ul><p><strong>7、简要描述你的译码器架构,并思考该架构的优势以及不足。</strong><br>答:<br>我采用的分布式译码的控制信号驱动型:</p><p><strong>分布式译码</strong>:每一级都部署一个控制器,负责译出当前级所需控制信号。这种方法较为灵活,“现译现用”有效降低了流水级间传递的信号量,但是需要实例化多个控制器,增加了后续流水级的逻辑复杂度。</p><p><strong>控制信号驱动型</strong>:为每个指令定义一个 wire 型变量,使用或运算描述组合逻辑,对每个控制信号进行单独处理。这种方法在指令数量较多时适用,且代码量易于压缩,缺陷是如错添或漏添了某条指令,很难锁定出现错误的位置。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 计算机组成 </tag>
<tag> Verilog </tag>
</tags>
</entry>
<entry>
<title>2022北航计算机组成原理 Project 4</title>
<link href="/2022/11/01/CO_P4/"/>
<url>/2022/11/01/CO_P4/</url>
<content type="html"><![CDATA[<h1 id="Verilog-语言设计单周期-CPU"><a href="#Verilog-语言设计单周期-CPU" class="headerlink" title="Verilog 语言设计单周期 CPU"></a>Verilog 语言设计单周期 CPU</h1><hr><h2 id="设计草稿及模块安排"><a href="#设计草稿及模块安排" class="headerlink" title="设计草稿及模块安排"></a>设计草稿及模块安排</h2><h3 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h3><blockquote><p>mips</p></blockquote><blockquote><blockquote><p>PC<br>IM<br>GRF<br>ALU<br>EXT<br>DM</p></blockquote></blockquote><blockquote><blockquote><p>Controlled<br>MUX</p></blockquote></blockquote><hr><h3 id="模块安排"><a href="#模块安排" class="headerlink" title="模块安排"></a>模块安排</h3><p><strong>mips</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号</td></tr></tbody></table><p>mips模块是整个系统的主模块,其主要承担整体架构中各分模块的线路连接任务。</p><p><strong>PC</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号,置1时pc = 0x00003000</td></tr><tr><td>next_pc</td><td>32</td><td>in</td><td>下一条指令的地址</td></tr><tr><td>pc</td><td>32</td><td>out</td><td>当前指令的地址</td></tr></tbody></table><p>pc是程序执行指令的地址提供者,传入其的next_pc受跳转指令信号的影响。</p><p><strong>IM</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>pc</td><td>32</td><td>in</td><td>当前指令的地址</td></tr><tr><td>instr</td><td>32</td><td>out</td><td>根据pc取出的指令,注意0x00003000的地址偏移量</td></tr></tbody></table><p>IM是指令存储器,读取code.txt文件中的多条32位指令,根据传入的pc取指令。</p><p><strong>GRF</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号,置1时,32个寄存器存储值归0</td></tr><tr><td>RegWrite</td><td>1</td><td>in</td><td>写寄存器使能信号</td></tr><tr><td>A1</td><td>5</td><td>in</td><td>需要读取的存储器1的地址</td></tr><tr><td>A2</td><td>5</td><td>in</td><td>需要读取的存储器2的地址</td></tr><tr><td>A3</td><td>5</td><td>in</td><td>需要写入的存储器的地址</td></tr><tr><td>WD</td><td>32</td><td>in</td><td>需要写入寄存器的数据</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>当前指令的地址</td></tr><tr><td>RD1</td><td>32</td><td>out</td><td>读取的寄存器1中存储的32位数据</td></tr><tr><td>RD2</td><td>32</td><td>out</td><td>读取的寄存器2中存储的32位数据</td></tr></tbody></table><p>GRF是寄存器文件,具有读写功能。</p><p><strong>ALU</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>A</td><td>32</td><td>in</td><td>操作数1</td></tr><tr><td>B</td><td>32</td><td>in</td><td>操作数2</td></tr><tr><td>ALUCtrl</td><td>3</td><td>in</td><td>ALU运算操作选择信号:0–和;1–或;2–加;3–减</td></tr><tr><td>ALUResult</td><td>32</td><td>out</td><td>运算结果</td></tr><tr><td>ifequal</td><td>1</td><td>out</td><td>操作数1和操作数2相等时置1</td></tr></tbody></table><p>ALU为算数运算单元,ALUCtrl指令控制执行何种运算。</p><p><strong>EXT</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>imm16</td><td>16</td><td>in</td><td>带扩展的16位立即数</td></tr><tr><td>extop</td><td>1</td><td>in</td><td>扩展操作选择信号:0–0扩展;1–符号扩展</td></tr><tr><td>imm32</td><td>32</td><td>out</td><td>扩展完毕后的32位立即数</td></tr></tbody></table><p>EXT为数据位扩展模块,主要服务于I指令。</p><p><strong>DM</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>clk</td><td>1</td><td>in</td><td>系统时钟信号</td></tr><tr><td>reset</td><td>1</td><td>in</td><td>复位信号,置1时,数据存储器中数据全部归0</td></tr><tr><td>MemRead</td><td>1</td><td>in</td><td>读数据存储器使能信号</td></tr><tr><td>MemWrite</td><td>1</td><td>in</td><td>写数据存储器使能信号</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>当前指令的地址</td></tr><tr><td>MemAddress</td><td>32</td><td>in</td><td>读出/写入数据的地址</td></tr><tr><td>dataIn</td><td>32</td><td>in</td><td>写入数据存储器的数据</td></tr><tr><td>dataOut</td><td>32</td><td>out</td><td>从数据存储器读出的数据</td></tr></tbody></table><p>DM是数据存储器,具有读写功能。</p><p><strong>Controller</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>op</td><td>6</td><td>in</td><td>32位指令的26-31位</td></tr><tr><td>funct</td><td>6</td><td>in</td><td>32位指令的0-5位</td></tr><tr><td>RegDst</td><td>2</td><td>out</td><td>写寄存器地址的选择信号:0–rt;1–rd;2–$ra</td></tr><tr><td>ALUSrc</td><td>1</td><td>out</td><td>ALU操作数2选择信号:0–RD2;1–imm32</td></tr><tr><td>WD_sel</td><td>1</td><td>out</td><td>写入寄存器的数据选择信号:0–ALUResult;1–加载至高位的imm16;2–数据存储器的读出;3–pc+4</td></tr><tr><td>ALUCtrl</td><td>3</td><td>out</td><td>ALU运算操作选择信号:0–和;1–或;2–加;3–减</td></tr><tr><td>RegWrite</td><td>1</td><td>out</td><td>写寄存器使能信号</td></tr><tr><td>MemRead</td><td>1</td><td>out</td><td>读数据存储器使能信号</td></tr><tr><td>MemWrite</td><td>1</td><td>out</td><td>写数据存储器使能信号</td></tr><tr><td>extop</td><td>1</td><td>out</td><td>扩展操作选择信号:0–0扩展;1–符号扩展</td></tr><tr><td>branch_beq</td><td>1</td><td>out</td><td>beq指令识别信号</td></tr><tr><td>branch_j_jal</td><td>1</td><td>out</td><td>j,jal指令识别信号</td></tr><tr><td>branch_jr</td><td>1</td><td>out</td><td>jr指令识别信号</td></tr></tbody></table><p>Controller是控制(译码)器,根据 op 和 funct 识别是MIPS指令集中的何指令,并依此生成各模块和通路的控制信号。</p><p><strong>MUX</strong></p><table><thead><tr><th>管脚名</th><th>位数</th><th>in/out</th><th>功能解释</th></tr></thead><tbody><tr><td>rt</td><td>5</td><td>in</td><td>32位指令的16-20位</td></tr><tr><td>rd</td><td>5</td><td>in</td><td>32位指令的11-15位</td></tr><tr><td>RD2</td><td>32</td><td>in</td><td>寄存器2中存储的数据</td></tr><tr><td>imm32</td><td>32</td><td>in</td><td>32位立即数</td></tr><tr><td>imm16</td><td>16</td><td>in</td><td>16位立即数</td></tr><tr><td>ALUResult</td><td>32</td><td>in</td><td>ALU运算结果</td></tr><tr><td>dataOut</td><td>32</td><td>in</td><td>数据存储器读出的数据</td></tr><tr><td>pc</td><td>32</td><td>in</td><td>当前指令的地址</td></tr><tr><td>RegDst</td><td>2</td><td>in</td><td>写寄存器地址(A3_grf)的选择信号:0–rt;1–rd;2–$ra</td></tr><tr><td>ALUSrc</td><td>1</td><td>in</td><td>ALU操作数2(B_alu)选择信号:0–RD2;1–imm32</td></tr><tr><td>WD_sel</td><td>1</td><td>in</td><td>写入寄存器的数据(WD_grf)选择信号:0–ALUResult;1–加载至高位的imm16;2–数据存储器的读出;3–pc+4</td></tr><tr><td>pc4</td><td>32</td><td>in</td><td>pc+4</td></tr><tr><td>pc_beq</td><td>32</td><td>in</td><td>beq指令将会跳转到的指令地址</td></tr><tr><td>pc_j_jal</td><td>32</td><td>in</td><td>j,jal指令将会跳转到的指令地址</td></tr><tr><td>ifequal</td><td>1</td><td>in</td><td>来自ALU的判等信号</td></tr><tr><td>branch_beq</td><td>1</td><td>in</td><td>beq指令识别信号</td></tr><tr><td>branch_j_jal</td><td>1</td><td>in</td><td>j,jal指令识别信号</td></tr><tr><td>branch_jr</td><td>1</td><td>in</td><td>jr指令识别信号</td></tr><tr><td>A3_grf</td><td>5</td><td>out</td><td>经选择后的写寄存器地址</td></tr><tr><td>B_alu</td><td>32</td><td>out</td><td>经选择后的ALU操作数2</td></tr><tr><td>WD_grf</td><td>32</td><td>out</td><td>经选择后的存储器写入数据</td></tr><tr><td>next_pc</td><td>32</td><td>out</td><td>根据跳转信号选择后的下一条指令地址</td></tr></tbody></table><p>MUX是集成的选择模块,根据Controller等模块传入的控制信号和选择数据来选择各模块的某些输入信号。</p><hr><h3 id="指令及控制信号"><a href="#指令及控制信号" class="headerlink" title="指令及控制信号"></a>指令及控制信号</h3><table><thead><tr><th>指令名称</th><th>op</th><th>funct</th><th>RegDst</th><th>ALUSrc</th><th>WD_sel</th><th>ALUCtrl</th><th>RegWrite</th><th>MemRead</th><th>MemWrite</th><th>extop</th><th>branch_beq</th><th>branch_j_jal</th><th>branch_jr</th></tr></thead><tbody><tr><td>add</td><td>000000</td><td>100000</td><td>1</td><td>0</td><td>0</td><td>2</td><td>1</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td></tr><tr><td>sub</td><td>000000</td><td>100010</td><td>1</td><td>0</td><td>0</td><td>3</td><td>1</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td></tr><tr><td>jr</td><td>000000</td><td>001000</td><td>0</td><td>0</td><td>0</td><td>2</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>1</td></tr><tr><td>ori</td><td>001101</td><td>\</td><td>0</td><td>1</td><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>lw</td><td>100011</td><td>\</td><td>0</td><td>1</td><td>2</td><td>2</td><td>1</td><td>1</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td></tr><tr><td>sw</td><td>101011</td><td>\</td><td>0</td><td>1</td><td>0</td><td>2</td><td>0</td><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td></tr><tr><td>beq</td><td>000100</td><td>\</td><td>0</td><td>0</td><td>0</td><td>3</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td></tr><tr><td>lui</td><td>001111</td><td>\</td><td>0</td><td>0</td><td>1</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>jal</td><td>000011</td><td>\</td><td>2</td><td>0</td><td>3</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td></tr></tbody></table><hr><h3 id="设计思路"><a href="#设计思路" class="headerlink" title="设计思路"></a>设计思路</h3><p>由于单个模块的控制已经在各个模块的安排中充分介绍,此思路主要概述如何在顶层模块mips中将单个模块组织起来。</p><p>首先应当明确,Controller 主要起到译码作用,MUX 根据Controller输出的译码结果选择控制指令。</p><p>而需要被选择的端口在当前支持的指令下有以下4个</p><ul><li>GRF的写入地址:A3,由RegDst控制</li><li>GRF的写入数据:WD,由WD_sel控制</li><li>ALU的操作数2:B,由ALUSrc控制</li><li>下一条指令地址:next_pc,由branch_beq ifequal,branch_j_jal,branch_jr联合控制</li></ul><p>故MUX的输出只为GRF,ALU,PC提供输入。</p><p>而其他的通路值得注意的有</p><ul><li>GRF的A1连接rs,A2连接rt</li><li>ALU的A连接GRF的RD1</li><li>DM的MemAddress连接ALU的ALUResult</li><li>DM的dataIn连接GRF的RD2</li></ul><p>其余的控制指令和数据传输可根据名称对应互联。</p><hr><h2 id="测试方案"><a href="#测试方案" class="headerlink" title="测试方案"></a>测试方案</h2><p>只要使 CPU 的 IM 读入十六进制汇编程序(存储在code.txt中),运行之后查看其存储器和寄存器中的数据,和 Mars 运行结果比较,就可以判定程序的对错。</p><p>###测试程序</p><ul><li><p>ori指令</p><pre class=" language-c"><code class="language-c"> ori $<span class="token number">0</span><span class="token punctuation">,</span> $<span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">1</span> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">0</span> ori $t2<span class="token punctuation">,</span> $t2<span class="token punctuation">,</span> <span class="token number">65535</span> ori $t3<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">65534</span> ori $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">25779</span></code></pre></li><li><p>lui指令</p><pre class=" language-c"><code class="language-c"> lui $t1<span class="token punctuation">,</span> <span class="token number">1</span> lui $t2<span class="token punctuation">,</span> <span class="token number">65535</span> lui $t2<span class="token punctuation">,</span> <span class="token number">65533</span> lui $t3<span class="token punctuation">,</span> <span class="token number">42538</span></code></pre></li><li><p>sw指令</p><pre class=" language-c"><code class="language-c"> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">1</span> lui $t2<span class="token punctuation">,</span> <span class="token number">65535</span> sw $t1<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t2<span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> ori $t3<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">28381</span> sw $t3<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> ori $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">4</span> sw $t3<span class="token punctuation">,</span> <span class="token function">120</span><span class="token punctuation">(</span>$t4<span class="token punctuation">)</span></code></pre></li><li><p>lw指令</p><pre class=" language-c"><code class="language-c"> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">1</span> lui $t2<span class="token punctuation">,</span> <span class="token number">65535</span> sw $t1<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> sw $t2<span class="token punctuation">,</span> <span class="token function">4</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> ori $t3<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">28381</span> ori $t4<span class="token punctuation">,</span> $t4<span class="token punctuation">,</span> <span class="token number">4</span> sw $t3<span class="token punctuation">,</span> <span class="token function">120</span><span class="token punctuation">(</span>$t4<span class="token punctuation">)</span> ori $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> <span class="token number">8</span> lw $s1<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$<span class="token number">0</span><span class="token punctuation">)</span> lw $s2<span class="token punctuation">,</span> <span class="token function">0</span><span class="token punctuation">(</span>$t4<span class="token punctuation">)</span> lw $s3<span class="token punctuation">,</span> <span class="token function">116</span><span class="token punctuation">(</span>$s0<span class="token punctuation">)</span></code></pre></li><li><p>add指令</p><pre class=" language-c"><code class="language-c"> ori $s1<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> <span class="token number">1</span> lui $s2<span class="token punctuation">,</span> <span class="token number">65535</span> add $t0<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $s2 add $t0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> $s2 lui $t1<span class="token punctuation">,</span> <span class="token number">65535</span> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">65535</span> add $s3<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $t1</code></pre></li><li><p>sub指令</p><pre class=" language-c"><code class="language-c"> lui $t1<span class="token punctuation">,</span> <span class="token number">65535</span> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">65535</span> lui $t2<span class="token punctuation">,</span> <span class="token number">65535</span> ori $t2<span class="token punctuation">,</span> $t2<span class="token punctuation">,</span> <span class="token number">60000</span> sub $s1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> $t2 ori $t3<span class="token punctuation">,</span> <span class="token number">7227</span> sub $s1<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> $t3</code></pre></li><li><p>beq指令</p><pre class=" language-c"><code class="language-c"> ori $t0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> <span class="token number">1</span> ori $t3<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> <span class="token number">2</span> tag1<span class="token punctuation">:</span> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">63333</span> add $t0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> $t0 beq $t0<span class="token punctuation">,</span> $t3<span class="token punctuation">,</span> tag1 ori $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> <span class="token number">4</span> beq $t0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> tag2 ori $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> <span class="token number">0</span> tag2<span class="token punctuation">:</span> lui $s0<span class="token punctuation">,</span> <span class="token number">4</span> addi $s0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> $s0 beq $s0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> tag3 ori $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> <span class="token number">0</span> ori $t0<span class="token punctuation">,</span> $t0<span class="token punctuation">,</span> <span class="token number">0</span> tag3<span class="token punctuation">:</span> nop</code></pre></li><li><p>j指令</p><pre class=" language-c"><code class="language-c"> ori $t1<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> <span class="token number">123</span> j tag1 ori $t1<span class="token punctuation">,</span> $t2<span class="token punctuation">,</span> <span class="token number">1</span> tag1<span class="token punctuation">:</span> add $t2<span class="token punctuation">,</span> $t1<span class="token punctuation">,</span> $<span class="token number">0</span> tag2<span class="token punctuation">:</span> add $t2<span class="token punctuation">,</span> $t2<span class="token punctuation">,</span> <span class="token number">1</span> j tag2</code></pre></li><li><p>jal指令 jr指令</p><pre class=" language-c"><code class="language-c"> ori $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> <span class="token number">1</span> ori $s1<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> <span class="token number">13828</span> jal func ori $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> <span class="token number">2</span> ori $s1<span class="token punctuation">,</span> $s1<span class="token punctuation">,</span> <span class="token number">3</span> func<span class="token punctuation">:</span> add $s0<span class="token punctuation">,</span> $s0<span class="token punctuation">,</span> $s1 lui $s1<span class="token punctuation">,</span> <span class="token number">123</span> jr $ra</code></pre></li><li><p>综合测试</p></li></ul><pre class=" language-c"><code class="language-c">ori $a0<span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span><span class="token number">1999</span> ori $a1<span class="token punctuation">,</span>$a0<span class="token punctuation">,</span><span class="token number">111</span> lui $a2<span class="token punctuation">,</span><span class="token number">12345</span>lui $a3<span class="token punctuation">,</span><span class="token number">0xffff</span>nopori $a3<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span><span class="token number">0xffff</span>addu $s0<span class="token punctuation">,</span>$a0<span class="token punctuation">,</span>$a1 addu $s1<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$a3addu $s2<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$s0beq $s2<span class="token punctuation">,</span>$s3<span class="token punctuation">,</span>eeesubu $s0<span class="token punctuation">,</span>$a0<span class="token punctuation">,</span>$s2 subu $s1<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$a3eee<span class="token punctuation">:</span>subu $s2<span class="token punctuation">,</span>$a3<span class="token punctuation">,</span>$a0subu $s3<span class="token punctuation">,</span>$s2<span class="token punctuation">,</span>$s1ori $t0<span class="token punctuation">,</span>$<span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0x0000</span>sw $a0<span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>nopsw $a1<span class="token punctuation">,</span><span class="token function">4</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s0<span class="token punctuation">,</span><span class="token function">8</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s1<span class="token punctuation">,</span><span class="token function">12</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s2<span class="token punctuation">,</span><span class="token function">16</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $s5<span class="token punctuation">,</span><span class="token function">20</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t1<span class="token punctuation">,</span><span class="token function">20</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t7<span class="token punctuation">,</span><span class="token function">0</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t6<span class="token punctuation">,</span><span class="token function">20</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>sw $t6<span class="token punctuation">,</span><span class="token function">24</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>lw $t5<span class="token punctuation">,</span><span class="token function">12</span><span class="token punctuation">(</span>$t0<span class="token punctuation">)</span>jal endori $t0<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span><span class="token number">1</span>ori $t1<span class="token punctuation">,</span>$t1<span class="token punctuation">,</span><span class="token number">1</span>ori $t2<span class="token punctuation">,</span>$t2<span class="token punctuation">,</span><span class="token number">2</span>beq $t0<span class="token punctuation">,</span>$t2<span class="token punctuation">,</span>eeelui $t3<span class="token punctuation">,</span><span class="token number">1111</span>jal outend<span class="token punctuation">:</span>addu $t0<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span>$t7jr $raout<span class="token punctuation">:</span>addu $t0<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span>$t3ori $t2<span class="token punctuation">,</span>$t0<span class="token punctuation">,</span><span class="token number">0</span>beq $t0<span class="token punctuation">,</span>$t2<span class="token punctuation">,</span>qqqlui $v0<span class="token punctuation">,</span><span class="token number">10</span>qqq<span class="token punctuation">:</span>lui $v0<span class="token punctuation">,</span><span class="token number">11</span></code></pre><ul><li>机器码</li></ul><pre class=" language-c"><code class="language-c">340407cf<span class="token number">3485006f</span>3c0630393c07ffff<span class="token number">00000000</span><span class="token number">34e7ffff</span><span class="token number">00858021</span><span class="token number">00e78821</span>00f09021<span class="token number">12530002</span><span class="token number">00928023</span><span class="token number">00e78823</span><span class="token number">00e49023</span><span class="token number">02519823</span><span class="token number">34080000</span>ad040000<span class="token number">00000000</span>ad050004ad100008ad11000cad120010ad1500148d0900148d0f00008d0e0014ad0e00188d0d000c0c000c22<span class="token number">35080001</span><span class="token number">35290001</span>354a0002110affec3c0b04570c000c24010f4021<span class="token number">03e00008</span>010b4021350a0000110a00013c02000a3c02000b</code></pre><hr><h2 id="思考题解答"><a href="#思考题解答" class="headerlink" title="思考题解答"></a>思考题解答</h2><p><strong>阅读下面给出的 DM 的输入示例中(示例 DM 容量为 4KB,即 32bit × 1024字),根据你的理解回答,这个 addr 信号又是从哪里来的?地址信号 addr 位数为什么是 [11:2] 而不是 [9:0] ?</strong><br>答:<br>如设计思路中所说,DM的Addr来自ALU的ALUResult,因为现有支持的指令仅lw和sw需访问DM存储器,其地址由ALU模块计算地址地址为rs的寄存器存储的值和符号扩展后的32位立即数之和得到。位数为[11:2]是因为DM中数据<strong>按字寻址</strong>,而计算得到地址是<strong>以字节为一个地址单位</strong>的,32位系统下1字为4字节,故取地址除以4即为32位数据的存储地址。</p><p><strong>思考上述两种控制器设计的译码方式( 1.指令对应的控制信号如何取值;2.控制信号每种取值所对应的指令),给出代码示例,并尝试对比各方式的优劣。</strong><br>答:<br>本设计方案采用的是第1种译码方式(见Controller模块);现给出第2种译码方式的部分示例(以ALUCtrl为例):</p><pre class=" language-verilog"><code class="language-verilog"><span class="token keyword">wire</span> add<span class="token punctuation">,</span>sub<span class="token punctuation">,</span>jr<span class="token punctuation">,</span>ori<span class="token punctuation">,</span>lw<span class="token punctuation">,</span>sw<span class="token punctuation">,</span>beq<span class="token punctuation">,</span>lui<span class="token punctuation">,</span>jal<span class="token punctuation">;</span><span class="token keyword">assign</span> add <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b000000</span> <span class="token operator">&&</span> funct<span class="token operator">==</span><span class="token number">6'b100000</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> sub <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b000000</span> <span class="token operator">&&</span> funct<span class="token operator">==</span><span class="token number">6'b100010</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> jr <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b000000</span> <span class="token operator">&&</span> funct<span class="token operator">==</span><span class="token number">6'b001000</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> ori <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b001101</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> lw <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b100011</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> sw <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b101011</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> beq <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b000100</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> lui <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b001111</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> jal <span class="token operator">=</span> <span class="token punctuation">(</span>op<span class="token operator">==</span><span class="token number">6'b000011</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">assign</span> ALUCtrl <span class="token operator">=</span> <span class="token punctuation">(</span>add <span class="token operator">|</span> lw <span class="token operator">|</span> sw <span class="token operator">|</span>jr<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">2</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>sub<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">3</span> <span class="token punctuation">:</span> <span class="token punctuation">(</span>ori<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span></code></pre><p>第1中译码方式在添加指令的时候较为方便,只需添加case中的一种情况,集中地选择控制信号,但指令与控制信号的整体对应关系不易看出,可读性一般。第2种译码方式虽然在修改时需要分散地添加指令识别信号,但写起来十分简洁,可读性较好。</p><p><strong>在相应的部件中,复位信号的设计都是同步复位,这与 P3 中的设计要求不同。请对比同步复位与异步复位这两种方式的 reset 信号与 clk 信号优先级的关系。</strong><br>答:<br>同步复位:reset < clk<br>异步复位:reset > clk</p><p><strong>C 语言是一种弱类型程序设计语言。C 语言中不对计算结果溢出进行处理,这意味着 C 语言要求程序员必须很清楚计算结果是否会导致溢出。因此,如果仅仅支持 C 语言,MIPS 指令的所有计算指令均可以忽略溢出。 请说明为什么在忽略溢出的前提下,addi 与 addiu 是等价的,add 与 addu 是等价的。提示:阅读《MIPS32® Architecture For Programmers Volume II: The MIPS32® Instruction Set》中相关指令的 Operation 部分 。</strong><br>答:<br>根据RTL语言描述:addi、add与addiu、addu的区别在于当出现溢出时,addiu、addu不检查溢出,只取32位结果;addi、add开辟额外一个位的空间来检查溢出,若溢出则报告SignalException(IntegerOverflow)。</p>]]></content>
<categories>
<category> 体系结构 </category>
</categories>
<tags>
<tag> 计算机组成 </tag>
<tag> Verilog </tag>
</tags>
</entry>
</search>