---
# System prepended metadata

title: 從0到有製作自己的CPU！！ 第五周第一組課後KIM教學 20220802
tags: [' 伴學松 第一組筆記', RISCV]

---

---
tags: RISCV, 伴學松 第一組筆記
---
# 從0到有製作自己的CPU！！ 第五周第一組課後KIM教學 20220802
[TOC]

# 講解 REGISTER 結構

## 溫故知新
- 中央處理器(CPU)的主要工作就是抓取指令與執行指令, 
    - 它必須具備下列功能:
        - instruction memory 抓取指令：CPU必須具備到記憶體抓取指令的功能。
        - decode 解譯指令：CPU必須看得懂指令以便採取動作。
        - register 抓取資料：當CPU執行指令時, 必須所有的運算元(operands) 皆到齊, 因此, 它必須有從I/O設備或記憶體抓取資料的功能。
        - alu 處理資料：當資料齊備後, CPU必須能處理這些資料, 可能是算術運算（加、減、乘、除), 也可能是邏輯運算(AND、OR等)。
        - data memory 回存結果：CPU做完算術或邏輯運算後的結果必要時要回存到記憶體或I/O 裝置。
      
- 一個中央處理機具備上述五項功能, 因此它須擁以下最為基礎的架構下去


| `中央處理器(cpu)` | 英文| 功能 |
| ---- |:----:| ---- |
|   指令記憶體  | instruction memory| CPU必須看得懂指令以便採取動作 |      |  |     |          || ---- |:----:|----|
|   算術邏輯運算單元   |  ALU  |主要負責資料的計算或處理  |     |  |    |          || ---- |:----:|----|
|    控制單元   |Control unit | 控制資料流向並控制ALU的動作,它負責傳出 信號(signal) 給 CPU 內的其他部分來控制其動作，而這些動作主要有: 把 instruction register 中的 instruction 送到 decoder中、指定資料要放進或拿出到哪個暫存器裡、控制 ALU 該做哪一種的 operation、 Program Counter 的計算...等等，還有許多是目前沒辦法講清楚了，總之，所有再 CPU 內的所有動作其實都是在 Control Unit 規劃下進行的，要是沒有它， CPU 可就無法運作了。 |      |  |     |          || ---- |:----:|:----:|
|    連結路徑  | interconnection path| 負責連接CPU內部的元件, 以利資料或控制訊號在不同元件間流傳 |      |  |     |          || ---- |:----:|:----:|
|   解碼器   | decode| CPU必須看得懂指令以便採取動作 |      |  |     |          || ---- |:----:|----|
|   暫存器   | Registers| 1負責儲存資料,以利CPU快速存取 指令                         2是中央處理器用來暫存指令,數據和位址的電腦記憶體,而他也是CPU中多個既存器組成的陣列,通常由快速的靜態隨機讀寫存储器(SRAM)現實,這種RAM具有專門的讀端口與寫端口,可以多路併發訪問不同的寄存器 | ---- |:----:|---|
|  數據記憶體；資料記憶體  | data memory| CPU做完算術或邏輯運算後的結果必要時要回存到記憶體或I/O 裝置 |      |  |     |          || ---- |:----:|----|


![](https://i.imgur.com/SL7B0Pp.png)

# register

- 寄存器堆(register file)是CPU中多個寄存器組成的陣列，
- 通常由快速的靜態隨機讀寫存儲器(SRAM)實現。這種RAM具有專門的讀端口與寫端口，可以多路並發訪問不同的寄存器。　
- 　CPU的指令集架構總是定義了一批寄存器，用於在內存與CPU運算部件之間暫存數據。在更為簡化的CPU，這些架構寄存器(architectural registers)一一對應與CPU內的物理存在的寄存器。
- 　在更為複雜的CPU，使用寄存器重命名技術，使得執行期間哪個架構寄存器對應於哪個寄存器堆的物理存儲條目(physical entry stores)是動態改變的。寄存器堆是指令集架構的一部分，程序可以訪問，這與透明的CPU高速緩存(cache)不同。　　實現　　通常的設計佈局是一個簡單的陣列，在水平方向的一行就是寄存器的全字長寬度，一行的每一位元的存儲單元(bit cell)通過位線(Bit Line)讀/寫其數據。在垂直方向把寄存器一次即能全字長讀出。
- 　放大電路(Sense amplifier)通常設在底部，把讀出的小幅值的兩根位線(組成了一對差分電路)的電位差，放大為全幅值的邏輯值電位。更大的寄存器堆的設計是鏡像與旋轉後(tiling mirrored and rotated)拼貼這種簡單的寄存器陣列。　　
- 　寄存器堆的每個條目(entry，即一個物理寄存器)對每個端口(port)都有一條字線(word line)，每個位元的基本存儲單元，對每個讀端口有1條位線，對每個寫端口有2條位線。每個位元的基本存儲單元都連接到了供電的Vdd(高電平)與Vss(低電平或者接地)，這裡的d是指組成SRAM的場效應管的漏極(drain)，s是指場效應管的源極(source)。因此，佈線所佔面積隨端口的平方增加，晶體管是線性增加。多個冗餘的具有較少讀端口的寄存器堆可能會比具有全套多個讀端口的單一寄存器堆，面積更小、讀取更快。MIPS R8000的整數單元，有一個寄存器堆的實現，有32個條目，字長64位，具有9個讀端口及4個寫端口。

![](https://i.imgur.com/4w1KkJW.gif)

- 暫存器位於記憶體階層的最頂端，也是CPU可以讀寫的最快的記憶體，事實上所謂的暫存已經不像記憶體，而是非常短暫的讀寫少量資訊並馬上用到，因為通常程式執行的步驟中，這期間就會一直使用它。暫存器通常都是以他們可以儲存的位元數量來計量，舉例來說，一個8位元暫存器或32位元暫存器。在中央處理器中，包含暫存器的部件有指令暫存器（IR）、程式計數器和累加器。暫存器現在都以暫存器陣列的方式來實作，但是他們也可能使用單獨的正反器、高速的核心記憶體、薄膜記憶體以及在數種機器上的其他方式來實作出來。

# register 細分種類

|  `暫存器種類`  | `Function`| 
| ---- |:----:|
| 資料暫存器| 用來儲存整數數字（參考以下的浮點暫存器）。在某些簡單（或舊）的CPU，特別的資料暫存器是用於數學計算的累加器。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
| 位址暫存器  | 持有記憶體位址，以及用來存取記憶體。在某些簡單/舊的CPU裡，特別的位址暫存器是索引暫存器（可能出現一個或多個）。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
| 通用目的暫存器 | 可以儲存資料或位址兩者，也就是說他們是結合 資料/位址 暫存器的功用。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|浮點暫存器 | 用來儲存浮點數字。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|常數暫存器| 用來持有唯讀的數值（例如0、1、圓周率等等）。由於「其中的值不可更改」這一特殊性質，這些暫存器未必會有實體的硬體電路相對應，例如將從零常數暫存器讀的操作實現為接通目標暫存器的下拉電阻。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
| | 一般而言，即使真正在硬體中放置常數暫存器也未必會是出於體系結構理論上的考慮，而很可能是由硬體描述語言為了簡化操作而自動生成的電路。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|向量暫存器 | 用來儲存由向量處理器執行SIMD指令所得到的資料。。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|特殊目的暫存器 | 儲存CPU內部的資料，像是程式計數器（或稱為指令指標），堆疊暫存器，以及狀態暫存器（或稱微處理器狀態字組）。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|指令暫存器 | 儲存現在正在被執行的指令| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|變址暫存器 | 是在程式執行時用來更改運算元位址之用。| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
| | 在某些架構下，模式指示暫存器（也稱為「機器指示暫存器」）儲存和設定跟處理器自己有關的資料。由於他們的意圖目的是附加到特定處理器的設計，因此他們並不被預期會成微處理器世代之間保留的標準。有關從隨機存取記憶體提取資訊的暫存器與CPU（位於不同晶片的儲存暫存器集合）| 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|記憶體緩衝暫存器 | | 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|記憶體資料暫存器 || 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|記憶體位址暫存器 | | 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |
|記憶體型態範圍暫存器 | | 功能 | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |


- 暫存器也可以指代由一個指令之輸出或輸入可以直接索引到的暫存器群組，這些暫存器的更確切的名稱為「架構暫存器」。例如，x86指令集定義八個32位元暫存器的集合，但一個實作x86指令集的CPU內部可能會有八個以上的暫存器。


![](https://i.imgur.com/2yW1q3o.png)


# 講解 REGISTER 與 verilog 程式結構
> [name=bill503084699]
1. 暫存器（Register）是中央處理器用來暫存指令.數據和位址的電腦記憶體,而他也是CPU中多個既存器組成的陣列,通常由快速的靜態隨機讀寫存储器(SRAM)現實,這種RAM具有專門的讀端口與寫端口,可以多路併發訪問不同的寄存器。

![](https://i.imgur.com/oTlKj0Y.png)
2. 介紹以Register的架構所呈現出來的圖

      用第三組的圖去做詮釋
![](https://i.imgur.com/5RzVbCZ.jpg)

## 定義接腳

3. 依照慣例我們先把模組名稱定義出來, 接下來就是小括號" 埠列信號 "的部分, 將輸入跟指定輸出到哪一個 以rs1addr rs2addr 另外我們需要額外拉出兩條線控制輸入可以寫入還是說可以被讀, 以write anable跟read able 給列出來,將位址與 腳位是先定義出來

   然後define可以寫在其他地方? 但寫出來會vivado比較好認,之後才會用到 ,這邊就先暫時這樣寫,不過在教學上我們先
    


```verilog= 
`define regbus 31:0
`define addrbus 4:0
`define reglen 32
`define regcomb 5
`define on 1'b1
`define off 1'b0
`define regoff {`regcomb{`off}}
`define offword {32{`off}}

module regfile(
    input clk,
    input reset,
    //先定義出位置
    input[4:0] rs1data, //rs1 位址 
    input[4:0] rs2data, //rs2 位址
    input[4:0] wdata, //wb_data
    
    //再定義智能腳
    input ren1, //rs1 read enable
    input ren2, //rs2 read enable
    input wren, //write enable 
    
    //再定義出從Alu寫回來資料的線路
    input [31:0]wb_data, //寫入資料
    input [4:0]wb_add送r,  //寫入位址
    
    //最後設定輸出送到rs1 rs2 alu那邊的輸入
    output reg [31:0]rs1, //rs1輸出
    output reg [31:0]rs2, //rs2輸出 
);
endmodule
```
-    前面這些定義宣告都只是資料跟位置而已  接腳的話我們就先定義到這邊,但在reg 5? 裏頭還有很多定義資料的空間



  
4.  相關圖片比較(比較知道腳位寫在哪)

| 黑貓大大放大過後的register的圖  |   - 基於當時第三組臨時畫的圖給予重新修整 畢竟腳位的定義名稱跟黑貓寫得不一樣以當時畫的圖下去做修整|  這個是跟黑貓他原畫定義腳位名稱比較像的網路示意圖 | 
|:----:| ---- |:----:|
| ![](https://i.imgur.com/lwoR3Kw.png) ![](https://i.imgur.com/VnNXYDR.png)| ![](https://i.imgur.com/1td3mjj.jpg)|![](https://i.imgur.com/Mb9roNA.jpg)|  | |  | |  || ---- |:----:|:----:|:---------:|:----:|:-------:| -------- |

## 設定register 內定的假設式子

```verilog=
reg[31:0]regfile[31:0];
```
||1. 第一種講法 每個位置有32位元 ,然後能定值2的5次方
2. 第二種講法 在reg 5? 裏頭有很多定義資料的空間,而在每一個位址的每一格都是有著32位bits的資料(reg[31:0]),後面regfile[4:0]配定有1到32個位置,2的32次方,是32個位元的暫存器,有一種32位元大小的資料,資料變成32個,但定義上只能定義32乘31個,因為...0000那邊都要是0,這個後面的定義是說他可以定義到多大的位置,可以當成重複乘上去的
3. 第三種講發 他是定義出每一個資料的空間,你送資料進去就會處存在register 裡面的某一個格裡面,可以當成樓乘可以存32位元的東西,有點像c的陣列
4. 第四種講法 32bit暫存器有32bit||
5. kim 總結 32個抽屜 裏頭有32個格

```verilog= 
reg[31:0] memory[0:1023]; //4kb=1024*32bit 有1024個收屜裏頭有32格

reg[31:0] regfile[31:0];//第一種講法 每個位置有32位元 ,然後能定值2的5次方    //第二種講法 在reg 5? 裏頭有很多定義資料的空間,而在每一個位址的每一格都是有著32位bits的資料(reg[31:0]),後面regfile[4:0]配定有1到32個位置,2的32次方,是32個位元的暫存器,有一種32位元大小的資料,資料變成32個,但定義上只能定義32乘31個,因為...0000那邊都要是0,這個後面的定義是說他可以定義到多大的位置,可以當成重複乘上去的
                       //第三種講發 他是定義出每一個資料的空間,你送資料進去就會處存在register 裡面的某一個格裡面,可以當成樓乘可以存32位元的東西,有點像c的陣列
                       //第四種講法 32bit暫存器有32bit
parameter true = 1'b1;
parameter false = 1'b0;  // 寫一堆1跟0會搞混寫錯 ,,後面會改一個東西


```
 -  以原先的設的定值因為parameter 設定的值造成 後面列的值不需要設  ==1'b1 這樣 

------------
#### 補充下面
question :祥辰這邊有提到說在各式TYPR內基本上沒有在寫入rs1 rs2, 因此re好像是多餘的 
answer :但第三組是說可能還是要加一個可控制的選項
猜疑 : 不曉得是不是re1 re2 都是只寫出re 都沒差因為是不是都是讀取的關系
![](https://i.imgur.com/LeSMc7V.png) 

名名寫到 : if(reset=1'b1) 也可以改成 if(!reset) 到後來用vivado跑也可以用這個去做

------------
anwser
1. read enable 可以省略但可以多加一個可以控制的選項,總結就是寫一下比較好保險
3. if(reset=1'b1) reset 拉起來的時候去做重製
   if(!reset)     reset 放下來的時候去做重製

------------
clock always 的式子
```verilog=     
always@(posedge clk)begin  
    if(reset==1'b1)begin  
        if((we==1'b1)&&(wb_addr1 =0));//被告知要送到$0就拒絕不送
        regfile[wb_addr]<wb_data;    //[wb_addr]塞裡面你要對它做動作的位置,因此我們要寫入data寫到[wb_addr]的這個位置裡面,我們要寫入的動作還要連一條線去指定register要寫入到哪麼地方
    end
end
        
```
------------
#### 補充 下面

謝祥辰 — 2022/07/28 我在網路上查到的資料是指個數
不是bit 表示
willwho - 我記得當時做ADL的時候bit還可以 多個bit你還是要額外宣告它不然會出錯 但這邊都是1bit因此目前暫定不用

結論 - 但我們enable都是1bit 而已因此我們目前暫定不用改 
然後 == 代表說不關多少位元只要遇到==0 都會代表0的關係因此 

當時penquuin 提出來的問題,你先把off  0遞值 off0指示全0 ,因為沒試過說==能不能表 0

```verilog=   
`define regcomb 5 // comb為5
`define regoff {`regcomb{`off}}
`define offword {32{`off}}
```


------------
clk  將reset=1'b1 改成 !reset 的式子
```verilog=     
always@(posedge clk)begin  
    if(!reset)begin //willwho的補充我記得當時做ADL的時候bit還可以 多個bit你還是要額外宣告它不然會出錯 但這邊都是1bit因此目前暫定不用
        if((we==1'b1)&&(wb_addr1 ==0));//被告知要送到$0就拒絕不送
        regfile[wb_addr]<wb_data;    //[wb_addr]塞裡面你要對它做動作的位置,因此我們要寫入data寫到[wb_addr]的這個位置裡面,我們要寫入的動作還要連一條線去指定register要寫入到哪麼地方
    end
end
        
```
------------ 
-   if(reset=1'b1) reset 拉起來的時候去做重製
-   if(!reset)     reset 放下來的時候去做重製
rs1
```verilog=
always@(*)begin  //rs1的部分
    if((re=1'b1)&&(rs1_addr==0)) // 第一個條件可讀取且條件為0
        rs1=0;//輸出的值給予0
    else if((we==1'b1)&&(re==1'b1)&&(rs1_addr1=0))//第二個條件測說可以被同時讀取 與寫入 並且並非對0的值做事
        rs1=wb_data;//我們將給予的值下去做輸出
    else if((re==1'b1)&&(rs1_addr1=0))//都沒有例外的情況做正常的讀取
        rs1=regfile[rs1_addr];
    else
        rs1=0; //最後我們所有的條件都有了九寫一個default 
    end
end
```
------------
rs2

```verilog=
always@(*) begin //rs2的部分
    if((re==1'b1)&&(rs2_addr==0))//來源地址是$0的話就不拿 直接去拿0
        rs2=0;
    else if((we==1'b1)&&(re==1'b1)&&(rs2_addr1=0))
        rs2=wb_data;
    else if((rs2==1'b1)&&(rs2_addr1=0))
        rs2=regfile[rs2_addr];
    else
        rs2=0;
end
```
------------

```verilog= 
`define regbus 31:0
`define addrbus 4:0
`define reglen 32
`define regcomb 5
`define on 1'b1
`define off 1'b0
`define regoff {`regcomb{`off}}
`define offword {32{`off}}

module regfile(
    input clk,
    input reset,
    //先定義出位置
    input[4:0] rs1_addr, //rs1 位址 
    input[4:0] rs2_addr, //rs2 位址
    input[4:0] wdata, //wb_data
    
    //再定義智能腳
    input ren1, //rs1 read enable
    input ren2, //rs2 read enable
    input wren, //write enable 
    
    //再定義出從Alu寫回來資料的線路
    input [31:0]wb_data, //寫入資料
    input [4:0]wb_add送r,  //寫入位址
    
    //最後設定輸出送到rs1 rs2 alu那邊的輸入
    output reg [31:0]rs1, //rs1輸出
    output reg [31:0]rs2, //rs2輸出 
);
    reg[31:0] memory[0:1023]; //4kb=1024*32bit
    reg[31:0] regfile[31:0];  //每個位置有32位元 ,然後能定值2的5次方
    
    parameter true = 1'b1;
    parameter false = 1'b0;  // 寫一堆1跟0會搞混寫錯 ,,後面會改一個東西
    
    always@(posedge clk)begin  
    if(!reset)begin //willwho的補充我記得當時做ADL的時候bit還可以 多個bit你還是要額外宣告它不然會出錯 但這邊都是1bit因此目前暫定不用
        if((we)&&(wb_addr1 =0));
        regfile[wb_addr]<wb_data;    //[wb_addr]塞裡面你要對它做動作的位置,因此我們要寫入data寫到[wb_addr]的這個位置裡面,我們要寫入的動作還要連一條線去指定register要寫入到哪麼地方
    end
end
    
    always@(*)begin  //rs1的部分
    if((re)&&(rs1_addr==0)) // 第一個條件可讀取且條件為0
        rs1=0;
    else if((we)&&(re)&&(rs1_addr1=0))
        rs1=wb_data;
    else if((re)&&(rs1_addr1=0))
        rs1=regfile[rs1_addr];
    else
        rs1=0;
    end
end
    
    always@(*) begin //rs2的部分
    if((re)&&(rs2_addr==0))
        rs2=0;
    else if((we)&&(re)&&(rs2_addr1=0))
        rs2=wb_data;
    else if((rs2)&&(rs2_addr1=0))
        rs2=regfile[rs2_addr];
    else
        rs2=0;
end
endmodule
```
------------
    
最終呈現 register 電路圖

![](https://i.imgur.com/yYUHqF1.png)


```verilog= 

```
------------
#### 補充 下面

![](https://i.imgur.com/HRXvRxw.png)

為什麼有了 register 還要有 Data memroy 呢,
因為data memroy 的讀取速度   所以我們需要一個速度與register相近的東西,像我們去看cpu的規格表會有一個 l1 l2 l3 的快取記憶體 ,當l"x"後面的那個數字越小離cpu越近,或是可能做在cpu裡面,像l1 讀取速度就是最快的  l2 會慢一點點  l3 會在更慢,但容量越小速度越快 ,l2比l1大 ,l3比l2更大, 像cpu要抓資料會先從l1,l1抓不到會先從l2,l2抓不到就l3,幾級這樣往下 ,但如果直接抓外面的d room 或是memory 的話速度會落差太大< 會產生問題

威宇 補充 提問 這個抓資料的部分貌似像是 作業系統的排班的情況?

------------
    
## 參考資料

* [FPGA系統設計實務_蕭宇宏_Verilog 硬體描述語言介紹](https://youtube.com/playlist?list=PLI6pJZaOCtF3_-vE7VUn9RdhQ6KXpcFQD)
* [Verilog初級教程（10）Verilog的always塊](https://blog.csdn.net/Reborn_Lee/article/details/107052261) 
* [在Verilog裡邊 always@（*）語句是什麼意思？](https://zhidao.baidu.com/question/261901454.html?fr=iks&word=ALU+ALWAY%40&ie=gbk) 
* [HDLbits刷題中文完整版，按照刷題網站順序每日更新一道](https://blog.csdn.net/wszwszwszqwer/article/details/123764784)
* [yf869778412 verilog中的default應該賦捨麼樣的值](https://www.cnblogs.com/chengqi521/p/6721276.html)
* [暫存器（Register）和記憶體（RAM）的介紹](https://clay-atlas.com/blog/2021/05/09/computer-cn-register-random-access-memory/)
* [資訊科技概論](http://www.cinfo.kyu.edu.tw/ch_1.pdf) 
* [計算機概論](https://sites.google.com/site/ycvs911125/zi-gong-dao-lun/2-7) 
* [暫存器](https://zh.wikipedia.org/zh-tw/%E5%AF%84%E5%AD%98%E5%99%A8)
* [Abby碎碎念筆記本  [計組] Design A Datapath-1.基本的三種畫法](http://abby.logdown.com/posts/733600-co-design-a-datapath)
* [寄存器堆（register file）是什麼？](https://www.zhihu.com/question/22619798/answer/27936513)
* [CPU與記憶體(Memory)的運作機制](https://sites.google.com/site/nutncsie10412/ge-ren-jian-jie/ji-yi-ti)
* [工程師必學電子筆記](https://half-engr.com/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E5%BF%85%E5%AD%B8%E9%9B%BB%E5%AD%90%E7%AD%86%E8%A8%98-hackmd-notion/)
* 
* 原先 mikuthebest的寫法 也就是

```verilog= 


//`define regbus 31:0
//`define addrbus 4:0
//`define reglen 32
//`define regcomb 5
//`define on 1'b1
//`define off 1'b0
//`define regoff {`regcomb{`off}}
//`define offword {32{`off}}


module regfile(
    input clk,
    input reset,
    //先定義出位置
    input[31:0] rs1data, //rs1 位址 
    input[31:0] rs2data, //rs2 位址
    input[4:0] wdata, //wb_data
    
    //再定義智能腳
    input ren1, //rs1 read enable
    input ren2, //rs2 read enable
    input wren, //write enable 
    
    //再定義出從Alu寫回來資料的線路
    input [31:0]wb_data, //寫入資料
    input [4:0]wb_add送r,  //寫入位址
    
    //最後設定輸出送到rs1 rs2 alu那邊的輸入
    output reg [31:0]rs1, //rs1輸出
    output reg [31:0]rs2, //rs2輸出 
);
    reg[31:0] memory[0:1023]; //4kb=1024*32bit
    reg[31:0] regfile[31:0];  //每個位置有32位元 ,然後能定值2的5次方
    
    parameter true = 1'b1;
    parameter false = 1'b0;  // 寫一堆1跟0會搞混寫錯 ,,後面會改一個東西
    
    always@(posedge clk)begin  
    if(reset=1'b1)begin //willwho的補充我記得當時做ADL的時候bit還可以 多個bit你還是要額外宣告它不然會出錯 但這邊都是1bit因此目前暫定不用
        if((we==1'b1)&&(wb_addr1 =0));
        regfile[wb_addr]<wb_data;    //[wb_addr]塞裡面你要對它做動作的位置,因此我們要寫入data寫到[wb_addr]的這個位置裡面,我們要寫入的動作還要連一條線去指定register要寫入到哪麼地方
    end
end
    
    always@(*)begin  //rs1的部分
    if((re=1'b1)&&(rs1_addr==0)) // 第一個條件可讀取且條件為0
        rs1=0;
    else if((we==1'b1)&&(rs1_addr=0)&&(rs1_addr1=0))
        rs1=wb_data;
    else if((re==1'b1)&&(rs1_addr1=0))
        rs1=regfile[rs1_addr];
    else
        rs1=0;
    end
end
    
    always@(*) begin //rs2的部分
    if((re==1'b1)&&(rs2_addr==0))
        rs2=0;
    else if((we==1'b1)&&(re==1'b1)&&(rs2_addr1=0))
        rs2=wb_data;
    else if((rs2==1'b1)&&(rs2_addr1=0))
        rs2=regfile[rs2_addr];
    else
        rs2=0;
end
endmodule
```

