前言:之前也寫過(guò)一個(gè) toy_vm,里面也涉及到四個(gè)標(biāo)志位的更新阿宅,ALU 的難點(diǎn)也是這個(gè)四個(gè)標(biāo)志位的更新候衍,我每次都會(huì)忘這四個(gè)標(biāo)志位如何更新的,每次都要搜索半天洒放,這篇博客主要給出四個(gè)標(biāo)志位的更新規(guī)則蛉鹿,以及相應(yīng)的 verilog 代碼!
0X00 哪四個(gè)標(biāo)志位
有這四個(gè)標(biāo)志位往湿,在 ALU 中非常重要:
- zero 標(biāo)志位
- carry 標(biāo)志位
- negative 標(biāo)志位
- overflow 標(biāo)志位
0X01 四個(gè)標(biāo)志位更新的規(guī)則
以下標(biāo)志位的更新只有關(guān)于:
ADD妖异、ADDU、SUB领追、SUBU他膳、AND、OR蔓腐、XOR矩乐、NOR、LUI(至高位立即數(shù))、SLT(有符號(hào)比較)散罕、SLTU(無(wú)符號(hào)比較)分歇、SRA(算數(shù)右移)、SLL/SLR(邏輯欧漱、算數(shù)左移)职抡、SRL(算數(shù)右移)
zero 標(biāo)志位更新規(guī)則
- Z = 1 表示結(jié)果為 0,Z = 0 表示結(jié)果不為 0
- 對(duì)于比較操作误甚,若 a - b = 0缚甩。Z = 1。表示兩個(gè)數(shù)相等窑邦,否則為 0
- 所有操作都要更新 zero 標(biāo)志位
carry 標(biāo)志位更新規(guī)則
- 對(duì)于加減運(yùn)算來(lái)說(shuō)擅威,只有無(wú)符號(hào)運(yùn)算才會(huì)更新此標(biāo)志位
- 對(duì)于比較運(yùn)算來(lái)說(shuō),也只有無(wú)符號(hào)的比較才會(huì)更新此標(biāo)志位
- 無(wú)論是加還是減法最會(huì)都會(huì)變成加法冈钦,只用看所有位相加以后郊丛,最高位會(huì)不會(huì)產(chǎn)生進(jìn)位,產(chǎn)生進(jìn)位 carry = 1瞧筛,反之 carry = 0
- 所有左移運(yùn)算厉熟,carry 標(biāo)志位等于最后一個(gè)移出的值
- 其他的運(yùn)算不更新此標(biāo)志位
negative 標(biāo)志位更新規(guī)則
- 對(duì)于所有的運(yùn)算來(lái)說(shuō),negative 就是最高位的值较幌。比較運(yùn)算就是相減以后的最高位揍瑟。比如有兩個(gè) 32 位的變量相加,哪怕產(chǎn)生了 33 位乍炉,negative 標(biāo)志位就是最高位 32 位的值
overflow 標(biāo)志位更新規(guī)則
- 只有有符號(hào)的運(yùn)算才會(huì)更新 overflow 標(biāo)志位
- 只有超出有符號(hào)的表示范圍的時(shí)候 overflow = 1
0X02 Carry vs Overflow
Carry 和 Overflow 很容易搞混绢片,我來(lái)說(shuō)說(shuō)這兩者的區(qū)別。
- 首先最大的區(qū)別就是 Carry 標(biāo)志位是對(duì)無(wú)符號(hào)運(yùn)算(除所有左移運(yùn)算)來(lái)說(shuō)的岛琼,Overflow 標(biāo)志位是對(duì)有符號(hào)運(yùn)算來(lái)說(shuō)的
- 兩者表示的意思也不一樣杉畜,Carry 表示運(yùn)算過(guò)后最高位有沒(méi)有產(chǎn)生進(jìn)位(除所有左移運(yùn)算),而 Overflow 是判斷有符號(hào)數(shù)字有沒(méi)有超過(guò)當(dāng)前能表示的最大范圍
- 所以這兩者更新的代碼也不一樣
0X03 相應(yīng)代碼
zero 與 negative 標(biāo)志位好判斷衷恭,主要關(guān)注 carry 和 overflow
- 更新 zero,carry纯续,negative 標(biāo)志位
module ADDU(
input [31:0] a,
input [31:0] b,
output reg [31:0] r,
output reg zero,
output reg carry,
output reg negative,
output reg overflow
);
parameter WIDTH = 32;
parameter MSB = WIDTH - 1;
reg extra;
always @(*) begin
// 計(jì)算
{extra, r} = a + b;
// 更新 flag
zero = r ? 0 : 1;
carry = extra;
negative = r[MSB];
end
endmodule
carry 只需多保留一位随珠。如果進(jìn)位,這一位為 1猬错,不進(jìn)位為 0窗看。與 carry 標(biāo)志位特點(diǎn)一致
- 更新 zero,overflow倦炒,negative 標(biāo)志位
module ADD(
input [31:0] a,
input [31:0] b,
output reg [31:0] r,
output reg zero,
output reg carry,
output reg negative,
output reg overflow
);
parameter WIDTH = 32;
parameter MSB = WIDTH - 1;
reg extra;
always @(*) begin
// 計(jì)算
{extra, r} = {a[MSB], a} + {b[MSB], b};
// 更新 flag
zero = r ? 0 : 1;
negative = r[MSB];
overflow = ({extra, r[MSB]} == 2'b01) || ({extra, r[MSB]} == 2'b10);
end
endmodule
overflow 判斷的方法來(lái)自:https://stackoverflow.com/questions/24586842/signed-multiplication-overflow-detection-in-verilog/24587824#24587824
最后的 ALU 代碼显沈,我會(huì)整理以后,在 GitHub 中放出。