OpenCores
URL https://opencores.org/ocsvn/sgmii/sgmii/trunk

Subversion Repositories sgmii

[/] [sgmii/] [trunk/] [sim/] [BFMs/] [SGMII_altera/] [triple_speed_ethernet-library/] [altera_tse_reset_ctrl_lego.sv] - Rev 20

Compare with Previous | Blame | View Log

// (C) 2001-2010 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License Subscription 
// Agreement, Altera MegaCore Function License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Altera and sold by 
// Altera or its authorized distributors.  Please refer to the applicable 
// agreement for further details.
// 
// Reset controller building block. 
//
// Handles a single reset stage.  Can be daisy-chained with other blocks for purely sequential resets.
// Options include reset pulse length in clock cycles, and a counter for sdone stability checking.
//
//      $Header$
//

`timescale 1 ns / 1 ns

module  altera_tse_reset_ctrl_lego
#(
        parameter       reset_hold_til_rdone = 0,       // 1 means reset stays high until rdone arrives
                                                                                        // 0 means fixed pulse length, defined by reset_hold_cycles
        parameter       reset_hold_cycles = 1,  // reset pulse length in clock cycles
        parameter       sdone_delay_cycles = 0, // optional delay from rdone received til sdone sent to next block
        parameter       rdone_is_edge_sensitive = 0     // default is level sensitive rdone
)
(
        // clocks and PLLs
        input   wire    clock,
        input   wire    start,
        input   tri0    aclr,   // active-high asynchronous reset
        output  wire    reset,
        input   tri1    rdone,  // reset done signal
        output  reg     sdone   // sequence done for this lego
);
        localparam max_precision = 32;  // VCS requires this declaration outside the function
        function integer ceil_log2;
                input [max_precision-1:0] input_num;
                integer i;
                reg [max_precision-1:0] try_result;
                begin
                        i = 0;
                        try_result = 1;
                        while ((try_result << i) < input_num && i < max_precision)
                                i = i + 1;
                        ceil_log2 = i;
                end
        endfunction

        // How many bits are needed for 'reset_hold_cycles' counter?
        localparam rhc_bits = ceil_log2(reset_hold_cycles);
        localparam rhc_load_constant = (1 << rhc_bits) | (reset_hold_cycles-1);
        // How many bits are needed for 'sdone_delay_cycles' counter?
        localparam sdc_bits = ceil_log2(sdone_delay_cycles);
        localparam sdc_load_constant = (1 << sdc_bits)
                | ((rdone_is_edge_sensitive == 1 && sdone_delay_cycles > 1) ? sdone_delay_cycles-2 : sdone_delay_cycles-1);
        localparam sdone_stable_cycles = (sdone_delay_cycles > 1 ? sdone_delay_cycles+1 : 0);
        
        wire spulse;    // synchronous detection of 'start' 0-to-1 transition
        wire rhold;
        wire timed_reset_in_progress;
        wire rinit_next; // combinatorial input to rinit DFF
        wire rdonei;    // internal selector between rdone and rdsave (rdone_is_edge_sensitive==1)
        wire rdpulse;   // synchronous detection of 'rdone' 0-to-1 transition, when rdone_is_edge_sensitive==1

        reg  zstart = 0;        // delayed value of 'start' input, used for detection of 0-to-1 transition
        reg  rinit = 0;         // state bit that indicates sequence is in progress

        initial begin
                sdone = 0;      // 1 indicates sequence is done
        end


        // 'start' input, detect 0-to-1 transition that triggers sequence
        assign spulse = start & ~zstart;
        always @(posedge clock or posedge aclr)
                if (aclr == 1'b1)
                        zstart <= 0;
                else
                        zstart <= start;

        // rinit state bit, triggered by spulse, waits while rhold = 1
        assign rinit_next = spulse | (rinit & (rhold | ~rdonei | rdpulse)) | timed_reset_in_progress;
        always @(posedge clock or posedge aclr)
                if (aclr == 1'b1)
            rinit <= 1;
                else
                        rinit <= rinit_next;

        // optional internal 'rdone' generation logic, if rdone_is_edge_sensitive==1
        generate
        if (rdone_is_edge_sensitive == 0) begin
                assign rdpulse = 0;
                assign rdonei = rdone;
        end
        else begin
                // instantiate synchronous edge-detection logic for rdone
                reg  zrdone = 0;        // for edge-sensitive rdone, detect 0-to-1 transition synchronously
                reg  rdsave = 0;        // for edge-sensitive rdone, use this as internal rdone
                always @(posedge clock or posedge aclr) begin
                        if (aclr == 1'b1) begin
                                zrdone <= 0;
                                rdsave <= 0;
                        end
                        else begin
                                zrdone <= rdone;        // previous value of rdone for synchronous edge detection
                                rdsave <= ~spulse & (rdpulse | rdsave);
                        end
                end
                assign rdpulse = rdone & ~zrdone;
                assign rdonei = rdsave;
        end
        endgenerate

        // rhold depends on sdone_delay_cycles and rdone_is_edge_sensitive
        generate
        if (sdone_delay_cycles == 0 || (sdone_delay_cycles == 1 && rdone_is_edge_sensitive == 1))
                assign rhold = ~rdonei; // sdone_delay_cycles=0
        else begin
                // declare only when needed to avoid Quartus synthesis warnings
                reg  [sdc_bits:0] rhold_reg = 0; // for sdone_delay_cycles > 0
                if (sdone_delay_cycles == 1) begin
                        always @(posedge clock or posedge aclr) begin
                                if (aclr == 1'b1)
                                        rhold_reg <= 0;
                                else
                                        rhold_reg <= ~(rinit & rdonei);
                        end
                        assign rhold = rhold_reg[0];    // sdone_delay_cycles=1
                end
                else begin
                        // need to count cycles to make sure rdone is stable
                        always @(posedge clock or posedge aclr)
                        begin
                                if (aclr == 1'b1)
                                        rhold_reg <= 0;
                                else if ((rinit & rdonei & ~rdpulse) == 0)
                                  // keep load value until rinit & rdone both high, and no new rdone pulses
                                        rhold_reg <= sdc_load_constant[sdc_bits:0];
                                else
                                        rhold_reg <= rhold_reg - 1'b1;
                        end
                        assign rhold = rhold_reg[sdc_bits];     // sdone_delay_cycles > 1
                end
        end
        endgenerate
                
        // sdone state bit indicates that reset sequence completed.  Clear again on 'start'
        always @(posedge clock or posedge aclr)
                if (aclr == 1'b1)
                        sdone <= 0;
                else
                        sdone <= ~spulse & (sdone | (rinit & ~rinit_next));

        // reset pulse generation logic depends on 2 parameters
        generate
        if (reset_hold_til_rdone == 1) begin
                assign reset = rinit;
                assign timed_reset_in_progress = 0;
        end
        else if (reset_hold_cycles < 1) begin   // 0 is legal, but catch negative (illegal) values too
                assign reset = spulse;
                assign timed_reset_in_progress = 0;
        end
        else begin
                // declare only when needed to avoid Quartus synthesis warnings
                reg  [rhc_bits:0] zspulse = 0;  // bits for reset pulse if fixed length
                assign timed_reset_in_progress = zspulse[rhc_bits];
                assign reset = zspulse[rhc_bits];
                
                if (reset_hold_cycles == 1)
                        // a single-cycle reset pulse needs 1 register
                        always @(posedge clock or posedge aclr)
                                if (aclr == 1'b1)
                    zspulse <= 1;
                                else
                                        zspulse <= spulse;
                else begin
                        // multi-cycle reset pulse needs a counter
                        always @(posedge clock or posedge aclr)
                        begin
                                if (aclr == 1'b1)
                    zspulse <= {rhc_bits + 1 { 1'b1}};
                                else if (spulse == 1)
                                        zspulse <= rhc_load_constant[rhc_bits:0];
                                else if (zspulse[rhc_bits] == 1)
                                        zspulse <= zspulse - 1'b1;
                        end
                end
        end
        endgenerate

//      generate
//        case (reset_hold_til_rdone)
//          0 : m1 U1 (a, b, c);
//          2 : m2 U1 (a, b, c);
//          default : m3 U1 (a, b, c);
//        endcase
//      endgenerate

        // general assertions
        //synopsys translate_off
        // vlog/vcs/ncverilog:  +define+ALTERA_XCVR_ASSERTIONS
`ifdef ALTERA_XCVR_ASSERTIONS
                // when rdone is edge sensitive, last rdone +ve edge triggers sdone +ve edge,
                // 'sdone_delay_cycles' later. "##1 1" is an always-true cycle to match $rise(sdone)
                sequence rdone_last_edge;
                        @(posedge clock) $rose(rdone) ##1 !$rose(rdone) [*sdone_delay_cycles] ##1 1;
                endsequence

                // when rdone is level sensitive, stable rdone for 'sdone_delay_cycles' consecutive cycles
                // triggers sdone +ve edge. "##1 1" is an always-true cycle to match $rise(sdone)
                sequence rdone_stable_level;
                        @(posedge clock) rdone [*(sdone_delay_cycles+1)] ##1 1;
                endsequence

// Most assertions aren't valid when 'aclr' is active
//`define assert_awake(arg)     assert property (disable iff (aclr) arg )
        always @(aclr)
                if (aclr) $assertkill;
                else $asserton;

        generate
        always @(posedge clock) begin
                // A rising edge on start will result in reset high within 1 clock cycle
                assert property ($rose(start & ~aclr) |-> ##[0:1] reset);
                // A rising edge on reset will result in sdone low within 1 clock cycle
                assert property ($rose(reset) |-> ##[0:1] !sdone);

                // assertions for optional behavior: reset pulse length options
                if (reset_hold_til_rdone == 0 && reset_hold_cycles > 1)
                        // Verify fixed-length reset pulse option
                        assert property ($rose(reset) |-> reset [*reset_hold_cycles] ##1 !reset)
                        else $error("Reset pulse length should be %d", reset_hold_cycles);
                if (reset_hold_til_rdone == 0 && reset_hold_cycles == 1)
                        // Verify fixed 1-length reset pulse option
                        assert property ($rose(reset) |=> !reset);
                if (reset_hold_til_rdone == 0 && reset_hold_cycles == 0)
                        // Verify minimal-length reset pulse option, which mirrors 'start' edge detection
                        assert property ($rose(start & ~aclr) |-> reset ##1 !reset);
                if (reset_hold_til_rdone == 1) begin
                        // with hold-til-rdone, reset should not deassert until after rdone asserts, then deassert immediately
                        assert property ($rose(reset) && !rdone |=> $stable(reset) [*0:$] ##1 (reset && rdone) ##1 !reset);
                        assert property ($rose(reset) && rdone ##1 rdone [*sdone_delay_cycles] |=> !reset); // rdone was already high
                        //assert property ($rose(reset) && !rdone |-> ##[0:$] rdone ##1 !reset);
                end

                // assertions for optional behavior: sdone delay options and rdone edge sensitive option
                if (rdone_is_edge_sensitive == 1)
                        // rdone edge-sensitive option only has an effect when sdone_delay_cycles > 0
                        assert property ($rose(sdone) |-> rdone_last_edge.ended);
                if (rdone_is_edge_sensitive == 0)
                        // rdone defaults to level-sensitive
                        assert property ($rose(sdone) |-> (rdone_stable_level.ended or $past($fell(reset),1)));
        end
        endgenerate
`endif // ALTERA_XCVR_ASSERTIONS
        //synopsys translate_on
endmodule

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.