---
# System prepended metadata

title: Lab2 Review

---

# Lab2 Review
[TOC]

## Design Description
主要的架構是使用多工器(MUX)去選取不同的資料，並依`Sel`信號的不同，選取相對應的功能。下表帶大家快速 review 一下功能：
| Sel value | Function | Sel value | Function |
| --------- | -------- | --------- | -------- |
|   0000    | priority encoder |   1000    | 2-to-4 decoder |
|   0001    | A&B |   1001    | 4-to-16 decoder  |
|   0010    | A^B |   1010    | select the larger number|
|   0011    | A\*B |   1011    | select the smaller number|
|   0100    | A>>>1'b1 |   1100    | A+B | 2’s complement|
|   0101    | A<<<1'b1 |   1101    | A-B | 2’s complement |
|   0110    | A>>1'b1 |   1110    | \|A-B\| |
|   0111    | A<<1'b1 |   1111    | A\*B|

---
## Verilog Code
基本上，大家經過 Lab1、Lab2 的洗禮後應該對 design 的流程相當熟悉了：)以下會提供各功能 verilog 的寫法，供各位參考。

### 分析
這次 design 算是一個比較大的架構，所以事前分析是很重要的步驟，這會幫助你有計畫的安排線路名稱，之後寫出來的 code 會比較乾淨。

（一）數字有分 signed 跟 unsigned，所以可以分開宣告變數：
```verilog=
input [3:0] A;
input [3:0] B;

wire signed [3:0] A_s, B_s;

assign A_s = A;
assign B_s = B;
```
（二）主要架構是 mux，可以用 always block 實作：
```verilog=
wire [15:0] W_0000, W_0001, W_0010, W_0011;
wire [15:0] W_0100, W_0101, W_0110, W_0111;
wire [15:0] W_1000, W_1001, W_1010, W_1011;
wire [15:0] W_1100, W_1101, W_1110, W_1111;

always@(*)begin
	case(Sel)
		4'b0000: Out = W_0000;
		4'b0001: Out = W_0001;
		4'b0010: Out = W_0010;
		4'b0011: Out = W_0011;
		4'b0100: Out = W_0100;
		4'b0101: Out = W_0101;
		4'b0110: Out = W_0110;
		4'b0111: Out = W_0111;
		4'b1000: Out = W_1000;
		4'b1001: Out = W_1001;
		4'b1010: Out = W_1010;
		4'b1011: Out = W_1011;
		4'b1100: Out = W_1100;
		4'b1101: Out = W_1101;
		4'b1110: Out = W_1110;
		4'b1111: Out = W_1111;
	endcase
end
```
（三）每個功能所要選取的 bit 數不同，也依據功能看要做sign extension 或補0，利用 assign 的方式，把不同功能分別輸出的結果彙整，如下：
```verilog=
wire [3:0] OPand, OPxor;
wire signed [7:0] OPmul;
//variables declared here...
    
assign W_0000 = {13'd0, OPencode};
assign W_0001 = {12'd0, OPand};
assign W_0010 = {12'd0, OPxor};
assign W_0011 = {{8{OPmul[7]}}, OPmul};
assign W_0100 = {12'd0, OPsra};
assign W_0101 = {12'd0, OPsla};
assign W_0110 = {12'd0, OPsrl};
assign W_0111 = {12'd0, OPsll};
assign W_1000 = {12'd0, OPdecode_4};
assign W_1001 = OPdecode_16;
assign W_1010 = {12'd0, OPlag};
assign W_1011 = {12'd0, OPsml};
assign W_1100 = {{12{OPadd[3]}}, OPadd};
assign W_1101 = {{12{OPsub[3]}}, OPsub};
assign W_1110 = {12'd0, OPabs};
assign W_1111 = {{8{OPmul[7]}}, OPmul};
```
（四）偵測 overflow，針對三個 case 做處理
```verilog=
wire add_ov, sub_ov, abs_ov;

always@(*)begin
    case(Sel)
	    4'b1100: Ovf = add_ov;
	    4'b1101: Ovf = sub_ov;
	    4'b1110: Ovf = abs_ov;
	    default: Ovf = 1'b0;
    endcase
end
```
### 實作
以下就依各功能的 partial code 做說明：

`0000`：可以使用 always block。以 if、else 巢狀結構拼組。（也有看到同學使用`casex`的寫法，很好~）
```verilog=
always@(*)begin
	if(A[3]==1'b1)begin 
	OPencode = 3'b111;
	end else begin
		if(A[2]==1'b1) begin 
		OPencode = 3'b110;
		end else begin
			if(A[1]==1'b1)begin
			OPencode = 3'b101;
            //...

```
`0001`、`0010`、`0011`：直接使用內建指令。A\*B記得要用 signed number。
```verilog=
//0001
assign OPand = A&B;
//0010
assign OPxor = A^B;
//0011
assign OPmul = A_s*B_s;
```
`0100`、`0101`、`0110`、`0111`：直接使用內建指令。算數右移需要用 signed number。
```verilog=
//0100
assign OPsra = A_s>>>1'b1;
//0101
assign OPsla = A_s<<<1'b1;
//0110
assign OPsrl = A>>1'b1;
//0111
assign OPsll = A<<1'b1;
```
`1000`、`1001`：自建 module ，比較主流的方式是讓input port 有 A、B、enable、out：
```verilog=
module two_four_decoder(A,B,enable,out);
    input A, B, enable;
    output [3:0]out;
    wire not_A,not_B;
    
    not na0(not_A, A);
    not nb0(not_B, B);
    and a0(out[0], not_A, not_B, enable);
    and a1(out[1], not_A, B, enable);
    and a2(out[2], A, not_B, enable);
    and a3(out[3], A, B, enable);
endmodule
```
4-16 請參考附圖拼組：
|![](https://i.imgur.com/Dvf0w8s.gif)|
| --- |
(圖片來源：http://www.exploreroots.com/dc23.html)

`1010`、`1011`：建 1-bit 的 comparator，最後使用 mux 將結果作為選擇信號：
```verilog=
//Comparator ... (do it by yourself)
module selector(A, B, Out);
    input [3:0]A, B;
    output [3:0]Out;
    wire gt;
    
    Comparator cp0(A, B, gt);
    assign Out = (gt == 1'b1)? A : B;
endmodule
```
`1100`、`1101`、`1110`：adder 的部分應該大家都蠻熟悉的， **Cout = majority function, Sum = A xor B xor Cin**，而判別 overflow 的方式可以是 Cout[2] 跟 Cout[3] 做 xor 的結果，或是另外拉出來判斷都可以。而 subtractor 基本上是把 B 做convert 再 +1 的結果輸入 adder 並重新判別 overflow。最後就是 absolute value 的部分，這裡可能同學要注意的地方是，two's complement 的範圍在 -8~+7 之間，所以 -8 要翻過來時會 overflow。
```verilog=
//1-bit full adder
module adder(A, B, Cin, Cout, Sum);
    input A, B, Cin;
    output Sum, Cout;
    wire w0, w1, w2;
    
    and a0(w0,A,B);
    and a1(w1,A,Cin);
    and a2(w2,B,Cin);
    or o1(Cout, w2, w1, w0);
    xor x0(Sum, A, B, Cin);
endmodule

//Adder ... (do it by yourself)

//Subtractor
module Subtractor(A, B, Out);
    input [3:0]A, B;
    output [3:0]Out;
    wire [3:0]B_c;
    assign B_c = ~B + 1'b1;
    Adder a0(A, B_c, Out);
endmodule

//absolute value
module absolute(A, B, Out);
    input [3:0]A, B;
    output [3:0]Out;
    wire [3:0]out_tmp;
    Subtractor s0(A, B, out_tmp);
    assign Out = (out_tmp[3] == 1'b1)? ~out_tmp+1'b1 : out_tmp;
endmodule
```
`1111`：據說坊間有 two's complement 的乘法器，但我會都轉成正數相乘，再判斷正負號。
```verilog=
module Multiplier (a, b, p);
    input [3:0] a, b;
    output [7:0] p;
    wire [3:0] mul0, mul1, mul2, mul3; 
    wire [3:0] out0, out1, out2, out3, out4;
    wire q2, q3, q4, q6, q7, q8, q9, q10, q11, q12;
    wire s3, s4, s5, s8, s9, s10;

    and a01(mul0[0], a[0], b[0]);
    and a02(mul0[1], a[1], b[0]);
    and a03(mul0[2], a[2], b[0]);
    and a04(mul0[3], a[3], b[0]);
    //...
    FullAdder z01(.a( mul0[1] ), .b( mul1[0] ), .cin( 1'b0 ), .cout( q2 ), .sum( p[1] )); // s2 == p[1]
    FullAdder z02(.a( mul0[2] ), .b( mul1[1] ), .cin( q2 ), .cout( q3 ), .sum( s3 ));
    FullAdder z03(.a( mul0[3] ), .b( mul1[2] ), .cin( q3 ), .cout( q4 ), .sum( s4 ));
    FullAdder z04(.a( 1'b0 ), .b( mul1[3] ), .cin( q4 ), .cout( q5 ), .sum( s5 )); // q5 == s6
    //...
endmodule

module Mul(A, B, Out);
    input [3:0]A, B;
    output [7:0]Out;
    wire [3:0]A_p, B_p;
    wire [7:0]out_t, out_p;
    wire ab_x;
    
    xor x0(ab_x, A[3], B[3]);
    
    to_positive t0(A, A_p);//make A_p > 0
    to_positive t1(B, B_p);//make B_p > 0
    multiplier mul0(A_p, B_p, out_p);
    two_s_converter tw0(out_t, out_p);//same as "assign out_t = ~out_p + 1'b1;"
    mux mx0(Out, abx, out_t, out_p);//same as "assign Out = (ab_x == 1'b1)? out_t : out_p;"
    //notice the special case -8*...
endmodule
```

## Grading policy
- 有交有圖片有描述 (40%)
- 對 0000~1110 各功能有詳述 (說明 design 如何根據限制實作...等) (45%)
- Other detail or stuff we like. (15%)
- Bonus 實作詳述(4%)

## Q&A
**Q：** `module module_name(.A(...), .B(...), ...);`當中`.A(...)`有無指定差別為何？

**A：** 主要是關於接進去的線路有沒有順序上的安排，例如：
```verilog=
module M(a, b, c);
//...
endmodule

module M_another(...);
wire a, b, c;

M m_0(a, b, c);
M m_1(.b(b), .a(a), .c(c));
module
```
---
**Q：** 如果我們寫的 verilog 就能執行並且解決許多問題，那為什麼要用我們寫完的 code 再合成電路用 synthesis 去解決問題勒？感覺很多此一舉。

**A：** verilog 的 code 當中包含我們所常用的三種描述方式，但是如果真的要被實際製造出來，就必須回歸 gate level 的形式，而 synthesis 的過程就是幫助我們把其他兩種的電路描述法轉成 gate level。或者反過來說，如果執行 verilog 只是要跑 simulation，倒可以直接寫 C，應該容易許多。

---

**Q：** if-else 的條件敘述一定要在 always blocks裡？module 可以放在 always blocks 裡面？

**A：** if-else 的條件敘述一定要在 always blocks 裡。module 不可以放在 always blocks 裡。以上都是 verilog 的語法。再次強調接自建 module 的方式：
```verilog=
module M(a, b, c);
//c is output port, and a, b are input ports.
//...
endmodule

module M_another(...);
wire a, b, c;
reg R0;

//...
M m_0(a, b, c);
always@(*)begin
    if(...) R0=c;
    else R0=1'b0;
end
module
```

---

**Q：** 用 always 還是 assign？ 

**A：** 請參考[型別介紹](https://hackmd.io/s/HkErL41NN)中 reg 比較。

---

**Q：** 因為 verilog 是硬體敘述語言，有時候我的寫法會有點「偏軟體」，比如用了 for 迴圈，那想請問這樣不好的原因是什麼呢？

**A：** 因為 synthesis 的時候會無法合成出 for 迴圈的電路。如果要模擬 for 迴圈的行為，可以在 sequential 電路中實現。（TB 中可以跑 for 是因為沒有要合成，只是用來驗證電路的正確性。）

---

**Q：** 在主要的 module AM 中呼叫我自己寫的module 時，在 output port 中使用的型別是wire，但在有些module 中使用Behavior Modeling 時，會將output 的變數設定為reg，但這樣不會有型別上的衝突嗎？

**A：** 不會喔~這邊舉個例子：
```verilog=
module M(a, b, c);
input a, b;
output reg c;

always@(*)begin   //same as "assign c=a+b;".
    c=a+b;        //
end               //
endmodule

module M_another(...);
//...
wire a, b, c;
M m_0(a, b, c);   //OK~ no conflict.
module
```

# [HOMEPAGE](https://hackmd.io/s/HJdaLPTQV)