2014年5月29日 星期四

RTL coding習慣和backend之間的關聯

下個星期是端午連假,所以就提早把下個星期要發佈,提早發佈!

今天我跟大家說明一下,寫RTL程式時,我們應該要去怎麼思索verilog code的寫法。我並不是想說明verilog 的語法,而是你的verilog程式,在合成時,Design Compiler(DC)怎麼去看待你的程式,它是怎麼解讀你的程式。畢竟我們寫出來的程式,是要給Design Compiler(DC)合出正確的的電路。

以下來原來原始程式的一部份,因為保密原則,我只能給一點點範例來說。下以的電路設計是一個SmartBus slaververilog codeSMBCi_DP51iclock訊號,是input訊號。SMBDi_DP51idata訊號,也是input訊號。
原始的設計是把SMBCi_DP51i當成是clock source,但是因為SmartBus的結束訊號的行為,有些數位工程師會SMBDi當成是clock source,來設計出結束訊號的偵測。以下就是一些程式的範例,紅色部份就是當成clock source的訊號。

wire SMBCi_DP51 = SMBCi;
wire SMBDi_DP51 = SMBDi;

// detect start condition -------------------------------
always @(negedge SMBDi_DP51 or negedge rstb)
begin
        if ( ~ rstb )
                sta <= 1'b0;
        else
                sta <= SMBCi_DP51;
end

always @(negedge SMBDi_DP51 or negedge rstb)
begin
        if ( ~ rstb )
                re_sta <= 1'b0;
        else
                re_sta <= SMBCi_DP51 & ( AdrCmdCnt == 6'd18 );
end


// start pulse ------------------------------------------
always @(negedge SMBCi_DP51 or negedge rstb)
begin
        if ( ~ rstb )
                d_sta <= 1'b0;
        else
                d_sta <= sta;
end

assign sta_pulse = ! d_sta & sta ;    // for system reset


// detect stop condition -------------------------------
always @(posedge SMBDi_DP51 or negedge sta_rstb)
begin
        if ( ~ sta_rstb )
                sto <= 1'b0;
        else
                sto <= SMBCi_DP51;
end
always @( negedge SMBCi_DP51 or negedge rstb )
begin
        if ( ~ rstb )
                sr <= 24'h0;
        else if ( ( AckCycle == 0 ) & ( sta_pulse == 0 ) )
                sr <= { sr_P[22:0], SMBDi_DP51i };
end

wire set_Smb2xSramWe  = (Smb2xSramWr & set_Smb2We);

always @ (posedge set_Smb2xSramWe or negedge rst_Smb2xSramWe )
        if ( ~ rst_Smb2xSramWe )
                Smb2xSramWe_0 <= #1  1'b0;
        else
                Smb2xSramWe_0 <= #1  1'b1;

always @ (posedge clk_DP51 or negedge rstb )
        if ( ~ rstb )
                Smb2xSramWe_1 <= #1  1'b0;
        else
                Smb2xSramWe_1 <= #1  Smb2xSramWe_0;

always @ (posedge clk_DP51 or negedge rstb )
        if ( ~ rstb )
                Smb2xSramWe <= #1  1'b0;
        else
                Smb2xSramWe <= #1  Smb2xSramWe_1;


使用上面的程式來合成電路時,Design Compiler(DC)會出現一些訊息,來告訴你,有些DFF沒有constrains,所以無法檢查出它的timing. 而你在宣告clock來源,你要宣告在兩個地方,一個是SMBCi,另一個是SMBDi。亦或是在程式中,任意產生一個訊號來當成是另一個DFFclock source。對DC而言,這些行為會有跨clock domain的問題、DFF constrain不充足的問題等等。這些都是需要數位工程師一一去確認,是否這些不足的條件是沒有關係或是有關係?所以工程師要一一去檢查來自DCwarning message(以下只有一部份,紅色部份是因舉例的程式所特別挑出來的。).

以下是用DCcheck_timing的指令,所列出來的訊息。

Warning: Design 'A1133' contains unmapped cells.
        Use report_cell to list unmapped cells in the design. (OPT-309)

Warning: The following end-points are not constrained for maximum delay.

End point
---------------
MCU/PM/CLK_DIV/q3_reg/next_state
MCU/PM/CLK_DIV/q5_reg/next_state
MCU/PM/CLK_DIV/q7_reg/next_state
MCU/SM2RAM/ Smb2xSramWe_0_reg/next_state
MCU/Smbus/TSextCntEn_32K_reg/next_state
MCU/Smbus/d_sto_reg[0]/next_state
MCU/Smbus/re_sta_reg/next_state
MCU/Smbus/sta_reg/next_state
MCU/Smbus/sto_reg/next_state

Information: The clock network starting at 'MCU/TestMux/CLK_SW_32K/CLK' is gated by the
        following input pins.

Clock Output Pin        Clock Input Pin          Gating Input Pin
--------------------------------------------------------------------------------
MCU/TEST_RST/C32/Z_0    MCU/TEST_RST/C32/DATA1_0 MCU/TEST_RST/C32/DATA2_0
MCU/TEST_RST/C32/Z_0    MCU/TEST_RST/C32/DATA1_0 MCU/TEST_RST/C32/CONTROL1_0
MCU/TEST_RST/C32/Z_0    MCU/TEST_RST/C32/DATA1_0 MCU/TEST_RST/C32/CONTROL2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA1_0
MCU/CHIPDP8051/U_CLKCTRL/C266/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/CONTROL1_0
MCU/CHIPDP8051/U_CLKCTRL/C266/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA2_0           MCU/CHIPDP8051/U_CLKCTRL/C266/CONTROL2_0
MCU/CHIPDP8051/U_CLKCTRL/C275/Z
MCU/CHIPDP8051/U_CLKCTRL/C275/B
MCU/CHIPDP8051/U_CLKCTRL/C275/A
MCU/CHIPDP8051/U_CLKCTRL/C267/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA1_0
MCU/CHIPDP8051/U_CLKCTRL/C267/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C267/CONTROL1_0
MCU/CHIPDP8051/U_CLKCTRL/C267/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C267/CONTROL2_0
MCU/CHIPDP8051/U_CLKCTRL/C278/Z
MCU/CHIPDP8051/U_CLKCTRL/C278/B
MCU/CHIPDP8051/U_CLKCTRL/C278/A
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/Z_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA2_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA1_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/Z_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA2_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/CONTROL1_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/Z_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA2_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/CONTROL2_0
MCU/filter/C1371/Z      MCU/filter/C1371/A       MCU/filter/C1371/B
MCU/filter/C1383/Z      MCU/filter/C1383/A       MCU/filter/C1383/B

Information: The clock network starting at 'MCU/SM2RAM/SMB_CLK/SMBCi_DP51' is gated by the
        following input pins.

Clock Output Pin        Clock Input Pin          Gating Input Pin
--------------------------------------------------------------------------------
MCU/SM2RAM/C2184/Z_0    MCU/SM2RAM/C2184/DATA1_0 MCU/SM2RAM/C2184/DATA2_0
MCU/SM2RAM/C2184/Z_0    MCU/SM2RAM/C2184/DATA1_0 MCU/SM2RAM/C2184/CONTROL1_0
MCU/SM2RAM/C2184/Z_0    MCU/SM2RAM/C2184/DATA1_0 MCU/SM2RAM/C2184/CONTROL2_0
MCU/SM2RAM/C2185/Z_0    MCU/SM2RAM/C2185/DATA1_0 MCU/SM2RAM/C2185/DATA2_0
MCU/SM2RAM/C2185/Z_0    MCU/SM2RAM/C2185/DATA1_0 MCU/SM2RAM/C2185/CONTROL1_0
MCU/SM2RAM/C2185/Z_0    MCU/SM2RAM/C2185/DATA1_0 MCU/SM2RAM/C2185/CONTROL2_0
MCU/SM2RAM/C2186/Z_0    MCU/SM2RAM/C2186/DATA1_0 MCU/SM2RAM/C2186/DATA2_0
MCU/SM2RAM/C2186/Z_0    MCU/SM2RAM/C2186/DATA1_0 MCU/SM2RAM/C2186/CONTROL1_0
MCU/SM2RAM/C2186/Z_0    MCU/SM2RAM/C2186/DATA1_0 MCU/SM2RAM/C2186/CONTROL2_0
MCU/SM2RAM/C2187/Z_0    MCU/SM2RAM/C2187/DATA1_0 MCU/SM2RAM/C2187/DATA2_0
MCU/SM2RAM/C2187/Z_0    MCU/SM2RAM/C2187/DATA1_0 MCU/SM2RAM/C2187/CONTROL1_0
MCU/SM2RAM/C2187/Z_0    MCU/SM2RAM/C2187/DATA1_0 MCU/SM2RAM/C2187/CONTROL2_0
MCU/SM2RAM/C2189/Z_0    MCU/SM2RAM/C2189/DATA2_0 MCU/SM2RAM/C2189/DATA1_0
MCU/SM2RAM/C2189/Z_0    MCU/SM2RAM/C2189/DATA2_0 MCU/SM2RAM/C2189/CONTROL1_0
MCU/SM2RAM/C2189/Z_0    MCU/SM2RAM/C2189/DATA2_0 MCU/SM2RAM/C2189/CONTROL2_0
MCU/SM2RAM/C2188/Z_0    MCU/SM2RAM/C2188/DATA1_0 MCU/SM2RAM/C2188/DATA2_0
MCU/SM2RAM/C2188/Z_0    MCU/SM2RAM/C2188/DATA1_0 MCU/SM2RAM/C2188/CONTROL1_0
MCU/SM2RAM/C2188/Z_0    MCU/SM2RAM/C2188/DATA1_0 MCU/SM2RAM/C2188/CONTROL2_0
MCU/SM2RAM/C2174/Z_0    MCU/SM2RAM/C2174/DATA2_0 MCU/SM2RAM/C2174/DATA1_0
MCU/SM2RAM/C2174/Z_0    MCU/SM2RAM/C2174/DATA2_0 MCU/SM2RAM/C2174/CONTROL1_0
MCU/SM2RAM/C2174/Z_0    MCU/SM2RAM/C2174/DATA2_0 MCU/SM2RAM/C2174/CONTROL2_0

Information: The clock network starting at 'MCU/Smbus/SMB_CLK/SMBCi_DP51' is gated by the
        following input pins.

Clock Output Pin        Clock Input Pin          Gating Input Pin
--------------------------------------------------------------------------------
MCU/Smbus/C950/Z        MCU/Smbus/C950/B         MCU/Smbus/C950/A
MCU/Smbus/C978/Z        MCU/Smbus/C978/B         MCU/Smbus/C978/A
MCU/Smbus/C969/Z        MCU/Smbus/C969/B         MCU/Smbus/C969/A
MCU/Smbus/C973/Z        MCU/Smbus/C973/A         MCU/Smbus/C973/B
MCU/Smbus/C982/Z        MCU/Smbus/C982/A         MCU/Smbus/C982/B
MCU/Smbus/C925/Z_0      MCU/Smbus/C925/DATA1_0   MCU/Smbus/C925/DATA2_0
MCU/Smbus/C925/Z_0      MCU/Smbus/C925/DATA1_0   MCU/Smbus/C925/CONTROL1_0
MCU/Smbus/C925/Z_0      MCU/Smbus/C925/DATA1_0   MCU/Smbus/C925/CONTROL2_0


這麼長,又這麼多的訊息要用人工的方式檢查,是不是既累人又煩燥?
為什麼數位工程師要寫一個DC無法百分百辨識的程式?為什麼不順應DC的特性,寫一個它看懂的程式,既方便又安全。

以下是重寫原來的程式;做法是用一個比較快的clock當成唯一的clock source,而外部訊號SMBCi_DP51iSMBDi_DP51iclk_DP51的領域裏,都被當成是data 訊號處理。

wire SMBCi_DP51 = SMBCi_DP51i;
wire SMBDi_DP51 = SMBDi_DP51i;

//----------------------------------------------------------------------
// analyze SMBC and SMBD signal
//----------------------------------------------------------------------
reg SMBCi_DP51_d1t, SMBCi_DP51_d2t;
reg SMBDi_DP51_d1t, SMBDi_DP51_d2t;

always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
    begin
        SMBCi_DP51_d1t <=0;
        SMBCi_DP51_d2t <=0;
    end
    else
    begin
        SMBCi_DP51_d1t <=SMBCi_DP51;
        SMBCi_DP51_d2t <=SMBCi_DP51_d1t;
    end
end

always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
    begin
        SMBDi_DP51_d1t <=0;
        SMBDi_DP51_d2t <=0;
    end
    else
    begin
        SMBDi_DP51_d1t <=SMBDi_DP51;
        SMBDi_DP51_d2t <=SMBDi_DP51_d1t;
    end
end

wire SMBCi_DP51_rising, SMBCi_DP51_falling;
wire SMBDi_DP51_rising, SMBDi_DP51_falling;

assign SMBCi_DP51_rising  = (SMBCi_DP51  & (~SMBCi_DP51_d1t));
assign SMBCi_DP51_falling = (~SMBCi_DP51 & (SMBCi_DP51_d1t));

assign SMBDi_DP51_rising  = (SMBDi_DP51  & (~SMBDi_DP51_d1t));
assign SMBDi_DP51_falling = (~SMBDi_DP51 & (SMBDi_DP51_d1t));



// detect start condition -------------------------------
always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
        sta <=0;
    else if(SMBDi_DP51_falling)
        sta <= SMBCi_DP51;
    else
        sta <= sta;
end

always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
        re_sta <=0;
    else if(SMBDi_DP51_falling)
        re_sta <= SMBCi_DP51 & ( AdrCmdCnt == 6'd18 );
    else
        re_sta <= re_sta;
end


// start pulse ------------------------------------------
always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
        d_sta <=0;
    else if(SMBCi_DP51_falling)
        d_sta <=sta;
    else
        d_sta <= d_sta;
end


assign sta_pulse = ! d_sta & sta ;    // for system reset


// detect stop condition -------------------------------
always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
        sto <=0;
    else if(sta_pulse)
        sto <=0;
    else if(SMBDi_DP51_rising)
        sto <=SMBCi_DP51;
    else
        sto <= sto;
end

always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
    begin
        Smb2xSramWe_0 <= 0;
        Smb2xSramWe_1 <= 0;
    end
    else
    begin
        Smb2xSramWe_0 <= set_Smb2xSramWe;
        Smb2xSramWe_1 <= Smb2xSramWe_0;
    end
end

wire Smb2xSramWe_xor = (set_Smb2xSramWe ^ Smb2xSramWe_1) & Smb2xSramWe_1;

always@(posedge clk_DP51 or negedge rstb)
begin
    if(~rstb)
        Smb2xSramWe <= 0;
    else
        Smb2xSramWe <= Smb2xSramWe_xor;
end


使用新的程式重新合成新的電路,我們會發現DCreport出來的訊息裏,原來紅色字的訊息已經不見了。這表示DC百分百看懂你的程式,且因為constrain充足,所以它不會有無法辨別timing的情況。請看以下來自DCwarning message


Warning: Design 'A1133' contains unmapped cells.
        Use report_cell to list unmapped cells in the design. (OPT-309)

Warning: The following end-points are not constrained for maximum delay.

End point
---------------
MCU/PM/CLK_DIV/q3_reg/next_state
MCU/PM/CLK_DIV/q5_reg/next_state
MCU/PM/CLK_DIV/q7_reg/next_state
// No red words warning message
MCU/Smbus/TSextCntEn_32K_reg/next_state
MCU/Smbus/d_sto_reg[0]/next_state
MCU/Smbus/re_sta_reg/next_state
MCU/Smbus/sta_reg/next_state
MCU/Smbus/sto_reg/next_state


Information: The clock network starting at 'MCU/TestMux/CLK_SW_32K/CLK' is gated by the
        following input pins.

Clock Output Pin        Clock Input Pin          Gating Input Pin
--------------------------------------------------------------------------------
MCU/TEST_RST/C32/Z_0    MCU/TEST_RST/C32/DATA1_0 MCU/TEST_RST/C32/DATA2_0
MCU/TEST_RST/C32/Z_0    MCU/TEST_RST/C32/DATA1_0 MCU/TEST_RST/C32/CONTROL1_0
MCU/TEST_RST/C32/Z_0    MCU/TEST_RST/C32/DATA1_0 MCU/TEST_RST/C32/CONTROL2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA1_0
MCU/CHIPDP8051/U_CLKCTRL/C266/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/CONTROL1_0
MCU/CHIPDP8051/U_CLKCTRL/C266/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C266/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C266/CONTROL2_0
MCU/CHIPDP8051/U_CLKCTRL/C275/Z
MCU/CHIPDP8051/U_CLKCTRL/C275/B
MCU/CHIPDP8051/U_CLKCTRL/C275/A
MCU/CHIPDP8051/U_CLKCTRL/C267/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA1_0
MCU/CHIPDP8051/U_CLKCTRL/C267/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C267/CONTROL1_0
MCU/CHIPDP8051/U_CLKCTRL/C267/Z_0
MCU/CHIPDP8051/U_CLKCTRL/C267/DATA2_0
MCU/CHIPDP8051/U_CLKCTRL/C267/CONTROL2_0
MCU/CHIPDP8051/U_CLKCTRL/C278/Z
MCU/CHIPDP8051/U_CLKCTRL/C278/B
MCU/CHIPDP8051/U_CLKCTRL/C278/A
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/Z_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA2_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA1_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/Z_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA2_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/CONTROL1_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/Z_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/DATA2_0
MCU/CHIPDP8051/U_DP8051/U_TIMERS/C802/CONTROL2_0
MCU/filter/C1371/Z      MCU/filter/C1371/A       MCU/filter/C1371/B
MCU/filter/C1383/Z      MCU/filter/C1383/A       MCU/filter/C1383/B

// No red words warning message

Information: The clock network starting at 'MCU/Smbus/SMB_CLK/SMBCi_DP51' is gated by the
        following input pins.

Clock Output Pin        Clock Input Pin          Gating Input Pin
--------------------------------------------------------------------------------
MCU/Smbus/C950/Z        MCU/Smbus/C950/B         MCU/Smbus/C950/A
MCU/Smbus/C978/Z        MCU/Smbus/C978/B         MCU/Smbus/C978/A
MCU/Smbus/C969/Z        MCU/Smbus/C969/B         MCU/Smbus/C969/A
MCU/Smbus/C973/Z        MCU/Smbus/C973/A         MCU/Smbus/C973/B
MCU/Smbus/C982/Z        MCU/Smbus/C982/A         MCU/Smbus/C982/B
MCU/Smbus/C925/Z_0      MCU/Smbus/C925/DATA1_0   MCU/Smbus/C925/DATA2_0
MCU/Smbus/C925/Z_0      MCU/Smbus/C925/DATA1_0   MCU/Smbus/C925/CONTROL1_0
MCU/Smbus/C925/Z_0      MCU/Smbus/C925/DATA1_0   MCU/Smbus/C925/CONTROL2_0


IC design flow裏,是需要很多軟體的協助。因此,數位工程師在寫verilog 程式時,不應只想著要怎麼解決自己問題,同時也應該想想後段工程師及軟體的處境。想一想,應該怎麼寫,才能讓flow裏面所有的工程師都是可以順順利利的做事。這也是為什麼我之前要把數位工程師分門別類成不同風格。愈是可以讓design flow順暢的數位工程師,他的RTL code上就愈可以看出他的用心與堅持。
IC design的過程中,我們都會遇到許許多多奇怪的疑難雜症。我並不是堅持一定要用上述的方法解決問題。而是你的程式是要給DC合成,是否可以採用可以儘量減少這些需要人工檢查的訊息的程式風格?是否可以採用符合ATPGDRC rule的程式風格?減少後段工程師的負擔。這些都是數位工程師在front-end design時,就可以儘量避免的事情,為什麼不做?

多去想想在這個IC flow上其他工程師做的事情,有沒有自己可以在RTL階段時,就可以幫忙或是避免的做法?多了解後段工程師的想法,可以讓自己的RTL程式愈來愈適合後段的流程;同時,我們也可以把前段RTL的特性告訴後段工程師,讓他們更加了解,RTL並不是無敵的,它有無法做到的地方時,是否可以請後段工程師幫忙,做出符合產品要求的高品質的晶片。

IC design flow裏,並不是只有一個人在做,是由許多人一起合力完成。寫出讓大家都能順暢地工作的RTL程式,才是數位工程師應該要努力的方向。


1 則留言: