# HW-1 ***Four-bit Full Adder*** b1105167 張家凱 一、目的-使用verilog實現four-bit full adder 二、工具-vscode,xilinx-vivado 三、方法與步驟-詳細說明 **vscode部分**: 先寫出four_bit_adder.v檔,裡面包含包含兩模組,一個是全加器模組,另 一個是four_bit_adder模組(引用全加器模組)。接著建立新的file寫出 testbench檔-four_bit_adder_tb.v,同個模式再寫出makefile檔。 **vivado部分**: 利用vivado開啟four_bit_adder.v與four_bit_adder_tb.v進行simulation,並合成Schematic。 四、結果-觀察輸出、輸出波型與Schematic。 **vscode部分**: 觀察輸出![](https://hackmd.io/_uploads/rJHIEj8l6.png) 觀察輸出波型 ![](https://hackmd.io/_uploads/Hyme_jLgT.png) **vivado部分**: 觀察輸出波型: ![](https://hackmd.io/_uploads/Hy-UGV_g6.png) 結果全部吻合預期----->合成schematic ![](https://hackmd.io/_uploads/HkVjOs8lT.png) ![](https://hackmd.io/_uploads/Bk60XZ3xp.png) 七、心得-這是第一次使用verilog完成作業,儘管語法學起來不難但仍有許多沒有預期到的bug!!!,後來發現是testbench的技巧尚未純熟,導致vscode那邊無法compile,希望自己可以能更加精進。 八、參考文獻-軟硬體協同設計上課講義-林宏益教授編 # HW-2 **一、目的** -用verilog實現BCD to Decimal Decoder with Preset/Reset並提供vivado模擬報告。 **二、工具**-vscode,xilinx-vivado **三、方法與步驟**-詳細說明 1.先在vscode寫出RTL檔與testbench並驗證其結果 RTL CODE: ```verilog= module bcd_to_decimal ( A, // I 1-bit first inout bit B, // I 1-bit second input bit C, // I 1-bit third input bit D, // I 1-bit fourth input bit reset_n, preset, O // O 10-bit output ); input A,B,C,D,reset_n,preset; output [9:0]O; reg [9:0]O; always @(A or B or C or D or reset_n or preset) begin casez ({reset_n, preset}) 2'b0x : O = 10'b00_0000_0000; 2'b11 : O = 10'b00_0000_1111; 2'b10 : if ({D, C, B, A} == 4'b0000) O = 10'b11_1111_1110; else if({D, C, B, A} == 4'b0001) O = 10'b11_1111_1101; else if({D, C, B, A} == 4'b0010) O = 10'b11_1111_1011; else if({D, C, B, A} == 4'b0011) O = 10'b11_1111_0111; else if({D, C, B, A} == 4'b0100) O = 10'b11_1110_1111; else if({D, C, B, A} == 4'b0101) O = 10'b11_1101_1111; else if({D, C, B, A} == 4'b0110) O = 10'b11_1011_1111; else if({D, C, B, A} == 4'b0111) O = 10'b11_0111_1111; else if({D, C, B, A} == 4'b1000) O = 10'b10_1111_1111; else if({D, C, B, A} == 4'b1001) O = 10'b01_1111_1111; else O = 10'b11_1111_1111; default: O = 10'b11_1111_1111; endcase end endmodule ``` **testbench -暴力輸入** ![](https://hackmd.io/_uploads/Bk6JUMQWT.png) ----->結果吻合預期 觀察波形圖 ![](https://hackmd.io/_uploads/HJpSUzXZp.png) ----->同樣吻合預期 2.放入vivado做模擬 run simulation 確認輸出與輸入埠正確 ----->查看波形 ![](https://hackmd.io/_uploads/HJIvxvmWp.png) ----->符合預期 RTL ANALYSIS 的schematic 圖 ![](https://hackmd.io/_uploads/H1UpWvQZT.png) ![](https://hackmd.io/_uploads/H1ylfDm-T.png) ![](https://hackmd.io/_uploads/SkeWfPX-T.png) ![](https://hackmd.io/_uploads/HkmZzwXZT.png) ![](https://hackmd.io/_uploads/BJuZGPXZT.png) ![](https://hackmd.io/_uploads/S16ZzD7Zp.png) ----->10個多工器吻合預期 IMPLEMENTATION schematic: ![](https://hackmd.io/_uploads/Bk164wQZ6.png) 分析報告與心得: ![](https://hackmd.io/_uploads/HkV3SD7Wa.png) 在分析報告中,我的logic power為0.032w,雖然不是特別耗能,但是我覺得我的if else 語句造成elaborated schematic 圖超級長!,應該是RTL CODE沒有設計好,也許有更好的解法尚未想到。 ## FPGA 驗證 **當preset=1 reset=1** **輸出:1111000000** ![](https://hackmd.io/_uploads/SkUiwdpz6.jpg) **reset_n=1 preset=0** **輸入:0000 輸出:0111111111** ![](https://hackmd.io/_uploads/B1RpUdTMT.jpg) **輸入:0001 輸出:1011111111** ![](https://hackmd.io/_uploads/r1wdddTGa.jpg) # HW-3、4 ## 目的 當reset_n=1,則輸入有效 當輸入: **D=0 C=0 B=0 A=0** 則七段顯示器顯示0-----> 輸出: **a=0 b=0 c=0 d=0 e=0 f=0 g=1 dp=1** (因共陰故0的地方亮) ...以此類推... 當reset_n=0,則輸入無效 輸入: **D=x C=x B=x A=x** 七段顯示器顯示H----> 輸出: **a=1 b=0 c=0 d=1 e=0 f=0 g=0 dp=1** ![](https://hackmd.io/_uploads/B1K4LdoGa.png) ![](https://hackmd.io/_uploads/ryufr_oG6.png) ## HDL CODE說明 ``` verilog module segment7 ( A, B, C, D, reset_n, disp ); input reset_n,A,B,C,D; reg [7:0] disp; output [7:0] disp; wire [4:0] BCD_code; assign BCD_code={reset_n,D,C,B,A}; always @(BCD_code) case (BCD_code) 5'b10000: disp=8'b0000_0011; 5'b10001: disp=8'b1001_1111; 5'b10010: disp=8'b0010_0101; 5'b10011: disp=8'b0000_1101; 5'b10100: disp=8'b1001_1001; 5'b10101: disp=8'b0100_1001; 5'b10110: disp=8'b0100_0001; 5'b10111: disp=8'b0001_1111; 5'b11000: disp=8'b0000_0001; 5'b11001: disp=8'b0000_1001; 5'b11010: disp=8'b0001_0001; 5'b11011: disp=8'b1100_0001; 5'b11100: disp=8'b0110_0011; 5'b11101: disp=8'b1000_0101; 5'b11110: disp=8'b0110_0001; 5'b11111: disp=8'b0111_0001; default : disp=8'b10010001//五個位元32個數已經定義16個 //故0xxxx都是8'b10010001---->顯示H endcase endmodule ``` ## Testbench Code說明 1.檢測當reset_n=0 輸出是否正確 2.檢測reset_n=1 時的所有輸出 ``` verilog module segment7_tb(); reg reset_n, D, C, B, A; wire [7:0] disp; integer i;//給reset_n=1時的迴圈用 initial begin $dumpfile("segment7.vcd"); $dumpvars(0, display_unit); $monitor("reset_n = %b, D = %b C = %b B = %b A = %b | a = %b b = %b c = %b d = %b e = %b f = %b g = %b dp = %b" , reset_n, D, C, B, A, disp[7],disp[6],disp[5],disp[4],disp[3],disp[2],disp[1],disp[0]); #10; reset_n=1'b0; A = 1'b0; B = 1'b0; C = 1'b0; D = 1'b0; //測試reset有沒有用 #10; reset_n=1'b0; A = 1'b0; B = 1'b1; C = 1'b0; D = 1'b1; //測試reset有沒有用 #10; reset_n=1'b1; for (i = 0; i <= 15 ; i = i + 1 ) //迴圈輸入從0000~1111 begin D = i[3]; C = i[2]; B = i[1]; A = i[0]; #10; end #10 $finish; end segment7 display_unit ( .A(A), .B(B), .C(C), .D(D), .reset_n(reset_n), .disp(disp) ); endmodule ``` **結果:** ![](https://hackmd.io/_uploads/H1b12_izp.png) ## Schematic RTL ![](https://hackmd.io/_uploads/HJCgjx3zp.png) IMPLEMENTATION ![](https://hackmd.io/_uploads/H17Faxhz6.png) POWER ![](https://hackmd.io/_uploads/rkjapghMT.png) ## 工作站模擬 Verdi Tool ![](https://hackmd.io/_uploads/S1mnyuafa.png) ![](https://hackmd.io/_uploads/Skh-l_6zp.png) Wave ![](https://hackmd.io/_uploads/HkUWEupfa.png) **結果與預期相符--->成功!!** ## FPGA 驗證 **reset_n=0** 全部------>顯示H ![S__16121859.jpg](https://hackmd.io/_uploads/Hkk8kdM7a.jpg) **reset_n=1** 輸入:0000------>顯示0 ![S__16121861.jpg](https://hackmd.io/_uploads/B10Mg_fX6.jpg) **reset_n=1** 輸入:0001------>顯示1 ![S__16121862.jpg](https://hackmd.io/_uploads/r1sQxOzQT.jpg) **reset_n=1** 輸入:0010------>顯示2 ![S__16121863.jpg](https://hackmd.io/_uploads/B1TAe_G76.jpg) **reset_n=1** 輸入:0011------>顯示3 ![S__16121864.jpg](https://hackmd.io/_uploads/ByTyW_zQa.jpg) **reset_n=1** 輸入:0100------>顯示4 ![S__16121865.jpg](https://hackmd.io/_uploads/HJBQb_zmp.jpg) **reset_n=1** 輸入:0101------>顯示5 ![S__16121866.jpg](https://hackmd.io/_uploads/rkL4buzXT.jpg) **reset_n=1** 輸入:0110------>顯示6 ![S__16121867.jpg](https://hackmd.io/_uploads/r1R4ZdGXp.jpg) **reset_n=1** 輸入:0111------>顯示7 ![S__16121868.jpg](https://hackmd.io/_uploads/B1ZLbdzQ6.jpg) **reset_n=1** 輸入:1000------>顯示8 ![S__16121869.jpg](https://hackmd.io/_uploads/HJcLZOzmT.jpg) **reset_n=1** 輸入:1001------>顯示9 ![S__16121870.jpg](https://hackmd.io/_uploads/H1Xvb_zmp.jpg) **reset_n=1** 輸入:1010------>顯示A ![S__16121872.jpg](https://hackmd.io/_uploads/BJ5KW_MQ6.jpg) **reset_n=1** 輸入:1011------>顯示b ![S__16121873.jpg](https://hackmd.io/_uploads/r1fq-OM7a.jpg) **reset_n=1** 輸入:1100------>顯示C ![S__16121874.jpg](https://hackmd.io/_uploads/rkekfOzQT.jpg) **reset_n=1** 輸入:1101------>顯示d ![S__16121875.jpg](https://hackmd.io/_uploads/HJgQG_fXa.jpg) **reset_n=1** 輸入:1110------>顯示E ![S__16121876.jpg](https://hackmd.io/_uploads/SyZUMdfX6.jpg) **reset_n=1** 輸入:1111------>顯示F ![S__16121877.jpg](https://hackmd.io/_uploads/S1L5MOzQa.jpg) # HW-5 ## FSM Coverage 只有75%原因 ![370099462_2526763234178725_2726113974856680153_n](https://hackmd.io/_uploads/HkHDJyoNp.png) 在FSM Coverage看到,過程中並沒有執行到s0 ----> IDLE ## 推測------>看波型 ![87](https://hackmd.io/_uploads/r1ksMksNT.png) 看出inp 輸入延遲太長,導致inp一直為1,沒有回到0,讓s0回到IDLE。 ## 提升覆蓋率------>修改testbench **INP輸入延遲改成10ps** ![image](https://hackmd.io/_uploads/HJYi3yo4T.png) **波型確認** ![88](https://hackmd.io/_uploads/SJ3eJgjN6.png) 覆蓋率確認 ![image](https://hackmd.io/_uploads/rJ5CSJjNT.png) **---->皆有執行** ## 為何不能到達Line、Branch無法到達100% ![image](https://hackmd.io/_uploads/H1C3I1o4T.png) **軟體無法忽略default敘述,因為testbench沒有跑到可是卻有這行敘述,所以無法到達100%** ## 解決:忽略default這個覆蓋率 **修改編譯選項 --->新增 VCS coverage off/on 意義:模擬但不統計覆蓋率** **覆蓋率確認** ![image](https://hackmd.io/_uploads/By0Jfxi4T.png) --->SUCCEED!! # HW-6(UART) ## FPGA呈現 [影片連結](https://youtu.be/bnsP-E6n6Qc) ## Verilog code ```verilog= //top module `timescale 1ns / 1ps module rx_top( input clk, input rst, input rx_pin_in, output [7:0] seg7 ) ; wire rx_pin_H2L; H2L_detect rx_in_detect( .clk( clk ), .rst( rst ), .pin_in( rx_pin_in ), .sig_H2L( rx_pin_H2L ) ); wire rx_band_sig; wire clk_bps; rx_band_gen rx_band_gen( .clk( clk ), .rst( rst ), .band_sig( rx_band_sig ), .clk_bps( clk_bps ) ); wire [7:0] rx_data; rx_ctl rx_ctl( .clk( clk ), .rst( rst ), .rx_pin_in( rx_pin_in ), .rx_pin_H2L( rx_pin_H2L ), .rx_band_sig( rx_band_sig ), .rx_clk_bps( clk_bps ), .rx_data( rx_data ), .rx_done_sig( rx_done_sig ) ); ASCII2seg7 u_ASCII2seg7( .rst( rx_done_sig ), .ASCII( rx_data ), .seg7_out(seg7) ); endmodule ``` ```verilog= `timescale 1ns / 1ps module rx_band_gen( input clk, input rst, input band_sig, output reg clk_bps ); parameter SYS_RATE = 125000000; parameter BAND_RATE = 9600; parameter CNT_BAND = SYS_RATE / BAND_RATE; parameter HALF_CNT_BAND = CNT_BAND / 2; reg [13:0]cnt_bps; always @( posedge clk or posedge rst ) if( rst ) begin cnt_bps <= HALF_CNT_BAND; clk_bps <= 1'b0; end else if( !band_sig ) begin cnt_bps <= HALF_CNT_BAND; clk_bps <= 1'b0; end else if( cnt_bps == CNT_BAND ) begin cnt_bps <= 14'd0; clk_bps <= 1'b1; end else begin cnt_bps <= cnt_bps + 1'b1; clk_bps <= 1'b0; end endmodule ``` ```verilog= `timescale 1ns / 1ps module H2L_detect( input clk, input rst, input pin_in, output sig_H2L ); reg pin_pre; assign sig_H2L = !pin_in & pin_pre; always @( posedge clk or posedge rst ) if( rst ) pin_pre <= 1'b0; else pin_pre <= pin_in; endmodule ``` ```verilog= module ASCII2seg7 ( rst, ASCII, seg7_out ); input rst; input [7:0] ASCII; reg [7:0] seg7; output [7:0] seg7_out; always@( posedge rst ) begin //if ( rst ) begin case (ASCII) 8'b0011_0000: seg7=8'b00000011; 8'b0011_0001: seg7=8'b10011111; 8'b0011_0010: seg7=8'b00100101; 8'b0011_0011: seg7=8'b00001101; 8'b0011_0100: seg7=8'b10011001; 8'b0011_0101: seg7=8'b01001001; 8'b0011_0110: seg7=8'b01000001; 8'b0011_0111: seg7=8'b00011111; 8'b0011_1000: seg7=8'b00000001; 8'b0011_1001: seg7=8'b00001001; 8'b0100_0001: seg7=8'b00010001; 8'b0100_0010: seg7=8'b11000001; 8'b0100_0011: seg7=8'b11100101; 8'b0100_0100: seg7=8'b10000101; 8'b0100_0101: seg7=8'b01100001; 8'b0100_0110: seg7=8'b01110001; default: seg7=8'b01100001; endcase end assign seg7_out=seg7; endmodule ``` ```verilog= `timescale 1ns / 1ps module rx_ctl( input clk, input rst, input rx_pin_in, input rx_pin_H2L, output reg rx_band_sig, input rx_clk_bps, output reg[7:0] rx_data, output reg rx_done_sig ) ; localparam [3:0] IDLE = 4'd0, BEGIN = 4'd1, DATA0 = 4'd2, DATA1 = 4'd3, DATA2 = 4'd4, DATA3 = 4'd5, DATA4 = 4'd6, DATA5 = 4'd7, DATA6 = 4'd8, DATA7 = 4'd9, END = 4'd10, BFREE = 4'd11; reg [3:0] pos; always@( posedge clk or posedge rst ) if( rst ) begin rx_band_sig <= 1'b0; rx_data <= 8'd0; pos <= IDLE; rx_done_sig <= 1'b0; end else case( pos ) IDLE: if( rx_pin_H2L) begin rx_band_sig <= 1'b1; pos <= pos + 1'b1; rx_data <= 8'd0; end BEGIN: if( rx_clk_bps) begin if( rx_pin_in == 1'b0 ) begin pos <= pos + 1'b1; end else begin rx_band_sig <= 1'b0; pos <= IDLE; end end DATA0,DATA1,DATA2,DATA3,DATA4,DATA5,DATA6,DATA7: if( rx_clk_bps) begin rx_data[ pos - DATA0 ] <= rx_pin_in; pos <= pos + 1'b1; end END: if( rx_clk_bps) begin rx_done_sig <= 1'b1; pos <= pos + 1'b1; rx_band_sig <= 1'b0; end BFREE: begin rx_done_sig <= 1'b0; pos <= IDLE; end endcase endmodule ``` ## testbench ```verilog= `timescale 1ns / 1ps module rx_top_tb(); reg clk; reg rst; reg uart_rx; wire [7:0] seg7; integer i; reg [7:0] data_test=8'b0; // 100MHz 9600bps rx_top u_rx_top( .clk(clk), .rst(rst), .rx_pin_in(uart_rx), .seg7(seg7) ); initial begin clk=0; for (i=0;i<256;i=i+1) begin //8 bit 測256個資料 rst=1; #15 rst=0;uart_rx=1; #260415 uart_rx=0; #260415 uart_rx = data_test[0]; #260415 uart_rx = data_test[1]; #260415 uart_rx = data_test[2]; #260415 uart_rx = data_test[3]; #260415 uart_rx = data_test[4]; #260415 uart_rx = data_test[5]; #260415 uart_rx = data_test[6]; #260415 uart_rx = data_test[7]; #260415 uart_rx=1; data_test = data_test + 1; end $finish; end always #10 clk=~clk; endmodule ``` ## Coverage ![image](https://hackmd.io/_uploads/HyOWtt8Yp.png) ## Lint ![image](https://hackmd.io/_uploads/HyH7ttLta.png) ## Schematic ![image](https://hackmd.io/_uploads/SkmbLhG8a.png) # Reading experience 人月神話閱讀心得(張家凱,李旼學) --- ## 張家凱 關於人月神話的解釋,這是讓我非常印想深刻的一段,且就在開頭的第二章,所謂的人月就是人與時間的關係,在當工作可以被切分且工作的人「彼此不用溝通的條件下」,假設一個小任務一個人可以三天做完,那麼三人一天便可以做完,然而在軟體工程如果這樣來衡量工作規模是相當危險的,因為溝通成本也會隨著人數增長而提高(包括人員對產品概念性的不同),所以有的時候添加人手是拖延了進度而不是縮短。 而這也帶出了溝通的重要性,一直延伸到了為何巴別塔會失敗(Why Did The Tower of Babel Fail?),巴別塔故事中作者提到這項建設具備了許多成功的條件 1. 明確的目標 2. 人力 3. 材料 4. 足夠的時間 5. 充分的技術 然而最終為何失敗呢?他們缺少了「溝通」與「組織」,當人與人之間不能溝通,就無法合作,合作失敗意味著工作停頓,於是最終團隊土崩瓦解。作者同時也提到了各種方法等,包含建立交流 1. 非正式方法(良好的電話聯繫制度) 2. 會議(例行性的專案會議) 3. 工作手冊 建立良好組織架構減少溝通成本 1. 人力的配置 2. 專業分工 在第一版的二十年後,作者依然說著:「專案如果要成功,人的品質,以及人的組織與管理,遠遠比他們所運用的工具或技術來的重要。」,這也是讓我最終感動的地方,即使過了二十年依舊不變的定理,我也歸納、濃縮了幾個重點 1. 人的品質: 作者認為,優秀的工程師遠比普通的工程師更能夠提高專案的效率。他指出,優秀的人才可以在短時間內完成高質量的工作,而招聘優秀的人才比增加人數更為關鍵。 2. 人的組織: 良好的組織結構是確保專案成功的關鍵因素。有效的溝通和協作可以防止資訊不對等和做重複工作,提高整個團隊的效能,以免拖累軟體工程的進度。 3. 管理: 專案管理也是本書的核心價值,作者指出,良好的專案管理包括計畫、組織、追蹤和控制。管理者需要有適當的計畫和組織,以確保專案能夠按時交付。 總而言之,雖然「人月神話」還強調了許多概念,但是礙於篇幅我不能一一細說,且許多較為古老的技術,實在難以想像,但我相信在一個專案成功的例子中,人的品質、組織結構以及有效的管理比使用的工具或技術更為重要,這也是作者花好幾個章節所提到的。即使擁有最先進的技術,如果沒有優秀的人才和有效的管理,專案仍然可能陷入困境。此外這個概念也激勵著我成為更好的「新鮮人」,因為反過來說,公司應該不太願意培養一個「二流人才」,來拖累他們的產品進度,並成為一個「負資產」,而這也是我目前的心得,期許書中的概念能陪伴我之後的工作歲月。 --- ## 李旼學 --- 人月神話這本書,講述了軟體工程中專案管理的重要性。第一章的焦油坑,便比較了個人單獨寫出的程式與一系統產品的差別,若將程式產品化,所需成本為三倍,而將其進行整合測試等過程凝聚成一個系統,也就是系統化的過程,所需的成本也是三倍,而兩者是分開獨立計算的,所以要推出一個系統產品,複雜度是直線上升的。 因此,如何在一個龐大的軟體開發中,進行有效的管理,是一個至關重要的課題。而作者便在第二章提出人月的觀點,也就是人與時間之間的關係。在傳統的觀念中,我們或許會直覺地認為人多好辦事,但在軟體開發的世界並非如此,作者在文中說過一句有趣的話:生小孩就是要九個月,你叫多少媽生都是一樣,也就是人力與時間並非是線性關係,那只發生在工作可被切分而且無須溝通成本的情況下,如果在實際工程中採用此模型衡量成本與規模,無疑是一件危險的事情。舉一個在作業系統學到的Amdahl's Law,其在討論是否一直增加核心數,就能提升電腦的效能,結論是提升的效能變非是一個線性關係,而是與其serial(串列)的部分息息相關,若是serial port的部分越多,則增加的效能越少,所以我們應該要考慮的是增加parallel port的部分,也就是進行平行化處理,若將人比喻成core,似乎不論是人或是機器的法則,都意外地相近呢。 而作者也以本身經驗,對軟體開發時程進行以下的分配: 1.1/3 整體規劃 2.1/6 撰寫程式 3.1/4 組件測試與初步系統測試 4.1/4 系統測試以及完成組件 可以看出撰寫程式的時間其實是最少的,花最多的反而是對專案的時程內容等等規劃的時間,也就是所謂的工欲善其事,必先利其器,有良好的規劃與安排,對整體開發的構思,才能友善提高整體品質,減少無謂的溝通成本。而在組件與系統的測試也是十分重要的一個環節,開發的軟體產品必須經過維護以及測試,確保及功能的正確性,才能作為產品去銷售,在課堂中從撰寫verilog code,到現在正在教學的vcs,verdi, dc compiler作驗證,我想我們也是在run過一個小小小專案所必備的流程。 基於以上的概念,在處理一個專案時,如何最大化提升效率呢? 作者便提出了外科手術團隊的概念,以一人為主體,其他人則各司其職,作一個輔助的部分,處理一些小的專案,這樣明確的分工制度,除了能減少溝通成本,也能因為少數人進行決策,維持對產品的概念的整體性,減少不同人對產品概念的看法不同,在認知上造成差異的錯誤。 老實說,我並沒有看完整本書,但從前面大部分篇章,都能看到作者對團隊組織結構以及管理層面的探討。技術可能與時俱進,需要不斷去更新,但對專案組織等等的管理,卻是一個整體概念變化不大的部分,這也是為什麼人月神話經過了40年的光陰,仍然能被教授推薦閱讀的原因,這也是在職場與人co-working時很重要的部分,期許自己能先精進實力,爾後在職場的時光,能細品本書的字字句句。 # Final project ## UART 的實現與面積、功率的縮小 利用UART通訊協議來實現資料傳輸 ![image](https://hackmd.io/_uploads/HyNXBMMFp.png) 本次是實現9600bps的通訊協議 ## 架構 ![image](https://hackmd.io/_uploads/Sy5xb6XFT.png) ## 原版程式 目的:將PC端的傳輸訊號(ASCII)傳入至FPGA上(receiver端),輸入1到9顯示1到9,輸入A到E顯示A~E,其他輸入顯示E。 ```verilog= //TOP MODULE `timescale 1ns / 1ps module rx_top( input clk, input rst, input rx_pin_in, output [7:0] seg7 ); wire [7:0] rx_data; wire rx_band_sig; wire clk_bps; rx_band_gen rx_band_gen( .clk( clk ), .rst( rst ), .band_sig( rx_band_sig ), .clk_bps( clk_bps ) ); H2L_detect rx_in_detect( .clk( clk ), .rst( rst ), .pin_in( rx_pin_in ), .sig_H2L( rx_pin_H2L ) ); rx_ctl rx_ctl( .clk( clk ), .rst( rst ), .rx_pin_in( rx_pin_in ), .rx_band_sig( rx_band_sig ), .rx_clk_bps( clk_bps ), .rx_data( rx_data ), .rx_done_sig( rx_done_sig ) ); ASCII27 ASCII27( .rst( rx_done_sig ), .ascii( rx_data ), //rx_data訊號->ASCII .seg7(seg7) ); endmodule ``` ```verilog= //製造9600bps的除頻器 module rx_band_gen( input clk, input rst, input band_sig, output reg clk_bps ); parameter SYS_RATE = 125000000;//FPGA 之系統頻率 parameter BAND_RATE = 9600; parameter CNT_BAND = SYS_RATE / BAND_RATE; parameter HALF_CNT_BAND = CNT_BAND / 2; reg [13:0]cnt_bps; always @( posedge clk or posedge rst ) if( rst ) begin cnt_bps <= HALF_CNT_BAND; clk_bps <= 1'b0; end else if( !band_sig ) begin cnt_bps <= HALF_CNT_BAND; clk_bps <= 1'b0; end else if( cnt_bps == CNT_BAND ) begin cnt_bps <= 14'd0; clk_bps <= 1'b1; end else begin cnt_bps <= cnt_bps + 1'b1; clk_bps <= 1'b0; end ``` ![image](https://hackmd.io/_uploads/S1VsoXGY6.png) ```verilog= //偵測start 訊號 module H2L_detect( input clk, input rst, input pin_in, output sig_H2L ); reg pin_pre; assign sig_H2L = !pin_in & pin_pre; always @( posedge clk or posedge rst ) if( rst ) pin_pre <= 1'b0; else pin_pre <= pin_in; endmodule ``` ```verilog= //UART 狀態機 module rx_ctl( input clk, input rst, input rx_pin_in, input rx_pin_H2L, output reg rx_band_sig, input rx_clk_bps, output reg[7:0] rx_data, output reg rx_done_sig ) ; localparam [3:0] IDLE = 4'd0, BEGIN = 4'd1, DATA0 = 4'd2, DATA1 = 4'd3, DATA2 = 4'd4, DATA3 = 4'd5, DATA4 = 4'd6, DATA5 = 4'd7, DATA6 = 4'd8, DATA7 = 4'd9, END = 4'd10, BFREE = 4'd11; reg [3:0] pos; always@( posedge clk or posedge rst ) if( rst ) begin rx_band_sig <= 1'b0; rx_data <= 8'd0; pos <= IDLE; rx_done_sig <= 1'b0; end else case( pos ) IDLE://等待start 訊號,H2L發生跳到BEGIN if( rx_pin_H2L) begin rx_band_sig <= 1'b1;//產生rx_clk_bps訊號 pos <= pos + 1'b1; rx_data <= 8'd0; end BEGIN: if( rx_clk_bps) begin if( rx_pin_in == 1'b0 ) begin pos <= pos + 1'b1; end else begin rx_band_sig <= 1'b0; pos <= IDLE; end end DATA0,DATA1,DATA2,DATA3,DATA4,DATA5,DATA6,DATA7://儲存rx_data if( rx_clk_bps) begin rx_data[ pos - DATA0 ] <= rx_pin_in;//rx_pin_in資料儲存至rx_data pos <= pos + 1'b1; end END://完成接收,rx_done_sig輸出1, //rx_band_sig輸出0,停止產收rx_clk_bps訊號,跳到BFREE。 if( rx_clk_bps) begin rx_done_sig <= 1'b1; pos <= pos + 1'b1; rx_band_sig <= 1'b0; end BFREE://rx_done_sig輸出0,回到IDLE begin rx_done_sig <= 1'b0; pos <= IDLE; end endcase endmodule ``` ![image](https://hackmd.io/_uploads/rJJt0XzFa.png) ```verilog= //鍵盤數字ASCII轉七段顯示器數字(共陽)之模組 module ASCII2seg7 ( rst, ASCII, seg7_out ); input rst; input [7:0] ASCII; reg [7:0] seg7; output [7:0] seg7_out; always@( posedge rst ) begin case (ASCII) 8'b0011_0000: seg7<=8'b00000011; 8'b0011_0001: seg7<=8'b10011111; 8'b0011_0010: seg7<=8'b00100101; 8'b0011_0011: seg7<=8'b00001101; 8'b0011_0100: seg7<=8'b10011001; 8'b0011_0101: seg7<=8'b01001001; 8'b0011_0110: seg7<=8'b01000001; 8'b0011_0111: seg7<=8'b00011111; 8'b0011_1000: seg7<=8'b00000001; 8'b0011_1001: seg7=8'b00001001; 8'b0100_0001: seg7=8'b00010001; 8'b0100_0010: seg7=8'b11000001; 8'b0100_0011: seg7=8'b11100101; 8'b0100_0100: seg7=8'b10000101; 8'b0100_0101: seg7=8'b01100001; 8'b0100_0110: seg7=8'b01110001; default: seg7=8'b01100001; endcase end assign seg7_out=seg7; endmodule ``` ## 波型驗證圖 ![1](https://hackmd.io/_uploads/BkOw2uXtT.jpg) ![2](https://hackmd.io/_uploads/BJUu6dmtT.jpg) ![3](https://hackmd.io/_uploads/SyktTOXFp.jpg) ![4](https://hackmd.io/_uploads/S11RaO7FT.jpg) ![5](https://hackmd.io/_uploads/H1SJAOQtp.jpg) ![6](https://hackmd.io/_uploads/B1YgRumKT.jpg) ## Area and Power report Design Compiler 最小面積使用與最小動態功率Constraint ![image](https://hackmd.io/_uploads/HyQsq5mFp.png) ![image](https://hackmd.io/_uploads/ryhJo9XFp.png) ![image](https://hackmd.io/_uploads/r1E-i5Qt6.png) ![3B50837D-AA84-4E5A-A6FD-6EF2FB09A9CB](https://hackmd.io/_uploads/Sk2APK7K6.jpg) ---->沒有設面積2900up ![12](https://hackmd.io/_uploads/SJfskKXF6.jpg) | ## 第二版 思考狀態機的縮減,將接收資料狀態合併成一個狀態--->用編碼減少狀態 ```verilog= module rx_ctl( input clk, input rst, input rx_pin_in, input rx_pin_H2L, output reg rx_band_sig, input rx_clk_bps, output reg[7:0] rx_data, output reg rx_done_sig ); localparam [3:0] IDLE = 4'd0, BEGIN = 4'd1, DATA = 4'd2, // 合併所有數據狀態 END = 4'd3, BFREE = 4'd4; reg [3:0] pos; reg [2:0] data_bit_count; // 計數器用於追蹤數據位 always@(posedge clk or posedge rst) begin if(rst) begin rx_band_sig <= 1'b0; rx_data <= 8'd0; pos <= IDLE; rx_done_sig <= 1'b0; data_bit_count <= 3'd0; end else begin case(pos) IDLE: begin if(rx_pin_H2L) begin rx_band_sig <= 1'b1; pos <= BEGIN; rx_data <= 8'd0; data_bit_count <= 3'd0; end end BEGIN: begin if(rx_clk_bps) begin if(rx_pin_in == 1'b0) begin pos <= DATA; end else begin rx_band_sig <= 1'b0; pos <= IDLE; end end end DATA: begin if(rx_clk_bps) begin rx_data[data_bit_count] <= rx_pin_in; if(data_bit_count == 3'd7) begin pos <= END; end else begin data_bit_count <= data_bit_count + 1'b1; end end end END: begin if(rx_clk_bps) begin rx_done_sig <= 1'b1; pos <= BFREE;//也可寫<=pos+1 rx_band_sig <= 1'b0; end end BFREE: begin rx_done_sig <= 1'b0; pos <= IDLE; end endcase end end endmodule ``` ## Second ver. Area and Power report ![messageImage_1705379431048](https://hackmd.io/_uploads/rJCyPKQtp.jpg) ![14](https://hackmd.io/_uploads/HyG2xKQYp.jpg) 面積由原本的2473縮小為2354,縮小率大約為4.8%. ## 第三版 1. 合併狀態後思考著編碼方式的差別,因為one-hot編碼,每個編碼都只有一個高位元所以邏輯上不會合成出複雜的decoder電路。參考課本第299頁 ![17](https://hackmd.io/_uploads/SknBEtmKT.jpg) ![18](https://hackmd.io/_uploads/B1g_NFmYp.jpg) 隱憂:相較第二版的2進制只需要3位元,one-hot需要5位元---->面積下降不大。 好處:也因為邏輯轉換上較為簡單(每次只有一個1變0,一個0變1,而二進位可能有多位轉換)我們可以推測,功率會比較小。 ```verilog= module rx_ctl( input clk, input rst, input rx_pin_in, input rx_pin_H2L, output reg rx_band_sig, input rx_clk_bps, output reg [7:0] rx_data, output reg rx_done_sig ); // 使用one-hot編碼定義狀態 localparam [4:0] IDLE = 5'b00001, BEGIN = 5'b00010, DATA = 5'b00100, // 合併所有數據狀態 END = 5'b01000, BFREE = 5'b10000; reg [4:0] pos; reg [2:0] data_bit_count; // 計數器用於追蹤數據位 always @(posedge clk or posedge rst) begin if (rst) begin rx_band_sig <= 1'b0; rx_data <= 8'd0; pos <= IDLE; rx_done_sig <= 1'b0; data_bit_count <= 3'd0; end else begin case (pos) // 使用one-hot狀態機 IDLE: begin if (rx_pin_H2L) begin rx_band_sig <= 1'b1; pos <= BEGIN; rx_data <= 8'd0; data_bit_count <= 3'd0; end end BEGIN: begin if (rx_clk_bps) begin if (rx_pin_in == 1'b0) begin pos <= DATA; end else begin rx_band_sig <= 1'b0; pos <= IDLE; end end end DATA: begin if (rx_clk_bps) begin rx_data[data_bit_count] <= rx_pin_in; if (data_bit_count == 3'd7) begin pos <= END; end else begin data_bit_count <= data_bit_count + 1'b1; end end end END: begin if (rx_clk_bps) begin rx_done_sig <= 1'b1; pos <= BFREE; rx_band_sig <= 1'b0; end end BFREE: begin if (rx_clk_bps) begin rx_done_sig <= 1'b0; pos <= IDLE; end end endcase end end endmodule ``` ## Third Ver. Area and Power report ![14D05D22-82A3-453C-8F2C-6A6D485D45F6](https://hackmd.io/_uploads/H1WhuKmKp.jpg) ![16](https://hackmd.io/_uploads/HksHfFmtT.jpg) 與原面積相比,由2473降至2306,縮小率約為6.75%. ## UART在FPGA上的實測 ![100](https://hackmd.io/_uploads/SJChg9QKp.jpg) ![101](https://hackmd.io/_uploads/rkZCx5QKT.jpg) ![102](https://hackmd.io/_uploads/S1lgW9XFa.jpg) ![103](https://hackmd.io/_uploads/H1D4-9QYp.jpg) ![104](https://hackmd.io/_uploads/ByXr-qmKa.jpg) ![105](https://hackmd.io/_uploads/H12BZ57Y6.jpg) [demo影片](https://youtu.be/bnsP-E6n6Qc?si=9rLoodm-iH_VMuvb)