FPGA:PLL&RAM的原理及代碼


IP核是面向可編程邏輯門陣列(FPGA)芯片優化的,實現電子設計中常用功能的封裝模塊;包括固化在芯片內部的硬IP核,以及可編程調用的軟IP核;

IP核通過 菜單欄Tools >>MegaWizard Plug-In Manager 來創建或修改;也可以這樣查看各種IP核,以及芯片支持的IP核種類;

本文主要參考野火的教程;

1 PLL核

  1.1 PLL的簡單原理,與使用無關,可跳過,只做原理了解;

  PLL phase lock loop鎖相環:通過對輸入時鍾分頻,倍頻來輸出需要的時鍾信號的IP核;

  

    1.1.1 倍頻原理

      首先將輸入信號ref_clk輸入到鑒頻鑒相器中;該輸入信號ref_clk的負反饋信號,經過分頻器后也輸入到鑒頻鑒相器中;

      鑒頻鑒相器通過比較兩個信號的頻率,輸出對應的電壓差,倍頻時電壓差大於1;

      電壓差信號通過環路濾波器LF,過濾掉帶寬內外的噪聲,維持信號的穩定性;

      電壓差信號繼續通過壓控振盪器VCO,震盪輸出當前電壓差對應的頻率信號;

      頻率一部分作為倍頻信號輸出,一部分通過分頻器DIV之后,再輸入回鑒頻鑒相器作為比較信號;

    1.1.2 分頻原理

      首先將輸入信號ref_clk通過分頻器,分頻后輸入鑒頻鑒相器中;同時該信號濾波震盪后的頻率信號也輸入到鑒頻鑒相器中;

      鑒頻鑒相器通過比較兩個信號的頻率,輸出對應的電壓差,分頻時電壓差小於1;

      電壓差信號通過環路濾波器LF,過濾掉帶寬內外的噪聲,維持信號的穩定性;

      電壓差信號繼續通過壓控振盪器VCO,震盪輸出當前電壓差對應的頻率信號;

      頻率一部分作為分頻信號輸出,一部分輸入回鑒頻鑒相器作為比較信號;

  1.2 PLL核創建

    想要創建一個pll核,首先使用tools >> MegaWizard Plug-In Manager >>按需求創建ip核;

    然后編寫一個pll核的實例化模塊pll.v,編寫一個pll的測試模塊pll_tb.v;

    然后通過Assignments >> settings >> EDA Tool Settings >> simulation  >>配置一下testbench,使用RTL simulation來查看分頻信號是否正確;

2 RAM核

  RAM(random access memory)隨機存取存儲器,可以從任何指定地址寫入或讀出數據,掉電丟失;

  Altera一共推出了單端口RAM和雙端口RAM兩種IP核;

  1)讀操作:全部存儲器類型的讀操作均在上升沿觸發;

  2)寫操作:上升沿觸發的存儲器類型:M9K, M10K, M20K, M144K, M-RAM;

       下降沿觸發的存儲器類型:M4K, M512;

  2.1 單端口RAM

    2.1.1 對於單端口 RAM,只有一組地址線,讀寫操作不能同時進行;

      以下代碼首先在上升沿配置了讀寫使能信號,和讀寫計數值;然后下降沿通過對使能信號和計數值的判斷,來配置地址和數據;

      讀寫使能和計數的最后一個字節,剛好在對ram核處理的上升沿變化,但是因為是非阻塞賦值,取值為上升沿之前的值,所以可以取到正確值;

/**ipcore.v 單端口ram的實例代碼*********/
module ipcore(
    input sys_clk,
    input sys_rst_n,
    
    output ram1_wren,
    output wire[9:0] wire_input_data,    //調試查看信號
    output ram1_rden,
    output wire[9:0] wire_output_data,   //調試查看信號
    output reg[4:0] ram1_address
);
    
/**ram 實例ram1_inst***************************/    
reg[9:0] ram1_input_data;                //ram的輸入信號
wire[9:0] ram1_output_data;              //ram的輸出信號
reg[7:0] cnt;
ram ram1_inst
(
    .address     (ram1_address),
    .clock        (sys_clk),
    .data            (ram1_input_data),
    .rden            (ram1_rden),
    .wren            (ram1_wren),
    .q                (ram1_output_data)
);
/**步驟1:配置寫入計數值cnt,讀寫xx_en信號***********/
assign ram1_wren = (cnt< 8'd8)? 1'b1:1'b0;
assign ram1_rden = (cnt>=8'd8)? 1'b1:1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n) begin
        cnt <= 8'd0;
    end
    else if(cnt != 8'd15)
        cnt <= cnt + 1'b1;
    else
        cnt <= 8'd0;
end
/**步驟2:在時鍾的下降沿配置地址和收發數據***********/
assign wire_input_data = ram1_input_data;     //調試用 
assign wire_output_data = ram1_output_data;   //調試用
always@(negedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n) begin                
        ram1_address <= 5'd0;
        ram1_input_data <= 10'd0;
    end
    else if(ram1_wren && !cnt) begin    //寫使能
        ram1_address <= 5'd0;
        ram1_input_data <= 10'd0;
    end
    else if(ram1_wren && cnt ) begin    //寫使能
        ram1_address <= ram1_address + 1'b1;
        ram1_input_data <= ram1_input_data + 1'b1;
    end
    else if(ram1_rden && cnt==8'd8) begin//讀使能
        ram1_address <= 5'd0;
    end
    else if(ram1_rden && cnt!=8'd8) begin//讀使能
    ram1_address <= ram1_address + 1'b1;
    end
end
/***************************************************/
/**為什么使用下降沿來改修數據呢?因為ram數據都在上升沿采樣,所以上升沿的數據應該是穩定的;
***看網上說盡量不要使用下降沿,因為下降沿上升沿所需時間不同,在高速系統中不穩定;
***************************************************/
    
endmodule

    2.1.2 testbench

/**ipcore_tb.v *****/
`timescale 1ns/1ns
module ipcore_tb();

reg sys_clk;
reg sys_rst_n; 
initial begin
    sys_rst_n = 1'b0;
    sys_clk = 1'b1;
    #40 sys_rst_n = 1'b1;
end

always #10 sys_clk <= ~sys_clk;
/*50MHz,20ns一個周期;*/

wire ram1_rden;
wire ram1_wren;
wire[4:0] ram1_address;
wire[9:0] wire_output_data;
wire[9:0] wire_input_data;

ipcore i1 (
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    
    .ram1_wren(ram1_wren),
    .wire_input_data(wire_input_data),
    .ram1_rden(ram1_rden),
    .wire_output_data(wire_output_data),
    .ram1_address(ram1_address)
);

endmodule

    2.1.3 仿真截圖

    

  2.2 簡單雙端口 RAM
    讀操作和寫操作有專用地址端口(一個讀端口和一個寫端口),即寫端口只能寫不能讀,而讀端口只能讀不能寫;
  2.3 真正雙端口 RAM
    有兩個地址端口用於讀寫操作(兩個讀/寫端口),即兩個地址端口都可以進行讀寫操作;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM