The Elements of Logic Design Style

Appendix B: Sample Verilog Files for Modeling a Datapath

Shing Kong

March 2001

Copyright (c) 2001 by Shing Ip Kong. All Rights Reserved.

Filed at: http://www.cs.wisc.edu/~markhill/kong/appendixB.html

Main text at: http://www.cs.wisc.edu/~markhill/kong



Appendix B: Sample Verilog Files for Modeling a Datapath     $Revision: 1.1 $
-----------------------------------------------------------------------------

/****************************************************************************
 *
 * File Name: link_txdp.v
 *
 * Comment: Link Layer datapath for data transmission
 *
 *	The datapath here excludes the part that is interfaced to the
 *	SERDES so everything here should run on the txclk4x.
 *
 * Author: Shing Kong
 * Creation Date: 3/26/2001
 *
 * $Source: /proj/gemini/cvs_root/P2002/Notes/Style/appendixB,v $
 * $Date: 2001/12/06 21:49:07 $
 * $Revision: 1.1 $
 *
 *===========================================================================
 * Copyright (c) 2001 by Shing Ip Kong.  All Rights Reserved.
 ****************************************************************************/
/*
 * $Id: appendixB,v 1.1 2001/12/06 21:49:07 kong Exp $
 */
`include "link_defs.v"		// See ../../CommonFiles

module link_txdp (
    // Outputs
    txencdata,
    next_txnrd,

    // Inputs
    tp_txdata,
    r2t_rxsnprim,
    r2t_rxsnrrdy,
    r2t_rxsnrip,
    r2t_rxsnrok,
    r2t_rxsnrerr,
    r2t_rxsndmat,
    r2t_rxsnsync,
    r2t_rxsnhold,
    r2t_rxsnholda,
    txscram_on,
    txscr_init,
    txscr_run,
    txcrc_init,
    txcrc_cal,
    txsn_CRC,
    txsn_data,
    txsn_sync,
    txsn_align,
    txsn_xrdy,
    txsn_sof,
    txsn_holda,
    txsn_hold,
    txsn_eof,
    txsn_wtrm,
    cur_txnrd,
    txclk4x,
    lktx_reset);

    /*
     * Output to SERDES Interface
     */
    output [0:39]	txencdata;	// Encoded transmit data

    /*
     * Output to the Link Layer Transmit Controller
     */
    output		next_txnrd;	// New negative running disparity

    /*
     * Inputs from the Transport Layer
     */
    input [31:0]	tp_txdata;

    /*
     * Inputs from the Link Layer Receiver (link_rx.v)
     * These signals have been synchronized with respect to txclk4x
     */
    input		r2t_rxsnprim;	// RX controls the primitive sending
    input		r2t_rxsnrrdy;	// RX sends the R_RDY primitive
    input		r2t_rxsnrip;	// RX sends the R_RIP primitive
    input		r2t_rxsnrok;	// RX sends the R_OK  primitive
    input		r2t_rxsnrerr;	// RX sends the R_ERR primitive
    input		r2t_rxsndmat;	// RX sends the DMAT  primitive

    // The following primitives can be sent by either link_txctl or link_rxctl
    input		r2t_rxsnsync;	// Sends the SYNC primitive
    input		r2t_rxsnhold;	// Sends the HOLD primitive
    input		r2t_rxsnholda;	// Sends the HOLDA primitive

    /*
     * Inputs from the Link Layer Transmit Controller (link_txctl.v)
     */
    input		txscram_on;	// Turn on data scrambling
    input		txscr_init;	// Initialize the scrambler
    input		txscr_run;	// Increment the scrambler polynomial

    input		txcrc_init;	// Initialize the CRC calculator
    input		txcrc_cal;	// Update the CRC output

    input		txsn_CRC;	// Send out the CRC pattern
    input		txsn_data;	// Send data or CRC (nor primitive)

    input		txsn_sync;	// TX sends the SYNC  primitive 
    input		txsn_align;	// TX sends the ALIGN primitive
    input		txsn_xrdy;	// TX sends the X_RDY primitive
    input		txsn_sof;	// TX sends the SOF   primitive
    input		txsn_holda;	// TX sends the HOLDA primitive
    input		txsn_hold;	// TX sends the HOLD  primitive
    input		txsn_eof;	// TX sends the EOF   primitive
    input		txsn_wtrm;	// TX sends the WTRM  primitive

    input		cur_txnrd;	// Current negative running disparity

    /*
     * Clocks and reset signals
     */
    input 		txclk4x;	// Transmit clock 
    input		lktx_reset;

    /*
     * Interconnections within this portion of the datapath
     */
    wire [`num_prim:0]			// Number of primitives + D10.2
			sel_prim;	// Select the proper primitives

    wire [31:0]		scr_out;	// Output of the scrambler
    wire [31:0]		crc_out;	// Output of the CRC calculator
    wire [31:0]		prim_out;	// Output of the Primitive generator

    wire [31:0]		crc_data;	// Output of the CRC mux
    wire [31:0]		scram_data;	// Scrambled data
    wire [31:0]		scrcrcdata;	// Data or CRC after scrambled

    wire [31:0]		rawtxdata;	// TX Data before 8b/10b coding
    wire [31:0]		clk_rawtxdata;	// rawtxdata after registered
    wire [0:39]		enctxdata;	// TX Data after 8b/10b coding

    // Running negative disparity after encoding Byte 0, Byte 1, and Byte 2
    wire [2:0]		txnrd_byte;


    wire 		clk_sendprim;	// ~(txsn_data | txsn_CRC) registered

    /*
     * Simple logic to form the primitive selct vector
     *
     * First, deal with the 3 primitives that can be sent by either
     * the Transmit (link_txctl) or the Receive (link_rxctl) controller
     *
     * Then we just need to proper connection with assign statements
     */
     v_mux2e #(3) txrx_selmux (
	{sel_prim[`B_HOLDA], sel_prim[`B_HOLD], sel_prim[`B_SYNC]},
	r2t_rxsnprim,
	{txsn_holda, txsn_hold, txsn_sync},
	{r2t_rxsnholda, r2t_rxsnhold, r2t_rxsnsync});

    // Primitive send by the Transmit Controller
    assign sel_prim[`B_ALIGN] = txsn_align;
    assign sel_prim[`B_X_RDY] = txsn_xrdy;
    assign sel_prim[`B_SOF]   = txsn_sof;
    assign sel_prim[`B_EOF]   = txsn_eof;
    assign sel_prim[`B_WTRM]  = txsn_wtrm;

    // Primitive send by the Receive Controller
    assign sel_prim[`B_R_RDY] = r2t_rxsnrrdy;
    assign sel_prim[`B_R_IP]  = r2t_rxsnrip;
    assign sel_prim[`B_R_OK]  = r2t_rxsnrok;
    assign sel_prim[`B_R_ERR] = r2t_rxsnrerr;
    assign sel_prim[`B_DMAT]  = r2t_rxsndmat;

    /*** Debug 4/13/2001: For now set these to zeros ***/    
    assign sel_prim[`B_CONT]    = 1'b0;
    assign sel_prim[`B_PMREQ_P] = 1'b0;
    assign sel_prim[`B_PMREQ_S] = 1'b0;
    assign sel_prim[`B_PMACK]   = 1'b0;
    assign sel_prim[`B_PMNAK]   = 1'b0;
    assign sel_prim[`B_D10_2]   = 1'b0;

    /*
     * Scrambler
     */
    l_scramble scrambler (
	.scr_out (scr_out),		.scr_in (32'hc2d2768d),
	.scr_init (txscr_init),		.scr_run (txscr_run),
	.clk (txclk4x),			.reset (lktx_reset));

    /*
     * CRC Calculator
     */
    l_crccal crc_calculator (
	.crc_out (crc_out),
	.crc_in (32'h52325032),		.datain (tp_txdata),
	.crc_init (txcrc_init),		.crc_cal (txcrc_cal),
	.clk (txclk4x),			.reset (lktx_reset));

    // MUX to select between sending data or sending the CRC pattern
    v_mux2e #(32) crc_mux (crc_data, txsn_CRC, tp_txdata, crc_out);

    // Scramble the data by performing a bit-wise exclusive OR
    assign scram_data = crc_data ^ scr_out;

    // MUX to decide if we want to send the scrambled data
    v_mux2e #(32) scramble_mux (scrcrcdata, txscram_on, crc_data, scram_data);

    /*
     * Generate the primitive (prime_out) based on the selection (sel_prim)
     */
    l_primgen primgen (.prim_out (prim_out),	.sel_prim (sel_prim));

    // Decide if we should send the primitive out
    v_mux2e #(32) prim_mux (rawtxdata, (txsn_data | txsn_CRC),
	prim_out, scrcrcdata);

    // Registered the data before sending them to the 8b/10b encoders
    v_reg #(32) rawdata_ff  (clk_rawtxdata, txclk4x, rawtxdata);
    v_reg #(1)  sendprim_ff (clk_sendprim, txclk4x, ~(txsn_data | txsn_CRC));

    /*
     * Perform the 8b/10b encoding.  The encoder for Byte 0 (enc8b10bk)
     * can encode the 8-bit D28_3 and D28_5 data words into the 10-bit
     * K28_3 and K28_5 code words if the "K" control input is set to 1.
     */
    enc8b10bk enc_byte0 (	// Byte 0 encoder
	.do (enctxdata[0:9]),		.nrdo (txnrd_byte[0]),
	.di (clk_rawtxdata[7:0]), 	.nrdi (cur_txnrd),
	.k (clk_sendprim));

    enc8b10b  enc_byte1 (	// Byte 1 Encoder
	.do (enctxdata[10:19]),		.nrdo (txnrd_byte[1]),
	.di (clk_rawtxdata[15:8]),	.nrdi (txnrd_byte[0]));

    enc8b10b  enc_byte2 (	// Byte 2 Encoder
	.do (enctxdata[20:29]),		.nrdo (txnrd_byte[2]),
	.di (clk_rawtxdata[23:16]),	.nrdi (txnrd_byte[1]));

    enc8b10b  enc_byte3 (	// Byte 3 Encoder
	.do (enctxdata[30:39]),		.nrdo (next_txnrd),
	.di (clk_rawtxdata[31:24]),	.nrdi (txnrd_byte[2]));

    v_reg #(40) encdata_ff (txencdata, txclk4x, enctxdata);

endmodule // link_txdp

/****************************************************************************
 *
 * File Name: link_library.v
 *
 * Comment: Components for the Link layer datapath.
 *
 * Author: Shing Kong
 * Creation Date: 1/25/2001
 *
 * $Source: /proj/gemini/cvs_root/P2002/Notes/Style/appendixB,v $
 * $Date: 2001/12/06 21:49:07 $
 * $Revision: 1.1 $
 *
 *===========================================================================
 * Copyright (c) 2001 by Shing Ip Kong.  All Rights Reserved.
 ****************************************************************************/
/*
 * $Id: appendixB,v 1.1 2001/12/06 21:49:07 kong Exp $
 */

/****************************************************************************
 * All the library elements in this file have names start with: "l_"
 ***************************************************************************/

`include "link_defs.v"

/****************************************************************************
 * l_scramble: 32-bit scrambler that can be:
 *  a. Reset to all zeros asynchronously
 *  b. Load a fix pattern synchronously.
 *  c. Keep its old value if scramble is not enable.
 *  d. Update its output synchronously based on a LFSR algorithm.
 ***************************************************************************/
module l_scramble (scr_out, scr_in, scr_init, scr_run, clk, reset);
    output [31:0]	scr_out;	// Scrambler's output

    input [31:0]	scr_in;		// Initial pattern to be loaded
    input		scr_init;	// Load the initial pattern
    input		scr_run;	// Update scr_out based on a LFSR
    input		clk;
    input		reset;

    reg [31:0]		scram;		// Scramble data pattern
    reg 		a15, a14, a13,	// Intermediate scramble bits
			a12, a11, a10,
			a9, a8, a7, a6, a5, a4, a3, a2, a1, a0;	

    wire [31:0]		runmuxout;	// Output of the scr_run MUX
    wire [31:0]		lastmux;	// Output of the final MUX

    /*
     * Combinational logic to produce the scramble pattern,
     * which should be updated whenever scr_out changes.
     * This logic was copied from Frank Lee's scramble.v
     */
    always @(scr_out) begin
	a15 = scr_out[31] ^ scr_out[29] ^ scr_out[20] ^ scr_out[16];
	a14 =               scr_out[30] ^ scr_out[21] ^ scr_out[17];
	a13 =               scr_out[31] ^ scr_out[22] ^ scr_out[18];
	a12 =                             scr_out[23] ^ scr_out[19];
	a11 =                             scr_out[24] ^ scr_out[20];
	a10 =                             scr_out[25] ^ scr_out[21];
	a9  =                             scr_out[26] ^ scr_out[22];
	a8  =                             scr_out[27] ^ scr_out[23];
	a7  =                             scr_out[28] ^ scr_out[24];
	a6  =                             scr_out[29] ^ scr_out[25];
	a5  =                             scr_out[30] ^ scr_out[26];
	a4  =                             scr_out[31] ^ scr_out[27];
	a3  =                                           scr_out[28];
	a2  =                                           scr_out[29];
	a1  =                                           scr_out[30];
	a0  =                                           scr_out[31];

	scram[31] = a15^a14^    a12^a11^a10^      a7^a6^a5^            a0;
	scram[30] = a15^    a13^a12^a11^       a8^a7^a6^            a1^a0;
	scram[29] =     a14^a13^a12^        a9^a8^a7^            a2^a1;
	scram[28] = a15^a14^a13^        a10^a9^a8^            a3^a2;
	scram[27] = a15^a14^        a11^a10^a9^            a4^a3^      a0;
	scram[26] = a15^        a12^a11^a10^            a5^a4^      a1^a0;
	scram[25] =         a13^a12^a11^             a6^a5^      a2^a1;
	scram[24] =     a14^a13^a12^              a7^a6^      a3^a2^   a0;
	scram[23] = a15^a14^a13^               a8^a7^      a4^a3^   a1^a0;
	scram[22] = a15^a14^                a9^a8^      a5^a4^   a2^a1^a0;
	scram[21] = a15^                a10^a9^      a6^a5^   a3^a2^a1;
	scram[20] =                 a11^a10^      a7^a6^   a4^a3^a2;
	scram[19] =             a12^a11^       a8^a7^   a5^a4^a3^      a0;
	scram[18] =         a13^a12^        a9^a8^   a6^a5^a4^      a1;
	scram[17] =     a14^a13^        a10^a9^   a7^a6^a5^      a2^   a0;
	scram[16] = a15^a14^        a11^a10^   a8^a7^a6^      a3^   a1^a0;
	scram[15] = a15^        a12^a11^    a9^a8^a7^      a4^   a2^a1^a0;
	scram[14] =         a13^a12^    a10^a9^a8^      a5^   a3^a2^a1;
	scram[13] =     a14^a13^    a11^a10^a9^      a6^   a4^a3^a2;
	scram[12] = a15^a14^    a12^a11^a10^      a7^   a5^a4^a3;
	scram[11] = a15^    a13^a12^a11^       a8^   a6^a5^a4;
	scram[10] =     a14^a13^a12^        a9^   a7^a6^a5;
	scram[9]  = a15^a14^a13^        a10^   a8^a7^a6;
	scram[8]  = a15^a14^        a11^    a9^a8^a7;
	scram[7]  = a15^        a12^    a10^a9^a8;
	scram[6]  =         a13^    a11^a10^a9;
	scram[5]  =     a14^    a12^a11^a10;
	scram[4]  = a15^    a13^a12^a11;
	scram[3]  =     a14^a13^a12;
	scram[2]  = a15^a14^a13;
	scram[1]  = a15^a14;
	scram[0]  = a15;
    end // Scrambling logic

    /*                                   Priority:
     *          scram   scr_out          -------------------------------
     *              |   |                reset (asynchronous):   highest
     *          +---v---v---+            scr_init (synchronous): middle
     * scr_run-->\S 1   0  /             scr_run (synchronous):  lowest
     *            +---+---+  scr_in
     *                |       |
     *            +---v-------v---+
     *             \  0       1 S/<--scr_init (higher priority than scr_run)
     *              +-----+-----+
     *                    |
     *                    v
     *                  lastmux
     */ 
    v_mux2e #(32) run_mux (runmuxout, scr_run, scr_out, scram);
    v_mux2e #(32) init_mux (lastmux, scr_init, runmuxout, scr_in);
    v_regre #(32) scr_ff (scr_out, clk, lastmux, (scr_run | scr_init), reset); 

endmodule // l_scramble

/****************************************************************************
 * l_crccal: 32-bit CRC calculator that can be:
 *  a. Reset to all zeros asynchronously
 *  b. Load a fix pattern synchronously.
 *  c. Keep its old value if CRC calculation is not enable.
 *  d. Update its output synchronously based on its input
 ***************************************************************************/
module l_crccal (crc_out, crc_in, datain, crc_init, crc_cal, clk, reset);

    output [31:0]	crc_out;	// CRC calculator's output

    input [31:0]	crc_in;		// Initial patern to be loaded
    input [31:0]	datain;		// Data contribute to CRC calculation
    input		crc_init;	// Load the initial pattern
    input		crc_cal;	// Calculate crc_out based on a LFSR
    input		clk;
    input		reset;

    reg [31:0]		x;		// Temporary variable for CRC
    reg [31:0]		crc;		// Output of the CRC random logic

    wire [31:0]		runmuxout;	// Output of the crc_cal MUX
    wire [31:0]		lastmux;	// Output of the final MUX

    /*
     * Combinational logic to calculates the CRC output.
     * Its output should be updated whenever crc_out or datain changes.
     * This logic was copied from Frank Lee's satacrc.v
     */
    always @(crc_out or datain) begin
	x = datain ^ crc_out;
	crc = (x[0]?  32'b00000100110000010001110110110111: 32'b0)
	    ^ (x[1]?  32'b00001001100000100011101101101110: 32'b0)
	    ^ (x[2]?  32'b00010011000001000111011011011100: 32'b0)
	    ^ (x[3]?  32'b00100110000010001110110110111000: 32'b0)
	    ^ (x[4]?  32'b01001100000100011101101101110000: 32'b0)
	    ^ (x[5]?  32'b10011000001000111011011011100000: 32'b0)
	    ^ (x[6]?  32'b00110100100001100111000001110111: 32'b0)
	    ^ (x[7]?  32'b01101001000011001110000011101110: 32'b0)
	    ^ (x[8]?  32'b11010010000110011100000111011100: 32'b0)
	    ^ (x[9]?  32'b10100000111100101001111000001111: 32'b0)
	    ^ (x[10]? 32'b01000101001001000010000110101001: 32'b0)
	    ^ (x[11]? 32'b10001010010010000100001101010010: 32'b0)
	    ^ (x[12]? 32'b00010000010100011001101100010011: 32'b0)
	    ^ (x[13]? 32'b00100000101000110011011000100110: 32'b0)
	    ^ (x[14]? 32'b01000001010001100110110001001100: 32'b0)
	    ^ (x[15]? 32'b10000010100011001101100010011000: 32'b0)
	    ^ (x[16]? 32'b00000001110110001010110010000111: 32'b0)
	    ^ (x[17]? 32'b00000011101100010101100100001110: 32'b0)
	    ^ (x[18]? 32'b00000111011000101011001000011100: 32'b0)
	    ^ (x[19]? 32'b00001110110001010110010000111000: 32'b0)
	    ^ (x[20]? 32'b00011101100010101100100001110000: 32'b0)
	    ^ (x[21]? 32'b00111011000101011001000011100000: 32'b0)
	    ^ (x[22]? 32'b01110110001010110010000111000000: 32'b0)
	    ^ (x[23]? 32'b11101100010101100100001110000000: 32'b0)
	    ^ (x[24]? 32'b11011100011011011001101010110111: 32'b0)
	    ^ (x[25]? 32'b10111100000110100010100011011001: 32'b0)
	    ^ (x[26]? 32'b01111100111101010100110000000101: 32'b0)
	    ^ (x[27]? 32'b11111001111010101001100000001010: 32'b0)
	    ^ (x[28]? 32'b11110111000101000010110110100011: 32'b0)
	    ^ (x[29]? 32'b11101010111010010100011011110001: 32'b0)
	    ^ (x[30]? 32'b11010001000100111001000001010101: 32'b0)
	    ^ (x[31]? 32'b10100110111001100011110100011101: 32'b0);
    end // End of the combinational logic that calculates the CRC

    /*                                   Priority:
     *            crc   crc_out          -------------------------------
     *              |   |                reset (asynchronous):   highest
     *          +---v---v---+            crc_init (synchronous): middle
     * crc_cal-->\S 1   0  /             crc_cal (synchronous):  lowest
     *            +---+---+  crc_in
     *                |       |
     *            +---v-------v---+
     *             \  0       1 S/<--crc_init (higher priority than crc_cal)
     *              +-----+-----+
     *                    |
     *                    v
     *                  lastmux
     */ 
    v_mux2e #(32) run_mux (runmuxout, crc_cal, crc_out, crc);
    v_mux2e #(32) init_mux (lastmux, crc_init, runmuxout, crc_in);
    v_regre #(32) crc_ff (crc_out, clk, lastmux, (crc_cal | crc_init), reset); 
endmodule // l_crccal

/****************************************************************************
 * l_primgen: 32-bit primitive generator
 *	This 32-bit primitive must be encoded by the 8-bit/10-bit encoder
 *	to become the actual 40-bit SATA primitives.
 *
 *	One interesting feature here is that Byte 0 of the 32-bit primitive
 *	is either D28.3 or D28.5 and when it is encoded to K28.3 and K28.5
 *	by a 8-bit/10-bit encoder with the control bit (K) set to 1.
 *
 ***************************************************************************/
module l_primgen (prim_out, sel_prim);

    output [31:0]		prim_out;	// 32-bit primitive
    input [`num_prim:0]		sel_prim;	// Primitive + D10.2 select

    reg [31:0]			prim_out;

    always @(sel_prim) begin
	if (sel_prim[`B_ALIGN]) begin
	    //******** {Byte 3, Byte 2, Byte 1, Byte 0}
	    prim_out = {`D27_3, `D10_2, `D10_2, `D28_5};
	end
	else if (sel_prim[`B_SYNC]) begin
	    prim_out = {`D21_5, `D21_5, `D21_4, `D28_3};
	end
	else if (sel_prim[`B_CONT]) begin
	    prim_out = {`D25_4, `D25_4, `D10_5, `D28_3};
	end
	else if (sel_prim[`B_HOLD]) begin
	    prim_out = {`D21_6, `D21_6, `D10_5, `D28_3};
	end
	else if (sel_prim[`B_HOLDA]) begin
	    prim_out = {`D21_4, `D21_4, `D10_5, `D28_3};
	end
	else if (sel_prim[`B_R_RDY]) begin
	    prim_out = {`D10_2, `D10_2, `D21_4, `D28_3};
	end
	else if (sel_prim[`B_R_IP]) begin
	    prim_out = {`D21_2, `D21_2, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_R_OK]) begin
	    prim_out = {`D21_1, `D21_1, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_R_ERR]) begin
	    prim_out = {`D22_2, `D22_2, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_X_RDY]) begin
	    prim_out = {`D23_2, `D23_2, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_SOF]) begin
	    prim_out = {`D23_1, `D23_1, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_EOF]) begin
	    prim_out = {`D21_6, `D21_6, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_DMAT]) begin
	    prim_out = {`D22_1, `D22_1, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_WTRM]) begin
	    prim_out = {`D24_2, `D24_2, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_PMREQ_P]) begin
	    prim_out = {`D23_0, `D23_0, `D21_5, `D28_3};
	end
	else if (sel_prim[`B_PMREQ_S]) begin
	    prim_out = {`D21_3, `D21_3, `D21_4, `D28_3};
	end
	else if (sel_prim[`B_PMACK]) begin
	    prim_out = {`D21_4, `D21_4, `D21_4, `D28_3};
	end
	else if (sel_prim[`B_PMNAK]) begin
	    prim_out = {`D21_7, `D21_7, `D21_4, `D28_3};
	end
	else if (sel_prim[`B_D10_2]) begin
	    // Special four D10_2 words in a row
	    prim_out = {`D10_2, `D10_2, `D10_2, `D10_2};
	end
	else begin	// None are selected: send ALIGN
	    prim_out = {`D27_3, `D10_2, `D10_2, `D28_5};
	end
    end

endmodule // l_primgen

/****************************************************************************
 * l_primdec: primitive decoder
 ***************************************************************************/
module l_primdec (prim_vector, prim_in, k28_3, k28_5);

    output [`num_prim-1:0]
			prim_vector;	// Primitive vector

    input [31:8]	prim_in;	// Bytes 3, 2, and 1 of the primitive

    input		k28_3;		// Byte 0 is a K28_3 character
    input		k28_5;		// Byte 0 is a K28_5 character

    wire [`num_prim-1:0]
			maybe;	// May be vector

    // Basic primitives
    v_comparator #(24) align_cmp (
	.out (maybe[`B_ALIGN]),
	.in1 (prim_in),		.in2 ({`D27_3, `D10_2, `D10_2}));
    assign prim_vector[`B_ALIGN] = maybe[`B_ALIGN] & k28_5;

    v_comparator #(24) sync_cmp (
	.out (maybe[`B_SYNC]),
	.in1 (prim_in),		.in2 ({`D21_5, `D21_5, `D21_4}));
    assign prim_vector[`B_SYNC] = maybe[`B_SYNC] & k28_3;

    v_comparator #(24) cont_cmp (
	.out (maybe[`B_CONT]),
	.in1 (prim_in),		.in2 ({`D25_4, `D25_4, `D10_5}));
    assign prim_vector[`B_CONT] = maybe[`B_CONT] & k28_3;

    // Flow control primitives
    v_comparator #(24) hold_cmp (
	.out (maybe[`B_HOLD]),
	.in1 (prim_in),		.in2 ({`D21_6, `D21_6, `D10_5}));
    assign prim_vector[`B_HOLD] = maybe[`B_HOLD] & k28_3;

    v_comparator #(24) holda_cmp (
	.out (maybe[`B_HOLDA]),
	.in1 (prim_in),		.in2 ({`D21_4, `D21_4, `D10_5}));
    assign prim_vector[`B_HOLDA] = maybe[`B_HOLDA] & k28_3;

    v_comparator #(24) r_rdy_cmp (
	.out (maybe[`B_R_RDY]),
	.in1 (prim_in),		.in2 ({`D10_2, `D10_2, `D21_4}));
    assign prim_vector[`B_R_RDY] = maybe[`B_R_RDY] & k28_3;

    v_comparator #(24) r_ip_cmp (
	.out (maybe[`B_R_IP]),
	.in1 (prim_in),		.in2 ({`D21_2, `D21_2, `D21_5}));
    assign prim_vector[`B_R_IP] = maybe[`B_R_IP] & k28_3;

    v_comparator #(24) r_ok_cmp (
	.out (maybe[`B_R_OK]),
	.in1 (prim_in),		.in2 ({`D21_1, `D21_1, `D21_5}));
    assign prim_vector[`B_R_OK] = maybe[`B_R_OK] & k28_3;

    v_comparator #(24) r_err_cmp (
	.out (maybe[`B_R_ERR]),
	.in1 (prim_in),		.in2 ({`D22_2, `D22_2, `D21_5}));
    assign prim_vector[`B_R_ERR] = maybe[`B_R_ERR] & k28_3;

    v_comparator #(24) x_rdy_cmp (
	.out (maybe[`B_X_RDY]),
	.in1 (prim_in),		.in2 ({`D23_2, `D23_2, `D21_5}));
    assign prim_vector[`B_X_RDY] = maybe[`B_X_RDY] & k28_3;

    v_comparator #(24) sof_cmp (
	.out (maybe[`B_SOF]),
	.in1 (prim_in),		.in2 ({`D23_1, `D23_1, `D21_5}));
    assign prim_vector[`B_SOF] = maybe[`B_SOF] & k28_3;

    v_comparator #(24) eof_cmp (
	.out (maybe[`B_EOF]),
	.in1 (prim_in),		.in2 ({`D21_6, `D21_6, `D21_5}));
    assign prim_vector[`B_EOF] = maybe[`B_EOF] & k28_3;

    v_comparator #(24) dmat_cmp (
	.out (maybe[`B_DMAT]),
	.in1 (prim_in),		.in2 ({`D22_1, `D22_1, `D21_5}));
    assign prim_vector[`B_DMAT] = maybe[`B_DMAT] & k28_3;

    v_comparator #(24) wtrm_cmp (
	.out (maybe[`B_WTRM]),
	.in1 (prim_in),		.in2 ({`D24_2, `D24_2, `D21_5}));
    assign prim_vector[`B_WTRM] = maybe[`B_WTRM] & k28_3;

    // Power management primitives
    v_comparator #(24) pmreq_p_cmp (
	.out (maybe[`B_PMREQ_P]),
	.in1 (prim_in),		.in2 ({`D23_0, `D23_0, `D21_5}));
    assign prim_vector[`B_PMREQ_P] = maybe[`B_PMREQ_P] & k28_3;

    v_comparator #(24) pmreq_s_cmp (
	.out (maybe[`B_PMREQ_S]),
	.in1 (prim_in),		.in2 ({`D21_3, `D21_3, `D21_4}));
    assign prim_vector[`B_PMREQ_S] = maybe[`B_PMREQ_S] & k28_3;

    v_comparator #(24) pmack_cmp (
	.out (maybe[`B_PMACK]),
	.in1 (prim_in),		.in2 ({`D21_4, `D21_4, `D21_4}));
    assign prim_vector[`B_PMACK] = maybe[`B_PMACK] & k28_3;

    v_comparator #(24) pmnak_cmp (
	.out (maybe[`B_PMNAK]),
	.in1 (prim_in),		.in2 ({`D21_7, `D21_7, `D21_4}));
    assign prim_vector[`B_PMNAK] = maybe[`B_PMNAK] & k28_3;

endmodule // l_primgen

/****************************************************************************
 *
 * File Name: link_defs.v
 *
 * Comment: Definitions for the Link Layer
 *
 * Author: Shing Kong
 * Creation Date: 1/29/2001
 *
 * $Source: /proj/gemini/cvs_root/P2002/Notes/Style/appendixB,v $
 * $Date: 2001/12/06 21:49:07 $
 * $Revision: 1.1 $
 *
 *===========================================================================
 * Copyright (c) 2001 by Shing Ip Kong.  All Rights Reserved.
 ****************************************************************************/
/*
 * $Id: appendixB,v 1.1 2001/12/06 21:49:07 kong Exp $
 */

/*
 * Number of primitives and the bit position of the 1-hot encoded vector
 */
`define num_prim	 18

// Basic Primitives
`define B_ALIGN		  0
`define B_SYNC		  1
`define B_CONT		  2

// Flow Control Primitives
`define B_HOLD		  3
`define B_HOLDA		  4
`define B_R_RDY		  5
`define B_R_IP		  6
`define B_R_OK		  7
`define B_R_ERR		  8
`define B_X_RDY		  9
`define B_SOF		 10
`define B_EOF		 11
`define B_DMAT		 12
`define B_WTRM		 13

// Power Management Primitives
`define B_PMREQ_P	 14
`define B_PMREQ_S	 15
`define B_PMACK		 16
`define B_PMNAK		 17

// Special patterns (not a primitive) to be generated
// by the l_primgen: four consecutive D10_2's
`define B_D10_2	 	18

/*
 * Define the 8-bit pattern for the primitives
 *
 * Note: The 8-bit D28_3 and D28_5 will be encoded into the 10-bit
 *       K28_3 and K28_5 patterns by the 8B/10B encoder with its
 *	 control bit (K) set to 1.
 */
`define D10_2		8'b010_01010		// 0x4A
`define D10_4		8'b100_01010		// 0x8A
`define D10_5		8'b101_01010		// 0xAA

`define D21_1		8'b001_10101		// 0x35
`define D21_2		8'b010_10101		// 0x55
`define D21_3		8'b011_10101		// 0x75
`define D21_4		8'b100_10101		// 0x95
`define D21_5		8'b101_10101		// 0xB5
`define D21_6		8'b110_10101		// 0xD5
`define D21_7		8'b111_10101		// 0xF5

`define D22_1		8'b001_10110		// 0x36
`define D22_2		8'b010_10110		// 0x56

`define D23_0		8'b000_10111		// 0x17
`define D23_1		8'b001_10111		// 0x37
`define D23_2		8'b010_10111		// 0x57

`define D24_2		8'b010_11000		// 0x58

`define D25_4		8'b100_11001		// 0x99

`define D27_3		8'b011_11011		// 0x7B
`define D27_4		8'b100_11011		// 0x9B

`define D28_3		8'b011_11100		// 0x7C
`define D28_5		8'b101_11100		// 0xBC

/*
 * Define the bit position and state values for the transmit finite state
 * machine (FSM in the link_txctl).  This FSM implements the "Link Idle
 * State Diagram" (P. 145 of the SATA V1 Spec.) and the "Link Transmit
 * State Diagram" (P. 148 of the SATA V1 Spec).
 *
 * The two states below are not shown explicitly in the two state diagrams
 * described above:
 *     BUSYRCV: we have kicked off the receive finite state machine
 *         (see below) and therefore cannot transmit any of our own data.
 *
 *     POWERDOWN: we have entered the power saving states, which will
 *         be handled by the Power Management State machine.
 */
// Number of TX states and bit position of the 1-hot state encoding
`define num_lktxstate	15
`define B_NOCOMM	 0
`define B_SENDALIGN	 1
`define B_NOCOMMERR	 2
`define B_TXIDLE	 3
`define B_HSENDCHKRDY	 4
`define B_DSENDCHKRDY	 5
`define B_SENDSOF	 6
`define B_SENDDATA	 7
`define B_RCVRHOLD	 8
`define B_SENDHOLD	 9
`define B_SENDCRC	10
`define B_SENDEOF	11
`define B_WAIT		12
`define B_BUSYRCV	13
`define B_POWERDOWN	14

// State Values
`define RESET		15'h0000	// All bits are zeros
`define NOCOMM		15'h0001	// Bit 0 is set
`define SENDALIGN	15'h0002	// Bit 1 is set
`define NOCOMMERR	15'h0004	// Bit 2 is set
`define TXIDLE		15'h0008
`define HSENDCHKRDY	15'h0010
`define DSENDCHKRDY	15'h0020
`define SENDSOF		15'h0040
`define SENDDATA	15'h0080
`define RCVRHOLD	15'h0100
`define SENDHOLD	15'h0200
`define SENDCRC		15'h0400
`define SENDEOF		15'h0800
`define WAIT		15'h1000
`define BUSYRCV		15'h2000	// Link layer is busy receiving data
`define POWERSAVE	15'h4000	// Link layer is power down

/*
 * Define the state values and bit position for the receive finite state
 * machine (FSM in the link_rxctl).  This FSM implements the "Link
 * Receive State Diagram" (P. 154 of the SATA V1 Spec).
 */
// Number of RX states and bit position of the 1-hot state encoding
`define num_lkrxstate	11
`define B_RXIDLE	 0
`define B_RCVCHKRDY	 1
`define B_RCVWAITFIFO	 2
`define B_RCVDATA	 3
`define B_RXSNHOLD	 4
`define B_RXSNHOLDA	 5
`define B_RCVEOF	 6
`define B_GOODCRC	 7
`define B_GOODEND	 8
`define B_BADEND	 9
`define B_WAITTXID	10	// Wait for TX FSM to return to idle state

// State Values
`define RXIDLE		11'h001
`define RCVCHKRDY	11'h002
`define RCVWAITFIFO	11'h004
`define RCVDATA		11'h008
`define RXSNHOLD	11'h010
`define RXSNHOLDA	11'h020
`define RCVEOF		11'h040
`define GOODCRC		11'h080
`define GOODEND		11'h100
`define BADEND		11'h200
`define WAITTXID	11'h400