zynq-sandbox

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit a4419135c7fd3087fee9b7fe450b1037e1f7741f
parent ab7c1ad80ee867a96d550ee736f0976327e8c4c6
Author: Brian Swetland <swetland@frotz.net>
Date:   Fri,  4 Jul 2014 03:48:43 -0700

xilinx_async_fifo: wrapper around native fifo block

Diffstat:
Ahdl/sync_oneway.sv | 35+++++++++++++++++++++++++++++++++++
Ahdl/xilinx_async_fifo.sv | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 227 insertions(+), 0 deletions(-)

diff --git a/hdl/sync_oneway.sv b/hdl/sync_oneway.sv @@ -0,0 +1,35 @@ +// Copyright 2014 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +(* keep_hierarchy = "yes" *) +module sync_oneway( + input txclk, + input txdat, + input rxclk, + output rxdat + ); + +reg a, b, c; + +always_ff @(posedge txclk) + a <= txdat; + +always_ff @(posedge rxclk) begin + b <= a; + c <= b; +end + +assign rxdat = c; + +endmodule diff --git a/hdl/xilinx_async_fifo.sv b/hdl/xilinx_async_fifo.sv @@ -0,0 +1,192 @@ +// Copyright 2014 Brian Swetland <swetland@frotz.net> +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`timescale 1ns/1ps + +// reset in synchronous with wrclk +// on reset=1, active will go low on the next clock +// active will return high once the reset is complete +// reset will take a bit longer than 12 wrclk or rdclk +// (whichever is slower) + +(* keep_hierarchy = "yes" *) +module xilinx_async_fifo( + input wrclk, + input rdclk, + input reset, + + input [WIDTH-1:0]wr_data, + input wr_en, + + input rd_en, + output [WIDTH-1:0]rd_data, + + output o_empty, + output o_ready, // can absorb >= 16 writes + output o_active + ); + +parameter WIDTH = 16; + +wire fifo_res, fifo_act; + +fifo_reset fifo_reset_0( + .clk1(wrclk), + .i_res(reset), + .clk2(rdclk), + .o_res(fifo_res), + .o_act(fifo_act) + ); + +wire [31:0]do_data, di_data; +wire almostfull; +assign o_ready = ~almostfull; + +assign o_active = fifo_act; +assign rd_data = do_data[WIDTH-1:0]; +assign di_data[WIDTH-1:0] = wr_data; + +FIFO18E1 #( + .ALMOST_EMPTY_OFFSET(13'h80), + .ALMOST_FULL_OFFSET(13'h80), // TODO + .DATA_WIDTH(36), + .DO_REG(1), + .EN_SYN("FALSE"), + .FIFO_MODE("FIFO18_36"), + .FIRST_WORD_FALL_THROUGH("TRUE"), + .INIT(32'h0), + .SIM_DEVICE("7SERIES"), + .SRVAL(36'h0) + ) fifo ( + .DO(do_data), + .DOP(), + .ALMOSTEMPTY(), + .ALMOSTFULL(almostfull), + .EMPTY(o_empty), + .FULL(), + .RDCOUNT(), + .RDERR(), + .WRCOUNT(), + .WRERR(), + .RDCLK(rdclk), + .RDEN(fifo_act & rd_en), + .RST(fifo_res), + .WRCLK(wrclk), + .WREN(fifo_act & wr_en), + .DI(di_data), + .DIP(), + .REGCE(), + .RSTREG() + ); + +endmodule + + +// on i_res (sync w/ clk1): +// 1. o_res will go high, i_act will go low +// 2. after at least 6 cycles of clk1 and clk2, o_res will go high +// 2. after at least 6 more cycles of clk1 and clk2, o_act will go high + +(* keep_hierarchy = "yes" *) +module fifo_reset( + input clk1, + input clk2, + input i_res, + output reg o_res = 0, + output reg o_act = 1 + ); + +typedef enum { IDLE, RESET0, RESET1, WAIT } state_t; +state_t state1 = IDLE; +state_t next_state1; +reg [5:0]shift1 = 0; +reg [5:0]next_shift1; + +// signal from clk1 domain to clk2 +reg dat = 0; +reg next_dat; + +reg next_res; +reg next_act; + +// return from clk2 domain (after 6bit sr) +reg ack; + +always_comb begin + next_state1 = state1; + next_shift1 = shift1; + next_dat = dat; + next_res = o_res; + next_act = o_act; + case (state1) + IDLE: begin + if (i_res) begin + next_act = 0; + next_state1 = RESET0; + end + end + RESET0: begin + next_res = 1; + next_state1 = RESET1; + next_shift1 = 6'b111111; + next_dat = 1; + end + RESET1: begin + next_shift1 = { 1'b0, shift1[5:1] }; + if ((shift1[0] == 0) && (ack==1)) begin + next_res = 0; + next_state1 = WAIT; + next_dat = 0; + next_shift1 = 6'b111111; + end + end + WAIT: begin + next_shift1 = { 1'b0, shift1[5:1] }; + if ((shift1[0] == 0) && (ack==0)) begin + next_act = 1; + next_state1 = IDLE; + end + end + endcase +end + +always_ff @(posedge clk1) begin + state1 <= next_state1; + shift1 <= next_shift1; + dat <= next_dat; + o_res <= next_res; + o_act <= next_act; +end + +wire shift2_in; +reg [5:0]shift2 = 0; + +always @(posedge clk2) + shift2 <= { shift2_in, shift2[5:1] }; + +sync_oneway sync0( + .txclk(clk1), + .txdat(dat), + .rxclk(clk2), + .rxdat(shift2_in) + ); + +sync_oneway sync1( + .txclk(clk2), + .txdat(shift2[0]), + .rxclk(clk1), + .rxdat(ack) + ); + +endmodule