mirror of
https://github.com/aolofsson/oh.git
synced 2025-01-17 20:02:53 +08:00
19fa611bb9
- adding more chip code - pushing memory stuff into common - making common "oh_" naming class -
283 lines
8.0 KiB
Verilog
283 lines
8.0 KiB
Verilog
`include "elink_constants.v"
|
|
module etx_clocks (/*AUTOARG*/
|
|
// Outputs
|
|
tx_lclk_io, tx_lclk90, tx_lclk_div4, cclk_p, cclk_n, etx_nreset,
|
|
etx_io_nreset, chip_nreset, tx_active,
|
|
// Inputs
|
|
sys_nreset, soft_reset, sys_clk
|
|
);
|
|
|
|
`ifdef TARGET_SIM
|
|
parameter RCW = 4; // reset counter width
|
|
`else
|
|
parameter RCW = 8; // reset counter width
|
|
`endif
|
|
|
|
//Frequency Settings (Mhz)
|
|
parameter FREQ_SYSCLK = 100;
|
|
parameter FREQ_TXCLK = 300;
|
|
parameter FREQ_CCLK = 600;
|
|
parameter TXCLK_PHASE = 90; //txclk phase shift
|
|
|
|
//Don't touch these! (derived parameters)
|
|
parameter MMCM_VCO_MULT = 12; //TX + CCLK
|
|
localparam real SYSCLK_PERIOD = 1000.000000 / FREQ_SYSCLK;
|
|
localparam integer TXCLK_DIVIDE = MMCM_VCO_MULT * FREQ_SYSCLK / FREQ_TXCLK;
|
|
localparam integer CCLK_DIVIDE = MMCM_VCO_MULT * FREQ_SYSCLK / FREQ_CCLK;
|
|
|
|
//Input clock, reset, config interface
|
|
input sys_nreset; // por reset (hw)
|
|
input soft_reset; // rx enable signal (sw)
|
|
|
|
//Main input clocks
|
|
input sys_clk; // always on input clk cclk/TX MMCM
|
|
|
|
//TX Clocks
|
|
output tx_lclk_io; // tx clock for high speeed IO
|
|
output tx_lclk90; // tx output clock shifted by 90 degrees
|
|
output tx_lclk_div4; // tx slow clock for logic
|
|
|
|
//Epiphany "free running" clock
|
|
output cclk_p, cclk_n;
|
|
|
|
//Reset
|
|
output etx_nreset; // reset for tx core logic
|
|
output etx_io_nreset; // io reset (synced to high speed clock)
|
|
output chip_nreset; // reset fpr Epiphany chip
|
|
output tx_active; // enable for rx path (ensures active clock)
|
|
|
|
//############
|
|
//# WIRES
|
|
//############
|
|
|
|
//CCLK
|
|
wire cclk_reset;
|
|
wire cclk_mmcm;
|
|
wire cclk_bufio;
|
|
wire cclk_oddr;
|
|
|
|
//TX
|
|
wire tx_lclk_mmcm;
|
|
wire tx_lclk90_mmcm;
|
|
wire tx_lckl_div4_mmcm;
|
|
|
|
//MMCM & PLL
|
|
wire cclk_fb;
|
|
//wire cclk_fb_out;
|
|
wire lclk_fb_i;
|
|
wire pll_reset;
|
|
wire mmcm_locked;
|
|
reg mmcm_locked_reg;
|
|
reg mmcm_locked_sync;
|
|
wire lclk_locked;
|
|
wire tx_nreset;
|
|
wire mmcm_reset;
|
|
wire tx_lclk_div4_mmcm;
|
|
|
|
//###########################
|
|
// RESET STATE MACHINE
|
|
//###########################
|
|
|
|
reg [RCW:0] reset_counter = 'b0; //works b/c of free running counter!
|
|
reg heartbeat;
|
|
reg [2:0] reset_state;
|
|
reg [1:0] reset_pipe_lclkb;
|
|
reg [1:0] reset_pipe_lclk_div4b;
|
|
|
|
//wrap around counter that generates a 1 cycle heartbeat
|
|
//free running counter...
|
|
always @ (posedge sys_clk)
|
|
begin
|
|
reset_counter[RCW-1:0] <= reset_counter[RCW-1:0]+1'b1;
|
|
heartbeat <= ~(|reset_counter[RCW-1:0]);
|
|
end
|
|
|
|
//two clock synchronizer
|
|
always @ (posedge sys_clk)
|
|
begin
|
|
mmcm_locked_reg <= mmcm_locked;
|
|
mmcm_locked_sync <= mmcm_locked_reg;
|
|
end
|
|
|
|
`define TX_RESET_ALL 3'b000
|
|
`define TX_START_CCLK 3'b001
|
|
`define TX_STOP_CCLK 3'b010
|
|
`define TX_DEASSERT_RESET 3'b011
|
|
`define TX_HOLD_IT 3'b100 //???
|
|
`define TX_ACTIVE 3'b101
|
|
|
|
//Reset sequence state machine
|
|
always @ (posedge sys_clk or negedge sys_nreset)
|
|
if(!sys_nreset)
|
|
reset_state[2:0] <= `TX_RESET_ALL;
|
|
else if(heartbeat)
|
|
case(reset_state[2:0])
|
|
`TX_RESET_ALL :
|
|
if(~soft_reset)
|
|
reset_state[2:0] <= `TX_START_CCLK;
|
|
`TX_START_CCLK :
|
|
if(mmcm_locked_sync)
|
|
reset_state[2:0] <= `TX_STOP_CCLK;
|
|
`TX_STOP_CCLK :
|
|
reset_state[2:0] <= `TX_DEASSERT_RESET;
|
|
`TX_DEASSERT_RESET :
|
|
reset_state[2:0] <= `TX_HOLD_IT;
|
|
`TX_HOLD_IT :
|
|
if(mmcm_locked_sync)
|
|
reset_state[2:0] <= `TX_ACTIVE;
|
|
`TX_ACTIVE:
|
|
if(soft_reset)
|
|
reset_state[2:0] <= `TX_RESET_ALL; //stay there until nex reset
|
|
|
|
endcase // case (reset_state[2:0])
|
|
|
|
//reset mmcm (async)
|
|
assign mmcm_reset = (reset_state[2:0]==`TX_RESET_ALL) |
|
|
(reset_state[2:0]==`TX_STOP_CCLK) |
|
|
(reset_state[2:0]==`TX_DEASSERT_RESET)
|
|
;
|
|
|
|
//reset chip (active low)
|
|
assign chip_nreset = (reset_state[2:0]==`TX_DEASSERT_RESET) |
|
|
(reset_state[2:0]==`TX_HOLD_IT) |
|
|
(reset_state[2:0]==`TX_ACTIVE);
|
|
|
|
//reset the elink
|
|
assign tx_nreset = ~(reset_state[2:0] != `TX_ACTIVE);
|
|
|
|
|
|
assign tx_active = (reset_state[2:0] == `TX_ACTIVE);
|
|
|
|
//#############################
|
|
//#RESET SYNCING
|
|
//#############################
|
|
|
|
oh_rsync rsync_io (// Outputs
|
|
.nrst_out (etx_io_nreset),
|
|
// Inputs
|
|
.clk (tx_lclk_io),
|
|
.nrst_in (tx_nreset));
|
|
|
|
oh_rsync rsync_core (// Outputs
|
|
.nrst_out (etx_nreset),
|
|
// Inputs
|
|
.clk (tx_lclk_div4),
|
|
.nrst_in (tx_nreset));
|
|
|
|
`ifdef TARGET_XILINX
|
|
|
|
//###########################
|
|
// MMCM FOR TXCLK + CCLK
|
|
//###########################
|
|
MMCME2_ADV
|
|
#(
|
|
.BANDWIDTH("OPTIMIZED"),
|
|
.CLKFBOUT_MULT_F(MMCM_VCO_MULT),
|
|
.CLKFBOUT_PHASE(0.0),
|
|
.CLKIN1_PERIOD(SYSCLK_PERIOD),
|
|
.CLKOUT0_DIVIDE_F(CCLK_DIVIDE), //cclk_c
|
|
.CLKOUT1_DIVIDE(TXCLK_DIVIDE), //tx_lclk
|
|
.CLKOUT2_DIVIDE(TXCLK_DIVIDE), //tx_lclk90
|
|
.CLKOUT3_DIVIDE(TXCLK_DIVIDE*4), //tx_lclk_div4
|
|
.CLKOUT4_DIVIDE(128), //N/A
|
|
.CLKOUT5_DIVIDE(128), //N/A
|
|
.CLKOUT6_DIVIDE(128), //N/A
|
|
.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),
|
|
.CLKOUT6_DUTY_CYCLE(0.5),
|
|
.CLKOUT0_PHASE(0.0),
|
|
.CLKOUT1_PHASE(0.0),
|
|
.CLKOUT2_PHASE(TXCLK_PHASE),
|
|
.CLKOUT3_PHASE(0.0),
|
|
.CLKOUT4_PHASE(0.0),
|
|
.CLKOUT5_PHASE(0.0),
|
|
.CLKOUT6_PHASE(0.0),
|
|
.DIVCLK_DIVIDE(1.0),
|
|
.REF_JITTER1(0.01),
|
|
.STARTUP_WAIT("FALSE")
|
|
) mmcm_cclk
|
|
(
|
|
.CLKOUT0(cclk_mmcm),
|
|
.CLKOUT0B(),
|
|
.CLKOUT1(tx_lclk_mmcm),
|
|
.CLKOUT1B(),
|
|
.CLKOUT2(tx_lclk90_mmcm),//goes directly to IO
|
|
.CLKOUT2B(),
|
|
.CLKOUT3(tx_lclk_div4_mmcm),
|
|
.CLKOUT3B(),
|
|
.CLKOUT4(),
|
|
.CLKOUT5(),
|
|
.CLKOUT6(),
|
|
.PWRDWN(1'b0),
|
|
.RST(mmcm_reset), //reset
|
|
.CLKFBIN(cclk_fb),
|
|
.CLKFBOUT(cclk_fb), //feedback clock
|
|
.CLKFBOUTB(), //inverted output feedback clock
|
|
.CLKIN1(sys_clk), //input clock
|
|
.CLKIN2(1'b0),
|
|
.CLKINSEL(1'b1),
|
|
.DADDR(7'b0),
|
|
.DCLK(1'b0),
|
|
.DEN(1'b0),
|
|
.DI(16'b0),
|
|
.DWE(1'b0),
|
|
.DRDY(),
|
|
.DO(),
|
|
.LOCKED(mmcm_locked), //locked indicator
|
|
.PSCLK(1'b0),
|
|
.PSEN(1'b0),
|
|
.PSDONE(),
|
|
.PSINCDEC(1'b0),
|
|
.CLKFBSTOPPED(),
|
|
.CLKINSTOPPED()
|
|
);
|
|
|
|
|
|
//Tx clock buffers
|
|
BUFG i_lclk_bufg (.I(tx_lclk_mmcm), .O(tx_lclk_io)); //300MHz
|
|
BUFG i_lclk_div4_bufg (.I(tx_lclk_div4_mmcm),.O(tx_lclk_div4)); //75MHz
|
|
BUFG i_lclk90_bufg (.I(tx_lclk90_mmcm), .O(tx_lclk90)); //300MHz 90deg clock
|
|
// BUFG i_fb_buf (.I(cclk_fb_out), .O(cclk_fb_in)); //FB
|
|
|
|
//###########################
|
|
// CCLK
|
|
//###########################
|
|
|
|
//CCLK bufio
|
|
BUFIO bufio_cclk(.O(cclk_bufio), .I(cclk_mmcm));
|
|
|
|
//CCLK oddr
|
|
ODDR #(.DDR_CLK_EDGE ("SAME_EDGE"), .SRTYPE("ASYNC"))
|
|
oddr_lclk (
|
|
.Q (cclk_oddr),
|
|
.C (cclk_bufio),
|
|
.CE (1'b1),
|
|
.D1 (1'b1),
|
|
.D2 (1'b0),
|
|
.R (1'b0),
|
|
.S (1'b0));
|
|
|
|
//CCLK differential buffer
|
|
OBUFDS cclk_obuf (.O (cclk_p),
|
|
.OB (cclk_n),
|
|
.I (cclk_oddr)
|
|
);
|
|
`else // !`ifdef TARGET_XILINX
|
|
assign cclk_p = sys_clk;
|
|
assign cclk_n = sys_clk;
|
|
assign tx_lclk_io = sys_clk;
|
|
assign tx_lclk_div4 = sys_clk;
|
|
assign tx_lclk90 = sys_clk;
|
|
|
|
`endif // `ifdef TARGET_XILINX
|
|
|
|
endmodule // eclocks
|
|
// Local Variables:
|
|
// verilog-library-directories:("." "../../common/hdl")
|
|
// End:
|
|
|