顯示具有 Spartan6 標籤的文章。 顯示所有文章
顯示具有 Spartan6 標籤的文章。 顯示所有文章

2014年9月24日 星期三

Increase BRAM in spartan6

Reference :



在移植cf r/w的程式到spartan6的時後發現spartan bram只能到64kb. 但是要寫cf卡至少需要128kb,後來google了一下發現有別的路徑可以繞一下

XPS中把bram調成128k會出現下列的錯誤訊息表示spartan6只用調到64k

在右邊加入一個block ram,兩個bram control,可能因為版本的關係所以我的名稱跟reference不一樣




把接線接上

然後把address填入,注意兩個bram address需要連續


接著generate netlist
SDK中加入xilfatfs librarygenerate linked script 會出現如預期的bram不夠訊息


打開lscript.ld 把原本的
microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl : ORIGIN = 0x00000050, LENGTH = 0x0000FFB0
bram_cntlr_0_bram_cntlr_1 : ORIGIN = 0x00010000, LENGTH = 0x00010000
改成
microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl : ORIGIN = 0x00000050, LENGTH = 0x0001FFB0



_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x1D4C0;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x1D4C0;

/* Define Memories in the system */

MEMORY
{
microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl : ORIGIN = 0x00000050, LENGTH = 0x0001FFB0
//bram_cntlr_0_bram_cntlr_1 : ORIGIN = 0x00010000, LENGTH = 0x00010000
ddr3_sdram_S_AXI_BASEADDR : ORIGIN = 0xA4000000, LENGTH = 0x04000000
}

/* Specify the default entry point to the program */

ENTRY(_start)

/* Define the sections, and where they are mapped in memory */

SECTIONS
{
.vectors.reset 0x00000000 : {
*(.vectors.reset)
}

.vectors.sw_exception 0x00000008 : {
*(.vectors.sw_exception)
}

.vectors.interrupt 0x00000010 : {
*(.vectors.interrupt)
}

.vectors.hw_exception 0x00000020 : {
*(.vectors.hw_exception)
}

.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.init : {
KEEP (*(.init))
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.fini : {
KEEP (*(.fini))
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
PROVIDE(__DTOR_END__ = .);
PROVIDE(___DTORS_END___ = .);
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.sdata2 : {
. = ALIGN(8);
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
. = ALIGN(8);
__sdata2_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.data : {
. = ALIGN(4);
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
__data_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.got : {
*(.got)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.got1 : {
*(.got1)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.got2 : {
*(.got2)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.eh_frame : {
*(.eh_frame)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.jcr : {
*(.jcr)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.gcc_except_table : {
*(.gcc_except_table)
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.sdata : {
. = ALIGN(8);
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.sbss (NOLOAD) : {
. = ALIGN(4);
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
. = ALIGN(8);
__sbss_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

.bss (NOLOAD) : {
. = ALIGN(4);
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end = .;
} > microblaze_0_i_bram_ctrl_microblaze_0_d_bram_ctrl

_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );

_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );

/* Generate Stack and Heap definitions */

.heap (NOLOAD) : {
. = ALIGN(8);
_heap = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
} > ddr3_sdram_S_AXI_BASEADDR

.stack (NOLOAD) : {
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(8);
_stack = .;
__stack = _stack;
} > ddr3_sdram_S_AXI_BASEADDR

_end = .;
}



SAVE以後自動產生一個新的elf,空間不足的error dispearrrrrrr !
如果之後ISE generate new bit產生
NgdBuild:989 - Failed to process BMM information edkBmmFile.bmm
這個error,則清掉isexpsfile在重新產生

我在ml605上模擬這個環境
結果在SDKprogram FPGA的時候出現下列錯誤
表示bmm file也需要被更改



ISE上把edkBmmFile_bd.bmm 打開,把原本的兩個RAM合併成一個,並把ADDRESS範圍加大
ADDRESS_MAP microblaze_0 MICROBLAZE-LE 100

///////////////////////////////////////////////////////////////////////////////
//
// Processor 'microblaze_0' address space 'microblaze_0_bram_block_combined' 0x00000000:0x0000FFFF (64 KBytes).
//
///////////////////////////////////////////////////////////////////////////////

ADDRESS_SPACE microblaze_0_bram_block_combined RAMB32 [0x00000000:0x0001FFFF]
BUS_BLOCK
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_0 RAMB32 [31:30] [0:16383] INPUT = microblaze_0_bram_block_combined_0.mem PLACED = X6Y19;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_1 RAMB32 [29:28] [0:16383] INPUT = microblaze_0_bram_block_combined_1.mem PLACED = X7Y17;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_2 RAMB32 [27:26] [0:16383] INPUT = microblaze_0_bram_block_combined_2.mem PLACED = X3Y15;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_3 RAMB32 [25:24] [0:16383] INPUT = microblaze_0_bram_block_combined_3.mem PLACED = X6Y14;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_4 RAMB32 [23:22] [0:16383] INPUT = microblaze_0_bram_block_combined_4.mem PLACED = X4Y15;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_5 RAMB32 [21:20] [0:16383] INPUT = microblaze_0_bram_block_combined_5.mem PLACED = X3Y16;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_6 RAMB32 [19:18] [0:16383] INPUT = microblaze_0_bram_block_combined_6.mem PLACED = X4Y12;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_7 RAMB32 [17:16] [0:16383] INPUT = microblaze_0_bram_block_combined_7.mem PLACED = X4Y16;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_8 RAMB32 [15:14] [0:16383] INPUT = microblaze_0_bram_block_combined_8.mem PLACED = X4Y23;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_9 RAMB32 [13:12] [0:16383] INPUT = microblaze_0_bram_block_combined_9.mem PLACED = X6Y20;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_10 RAMB32 [11:10] [0:16383] INPUT = microblaze_0_bram_block_combined_10.mem PLACED = X6Y16;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_11 RAMB32 [9:8] [0:16383] INPUT = microblaze_0_bram_block_combined_11.mem PLACED = X4Y10;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_12 RAMB32 [7:6] [0:16383] INPUT = microblaze_0_bram_block_combined_12.mem PLACED = X4Y21;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_13 RAMB32 [5:4] [0:16383] INPUT = microblaze_0_bram_block_combined_13.mem PLACED = X4Y22;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_14 RAMB32 [3:2] [0:16383] INPUT = microblaze_0_bram_block_combined_14.mem PLACED = X3Y17;
u_microblaze/microblaze_0_bram_block/microblaze_0_bram_block/ramb36e1_15 RAMB32 [1:0] [0:16383] INPUT = microblaze_0_bram_block_combined_15.mem PLACED = X5Y12;
END_BUS_BLOCK;
BUS_BLOCK
u_microblaze/bram_block_0/bram_block_0/ramb36e1_0 RAMB32 [31:30] [0:16383] INPUT = bram_block_0_combined_0.mem PLACED = X5Y17;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_1 RAMB32 [29:28] [0:16383] INPUT = bram_block_0_combined_1.mem PLACED = X4Y20;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_2 RAMB32 [27:26] [0:16383] INPUT = bram_block_0_combined_2.mem PLACED = X4Y14;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_3 RAMB32 [25:24] [0:16383] INPUT = bram_block_0_combined_3.mem PLACED = X5Y14;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_4 RAMB32 [23:22] [0:16383] INPUT = bram_block_0_combined_4.mem PLACED = X5Y15;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_5 RAMB32 [21:20] [0:16383] INPUT = bram_block_0_combined_5.mem PLACED = X4Y17;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_6 RAMB32 [19:18] [0:16383] INPUT = bram_block_0_combined_6.mem PLACED = X4Y13;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_7 RAMB32 [17:16] [0:16383] INPUT = bram_block_0_combined_7.mem PLACED = X5Y16;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_8 RAMB32 [15:14] [0:16383] INPUT = bram_block_0_combined_8.mem PLACED = X4Y24;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_9 RAMB32 [13:12] [0:16383] INPUT = bram_block_0_combined_9.mem PLACED = X5Y20;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_10 RAMB32 [11:10] [0:16383] INPUT = bram_block_0_combined_10.mem PLACED = X6Y15;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_11 RAMB32 [9:8] [0:16383] INPUT = bram_block_0_combined_11.mem PLACED = X4Y11;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_12 RAMB32 [7:6] [0:16383] INPUT = bram_block_0_combined_12.mem PLACED = X5Y21;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_13 RAMB32 [5:4] [0:16383] INPUT = bram_block_0_combined_13.mem PLACED = X5Y22;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_14 RAMB32 [3:2] [0:16383] INPUT = bram_block_0_combined_14.mem PLACED = X3Y18;
u_microblaze/bram_block_0/bram_block_0/ramb36e1_15 RAMB32 [1:0] [0:16383] INPUT = bram_block_0_combined_15.mem PLACED = X5Y13;
END_BUS_BLOCK;
END_ADDRESS_SPACE;




END_ADDRESS_MAP;


這邊要注意的是如果重新產生BIT file,bmm又會被改寫成原本未合併的,最好複製一份更名,SDK上就用更名過的



xilinxQA上說產生download.bit file要在tcl下使用standalone data2mem,但是我在SDK上用Programm FPGA也可以用



2014年5月14日 星期三

PLL Output Pin

如何將pll 產生的clock輸出到output來控制其他IC
target spartan6,ISE14.4
一開始連doc都沒看就如下好傻好天真的把plloutput經由bufg送到pad
結果果然產生error ........

在使用pll的時候不要忘了相乘以後的頻率範圍要在spec上的VCO Freg範圍內, 不然error就會來找你拉!

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity pll_out_top is
    Port ( 
    osc_200_p  : in  STD_LOGIC;
    osc_200_n  : in  STD_LOGIC;
    reset   : in  STD_LOGIC;
    pll_out0  : out  STD_LOGIC;
    pll_out1  : out  STD_LOGIC);

end pll_out_top;

architecture Behavioral of pll_out_top is
signal clkin  : std_logic;
signal clk_fb  : std_logic;
signal locked  : std_logic;
signal pll_clkout0,pll_clkout1 : std_logic;

begin

  -- Input Clock Buffer
  clkin1_ibuf : IBUFGDS
  port map (
    I  => osc_200_p,
    IB => osc_200_n,
    O  => clkin);
  
   PLL_BASE_inst : PLL_BASE
   generic map (
      BANDWIDTH => "OPTIMIZED",          
      CLKFBOUT_MULT => 4,        
      CLKFBOUT_PHASE => 0.0,   
      CLKIN_PERIOD => 5.0,           
    
      CLKOUT0_DIVIDE => 2,
      CLKOUT1_DIVIDE => 4,
      CLKOUT2_DIVIDE => 1,
      CLKOUT3_DIVIDE => 1,
      CLKOUT4_DIVIDE => 1,
      CLKOUT5_DIVIDE => 1,
    
      CLKOUT0_DUTY_CYCLE => 0.5,
      CLKOUT1_DUTY_CYCLE => 0.5,
      CLKOUT2_DUTY_CYCLE => 0.5,
      CLKOUT3_DUTY_CYCLE => 0.5,
      CLKOUT4_DUTY_CYCLE => 0.5,
      CLKOUT5_DUTY_CYCLE => 0.5,
     
      CLKOUT0_PHASE => 0.0,
      CLKOUT1_PHASE => 0.0,
      CLKOUT2_PHASE => 0.0,
      CLKOUT3_PHASE => 0.0,
      CLKOUT4_PHASE => 0.0,
      CLKOUT5_PHASE => 0.0,
      CLK_FEEDBACK => "CLKFBOUT",         
      COMPENSATION => "SYSTEM_SYNCHRONOUS", 
      DIVCLK_DIVIDE => 1,                   
      REF_JITTER => 0.1,                    
      RESET_ON_LOSS_OF_LOCK => FALSE       
   )
   port map (
      CLKFBOUT => clk_fb, 
      
      CLKOUT0 => pll_clkout0,
      CLKOUT1 => pll_clkout1,
      CLKOUT2 => open,
      CLKOUT3 => open,
      CLKOUT4 => open,
      CLKOUT5 => open,
      LOCKED => locked,     
      CLKFBIN => clk_fb,   
      CLKIN => clkin,       
      RST => reset            
   );  
  
  u_BUFG0  : BUFG PORT MAP (I => pll_clkout0, O => pll_out0);
  u_BUFG1  : BUFG PORT MAP (I => pll_clkout1, O => pll_out1);
  
end Behavioral;

Error
ERROR:Place:1205 - This design contains a global buffer instance, <u_BUFG0>,
driving the net, <pll_out0_OBUF>, that is driving the following (first 30)
non-clock load pins off chip.
< PIN: pll_out0.O; >
This design practice, in Spartan-6, can lead to an unroutable situation due
to limitations in the global routing. If the design does route there may be
excessive delay or skew on this net. It is recommended to use a Clock
Forwarding technique to create a reliable and repeatable low skew solution:
instantiate an ODDR2 component; tie the .D0 pin to Logic1; tie the .D1 pin to
Logic0; tie the clock net to be forwarded to .C0; tie the inverted clock to
.C1. If you wish to override this recommendation, you may use the
CLOCK_DEDICATED_ROUTE constraint (given below) in the .ucf file to demote
this message to a WARNING and allow your design to continue. Although the net
may still not route, you will be able to analyze the failure in FPGA_Editor.
CLOCK_DEDICATED_ROUTE = FALSE; >


ERROR:Place:1136 - This design contains a global buffer instance, <u_BUFG0>,
driving the net, <pll_out0_OBUF>, that is driving the following (first 30)
non-clock load pins.
< PIN: pll_out0.O; >
This is not a recommended design practice in Spartan-6 due to limitations in
the global routing that may cause excessive delay, skew or unroutable
situations. It is recommended to only use a BUFG resource to drive clock
loads. If you wish to override this recommendation, you may use the
CLOCK_DEDICATED_ROUTE constraint (given below) in the .ucf file to demote
this message to a WARNING and allow your design to continue.
< PIN "u_BUFG0.O" CLOCK_DEDICATED_ROUTE = FALSE; >


xilinxclock手冊裡面寫如果要從pll傳到pad必須經過ODDR2 buffer,而且ODDR2 的輸出必須經由OBUF送出,不可以在輸入FPGA中的其他邏輯,不然會有Package error

ERROR : PACK 2530 ::The dual data rate register "u_ODDR2_0" failed to join an OLOGIC component as required.




在圖上是接clkfbout但是也可以用再clkout0-5,drp的官方範例裡面有用到
code改成如下,便可解決以上的error
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity pll_out_top is
    Port (
    osc_200_p  : in  STD_LOGIC;
    osc_200_n  : in  STD_LOGIC;
    reset   : in  STD_LOGIC;
    pll_out0_p  : out  STD_LOGIC;
    pll_out0_n  : out  STD_LOGIC;
    pll_out1_p  : out  STD_LOGIC;
    pll_out1_n  : out  STD_LOGIC);
end pll_out_top;

architecture Behavioral of pll_out_top is
signal clkin     : std_logic;
signal clk_fb     : std_logic;
signal locked     : std_logic;
signal pll_clkout0,pll_clkout1   : std_logic;
signal   clkbufout0,clkbufout1     : std_logic;
signal   n_clkbufout0,n_clkbufout1  : std_logic;
signal   oddr2out0,oddr2out1  : std_logic;
signal  pll_out0,pll_out1  : std_logic;

begin

  -- Input Clock Buffer
  clk_buf : IBUFGDS
  port map (
    I  => osc_200_p,
    IB => osc_200_n,
    O  => clkin);
 
   PLL_BASE_inst : PLL_BASE
   generic map (
      BANDWIDTH => "OPTIMIZED",
      CLKFBOUT_MULT => 4,      
      CLKFBOUT_PHASE => 0.0,   
                              
      CLKIN_PERIOD => 5.0,     
                               
      CLKOUT0_DIVIDE => 2,
      CLKOUT1_DIVIDE => 4,
      CLKOUT2_DIVIDE => 1,
      CLKOUT3_DIVIDE => 1,
      CLKOUT4_DIVIDE => 1,
      CLKOUT5_DIVIDE => 1,
      CLKOUT0_DUTY_CYCLE => 0.5,
      CLKOUT1_DUTY_CYCLE => 0.5,
      CLKOUT2_DUTY_CYCLE => 0.5,
      CLKOUT3_DUTY_CYCLE => 0.5,
      CLKOUT4_DUTY_CYCLE => 0.5,
      CLKOUT5_DUTY_CYCLE => 0.5,
      CLKOUT0_PHASE => 0.0,
      CLKOUT1_PHASE => 0.0,
      CLKOUT2_PHASE => 0.0,
      CLKOUT3_PHASE => 0.0,
      CLKOUT4_PHASE => 0.0,
      CLKOUT5_PHASE => 0.0,
      CLK_FEEDBACK => "CLKFBOUT",         
      COMPENSATION => "SYSTEM_SYNCHRONOUS",
      DIVCLK_DIVIDE => 1,                 
      REF_JITTER => 0.1,                 
      RESET_ON_LOSS_OF_LOCK => FALSE     
   )
   port map (
      CLKFBOUT => clk_fb, -- 1-bit output: PLL_BASE feedback output
      CLKOUT0 => pll_clkout0,
      CLKOUT1 => pll_clkout1,
      CLKOUT2 => open,
      CLKOUT3 => open,
      CLKOUT4 => open,
      CLKOUT5 => open,
      LOCKED => locked,     -- 1-bit output: PLL_BASE lock status output
      CLKFBIN => clk_fb,   -- 1-bit input: Feedback clock input
      CLKIN => clkin,       -- 1-bit input: Clock input
      RST => reset            -- 1-bit input: Reset input
   ); 
 
  u_BUFG0  : BUFG PORT MAP (I => pll_clkout0, O => clkbufout0);
  u_BUFG1  : BUFG PORT MAP (I => pll_clkout1, O => clkbufout1);
  
  n_clkbufout0  <= NOT clkbufout0;
  n_clkbufout1  <= NOT clkbufout1;
 
  u_ODDR2_0 : ODDR2
   generic map(
      DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1"
      INIT => '0', -- Sets initial state of the Q output to '0' or '1'
      SRTYPE => "SYNC") -- Specifies "SYNC" or "ASYNC" set/reset
   port map (
      Q  => oddr2out0, -- 1-bit output data
      C0 => clkbufout0, -- 1-bit clock input
      C1 => n_clkbufout0, -- 1-bit clock input
      CE => '1',  -- 1-bit clock enable input
      D0 => '1',   -- 1-bit data input (associated with C0)
      D1 => '0',   -- 1-bit data input (associated with C1)
      R  => reset,    -- 1-bit reset input
      S  => '0'     -- 1-bit set input
   );
 
 u_ODDR2_1 : ODDR2
   generic map(
      DDR_ALIGNMENT => "NONE", -- Sets output alignment to "NONE", "C0", "C1"
      INIT => '0', -- Sets initial state of the Q output to '0' or '1'
      SRTYPE => "SYNC") -- Specifies "SYNC" or "ASYNC" set/reset
   port map (
      Q  => oddr2out1, -- 1-bit output data
      C0 => clkbufout1, -- 1-bit clock input
      C1 => n_clkbufout1, -- 1-bit clock input
      CE => '1',  -- 1-bit clock enable input
      D0 => '1',   -- 1-bit data input (associated with C0)
      D1 => '0',   -- 1-bit data input (associated with C1)
      R  => reset,    -- 1-bit reset input
      S  => '0'     -- 1-bit set input
   );

  u_OBUF0 : OBUF PORT MAP (I => oddr2out0, O => pll_out0);
  u_OBUF1 : OBUF PORT MAP (I => oddr2out1, O => pll_out1);
end Behavioral;

注意最後是接OBUF,不可以接BUFG,不然會有ERROR : PACK 2530 ::The dual data rate register "u_ODDR2_0 " failed to join an OLOGIC component as required.

如果是differential outputs則改成如下,我覺得很奇怪為什麼手冊裡面沒有詳細的OBUFDS,
我是再Spartan3 裡面找到pinout的

OBUFDS_0 : OBUFDS
  port map (
  O => pll_out0_p, -- Diff_p output (connect to top-level port)
  OB => pll_out0_n, -- Diff_n output (connect to top-level port)
  I => oddr2out0 -- Buffer input
  );
 
  OBUFDS_1 : OBUFDS
  port map (
  O => pll_out1_p, -- Diff_p output (connect to top-level port)
  OB => pll_out1_n, -- Diff_n output (connect to top-level port)
  I => oddr2out1 -- Buffer input
  );