之前做LDPC編碼器時,學習了一下非同步FIFO的相關知識,主要參考了http://www.cnblogs.com/aslmer/p/6114216.html,併在此基礎上根據項目需求,添加了一個讀控制模塊。因為後面編碼模塊的需要,因此fifo_in模塊要求滿足下麵功能: a、存儲輸入數據 b、當fi ...
之前做LDPC編碼器時,學習了一下非同步FIFO的相關知識,主要參考了http://www.cnblogs.com/aslmer/p/6114216.html,併在此基礎上根據項目需求,添加了一個讀控制模塊。因為後面編碼模塊的需要,因此fifo_in模塊要求滿足下麵功能:
a、存儲輸入數據
b、當fifo中存儲數據的個數達到x時,產生激勵信號,並連續輸出這x個數據
c、當後面編碼模塊處於編碼過程中時,禁止數據輸出
d、x是根據不同編碼碼率而確定的,因此要時常變化(這個功能時聯合其他模塊共同實現的)
1、fifo_in.v 是頂層模塊,作用是將各個小模塊例化聯繫起來。
輸入信號encoding是由後面編碼模塊產生,表示是否在編碼過程中。輸入信號in_length輸入的數就是個數要求x,由碼率選擇模塊產生。
輸出信號start_code是給編碼模塊的激勵信號。輸出信號rd_over表示當前一串數據已經輸出完畢,主要用於給碼率選擇模塊改變x的值時用。
1 module fifo_in 2 ( 3 //input 4 input wr_clk, 5 input encoding, 6 input wr_rst_n, 7 input wr_ask, 8 input [2:0] wr_data, 9 input rd_clk, 10 input rd_rst_n, 11 input [9:0] in_length, 12 //output 13 output wr_full,//寫滿 14 output rd_empty,//讀空 15 output [2:0] rd_data, 16 output rd_en, 17 output start_code, 18 output rd_over 19 ); 20 wire wr_en; 21 wire [9:0] wr_addr; 22 wire [9:0] rd_addr; 23 wire rd_ask; 24 25 assign wr_en =(wr_ask) && (!wr_full); 26 fifo_in_control fifo_in_control 27 ( 28 //input 29 .wr_clk(wr_clk), 30 .wr_rst_n(wr_rst_n), 31 .wr_ask(wr_ask), 32 //.wr_data(wr_data), 33 .rd_clk(rd_clk), 34 .rd_rst_n(rd_rst_n), 35 .rd_ask(rd_ask), 36 //output 37 .wr_full(wr_full),//寫滿 38 .rd_empty(rd_empty),//讀空 39 .wr_addr(wr_addr), 40 .rd_addr(rd_addr) 41 //output [2:0] rd_data 42 ); 43 fifo_in_rd_control fifo_in_rd_control 44 ( 45 //input 46 .rd_clk(rd_clk), 47 .rd_rst_n(rd_rst_n), 48 .rd_addr(rd_addr), 49 .wr_addr(wr_addr), 50 .in_length(in_length), 51 .encoding(encoding), 52 //output 53 .rd_ask(rd_ask), 54 .start_code_1(start_code), 55 .rd_en_1(rd_en), 56 .rd_over(rd_over) 57 58 ); 59 fifo_in_mem fifo_in_mem ( 60 .data(wr_data), 61 .rdaddress(rd_addr), 62 .rdclock(rd_clk), 63 .wraddress(wr_addr), 64 .wrclock(wr_clk), 65 .wren(wr_en), 66 .q(rd_data) 67 ); 68 endmoduleView Code
2、fifo_in_control.v 是非同步fifo的主要程式,我從上面那個網址抄來的,網址內的講解也非常清楚,使用格雷碼來避免讀寫地址的混亂。
1 module fifo_in_control 2 ( 3 //input 4 input wr_clk, 5 input wr_rst_n, 6 input wr_ask, 7 //input [2:0] wr_data, 8 input rd_clk, 9 input rd_rst_n, 10 input rd_ask, 11 //output 12 output reg wr_full,//寫滿 13 output reg rd_empty,//讀空 14 output [9:0] wr_addr, 15 output [9:0] rd_addr 16 //output [2:0] rd_data 17 ); 18 19 reg [10:0] rd_proint_gray;//格雷碼形式的寫指針 20 reg [10:0] rd_proint_gray_1;//格雷碼形式的寫指針_延時一個寫時鐘 21 reg [10:0] rd_proint_gray_2;//格雷碼形式的寫指針_延時兩個寫時鐘(同步到寫時鐘的讀指針) 22 23 reg [10:0] wr_proint_gray;//格雷碼形式的讀指針 24 reg [10:0] wr_proint_gray_1;//格雷碼形式的讀指針_延時一個讀時鐘 25 reg [10:0] wr_proint_gray_2;//格雷碼形式的讀指針_延時兩個讀時鐘(同步到讀時鐘的寫指針) 26 27 reg [10:0] wr_proint_bin;//二進位形式的寫指針 28 wire [10:0] wr_proint_bin_next; 29 wire [10:0] wr_proint_gray_next; 30 wire wr_full_val; 31 32 reg [10:0] rd_proint_bin;//二進位形式的讀指針 33 wire [10:0] rd_proint_bin_next; 34 wire [10:0] rd_proint_gray_next; 35 wire rd_empty_val; 36 //--------------------------------------------------------------------------------- 37 always @(posedge wr_clk or negedge wr_rst_n)//讀指針同步到寫時鐘 38 begin 39 if (!wr_rst_n) 40 begin 41 rd_proint_gray_1 <= 0; 42 rd_proint_gray_2 <= 0; 43 end 44 else 45 begin 46 rd_proint_gray_1 <= rd_proint_gray; 47 rd_proint_gray_2 <= rd_proint_gray_1; 48 end 49 end 50 //-------------------------------------------------------------------------------- 51 always @(posedge rd_clk or negedge rd_rst_n)//寫指針同步到讀時鐘 52 begin 53 if (!rd_rst_n) 54 begin 55 wr_proint_gray_1 <= 0; 56 wr_proint_gray_2 <= 0; 57 end 58 else 59 begin 60 wr_proint_gray_1 <= wr_proint_gray; 61 wr_proint_gray_2 <= wr_proint_gray_1; 62 end 63 end 64 //--------------------------------------------------------------------------------- 65 //寫滿判決 66 always @(posedge wr_clk or negedge wr_rst_n) 67 begin 68 if (!wr_rst_n) 69 {wr_proint_bin, wr_proint_gray} <= 0; 70 else 71 {wr_proint_bin, wr_proint_gray} <= {wr_proint_bin_next, wr_proint_gray_next}; 72 end 73 74 // Memory write-address pointer (okay to use binary to address memory) 75 assign wr_addr = wr_proint_bin[9:0]; 76 assign wr_proint_bin_next = wr_proint_bin + (wr_ask & ~wr_full); 77 assign wr_proint_gray_next = (wr_proint_bin_next>>1) ^ wr_proint_bin_next; //二進位轉為格雷碼 78 assign wr_full_val = (wr_proint_gray_next=={~rd_proint_gray_2[10:9],rd_proint_gray_2[8:0]}); //當最高位和次高位不同其餘位相同時則寫指針超前於讀指針一圈,即寫滿 79 80 always @(posedge wr_clk or negedge wr_rst_n) 81 begin 82 if (!wr_rst_n) 83 wr_full <= 1'b0; 84 else 85 wr_full <= wr_full_val; 86 end 87 //---------------------------------------------------------------------------------- 88 //讀空判決 89 always @(posedge rd_clk or negedge rd_rst_n) 90 begin 91 if (!rd_rst_n) 92 begin 93 rd_proint_bin <= 0; 94 rd_proint_gray <= 0; 95 end 96 else 97 begin 98 rd_proint_bin <= rd_proint_bin_next; //直接作為存儲實體的地址 99 rd_proint_gray <= rd_proint_gray_next; 100 end 101 end 102 // Memory read-address pointer (okay to use binary to address memory) 103 assign rd_addr = rd_proint_bin[9:0]; //直接作為存儲實體的地址 104 assign rd_proint_bin_next = rd_proint_bin + (rd_ask & ~rd_empty);//不空且有讀請求的時候讀指針加1 105 assign rd_proint_gray_next = (rd_proint_bin_next>>1) ^ rd_proint_bin_next;//將二進位的讀指針轉為格雷碼 106 // FIFO empty when the next rptr == synchronized wptr or on reset 107 assign rd_empty_val = (rd_proint_gray_next == wr_proint_gray_2); //當讀指針等於同步後的寫指針,則為空。 108 109 always @(posedge rd_clk or negedge rd_rst_n) 110 begin 111 if (!rd_rst_n) 112 rd_empty <= 1'b1; 113 else 114 rd_empty <= rd_empty_val; 115 end 116 117 endmoduleView Code
3、fifo_in_rd_control.v 是fifo_in的讀控制模塊,狀態機分為五個狀態。數據length記錄當前fifo中存儲數據的個數,當其大於x(in_length)時,可以進行輸出。當fifo中存儲數據的個數一直大於x時,兩串輸出數據的間隔只有幾個時鐘周期,有時會造成encoding信號還沒有生效,新的一串數據已經開始輸出,因此設置delay狀態,稍等幾個周期,確定編碼模塊是否在工作。
1 module fifo_in_rd_control 2 ( 3 //input 4 input rd_clk, 5 input rd_rst_n, 6 input [9:0] rd_addr, 7 input [9:0] wr_addr, 8 input [9:0] in_length, 9 input encoding, 10 //output 11 output reg rd_ask, 12 output reg start_code_1, 13 output reg rd_en_1, 14 output reg rd_over 15 ); 16 reg [9:0] length;//當前fifo中存儲數據的個數 17 reg [4:0] state; 18 reg [9:0] count;//計輸出數據的個數 19 // reg [9:0] in_length_next; 20 //reg rd_over; 21 reg start_code; 22 reg rd_en; 23 reg [1:0]i;//延時幾個時鐘 24 25 parameter hold = 5'b00001; 26 parameter delay = 5'b00010; 27 parameter start = 5'b00100; 28 parameter read = 5'b01000; 29 parameter over = 5'b10000; 30 31 32 always @(posedge rd_clk or negedge rd_rst_n) 33 begin 34 start_code_1 <= start_code; 35 rd_en_1 <= rd_en; 36 end 37 always @(posedge rd_clk or negedge rd_rst_n) 38 begin 39 if(!rd_rst_n) 40 begin 41 state <= hold; 42 rd_ask <= 0; 43 start_code <= 0; 44 rd_en <= 0; 45 rd_over <= 0; 46 end 47 else if(encoding) 48 begin 49 state <= hold; 50 rd_ask <= 0; 51 start_code <= 0; 52 rd_en <= 0; 53 rd_over <= 0; 54 end 55 else 56 case(state) 57 hold: 58 if(in_length <= length) 59 begin 60 state <= delay; 61 rd_over <= 0; 62 i <= 2'b00; 63 end 64 else 65 begin 66 state <= hold; 67 rd_over <= 0; 68 end 69 delay: 70 if(i >= 2) 71 state <= start; 72 else 73 i <= i + 1; 74 start: 75 begin 76 state <= read; 77 start_code <= 1; 78 end 79 read: 80 if(count == in_length-1) 81 begin 82 state <= over; 83 rd_en <= 0; 84 rd_ask <= 0; 85 end 86 else 87 begin 88 state <= read; 89 rd_en <= 1; 90 rd_ask <= 1; 91 start_code <= 0; 92 end 93 over: 94 begin 95 state <= hold; 96 rd_over <= 1; 97 end 98 default:state <= hold; 99 endcase 100 end 101 102 always @(posedge rd_clk or negedge rd_rst_n) 103 begin 104 if(!rd_rst_n) 105 length <= 0; 106 else if(wr_addr < rd_addr) 107 length <= (10'd1023 ^ rd_addr) + wr_addr + 10'd1; 108 else 109 length <= wr_addr - rd_addr; 110 end 111 112 always @(posedge rd_clk or negedge rd_rst_n) 113 begin 114 if(!rd_rst_n) 115 count <= 10'd0; 116 else if(rd_en) 117 count <= count + 10'd1; 118 else if(start_code) 119 count <= 10'd0; 120 else 121 count <= count; 122 end 123 124 // always @(posedge rd_clk or negedge rd_rst_n) 125 // begin 126 // if(!rd_rst_n) 127 // in_length_next <= in_length; 128 // else if(rd_over) 129 // in_length_next <= in_length; 130 // else 131 // in_length_next <= in_length_next; 132 // end 133 134 endmoduleView Code
4、fifo_in_mem.v 生成存儲實體,FIFO 的本質是RAM,因此在設計存儲實體的時候有兩種方法:用數組存儲數據或者調用RAM的IP核。我是採用IP核的方法。
1 // megafunction wizard: %RAM: 2-PORT% 2 // GENERATION: STANDARD 3 // VERSION: WM1.0 4 // MODULE: altsyncram 5 6 // ============================================================ 7 // File Name: fifo_in_mem.v 8 // Megafunction Name(s): 9 // altsyncram 10 // 11 // Simulation Library Files(s): 12 // altera_mf 13 // ============================================================ 14 // ************************************************************ 15 // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 // 17 // 17.1.0 Build 590 10/25/2017 SJ Standard Edition 18 // ************************************************************ 19 20 21 //Copyright (C) 2017 Intel Corporation. All rights reserved. 22 //Your use of Intel Corporation's design tools, logic functions 23 //and other software and tools, and its AMPP partner logic 24 //functions, and any output files from any of the foregoing 25 //(including device programming or simulation files), and any 26 //associated documentation or information are expressly subject 27 //to the terms and conditions of the Intel Program License 28 //Subscription Agreement, the Intel Quartus Prime License Agreement, 29 //the Intel FPGA IP License Agreement, or other applicable license 30 //agreement, including, without limitation, that your use is for 31 //the sole purpose of programming logic devices manufactured by 32 //Intel and sold by Intel or its authorized distributors. Please 33 //refer to the applicable agreement for further details. 34 35 36 // synopsys translate_off 37 `timescale 1 ps / 1 ps 38 // synopsys translate_on 39 module fifo_in_mem ( 40 data, 41 rdaddress, 42 rdclock, 43 wraddress, 44 wrclock, 45 wren, 46 q); 47 48 input [2:0] data; 49 input [9:0] rdaddress; 50 input rdclock; 51 input [9:0] wraddress; 52 input wrclock; 53 input wren; 54 output [2:0] q; 55 `ifndef ALTERA_RESERVED_QIS 56 // synopsys translate_off 57 `endif 58 tri1 wrclock; 59 tri0 wren; 60 `ifndef ALTERA_RESERVED_QIS 61 // synopsys translate_on 62 `endif 63 64 wire [2:0] sub_wire0; 65 wire [2:0] q = sub_wire0[2:0]; 66 67 altsyncram altsyncram_component ( 68 .address_a (wraddress), 69 .address_b (rdaddress), 70 .clock0 (wrclock), 71 .clock1 (rdclock), 72 .data_a (data), 73 .wren_a (wren), 74 .q_b (sub_wire0), 75 .aclr0 (1'b0), 76 .aclr1 (1'b0), 77 .addressstall_a (1'b0), 78 .addressstall_b (1'b0), 79 .byteena_a (1'b1), 80 .byteena_b (1'b1), 81 .clocken0 (1'b1), 82 .clocken1 (1'b1), 83 .clocken2 (1'b1), 84 .clocken3 (1'b1), 85 .data_b ({3{1'b1}}), 86 .eccstatus (), 87 .q_a (), 88 .rden_a (1'b1), 89 .rden_b (1'b1), 90 .wren_b (1'b0)); 91 defparam 92 altsyncram_component.address_aclr_b = "NONE", 93 altsyncram_component.address_reg_b = "CLOCK1", 94 altsyncram_component.clock_enable_input_a = "BYPASS", 95 altsyncram_component.clock_enable_input_b = "BYPASS", 96 altsyncram_component.clock_enable_output_b = "BYPASS", 97 altsyncram_component.intended_device_family = "Cyclone V", 98 altsyncram_component.lpm_type = "altsyncram", 99 altsyncram_component.numwords_a = 1024, 100 altsyncram_component.numwords_b = 1024, 101 altsyncram_component.operation_mode = "DUAL_PORT", 102 altsyncram_component.outdata_aclr_b = "NONE", 103 altsyncram_component.outdata_reg_b = "CLOCK1", 104 altsyncram_component.power_up_uninitialized = "FALSE", 105 altsyncram_component.widthad_a = 10, 106 altsyncram_component.widthad_b = 10, 107 altsyncram_component.width_a = 3, 108 altsyncram_component.width_b = 3, 109 altsyncram_component.width_byteena_a = 1; 110 111<