Skip to content

Latest commit

 

History

History
259 lines (187 loc) · 6.17 KB

P4课上测试回忆.md

File metadata and controls

259 lines (187 loc) · 6.17 KB

2020 P4课上测试回忆

分享一个dl做的解析

roife的GitHub博客

2020.11.28

终于,献出了首挂。 所以以下是第一次上机的题目
以后,,只能带来第二次上机的题目了。。。

bsoal

branch and link if odd

判断从寄存器读出来的那个数,
转换成二进制以后,
里面的“1”的个数是不是奇数。

举栗子,
5转二进制是101,两个1,不跳转,
8转二进制是1000,只有一个1,跳转

用for循环应该可以解决?我的做法是:

wire odd;   // is odd??
reg[31:0] num;   // how many "1" in RegRead1??
initial begin
    num = 0;
end
integer i;
always@(*) begin
    for(i = 0; i < 32; i = i + 1) begin
        if(RegRead1[i] == 1) begin
            num = num + 1;
        end
    end
end
assign odd = num[0]

不知道为啥,我老是过不去第一和第二个点。


update on 2020.11.28-23:32

我知道为啥错了。
每次使用for循环来计算RegRead1中“1”的个数时,
没有把中间变量num清零。

突然想起这也是P2的一个考点,
这也证明了,侥幸躲过去的坑,还是会回来坑你的!

留下了不学无术的泪水。

附上正确的代码,只多了一行:

wire odd;   // is odd??
reg[31:0] num;   // how many "1" in RegRead1??
initial begin
    num = 0;
end
integer i;
always@(*) begin
    num = 0;    // shit
    for(i = 0; i < 32; i = i + 1) begin
        if(RegRead1[i] == 1) begin
            num = num + 1;
        end
    end
end
assign odd = num[0]

许嵩有首歌叫做《如果当时》,
或许,如果当时我检查仿真波形,将odd和num信号拖进去,
就会是完全不一样的结局,
but
《如果当时》有2020年版本,可是我的这次P4还是永远地回不来了
: )

做计组,要笑


要在三个地方加线:
一个是controller.v要多加一个odd输入,再对各种控制信号进行精细的控制。
还有一个是datapath.v里加一个odd的输出
最后还要在mips里把俩端口连起来。
当然,架构不一样,加的线自然也不一样。

xor

这个只要在ALU和ALU Operation上改就好了

我课上不知道异或的运算符是啥,但是XOR竟然是Verilog关键字???

异或的运算符是"^"
如果实在不会,打开Logisim,找到异或原件,写出真值表。
然后用~、&和|构造就好了。

XOR、NXOR,在languange template也能找到。

swrr

我猜测英文是:Store Word Right Rotate 要求:

  1. swrr

  2. DM输出要求“字对齐”

以下是swrr:

MemAddr = GPR[base] + SignExt(imm16)
temp = Addr_1...0
if (temp == 0):
    DM[MemAddr[11:2]] <= GPR[rt]
else :
    if DM[MemAddr[11:2]] <= GPR[rt]_(8*temp-1...0)||GPR[rt]_(31...8*temp)

我对RTL语言和PDF指令描述的鄙视已经无法用文字来形容了。

首先是读题:
侬要知道Addr再下角标一个1...0是什么意思。: )
原来就是Addr[1:0]啊(做恍然大悟状)
我再翻译一遍题目:

MemAddr = GRF[rs] + SignExt(imm16)  // 就是ALU的res
temp = Addr[1:0]
if (temp == 0):
    DM[MemAddr[11:2]] <= GRF[rt]
else :
    DM[MemAddr[11:2]] <= {GRF[rt][8*temp-1], GRF[rt][31:8*temp]}

这个读题比做题难

利用assign配合swrr和temp的信号,
将GRF[rt]的值重新拼接作为MUX的输出就好了。

来谈下我犯的几个错:

  1. swrr的判断,op == 6'hXXX
    应该是6'bXXX

  2. SignExt的信号没跟上

  3. 没有在顶层模块中连接swrr的信号

  4. 最重要的,“字对齐”是什么意思???

可以说,被那个bsoal弄到没脾气了,加上看不懂题目描述,做这题真的挺不爽的,一直在犯错。

字对齐要求必须是4的倍数,而我们原来的输出都是byte的地址。
所以我们的$display要改成
{MemAddr[31:2], {2{1'b0}}}
真地搞不懂这个“字对齐”怎么翻译过来的。。。
怪不得我的写入地址老是出错呢

总结

各种信号的控制真的很重要。
像GRF的写使能,DM的写使能、EXT的符号扩展信号...

这次挂的太狗血了。。。。
一个字对齐,一个中间变量清零。

2020.12.5

终于过了 : )
branch + link 指令还是做不出来 : (

bszeal

branch if suffix-zero equal and link

指令内容:

  1. 无条件link

  2. 读GRF[rs]和GRF[rt],
    如果二进制下,后缀零的个数相等,则branch。

后缀零的定义:

从低位往高位数有几个零,直到遇到1

10的二进制:1010,
第一个一出现在[1],后缀零有1个

12的二进制:1100, 第一个1出现在[2],后缀零有2个

这个难点在于后缀零的个数上,
Verilog的for循环里不能直接break,
不然会报 "< break > is not declared"

但是用while就可以解决,代码如下:

reg [31:0] num;
initial begin
    num = 0;
end
integer i;
always@(*) begin
    num = 0;
    i = 0;
    while ((i < 32) && (RegRead1[i] == 0)) begin
        num = num + 1;
        i = i + 1;
    end
end

当然也可以通过添加flag标记是否数到了1的方式解决,代码如下:

reg[31:0] num;
reg flag;
initial begin
    num = 0;
    flag = 0;   // ever met 1
end
integer i;
always@(*) begin
    for (i = 0; i < 32; i = i + 1) begin
        if (RegRead1[i]  == 0) begin
            if(flag == 0) begin
                num = num + 1;
            end
            else begin
                num = num + 0;
            end
        end
        else begin
            flag = 1;
        end
    end
end

本质上是一种有限状态机

xor

和上回一样,记得要逐个检查信号

lah

上回是store,这回是load

判断的逻辑和swrr差不多。

在datapath里,
对MemReadData进行一番修改,生成中间变量,
连接到向GRF写入数据的Mux上,
还是注意Controller的信号,
逐个检查和修改或者添加。

我甚至觉得这个题比swrr简单,
因为没有字对齐 : )