2010年6月28日 星期一

Color Transform Engine @ Verilog

Propose : 最近還找不到一個完整的 Project, 想說拿 "CIC" 的題目當練習,也可以自己磨練一下.XD 題目 :Color Transform Engine Motivation: 利用影像壓縮 "RGB 2 YUV"的方式,可減少存放在Memory的Frame大小.也可增加傳輸效率. 再硬體實現上,必須要有 Encoder ("RGB 2 YUV")跟 Decoder ("YUV 2 RGB")端, 才能正確的收發 Data. 可參考 97學年決賽競賽題目 (研究所組) 有詳細的說明 設計概念: 主要會面對 3 個問題 1. 如何做 float point 的運算, 因為 Verilog 不支援 float point.. Ref: float point @ verilog 2 . 如何把 Data Path 跟 Control Path 切乾淨 把 YUV2RGBRGB2YUV 分成兩個 PE(process element), 再用 Ctl status 來控制每個 status. 3. 處理 Input/Output 的 Sequence YUV / RGB 的 vector 擺放位置跟順序關係 底下就針對這3個 topic 來完成Design YUV2RGB.v 為 YUV2RGB PE RGB2YUV.v 為 RGB2YUV PE CTE.v 為 TOP CTL PS: Function code 要合成 驗證後才能確定 timing OK, 不會造成 Setup or Hold time fail CTE.v
`timescale 1ns/10ps

`include "YUV2RGB.v"
`include "RGB2YUV.v"

module CTE ( clk, 
             reset, 
             op_mode,
             in_en,
             yuv_in,
             rgb_in,
             busy,
             out_valid,
             rgb_out,
             yuv_out
);

input   clk ;
input   reset ;
input   op_mode;
input   in_en;
output  busy;
output  out_valid;
input   [7:0]   yuv_in;
output  [23:0]  rgb_out;
input   [23:0]  rgb_in;
output  [7:0]   yuv_out;

reg     [3:0] cur_st;
reg     [3:0] nxt_st;

reg     [7:0] reg_YUV2Y;
reg     [7:0] reg_YUV2U;
reg     [7:0] reg_YUV2V;
reg     [3:0] reg_yuv_cot;
reg     [3:0] reg_yuv_re_cot;

reg     [3:0] reg_rgb_cot;
reg     [3:0] reg_rgb_re_cot;
reg     [3:0] reg_rgb_re2_cot;
reg     [7:0] reg_RGB2R;
reg     [7:0] reg_RGB2G;
reg     [7:0] reg_RGB2B;


wire    [7:0] w_reg_YUV2Y;
wire    [7:0] w_reg_YUV2U;
wire    [7:0] w_reg_YUV2V;

wire    [7:0] w_reg_YUV2R;
wire    [7:0] w_reg_YUV2G;
wire    [7:0] w_reg_YUV2B;


wire    [7:0] w_reg_RGB2R;
wire    [7:0] w_reg_RGB2G;
wire    [7:0] w_reg_RGB2B;

wire    [7:0] w_reg_RGB2Y;
wire    [7:0] w_reg_RGB2U;
wire    [7:0] w_reg_RGB2V;


wire      busy;

parameter st_IDLE       = 3'b000; 
parameter st_YUV2RGB    = 3'b001;
parameter st_YUV_BUSY   = 3'b010;
parameter st_YUV2RGB_ot = 3'b011;
parameter st_RGB2YUV    = 3'b101;
parameter st_RGB_BUSY   = 3'b110;
parameter st_RGB2YUV_ot = 3'b111;


assign busy     = ( reg_yuv_cot ==3         || reg_rgb_cot ==1         )? 1'b1 : 1'b0;
assign out_valid= ( cur_st == st_YUV2RGB_ot || cur_st == st_RGB2YUV_ot )? 1'b1 : 1'b0;
assign rgb_done = ( reg_rgb_re_cot == 3     || reg_rgb_re2_cot ==1     )? 1'b1 : 1'b0;

assign rgb_out[23:16] = w_reg_YUV2R;
assign rgb_out[15: 8] = w_reg_YUV2G;
assign rgb_out[7 : 0] = w_reg_YUV2B;


assign w_reg_YUV2Y  = reg_YUV2Y;
assign w_reg_YUV2U  = reg_YUV2U;
assign w_reg_YUV2V  = reg_YUV2V;

assign w_reg_RGB2R  = reg_RGB2R;
assign w_reg_RGB2G  = reg_RGB2G;
assign w_reg_RGB2B  = reg_RGB2B;

assign yuv_out = ( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==1 && reg_rgb_re2_cot ==0 )? w_reg_RGB2U :
                 ( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==2 && reg_rgb_re2_cot ==0 )? w_reg_RGB2Y :
                 ( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==3 && reg_rgb_re2_cot ==0 )? w_reg_RGB2V :
                 ( cur_st == st_RGB2YUV_ot && reg_rgb_re_cot ==1 && reg_rgb_re2_cot ==1 )? w_reg_RGB2Y : 8'h00; 
//State_Transitions
// cur_st <= nxt_st
always @ (posedge clk or posedge reset) begin // State_Transitions
 if( reset )
    cur_st <= st_IDLE;
else
    cur_st <= nxt_st;
end

// Nxt_ST
always @ ( cur_st or op_mode or in_en or busy or rgb_done )begin // Nxt_ST
 case(cur_st)
  st_IDLE      : nxt_st = ( op_mode  ==1'b0                    )? st_YUV2RGB    : st_RGB2YUV;
 
  st_YUV2RGB   : nxt_st = ( op_mode  ==1'b0 &&  busy==1'b1     )? st_YUV_BUSY   : 
                          ( op_mode  ==1'b1                    )? st_IDLE       : st_YUV2RGB; 
  st_YUV_BUSY  : nxt_st = ( op_mode  ==1'b0                    )? st_YUV2RGB_ot : st_IDLE;
  st_YUV2RGB_ot: nxt_st = ( op_mode  ==1'b0                    )? st_YUV2RGB    : st_IDLE;
  
  st_RGB2YUV   : nxt_st = ( op_mode  ==1'b1 && busy==1'b1      )? st_RGB_BUSY   : st_IDLE;
  st_RGB_BUSY  : nxt_st = ( op_mode  ==1'b1                    )? st_RGB2YUV_ot : st_IDLE; 
  st_RGB2YUV_ot: nxt_st = ( op_mode  ==1'b1 && rgb_done ==1'b1 )? st_IDLE       : st_RGB2YUV_ot;   
 endcase
end 


always @ (posedge clk or posedge reset) begin // YUV2RGB translator
 if( reset ) begin
        reg_yuv_cot    <= 0;
        reg_yuv_re_cot <= 0;
   end
 
 else
    begin
     if( in_en ==1'b1 && op_mode ==1'b0 && reg_yuv_cot != 3 )begin
           if ( reg_yuv_cot == 0 && reg_yuv_re_cot == 0  )begin reg_YUV2U <= yuv_in; end
      else if ( reg_yuv_cot == 1 && reg_yuv_re_cot == 0  )begin reg_YUV2Y <= yuv_in; end
      else if ( reg_yuv_cot == 2 && reg_yuv_re_cot == 0  )begin reg_YUV2V <= yuv_in; end
      else if ( reg_yuv_cot == 2 && reg_yuv_re_cot == 1  )begin reg_YUV2Y <= yuv_in; end
                 
       reg_yuv_cot <= reg_yuv_cot+1;

   end
   else if ( cur_st == st_YUV_BUSY )begin
           if( reg_yuv_re_cot ==1 && reg_yuv_cot ==3 )begin
                  reg_yuv_cot    <=0;
                  reg_yuv_re_cot <=0;
           end
           else if(reg_yuv_re_cot ==0 && reg_yuv_cot ==3) begin
                   reg_yuv_re_cot <= reg_yuv_re_cot+1;
                   reg_yuv_cot <= reg_yuv_cot-1;
           end
   end
 end
end




always @ (posedge clk or posedge reset )begin // RGB2YUV translator
 if ( reset ) begin
     reg_rgb_cot    <= 0; 
     reg_rgb_re_cot <= 0;
     reg_rgb_re2_cot<= 0;
  end

 else
  begin
     if( in_en ==1'b1 && op_mode ==1'b1 && reg_rgb_cot !=1 )begin
          reg_RGB2R <= rgb_in[23:16];
          reg_RGB2G <= rgb_in[15: 8];
          reg_RGB2B <= rgb_in[7 : 0];

          reg_rgb_cot <= reg_rgb_cot +1; 
     end
     else if( cur_st == st_RGB_BUSY || cur_st == st_RGB2YUV_ot ) begin
             if( reg_rgb_re_cot == 3 && reg_rgb_re2_cot ==0 )begin
                reg_rgb_re_cot <= 0;
                reg_rgb_cot    <= 0;
                reg_rgb_re2_cot<= reg_rgb_re2_cot+1;
             end
             else if(reg_rgb_re_cot == 1 && reg_rgb_re2_cot ==1)begin
                reg_rgb_re_cot <= 0;
                reg_rgb_cot    <= 0;
                reg_rgb_re2_cot<= 0;
             end
             else
                reg_rgb_re_cot <= reg_rgb_re_cot+1;
     end
 end
end


 YUV2RGB Pe_YUV2RGB( .ot_R(w_reg_YUV2R),
                     .ot_G(w_reg_YUV2G),
                     .ot_B(w_reg_YUV2B),
                     .in_Y(w_reg_YUV2Y),
                     .in_U(w_reg_YUV2U),
                     .in_V(w_reg_YUV2V)
);


 RGB2YUV Pe_RGB2YUV( .ot_Y(w_reg_RGB2Y),
                     .ot_U(w_reg_RGB2U),
                     .ot_V(w_reg_RGB2V),
                     .in_R(w_reg_RGB2R),
                     .in_G(w_reg_RGB2G),
                     .in_B(w_reg_RGB2B)
);



endmodule


YUV2RGB.v


module YUV2RGB ( ot_R,
                 ot_G,
                 ot_B,
                 in_Y,
                 in_U,
                 in_V
);

output  [7 : 0 ] ot_R;
output  [7 : 0 ] ot_G;
output  [7 : 0 ] ot_B;

input   [7 : 0 ] in_Y;
input   [7 : 0 ] in_U;
input   [7 : 0 ] in_V;

wire    [0 : 0 ] p_n_Y;
wire    [0 : 0 ] p_n_U;
wire    [0 : 0 ] p_n_V;

wire    [7: 0 ] w_in_Y;
wire    [7: 0 ] w_in_U;
wire    [7: 0 ] w_in_V;

wire    [0 : 0 ] p_n_Y2R;
wire    [0 : 0 ] p_n_U2R;
wire    [0 : 0 ] p_n_V2R;
wire [7 : 0 ] ex_V2R; //1.625

wire    [0 : 0 ] p_n_Y2G;
wire    [0 : 0 ] p_n_U2G;
wire    [0 : 0 ] p_n_V2G;
wire [7 : 0 ] ex_U2G; //-0.25
wire [7 : 0 ] ex_V2G; //-0.78

wire    [0 : 0 ] p_n_Y2B;
wire    [0 : 0 ] p_n_U2B;
wire    [0 : 0 ] p_n_V2B;
wire [7 : 0 ] ex_U2B; //2

wire [19: 0 ] rst_Y2R;
wire [19: 0 ] rst_U2R;
wire [19: 0 ] rst_V2R;
wire [19: 0 ] w_rst_V2R;
wire    [19: 0 ] rst_R;

wire [19: 0 ] rst_Y2G;
wire [19: 0 ] rst_U2G;
wire [19: 0 ] w_rst_U2G;
wire [19: 0 ] rst_V2G;
wire [19: 0 ] w_rst_V2G;
wire [19: 0 ] rst_G;

wire [19: 0 ] rst_Y2B;
wire [19: 0 ] rst_U2B;
wire [19: 0 ] w_rst_U2B;
wire [19: 0 ] rst_V2B;
wire [19: 0 ] rst_B;

//&& Chek Positive or Negative, if Negative, reverse it 2 Postive and mark the sign bit
// Y sign extension
assign p_n_Y [0  : 0  ] = 1'b0;
assign w_in_Y[7 : 0 ] = in_Y[7 : 0 ];
    
// U sign extension
assign p_n_U [0 : 0 ] = in_U[7 : 7 ];  
assign w_in_U[7 : 0 ] = ( p_n_U ==1'b0 ) ? in_U[7 : 0 ] : 8'hff - in_U + 8'h01 ; 
 
// V sign extension
assign p_n_V [0 : 0 ] = in_V[7 : 7 ];  
assign w_in_V[7 : 0 ] = ( p_n_V ==1'b0 ) ? in_V[7 : 0 ] : 8'hff - in_V + 8'h01 ; 

// V2R = 0 => 8'h 1.a
assign p_n_V2R[0  : 0 ] = 1'b0;
assign ex_V2R [7  : 4 ] = 4'h1;
assign ex_V2R [3  : 0 ] = 4'ha;
 
// U2G = -0.25 => 8'h 0.4
assign p_n_U2G[0  : 0 ] = 1'b1;
assign ex_U2G [7  : 4 ] = 4'h0;
assign ex_U2G [3  : 0 ] = 4'h4;

// V2G = -0.75 => 8'h 0.c
assign p_n_V2G[0  : 0 ] = 1'b1;
assign ex_V2G [7  : 4 ] = 4'h0;
assign ex_V2G [3  : 0 ] = 4'hc;

// U2B = 2 => 8'h 2.0
assign p_n_U2B[0  : 0 ] = 1'b0;
assign ex_U2B [7  : 4 ] = 4'h2;
assign ex_U2B [3  : 0 ] = 4'h0;


// Y2R RST 
assign rst_Y2R[19 : 12] = 8'h00;
assign rst_Y2R[11 : 4 ] = in_Y[7 : 0 ];
assign rst_Y2R[3  : 0 ] = 4'h0;

// U2R RST
assign rst_U2R[19 : 0 ] = 20'h00000;

// V2R RST
assign w_rst_V2R = (  ex_V2R*w_in_V );
assign rst_V2R   = ( (p_n_V^p_n_V2R) == 1'b0 )? w_rst_V2R : (20'hfffff - w_rst_V2R + 20'h00001);

assign rst_R     = ( rst_Y2R + rst_U2R + rst_V2R );

assign ot_R      = ( rst_R[19] == 1'b0 && rst_R[19: 4 ] >= 16'h00ff ) ? 8'hff                  :
                   ( rst_R[19] == 1'b0 && rst_R[3 : 3 ] == 1'b1     ) ? rst_R[11 : 4 ] + 8'h01 :
                   ( rst_R[19] == 1'b1                              ) ? 8'h00                  : rst_R[11 : 4 ];

// Y2G RST
assign rst_Y2G[19 : 12] = 8'h00;
assign rst_Y2G[11 : 4 ] = in_Y[7 : 0 ];
assign rst_Y2G[3  : 0 ] = 4'h0;

// U2G RST
assign w_rst_U2G = (  ex_U2G*w_in_U );
assign rst_U2G   = ( (p_n_U^p_n_U2G) == 1'b0 )? w_rst_U2G : (20'hfffff - w_rst_U2G + 20'h00001);

// V2G RST
assign w_rst_V2G = (  ex_V2G*w_in_V );
assign rst_V2G   = ( (p_n_V^p_n_V2G) == 1'b0 )? w_rst_V2G : (20'hfffff - w_rst_V2G + 20'h00001);

assign rst_G     = ( rst_Y2G + rst_U2G + rst_V2G );

assign ot_G      = ( rst_G[19] == 1'b0 && rst_G[19 : 4 ] >= 16'h00ff ) ? 8'hff                 :
                   ( rst_G[19] == 1'b0 && rst_G[3  : 3 ] == 1'b1     ) ? rst_G[11 : 4 ] + 8'h01 :
                   ( rst_G[19] == 1'b1                               ) ? 8'h00                 : rst_G[11 : 4 ];

// Y2B RST
assign rst_Y2B[19 : 12] = 8'h00;
assign rst_Y2B[11 : 4 ] = in_Y[7 : 0 ];
assign rst_Y2B[3  : 0 ] = 4'h0;

// U2B RST
assign w_rst_U2B = (  ex_U2B*w_in_U );
assign rst_U2B   = ( (p_n_U^p_n_U2B) == 1'b0 )? w_rst_U2B : (20'hfffff - w_rst_U2B + 20'h00001);

// V2B RST
assign rst_V2B[19 : 0 ] = 20'h00000;

assign rst_B     = ( rst_Y2B + rst_U2B + rst_V2B );

assign ot_B      = ( rst_B[19] == 1'b0 && rst_B[19 :4 ] >= 20'h00ff ) ? 8'hff                  :
                   ( rst_B[19] == 1'b0 && rst_B[3  :3 ] == 1'b1     ) ? rst_B[11 : 4 ] + 8'h01 :
                   ( rst_B[19] == 1'b1                              ) ? 8'h00                  : rst_B[11 : 4 ];

endmodule

RGB2YUV.v

module RGB2YUV ( ot_Y,
                 ot_U,
                 ot_V,
                 in_R,
                 in_G,
                 in_B
);


output[7 : 0 ] ot_Y;
output[7 : 0 ] ot_U;
output[7 : 0 ] ot_V;

input [7 : 0 ] in_R;
input [7 : 0 ] in_G;
input [7 : 0 ] in_B;

wire  [43 : 0 ] ex_R2Y; //0.2909
wire  [43 : 0 ] ex_G2Y; //0.6303
wire  [43 : 0 ] ex_B2Y; //0.078
wire  [43 : 0 ] rst_Y;

wire  [43 : 0 ] ex_R2U; //0.1454
wire  [43 : 0 ] ex_G2U; //0.3151
wire  [43 : 0 ] ex_B2U; //0.4606
wire  [43 : 0 ] rst_U;

wire  [43 : 0 ] ex_R2V; //0.1454
wire  [43 : 0 ] ex_G2V; //0.3151
wire  [43 : 0 ] ex_B2V; //0.4606
wire  [43 : 0 ] rst_V;


// 0.2909
assign ex_R2Y  [43 : 0 ] = 44'h004A786C227;

//0.6303
assign ex_G2Y  [43 : 0 ] = 44'h00A15B573EB;

//0.0787
assign ex_B2Y  [43 : 0 ] = 44'h001425AEE63;

assign rst_Y = (ex_R2Y*in_R) + (ex_G2Y*in_G) + (ex_B2Y*in_B);
assign ot_Y  = ( rst_Y[43] == 1'b0 && rst_Y[35] == 1'b1 )? rst_Y[43:36] + 8'h01 : rst_Y[43:36];
               
// 0.1454
assign ex_R2U [43 : 0 ] = 44'h002538EF34D;

//0.3151
assign ex_G2U [43 : 0 ] = 44'h0050AA64C30;

//0.4606
assign ex_B2U [43 : 0 ] = 44'h0075E9E1B09;

assign rst_U = -(ex_R2U*in_R) -(ex_G2U*in_G) + (ex_B2U*in_B);
assign ot_U  = ( rst_U[43] == 1'b0 && rst_U[35]   == 1'b1       )? rst_U[43:36] + 8'h01 : 
               ( rst_U[43] == 1'b1 && rst_U[35:0] <= 36'h666665 )? rst_U[43:36] - 8'h01 : rst_U[43:36];

// 0.4363
assign ex_R2V [43 : 0 ] = 44'h006FB15B574;

// 0.3878 
assign ex_G2V [43 : 0 ] = 44'h006346DC5D6;

// 0.0484
assign ex_B2V [43 : 0 ] = 44'h000C63F1412;

assign rst_V = (ex_R2V*in_R) -(ex_G2V*in_G) - (ex_B2V*in_B);
assign ot_V  = ( rst_V[43] == 1'b0 && rst_V[35]   == 1'b1       )? rst_V[43:36] + 8'h01 : 
               ( rst_V[43] == 1'b1 && rst_V[35:0] <= 36'h666665 )? rst_V[43:36] - 8'h01 : rst_V[43:36];


endmodule
compile
% iverilog -o CTE CTE.v testfixture1.v
% ./CTE
Simulation Results testfixture1.v Congratulations! All data have been generated successfully! testfixture2.v Square Distance of All YUV = 233.000000 Square of All YUV Signal = 21561234.000000 ----------------------------------------------------- So Your Error Ratio: (Square Distance of YUV)/(Square of All YUV Signal) = 0.000011 ----------------------------------------------------- Your Score Level: E Congratulations! CTE's Function2 Successfully! PS: 可以調整循環小數的精確度讓 Error Rate變小, 不過相對的 Area 跟 Time 會是 cost function Download http://sites.google.com/site/funningboy/verilog/ICC2009.tar?attredirects=0&d=1

2010年6月25日 星期五

float point @ verilog

Propose : 在Verilog 中, 要如何計算"浮點數"跟"負數"乘法運算可以利用shift 的方式,把小數點以下的bit 當成 int 來做運算,之後再根據 point 的 position, shit 出 "整數" 跟 "小數" 的部份 ex : 1.625 * 3 = 4.875 float 1.625 = 16'h1.A = 2'b0001.1010 constrain : 整數 8 bit width, 小數 8 bit width Step1 : 把point拿掉, 讓 16'h1.A 當成 16'h1A Step2 : 16'h1A * 16'h3 = 32'h4E Step3 : 加入先前的 point, 32'h4E -> 32'h4.E = float 4.875 Step4 : 4捨5入(positive), 5捨6入(negative) 取整數部份 Simulation Results tools : iverilog Verilog codes : float.v
module FLOAT( ot_c,
             in_a
);

parameter WIDTH = 8;

output  [WIDTH-1   : 0 ] ot_c;
input   [WIDTH-1   : 0 ] in_a;

wire    [0         : 0 ] p_n;
wire    [WIDTH*2-1 : 0 ] ex_f;
wire    [WIDTH-1   : 0 ] w_in_a;
wire    [WIDTH*2+7 : 0 ] w_rst;
wire    [WIDTH-1   : 0 ] w_ot_c;

//2'd 1.625 = 2'b 1.101
assign ex_f[15:8] = 16'h01;
assign ex_f[7 :0] = 16'ha0;

//define positive or negative
assign  p_n   = ( in_a[WIDTH-1] ==1'b1 )? 1'b1 : 1'b0;

assign w_in_a = ( p_n == 1'b1 )? ( 16'hff - in_a + 16'h01) : in_a;

assign w_rst  = ( ex_f*w_in_a );

assign w_ot_c =  w_rst[15:8];

assign ot_c   = ( p_n ==1'b0 && w_rst[7] == 1'b1     )? w_ot_c + 16'h01 :
               ( p_n ==1'b0 && w_rst[7] == 1'b0     )? w_ot_c          :
               ( p_n ==1'b1 && w_rst[7:0] >= 16'h99 )? 16'hff - w_ot_c :
               ( p_n ==1'b1 && w_rst[7:0] < 16'h99  )?16'hff - w_ot_c + 16'h01;
endmodule

float_tb.v
module FLOAT_TB;

 reg [7:0] t_in_a;

 initial begin
    # 10 t_in_a =  10;
    # 10 t_in_a = -10;
    # 10 t_in_a =   0;
    # 10 t_in_a =  77;
    # 10 t_in_a = -77;
    # 100 $stop;
 end

// range -128 ~ +127
//   127/1.625 ~= 77

wire [7:0] t_ot_c;
FLOAT f1 (t_ot_c, t_in_a);

 initial
    $monitor("At time %t, t_in_a = %h :: t_ot_c = %h",
             $time, t_in_a, t_ot_c);
endmodule //FLOAT_TB

compiler
% iverilog -o float float.v float_tb.v

% ./float
results At time 0, t_in_a = xx :: t_ot_c = xx At time 10, t_in_a = 0a :: t_ot_c = 10 At time 20, t_in_a = f6 :: t_ot_c = f0 At time 30, t_in_a = 00 :: t_ot_c = 00 At time 40, t_in_a = 4D :: t_ot_c = 7D At time 50, t_in_a = b3 :: t_ot_c = 83 other refs: (原創) 如何處理signed integer的加法運算與overflow? (SOC) (Verilog) (原創) 如何計算浮點數? (SOC) (Verilog)

2010年6月24日 星期四

AHB Slave emulator @ SystemC

continuous with AHB Master emulator @ SystemC

#include <systemc.h>
#include <iostream>

using namespace std;

#define WP_BUS_BUFF_DEP 32
#define WP_BUS_MEM_DEP  1024

enum AHB_BUS_SLAVE_TYPE {
 AHB_BUS_SLAVE_IDLE =0,
 AHB_BUS_SLAVE_NON =1,
 AHB_BUS_SLAVE_RD =2,
 AHB_BUS_SLAVE_WT =3,  
};

SC_MODULE(AHB_BUS_SLAVE) {
 sc_in<bool>  HSELx;
 sc_in<sc_uint<32> > HADDR;
 sc_in<bool>  HWRITE;
 sc_in<sc_uint<3> > HTRANS;
 sc_in<sc_uint<3> > HSIZE;
 sc_in<sc_uint<5> > HBURST;

 sc_in<sc_uint<32> > HWDATA;
 sc_in<bool>  HRESETn;
 sc_in<bool>  HCLK;
 sc_in<sc_uint<4> > HMASTER;
 sc_in<bool>  HMASTLOCK;

 sc_out<bool>  HREADY;
 sc_out<sc_uint<2> > HRESP;

 sc_out<sc_uint<32> > HRDATA;
 sc_out<sc_uint<16> > HSPLITx;   

        sc_signal<bool>  WP_BUS_MASTER_BUSY;
 sc_signal<bool>  WP_BUS_HREADY;
 sc_signal<sc_uint<32> > WP_BUS_HREADY_COT;
 sc_signal<sc_uint<2> > WP_BUS_HRESP;
 sc_signal<sc_uint<2> > WP_BUS_HRESP_COT;
 
 sc_signal<sc_uint<3> > WP_BUS_CUR_ST;
 sc_signal<sc_uint<3> > WP_BUS_NXT_ST;

 sc_signal<sc_uint<32> > WP_BUS_WT_HADDR_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_WT_HDATA_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_WT_HADDR_INX;
 sc_signal<sc_uint<32> > WP_BUS_WT_HDATA_INX;

 sc_signal<sc_uint<32> > WP_BUS_RD_HADDR_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_RD_HDATA_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_RD_HADDR_INX;
 sc_signal<sc_uint<32> > WP_BUS_RD_HDATA_INX;


 sc_signal<sc_uint<32> > WP_BUS_INT_MEM[WP_BUS_MEM_DEP];
 

 SC_CTOR(AHB_BUS_SLAVE){
 SC_METHOD(PRO_WP_BUS_ST);
 dont_initialize();
 sensitive << HRESETn;
 sensitive << HCLK.pos();

 SC_METHOD(PRO_WP_BUS_ST_DO);
 dont_initialize();
 sensitive << WP_BUS_CUR_ST;
 sensitive << HSELx;
 sensitive << HTRANS;
 sensitive << HWRITE;
 sensitive << WP_BUS_HRESP;
 sensitive << WP_BUS_RD_HDATA_INX;
 sensitive << WP_BUS_WT_HDATA_INX;
 sensitive << HBURST;

        SC_METHOD(PRO_WP_BUS_RSP);
 dont_initialize();
 sensitive << HCLK.pos();

        SC_METHOD(PRO_WP_BUS_WT);
 dont_initialize();
 sensitive << HCLK.pos();

        SC_METHOD(PRO_WP_BUS_RD);
 dont_initialize();
 sensitive << HCLK.pos();

 SC_METHOD(PRO_WP_BUS_MASTER_BUSY);
 dont_initialize();
 sensitive << HTRANS;

 SC_METHOD(PRO_WP_BUS_INT_MEM);
 dont_initialize();
 sensitive << WP_BUS_CUR_ST;

 AHB_BUS_SLAVE_VCD_DUMP();

 };

 void PRO_WP_BUS_ST();
 void PRO_WP_BUS_ST_DO();
 void   PRO_WP_BUS_RSP();


 void   PRO_WP_BUS_RD();
 void PRO_WP_BUS_WT();
 void   PRO_WP_BUS_MASTER_BUSY();
 void   PRO_WP_BUS_INT_MEM();
 void AHB_BUS_SLAVE_VCD_DUMP();
};


#include "AHB_BUS_SLAVE.h"
#include "AHB.h"

void AHB_BUS_SLAVE::PRO_WP_BUS_ST(){

 sc_uint<3> TMP_NXT_ST = ( HRESETn.read() == false ) ? AHB_BUS_SLAVE_IDLE : WP_BUS_NXT_ST.read();
 WP_BUS_CUR_ST.write(TMP_NXT_ST);
  
}


void AHB_BUS_SLAVE::PRO_WP_BUS_ST_DO(){

 sc_uint<3> TMP_CUR_ST = WP_BUS_CUR_ST.read();
 sc_uint<3> TMP_NXT_ST = WP_BUS_NXT_ST.read();

 switch(TMP_CUR_ST){
 case  AHB_BUS_SLAVE_IDLE : TMP_NXT_ST =   AHB_BUS_SLAVE_NON; break;
        case  AHB_BUS_SLAVE_NON  : TMP_NXT_ST = ( HSELx.read() == true && HTRANS.read()== AMBA_NONSEQ && HWRITE.read()== true )? AHB_BUS_SLAVE_WT : 
                                                ( HSELx.read() == true && HTRANS.read()== AMBA_NONSEQ && HWRITE.read()== false)? AHB_BUS_SLAVE_RD : AHB_BUS_SLAVE_NON;  break;
 case  AHB_BUS_SLAVE_RD   : TMP_NXT_ST = ( HSELx.read() == true && HWRITE.read()== false && WP_BUS_HRESP.read()  == AMBA_RETY )? AHB_BUS_SLAVE_NON :
                                                ( HSELx.read() == true && HWRITE.read()== false && WP_BUS_HRESP.read()  == AMBA_SPLIT)? AHB_BUS_SLAVE_NON :
                                                ( HSELx.read() == true && HWRITE.read()== false && WP_BUS_HRESP.read()  == AMBA_ERROR)? AHB_BUS_SLAVE_RD   :
                                                ( HSELx.read() == true && HWRITE.read()== false && 
                                                  WP_BUS_RD_HDATA_INX.read() == HBURST.read() )?      AHB_BUS_SLAVE_IDLE   :  AHB_BUS_SLAVE_RD; break; 
 case  AHB_BUS_SLAVE_WT   : TMP_NXT_ST = ( HSELx.read() == true && HWRITE.read()== true  && WP_BUS_HRESP.read()  == AMBA_RETY )? AHB_BUS_SLAVE_NON :
                                                ( HSELx.read() == true && HWRITE.read()== true  && WP_BUS_HRESP.read()  == AMBA_SPLIT)? AHB_BUS_SLAVE_NON :
                                                ( HSELx.read() == true && HWRITE.read()== true  && WP_BUS_HRESP.read()  == AMBA_ERROR)? AHB_BUS_SLAVE_WT   :
                                                ( HSELx.read() == true && HWRITE.read()== true  && 
                                                  WP_BUS_WT_HDATA_INX.read() == HBURST.read() )?      AHB_BUS_SLAVE_IDLE   :  AHB_BUS_SLAVE_WT; break; 
 }
 WP_BUS_NXT_ST.write(TMP_NXT_ST);
}

void AHB_BUS_SLAVE::PRO_WP_BUS_RSP(){
     sc_uint<32> TMP_HREADY_COT    = WP_BUS_HREADY_COT.read();
     sc_uint<32> TMP_HRESP_COT     = WP_BUS_HRESP_COT.read();
     sc_uint<32> TMP_CUR_ST        = WP_BUS_CUR_ST.read();
 
     ( (50  >= TMP_HREADY_COT && TMP_HREADY_COT >= 10 ) ||
       (100 >= TMP_HREADY_COT && TMP_HREADY_COT >= 60 ) ) ? WP_BUS_HREADY.write(true)   : WP_BUS_HREADY.write(false);

     ( (50  >= TMP_HREADY_COT && TMP_HREADY_COT >= 10 ) ||
       (100 >= TMP_HREADY_COT && TMP_HREADY_COT >= 60 ) ) ? HREADY.write(true)   : HREADY.write(false);
    
     if( (50  >= TMP_HREADY_COT && TMP_HREADY_COT >= 10 ) ||
         (100 >= TMP_HREADY_COT && TMP_HREADY_COT >= 60 ) ) { WP_BUS_HRESP.write(AMBA_OKAY);HRESP.write(AMBA_OKAY);  }
     else {
         ( TMP_HRESP_COT  == 0)? WP_BUS_HRESP.write(AMBA_RETY)  :
         ( TMP_HRESP_COT  == 1)? WP_BUS_HRESP.write(AMBA_SPLIT) :
         ( TMP_HRESP_COT  == 2)? WP_BUS_HRESP.write(AMBA_ERROR) : WP_BUS_HRESP.write(AMBA_ERROR);
   
         ( TMP_HRESP_COT  == 0)? HRESP.write(AMBA_RETY)  :
         ( TMP_HRESP_COT  == 1)? HRESP.write(AMBA_SPLIT) :
         ( TMP_HRESP_COT  == 2)? HRESP.write(AMBA_ERROR) : HRESP.write(AMBA_ERROR);
 
     }

     TMP_HRESP_COT  = ( TMP_CUR_ST == AHB_BUS_SLAVE_IDLE || TMP_HRESP_COT  == 2 )? 0 :
                      ( TMP_HREADY_COT ==100                                    )? TMP_HRESP_COT+1: TMP_HRESP_COT+0;
                                         
     TMP_HREADY_COT = ( TMP_CUR_ST == AHB_BUS_SLAVE_IDLE || TMP_HREADY_COT == 100 )? 0 : TMP_HREADY_COT +1; 

    WP_BUS_HREADY_COT.write(TMP_HREADY_COT); 
    WP_BUS_HRESP_COT.write(TMP_HRESP_COT);
}


void AHB_BUS_SLAVE::PRO_WP_BUS_MASTER_BUSY(){

      sc_uint<3> TMP_HTRANS = HTRANS.read();
        
       (TMP_HTRANS == AMBA_BUSY )? WP_BUS_MASTER_BUSY.write(true) : WP_BUS_MASTER_BUSY.write(false);
}


void AHB_BUS_SLAVE::PRO_WP_BUS_INT_MEM(){
     sc_uint<32> TMP_CUR_ST      = WP_BUS_CUR_ST.read();
    
   if(TMP_CUR_ST == AHB_BUS_SLAVE_IDLE){
       for(unsigned int i=0; i< WP_BUS_BUFF_DEP; i++ ){
          sc_uint<32> TMP_HADDR  = WP_BUS_WT_HADDR_BUFF[i].read();
          sc_uint<32> TMP_HDATA  = WP_BUS_WT_HDATA_BUFF[i].read();

   WP_BUS_INT_MEM[TMP_HADDR].write(TMP_HDATA);
      }
   } 

}


void AHB_BUS_SLAVE::PRO_WP_BUS_WT(){
     sc_uint<32> TMP_CUR_ST      = WP_BUS_CUR_ST.read();
     sc_uint<2>  TMP_HRESP       = WP_BUS_HRESP.read();      
     sc_uint<3>  TMP_HTRANS      = HTRANS.read();
     sc_uint<32> TMP_HADDR       = HADDR.read();
     sc_uint<32> TMP_HWDATA      = HWDATA.read();
     sc_uint<32> TMP_WT_HADDR_INX= WP_BUS_WT_HADDR_INX.read();
     sc_uint<32> TMP_WT_HDATA_INX= WP_BUS_WT_HDATA_INX.read();

     bool        TMP_HREADY      = WP_BUS_HREADY.read();
     bool        TMP_MASTER_BUSY = WP_BUS_MASTER_BUSY.read();
     bool        TMP_HWRITE      = HWRITE.read();
 
    TMP_WT_HADDR_INX =  (TMP_CUR_ST == AHB_BUS_SLAVE_IDLE || TMP_CUR_ST == AHB_BUS_SLAVE_NON ) ? 0 : TMP_WT_HADDR_INX+0;
    TMP_WT_HDATA_INX =  (TMP_CUR_ST == AHB_BUS_SLAVE_IDLE || TMP_CUR_ST == AHB_BUS_SLAVE_NON ) ? 0 : TMP_WT_HDATA_INX+0;
  
   if( (TMP_HTRANS == AMBA_NONSEQ || TMP_HTRANS == AMBA_SEQ ) && TMP_HREADY == true && TMP_HRESP == AMBA_OKAY && TMP_MASTER_BUSY==false && TMP_HWRITE ==true){
        TMP_HADDR = TMP_HADDR - WP_BUS_SLAVE_0; 
        WP_BUS_WT_HADDR_BUFF[TMP_WT_HADDR_INX++].write(TMP_HADDR);
    }
 
    if( TMP_HTRANS == AMBA_SEQ && TMP_HREADY == true && TMP_HRESP == AMBA_OKAY && TMP_MASTER_BUSY==false && TMP_HWRITE == true){
       WP_BUS_WT_HDATA_BUFF[TMP_WT_HDATA_INX++].write(TMP_HWDATA);
    }

  WP_BUS_WT_HADDR_INX.write(TMP_WT_HADDR_INX);
  WP_BUS_WT_HDATA_INX.write(TMP_WT_HDATA_INX);

}

void AHB_BUS_SLAVE::PRO_WP_BUS_RD(){
     sc_uint<32> TMP_CUR_ST      = WP_BUS_CUR_ST.read();
     sc_uint<2>  TMP_HRESP       = WP_BUS_HRESP.read();      
     sc_uint<3>  TMP_HTRANS      = HTRANS.read();
     sc_uint<32> TMP_HADDR       = HADDR.read();
     sc_uint<32> TMP_RD_HADDR_INX= WP_BUS_RD_HADDR_INX.read();
     sc_uint<32> TMP_RD_HDATA_INX= WP_BUS_RD_HDATA_INX.read();

     bool        TMP_HREADY      = WP_BUS_HREADY.read();
     bool        TMP_MASTER_BUSY = WP_BUS_MASTER_BUSY.read();
     bool        TMP_HWRITE      = HWRITE.read(); 
 
    TMP_RD_HADDR_INX =  (TMP_CUR_ST == AHB_BUS_SLAVE_IDLE || TMP_CUR_ST == AHB_BUS_SLAVE_NON ) ? 0 : TMP_RD_HADDR_INX+0;
    TMP_RD_HDATA_INX =  (TMP_CUR_ST == AHB_BUS_SLAVE_IDLE || TMP_CUR_ST == AHB_BUS_SLAVE_NON ) ? 0 : TMP_RD_HDATA_INX+0;
  
   if( (TMP_HTRANS == AMBA_NONSEQ || TMP_HTRANS == AMBA_SEQ ) && TMP_HREADY == true && TMP_HRESP == AMBA_OKAY && TMP_MASTER_BUSY==false && TMP_HWRITE==false){
        TMP_HADDR = TMP_HADDR - WP_BUS_SLAVE_0;
        WP_BUS_RD_HADDR_BUFF[TMP_RD_HADDR_INX++].write(TMP_HADDR); 
      }
 
    if( TMP_HTRANS == AMBA_SEQ && TMP_HREADY == true && TMP_HRESP == AMBA_OKAY && TMP_MASTER_BUSY==false && TMP_HWRITE==false){
        TMP_HADDR = WP_BUS_RD_HADDR_BUFF[TMP_RD_HDATA_INX++].read();
        sc_uint<32> TMP_HRDATA = WP_BUS_INT_MEM[TMP_HADDR].read();
       
        HRDATA.write(TMP_HRDATA);

    }

  WP_BUS_RD_HADDR_INX.write(TMP_RD_HADDR_INX);
  WP_BUS_RD_HDATA_INX.write(TMP_RD_HDATA_INX);

}


void AHB_BUS_SLAVE::AHB_BUS_SLAVE_VCD_DUMP(){
sc_trace_file *fp = sc_create_vcd_trace_file("AHB_BUS_SLAVE");
((vcd_trace_file*)fp)->sc_set_vcd_time_unit(-9);


sc_trace(fp, HSELx,"HSELx");
sc_trace(fp, HADDR,"HADDR");
sc_trace(fp, HWRITE,"HWRITE");
sc_trace(fp, HTRANS,"HTRANS");
sc_trace(fp, HSIZE,"HSIZE");
sc_trace(fp, HBURST,"HBURST");

sc_trace(fp, HWDATA,"HWDATA");
sc_trace(fp, HRESETn,"HRESETn");
sc_trace(fp, HCLK,"HCLK");
sc_trace(fp, HMASTER,"HMASTER");
sc_trace(fp, HMASTLOCK,"HMASTLOCK");

sc_trace(fp, HREADY,"HREADY");
sc_trace(fp, HRESP,"HRESP");

sc_trace(fp, HRDATA,"HRDATA");
sc_trace(fp, HSPLITx,"HSPLITx");   

sc_trace(fp, WP_BUS_HREADY,"WP_BUS_HREADY");
sc_trace(fp, WP_BUS_HREADY_COT,"WP_BUS_HREADY_COT");
sc_trace(fp, WP_BUS_HRESP,"WP_BUS_HRESP");
sc_trace(fp, WP_BUS_HRESP_COT,"WP_BUS_HRESP_COT");

sc_trace(fp, WP_BUS_CUR_ST,"WP_BUS_CUR_ST");
sc_trace(fp, WP_BUS_NXT_ST,"WP_BUS_NXT_ST");

sc_trace(fp, WP_BUS_WT_HADDR_BUFF[0],"WP_BUS_WT_HADDR_BUFF_0");
sc_trace(fp, WP_BUS_WT_HADDR_BUFF[1],"WP_BUS_WT_HADDR_BUFF_1");
sc_trace(fp, WP_BUS_WT_HADDR_BUFF[2],"WP_BUS_WT_HADDR_BUFF_2");

sc_trace(fp, WP_BUS_WT_HDATA_BUFF[0],"WP_BUS_WT_HDATA_BUFF_0");
sc_trace(fp, WP_BUS_WT_HDATA_BUFF[1],"WP_BUS_WT_HDATA_BUFF_1");
sc_trace(fp, WP_BUS_WT_HDATA_BUFF[2],"WP_BUS_WT_HDATA_BUFF_2");

sc_trace(fp, WP_BUS_WT_HADDR_INX,"WP_BUS_WT_HADDR_INX");
sc_trace(fp, WP_BUS_WT_HDATA_INX,"WP_BUS_WT_HDATA_INX");

sc_trace(fp, WP_BUS_RD_HADDR_BUFF[0],"WP_BUS_RD_HADDR_BUFF_0");
sc_trace(fp, WP_BUS_RD_HADDR_BUFF[1],"WP_BUS_RD_HADDR_BUFF_1");
sc_trace(fp, WP_BUS_RD_HADDR_BUFF[2],"WP_BUS_RD_HADDR_BUFF_2");

sc_trace(fp, WP_BUS_RD_HDATA_BUFF[0],"WP_BUS_RD_HDATA_BUFF_0");
sc_trace(fp, WP_BUS_RD_HDATA_BUFF[1],"WP_BUS_RD_HDATA_BUFF_1");
sc_trace(fp, WP_BUS_RD_HDATA_BUFF[2],"WP_BUS_RD_HDATA_BUFF_2");

sc_trace(fp, WP_BUS_RD_HADDR_INX,"WP_BUS_RD_HADDR_INX");
sc_trace(fp, WP_BUS_RD_HDATA_INX,"WP_BUS_RD_HDATA_INX");


}

2010年6月23日 星期三

AHB Master emulator @ SystemC

Hi all, this is an AHB Master emulator write in SystemC, it supports AHB Master Interface and protocol, such as " Burst type for single or package(1, 4, 8, 16) supported" , " Busy wait for current transaction" , "Response for error handle" ..., and you can easily package it with your IP by using sample Wrapper Interface such as "Ack" or "Valid" signals, this can be make sure the data is good and accessing is ok too. In general design, we using the "Read Buff" and "Write Buff" interface to capture the asynchronous data . "CTL/state Machine" is our control status, it defines each function works and each data paths. PS: this is only emulator model, not the official model for ARM company support, you can rewrite it in your requirement, and the configure and each model sets are already definition in our initial condition. target : in this platform, we use one Master and one Slave to recourse Read/Write tested without Arbiter detection. sample Waveform: sample code AHB_BUS_MASTER.h

#include <systemc.h>
#include <iostream>

using namespace std;

#define WP_BUS_BUFF_DEP 32

enum WP_BUS_TRANSFER_TYPE{
 WP_BUS_IDLE =0,
 WP_BUS_BUSY =1,
 WP_BUS_NONSEQ =2,
 WP_BUS_SEQ =3,
 WP_BUS_INI =4, // our define
};

SC_MODULE(AHB_BUS_MASTER) {
        //=============================================
        //  Wrapper Interface / Bus Interface
        //=============================================
 sc_in<bool>  HCLK;  //Fm Gb
 sc_in<bool>  HRESTn;  //Fm Gb
 sc_in<bool>  HGRANTx; //Fm Arbiter
 sc_in<bool>  HREADY;  //Fm Slave
 sc_in<sc_uint<2> > HRESP;  //Fm Arbiter/Slave
 sc_in<sc_uint<32> > HRDATA;  //Fm Slave

 sc_out<bool>  HBUSREQx; //To Aribiter
 sc_out<bool>  HLOCKx;  //To Aribiter
 sc_out<sc_uint<3> > HTRANS;  //
 sc_out<sc_uint<32> > HADDR;  //To Decoder
 sc_out<bool>  HWRITE;
 sc_out<sc_uint<3> > HSIZE;
 sc_out<sc_uint<5> > HBURST;
 sc_out<sc_uint<4> > HPROT;
 sc_out<sc_uint<32> > HWDATA;
 
 sc_signal<sc_uint<3> > WP_BUS_CUR_ST;
 sc_signal<sc_uint<3> > WP_BUS_NXT_ST;

 sc_signal<bool>  WP_BUS_START;
 sc_signal<bool>  WP_BUS_HWRITE;
 sc_signal<sc_uint<3> >  WP_BUS_HTRANS;
 sc_signal<sc_uint<3> > WP_BUS_HSIZE;
 sc_signal<sc_uint<32> > WP_BUS_INC_SIZE;
 sc_signal<sc_uint<4> > WP_BUS_HPROT; 
 sc_signal<sc_uint<5> > WP_BUS_BURST_SIZE;
 sc_signal<sc_uint<32> > WP_BUS_HADDR;
 sc_signal<sc_uint<32> > WP_BUS_INX;
 sc_signal<bool>  WP_BUS_HBUSY; 
 
 sc_signal<sc_uint<32> > WP_BUS_RD_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_UPDT_RD_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_RD_INX;
 
 sc_signal<sc_uint<32> > WP_BUS_WT_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_UPDT_WT_BUFF[WP_BUS_BUFF_DEP];
 
 sc_signal<sc_uint<32> > WP_BUS_HADDR_BUFF[WP_BUS_BUFF_DEP];
 sc_signal<sc_uint<32> > WP_BUS_UPDT_HADDR_BUFF[WP_BUS_BUFF_DEP];

 int GB_RW_COT;

 SC_CTOR(AHB_BUS_MASTER){
 //=================================
 // Wrapper / Bus Interface Function
 //=================================
 SC_METHOD(PRO_WP_BUS_ST);
 dont_initialize();
 sensitive << HRESTn;
 sensitive << HCLK.pos();

 SC_METHOD(PRO_WP_BUS_INI4SST);
 dont_initialize();
 sensitive << HCLK.pos();

 SC_METHOD(PRO_WP_BUS_ST_DO);
 dont_initialize();
 sensitive << WP_BUS_CUR_ST;
 sensitive << WP_BUS_START;
  sensitive << HGRANTx;
  sensitive << HREADY;
  sensitive << HRESP;
 sensitive << WP_BUS_HBUSY;
 sensitive << WP_BUS_INX;
 sensitive << WP_BUS_BURST_SIZE;

 SC_METHOD(PRO_WP_BUS_ST_OT);
 dont_initialize();
 sensitive << WP_BUS_CUR_ST;
   sensitive << WP_BUS_UPDT_HADDR_BUFF[0];
 
 SC_METHOD(PRO_WP_BUS_UPDAT_WT_BUFF);
 dont_initialize();
 sensitive << HCLK.pos();

 SC_METHOD(PRO_WP_BUS_UPDAT_HADDR_BUFF);
 dont_initialize();
 sensitive << HCLK.pos();

 SC_METHOD(PRO_WP_BUS_UPDAT_HBUSY);
 dont_initialize();
 sensitive << WP_BUS_CUR_ST;
 
 SC_METHOD(PRO_WP_BUS_UPDAT_RD_BUFF);
 dont_initialize();
 sensitive << HCLK.pos();

 AHB_BUS_MASTER_VCD_DUMP();

        GB_RW_COT =0;
  };

 void        AHB_BUS_MASTER_VCD_DUMP();

 void        PRO_WP_BUS_INI4SST();

 void        PRO_WP_BUS_ST();
        void        PRO_WP_BUS_ST_DO();
 void        PRO_WP_BUS_ST_OT();

 void        PRO_WP_BUS_UPDAT_WT_BUFF();
        void        PRO_WP_BUS_UPDAT_HADDR_BUFF();
 void        PRO_WP_BUS_UPDAT_HBUSY();
        void        PRO_WP_BUS_UPDAT_RD_BUFF();
 void        PRO_WP_BUS_INC_SIZE();

};
AHB_BUS_MASTER.cpp

#include <systemc.h>
#include "AHB_BUS_MASTER.h"
#include "AHB.h"

void AHB_BUS_MASTER::PRO_WP_BUS_ST(){
   
    sc_uint<3> TMP_NXT_ST = ( HRESTn.read()==false )? WP_BUS_INI : WP_BUS_NXT_ST.read(); 
    WP_BUS_CUR_ST.write(TMP_NXT_ST);
}

void AHB_BUS_MASTER::PRO_WP_BUS_ST_DO(){
    
    sc_uint<3> TMP_CUR_ST = WP_BUS_CUR_ST.read();   
    sc_uint<3> TMP_NXT_ST = WP_BUS_CUR_ST.read();   
    
    switch(TMP_CUR_ST){
       case WP_BUS_INI    : TMP_NXT_ST = ( WP_BUS_START.read() == true ) ? WP_BUS_IDLE   : WP_BUS_INI;    break; 
       case WP_BUS_IDLE   : TMP_NXT_ST = ( HGRANTx.read()      == true ) ? WP_BUS_NONSEQ : WP_BUS_IDLE;   break; 
       case WP_BUS_NONSEQ : TMP_NXT_ST = ( HREADY.read()       == true  || HRESP.read() == AMBA_OKAY  ) ? WP_BUS_SEQ  :
                                         ( HREADY.read()       == false && HRESP.read() == AMBA_ERROR ) ? WP_BUS_NONSEQ : 
                                         ( HREADY.read()       == false && HRESP.read() == AMBA_RETY  ) ? WP_BUS_IDLE : 
                                         ( HREADY.read()       == false && HRESP.read() == AMBA_SPLIT ) ? WP_BUS_IDLE : 
                                         ( WP_BUS_HBUSY.read() == true                                ) ? WP_BUS_BUSY : WP_BUS_NONSEQ; break;
       case WP_BUS_SEQ    : TMP_NXT_ST = ( (HREADY.read()      == true  || HRESP.read() == AMBA_OKAY  ) &&  WP_BUS_INX.read() == WP_BUS_BURST_SIZE.read() ) ? WP_BUS_INI :
                                         ( HREADY.read()       == false && HRESP.read() == AMBA_ERROR ) ? WP_BUS_SEQ : 
                                         ( HREADY.read()       == false && HRESP.read() == AMBA_RETY  ) ? WP_BUS_IDLE : 
                                         ( HREADY.read()       == false && HRESP.read() == AMBA_SPLIT ) ? WP_BUS_IDLE : 
                                         ( WP_BUS_HBUSY.read() == true                                ) ? WP_BUS_BUSY : WP_BUS_SEQ;    break;
       case WP_BUS_BUSY  : TMP_NXT_ST =  ( WP_BUS_HBUSY.read() == true )? WP_BUS_BUSY : WP_BUS_SEQ; break;    
     }

   WP_BUS_NXT_ST.write(TMP_NXT_ST);
}

void AHB_BUS_MASTER::PRO_WP_BUS_ST_OT(){

    sc_uint<3>    TMP_CUR_ST      = WP_BUS_CUR_ST.read();   
    sc_uint<2>    TMP_HTRANS      = WP_BUS_HTRANS.read();
    sc_uint<32>   TMP_HADDR       = WP_BUS_UPDT_HADDR_BUFF[0].read();
    sc_uint<3>    TMP_HSIZE       = WP_BUS_HSIZE.read();
    sc_uint<5>    TMP_BURST_SIZE  = WP_BUS_BURST_SIZE.read();
    sc_uint<4>    TMP_HPROT       = WP_BUS_HPROT.read();
    sc_uint<32>   TMP_HWDATA      = WP_BUS_UPDT_WT_BUFF[0].read();  
    bool          TMP_HWRITE      = WP_BUS_HWRITE,read();

    switch(TMP_CUR_ST){
 case WP_BUS_INI   : HTRANS.write(WP_BUS_INI);    HBUSREQx.write(false);  HLOCKx.write(false); break;
 case WP_BUS_IDLE  : HTRANS.write(WP_BUS_IDLE);   HBUSREQx.write(true);   HLOCKx.write(true);  break;
 case WP_BUS_NONSEQ: HTRANS.write(WP_BUS_NONSEQ); HBUSREQx.write(true);   HLOCKx.write(true);
       HWRITE.write(TMP_HWRITE);
                            HADDR.write(TMP_HADDR);
       HSIZE.write(TMP_HSIZE);
                            HBURST.write(TMP_BURST_SIZE);
       HPROT.write(TMP_HPROT);                                                   break;
 case WP_BUS_SEQ   : HTRANS.write(WP_BUS_SEQ);    HBUSREQx.write(true);   HLOCKx.write(true);
                            HADDR.write(TMP_HADDR);
                            HWDATA.write(TMP_HWDATA);                                                 break; 

 case WP_BUS_BUSY  : HTRANS.write(WP_BUS_BUSY); break;      
    } 
}

void AHB_BUS_MASTER::PRO_WP_BUS_UPDAT_HBUSY(){
     sc_uint<3>  TMP_CUR_ST     = WP_BUS_CUR_ST.read();

             ( TMP_CUR_ST == WP_BUS_NONSEQ || TMP_CUR_ST == WP_BUS_SEQ )? WP_BUS_HBUSY.write(true) : WP_BUS_HBUSY.write(false);
}

void AHB_BUS_MASTER::PRO_WP_BUS_UPDAT_HADDR_BUFF(){
     sc_uint<3>  TMP_CUR_ST     = WP_BUS_CUR_ST.read();
     sc_uint<32> TMP_BURST_SIZE = WP_BUS_BURST_SIZE.read();
     sc_uint<32> TMP_INX        = WP_BUS_INX.read();

             if( TMP_CUR_ST == WP_BUS_INI ||  HRESP.read()==AMBA_RETY || HRESP.read()==AMBA_SPLIT  ){
          for(unsigned int i=0; i < WP_BUS_BUFF_DEP; i++ ){ WP_BUS_UPDT_HADDR_BUFF[i].write( WP_BUS_HADDR_BUFF[i].read() ); }
                 TMP_INX = 0;

       }else if( (TMP_CUR_ST == WP_BUS_NONSEQ || TMP_CUR_ST == WP_BUS_SEQ) && HREADY.read() == true && HRESP.read()==AMBA_OKAY ){
  //update HADDR 
  for(unsigned int i=0; i < WP_BUS_BUFF_DEP-1; i++){ WP_BUS_UPDT_HADDR_BUFF[i].write( WP_BUS_UPDT_HADDR_BUFF[i+1].read() ); }
                TMP_INX++;
      }
    
    WP_BUS_INX.write(TMP_INX);
}

void AHB_BUS_MASTER::PRO_WP_BUS_UPDAT_WT_BUFF(){
        
     sc_uint<3>  TMP_CUR_ST     = WP_BUS_CUR_ST.read();
     sc_uint<5> TMP_BURST_SIZE = WP_BUS_BURST_SIZE.read();

             if( TMP_CUR_ST == WP_BUS_INI ||  HRESP.read()==AMBA_RETY || HRESP.read()==AMBA_SPLIT  ){
          for(unsigned int i=0; i < WP_BUS_BUFF_DEP; i++ ){ WP_BUS_UPDT_WT_BUFF[i].write( WP_BUS_WT_BUFF[i].read() ); }

       }else if( ( TMP_CUR_ST == WP_BUS_SEQ) && WP_BUS_HWRITE.read() ==true && HREADY.read() == true && HRESP.read()== AMBA_OKAY ){
  //update WRITE
  for(unsigned int i=0; i < WP_BUS_BUFF_DEP-1; i++){ WP_BUS_UPDT_WT_BUFF[i].write( WP_BUS_UPDT_WT_BUFF[i+1].read() ); }
      }
}


void AHB_BUS_MASTER::PRO_WP_BUS_UPDAT_RD_BUFF(){
        
     sc_uint<3>  TMP_CUR_ST      = WP_BUS_CUR_ST.read();
     sc_uint<5>  TMP_BURST_SIZE  = WP_BUS_BURST_SIZE.read();
     sc_uint<32> TMP_BUS_RD_INX  = WP_BUS_RD_INX.read();
     sc_uint<32> TMP_HRDATA      = HRDATA.read();

             if( TMP_CUR_ST == WP_BUS_INI ||  HRESP.read()==AMBA_RETY || HRESP.read()==AMBA_SPLIT  ){
          for(unsigned int i=0; i < WP_BUS_BUFF_DEP; i++ ){ WP_BUS_UPDT_RD_BUFF[i].write( WP_BUS_RD_BUFF[i].read() ); }
                 TMP_BUS_RD_INX =0;
     
       }else if( ( TMP_CUR_ST == WP_BUS_SEQ) && WP_BUS_HWRITE.read() ==false && HREADY.read() == true && HRESP.read()== AMBA_OKAY ){
                   WP_BUS_RD_BUFF[TMP_BUS_RD_INX++].write(TMP_HRDATA);           
      }
   WP_BUS_RD_INX.write(TMP_BUS_RD_INX);
}

void AHB_BUS_MASTER::PRO_WP_BUS_INI4SST(){
 
    sc_uint<3> TMP_CUR_ST = WP_BUS_CUR_ST.read();   
        int TMP_START    = WP_BUS_OFF;
 int TMP_SIZE     = AMBA_TS_16; 
        int TMP_HWRITE   = WP_BUS_ON;
        int TMP_BURST_TYPE  = AMBA_INC4;
        int TMP_OFFSET          = 0;
        int TMP_SLAVE   = 0;

    if( TMP_CUR_ST == WP_BUS_INI ){

  TMP_START    = WP_BUS_ON;
  TMP_SIZE     = AMBA_TS_16; 
         TMP_HWRITE   = ( GB_RW_COT ==0 )? WP_BUS_ON : WP_BUS_OFF;
         TMP_BURST_TYPE  = AMBA_INC4;
         TMP_OFFSET             = 1;
         TMP_SLAVE   = 0;

  GB_RW_COT = (GB_RW_COT+1) %2;
  
  cout << "BUS START  ::\t" << TMP_START  <<endl;
  cout << "BUS HSIZE  ::\t" << TMP_SIZE   <<endl;
         cout << "BUS HWRITE ::\t" << TMP_HWRITE <<endl;
         cout << "BUS BURST_TYPE ::\t" << TMP_BURST_TYPE <<endl;
         cout << "BUS SLAVE ::\t" << TMP_SLAVE << endl;
         cout << "BUS SLAVE OFFSET::\t" << TMP_OFFSET <<endl;  

 // WP_BUS_START set
         ( TMP_START == WP_BUS_ON) ? WP_BUS_START.write(true): WP_BUS_START.write(false);

 // CONTROL set
 // WP_BUS_HSIZE we support the 32bit bus length
        sc_uint<32> TMP_INC_SIZE = ( TMP_SIZE == AMBA_TS_8    ) ?  0x1  :
                                   ( TMP_SIZE == AMBA_TS_16   ) ?  0x2  :
                                   ( TMP_SIZE == AMBA_TS_32   ) ?  0x4  :
                                   ( TMP_SIZE == AMBA_TS_64   ) ?  0x8  :
                                   ( TMP_SIZE == AMBA_TS_128  ) ?  0x10 :
                                   ( TMP_SIZE == AMBA_TS_256  ) ?  0x20 :
                                   ( TMP_SIZE == AMBA_TS_512  ) ?  0x40 :
                                   ( TMP_SIZE == AMBA_TS_1024 ) ?  0x80 :  0x0; 

 WP_BUS_HSIZE.write(TMP_SIZE);
 WP_BUS_INC_SIZE.write(TMP_INC_SIZE);

 //WP_BUS_HPROT default set AMBA_DATA_ACCESS
 WP_BUS_HPROT.write(AMBA_DATA_ACCESS);


 //WP_BUS_HWRITE set
 (TMP_HWRITE == WP_BUS_ON) ? WP_BUS_HWRITE.write(true): WP_BUS_HWRITE.write(false);


 //WP_BUS_BURST set
  sc_uint<5> BURST_SIZE = ( TMP_BURST_TYPE == AMBA_SIGNLE                                ) ? 1 : 
             ( TMP_BURST_TYPE == AMBA_WRAP4  || TMP_BURST_TYPE == AMBA_INC4 ) ? 4 :
                                 ( TMP_BURST_TYPE == AMBA_WRAP8  || TMP_BURST_TYPE == AMBA_INC8 ) ? 8 :
                                 ( TMP_BURST_TYPE == AMBA_WRAP16 || TMP_BURST_TYPE == AMBA_INC16) ? 16: 0;

 WP_BUS_BURST_SIZE.write(BURST_SIZE);

 // random number 4 write out
        if ( TMP_HWRITE == WP_BUS_ON){
     for(unsigned int i=0; i < BURST_SIZE; i++){ WP_BUS_WT_BUFF[i].write( 10 + i); }   
 }


 sc_uint<32> TMP_SOFFSET = (TMP_OFFSET == 0 )? WP_BUS_OFFSET_0 :
                                  (TMP_OFFSET == 1 )? WP_BUS_OFFSET_1 :
                                  (TMP_OFFSET == 2 )? WP_BUS_OFFSET_2 :
                                  (TMP_OFFSET == 3 )? WP_BUS_OFFSET_3 : WP_BUS_OFFSET_D; 

        cout << "BUS SOFFSET ::\t" << TMP_SOFFSET <<endl;

 sc_uint<32> TMP_HADDR = (TMP_SLAVE == 0 ) ? WP_BUS_SLAVE_0 + TMP_SOFFSET :
                                (TMP_SLAVE == 1 ) ? WP_BUS_SLAVE_1 + TMP_SOFFSET :
                                (TMP_SLAVE == 2 ) ? WP_BUS_SLAVE_2 + TMP_SOFFSET : WP_BUS_DEFAULT;  

        cout <<" BUS HADDR ::\t"<< TMP_HADDR<<endl;
 
 // set INC/ WRAP initial ADDRESS if the HADDR is overflow
 sc_uint<32>  TMP_SHADDR = (TMP_HADDR & 0x0000000f) ;
        cout <<" BUS SHADDR ::\t"<< TMP_SHADDR <<endl;

        sc_uint<32>  TMP_BOUND;
        sc_uint<32>  TMP_INC;
        sc_uint<32>  TMP_DEC;

                       TMP_BOUND = ( TMP_SHADDR =0x0 ) ? 16 :
                            ( TMP_SHADDR =0x1 ) ? 15 : 
                                   ( TMP_SHADDR =0x2 ) ? 14 :
                                   ( TMP_SHADDR =0x3 ) ? 13 :
                                   ( TMP_SHADDR =0x4 ) ? 12 :
                                   ( TMP_SHADDR =0x5 ) ? 11 :
                                   ( TMP_SHADDR =0x6 ) ? 10 :
                                   ( TMP_SHADDR =0x7 ) ? 9  :
                                   ( TMP_SHADDR =0x8 ) ? 8  :
                                   ( TMP_SHADDR =0x9 ) ? 7  :
                                   ( TMP_SHADDR =0xa ) ? 6  :
                                   ( TMP_SHADDR =0xb ) ? 5  :
                                   ( TMP_SHADDR =0xc ) ? 4  :
                                   ( TMP_SHADDR =0xd ) ? 3  :
                                   ( TMP_SHADDR =0xe ) ? 2  :
                                   ( TMP_SHADDR =0xf ) ? 1  : 0 ;

                      TMP_INC =  TMP_BOUND/TMP_INC_SIZE-1;
                      cout << TMP_INC << endl; 
                      TMP_DEC =  BURST_SIZE - TMP_INC;

                 if (  TMP_BURST_TYPE == AMBA_SIGNLE ){
                                                         WP_BUS_HADDR_BUFF[0].write( TMP_HADDR );
          } else if(   TMP_BURST_TYPE == AMBA_WRAP4  ||
                       TMP_BURST_TYPE == AMBA_WRAP8  ||
                       TMP_BURST_TYPE == AMBA_WRAP16    ){ unsigned int j=0;
                                                      for( unsigned int i=0; i<TMP_INC; i++){
                                                         WP_BUS_HADDR_BUFF[j++].write( TMP_HADDR + i*TMP_INC_SIZE ); 
                                                         } 
                                                      for( unsigned int i=TMP_DEC; i>0; i--){ 
                                                          WP_BUS_HADDR_BUFF[j++].write( TMP_HADDR -i*TMP_INC_SIZE );
                                                         }
         } else if(    TMP_BURST_TYPE == AMBA_INC4  ||
                       TMP_BURST_TYPE == AMBA_INC8  ||
                       TMP_BURST_TYPE == AMBA_INC16     ){   
                                                       for(unsigned int i=0; i<BURST_SIZE; i++){
                                                           WP_BUS_HADDR_BUFF[i].write( TMP_HADDR + i*TMP_INC_SIZE );
                                                    }
         } 

        cout <<"==================="<<endl;
     }   
}



void AHB_BUS_MASTER::AHB_BUS_MASTER_VCD_DUMP(){
sc_trace_file *fp = sc_create_vcd_trace_file("AHB_BUS_MASTER");
((vcd_trace_file*)fp)->sc_set_vcd_time_unit(-9);

sc_trace(fp, HCLK,"HCLK");
sc_trace(fp, HRESTn,"HRESTn");
sc_trace(fp, HGRANTx,"HGRANTx");
sc_trace(fp, HREADY,"HREADY");
sc_trace(fp, HRESP,"HRESP");
sc_trace(fp, HRDATA,"HRDATA");


sc_trace(fp, HBUSREQx,"HBUSREQx");
sc_trace(fp, HLOCKx,"HLOCKx");
sc_trace(fp, HTRANS,"HTRANS");
sc_trace(fp, HADDR,"HADDR");
sc_trace(fp, HWRITE,"HWRITE");
sc_trace(fp, HSIZE,"HSIZE");
sc_trace(fp, HBURST,"HBURST");
sc_trace(fp, HPROT,"HPROT");
sc_trace(fp, HWDATA,"HWDATA");

sc_trace(fp, WP_BUS_START,"WP_BUS_START");
sc_trace(fp, WP_BUS_CUR_ST,"WP_BUS_CUR_ST");
sc_trace(fp, WP_BUS_NXT_ST,"WP_BUS_NXT_ST");
sc_trace(fp, WP_BUS_HWRITE,"WP_BUS_WHRITE");
sc_trace(fp, WP_BUS_HTRANS,"WP_BUS_HTRANS");
sc_trace(fp, WP_BUS_HSIZE,"WP_BUS_HSIZE");
sc_trace(fp, WP_BUS_INC_SIZE,"WP_BUS_INC_SIZE");
sc_trace(fp, WP_BUS_HPROT,"WP_BUS_HPROT");
sc_trace(fp, WP_BUS_BURST_SIZE,"WP_BUS_BURST_SIZE");
sc_trace(fp, WP_BUS_HADDR,"WP_BUS_HADDR");
sc_trace(fp, WP_BUS_INX,"WP_BUS_INX");
sc_trace(fp, WP_BUS_HBUSY,"WP_BUS_HBUSY");

sc_trace(fp, WP_BUS_HADDR_BUFF[0],"WP_BUS_HADDR_BUFF_0");
sc_trace(fp, WP_BUS_HADDR_BUFF[1],"WP_BUS_HADDR_BUFF_1");
sc_trace(fp, WP_BUS_HADDR_BUFF[2],"WP_BUS_HADDR_BUFF_2");
sc_trace(fp, WP_BUS_HADDR_BUFF[3],"WP_BUS_HADDR_BUFF_3");

sc_trace(fp, WP_BUS_UPDT_HADDR_BUFF[0],"WP_BUS_UPDT_HADDR_BUFF_0");
sc_trace(fp, WP_BUS_UPDT_HADDR_BUFF[1],"WP_BUS_UPDT_HADDR_BUFF_1");
sc_trace(fp, WP_BUS_UPDT_HADDR_BUFF[2],"WP_BUS_UPDT_HADDR_BUFF_2");
sc_trace(fp, WP_BUS_UPDT_HADDR_BUFF[3],"WP_BUS_UPDT_HADDR_BUFF_3");

sc_trace(fp, WP_BUS_UPDT_WT_BUFF[0],"WP_BUS_UPDT_WT_BUFF_0");
sc_trace(fp, WP_BUS_UPDT_WT_BUFF[1],"WP_BUS_UPDT_WT_BUFF_1");
sc_trace(fp, WP_BUS_UPDT_WT_BUFF[2],"WP_BUS_UPDT_WT_BUFF_2");
sc_trace(fp, WP_BUS_UPDT_WT_BUFF[3],"WP_BUS_UPDT_WT_BUFF_3");

sc_trace(fp, WP_BUS_UPDT_RD_BUFF[0],"WP_BUS_UPDT_RD_BUFF_0");
sc_trace(fp, WP_BUS_UPDT_RD_BUFF[1],"WP_BUS_UPDT_RD_BUFF_1");
sc_trace(fp, WP_BUS_UPDT_RD_BUFF[2],"WP_BUS_UPDT_RD_BUFF_2");
sc_trace(fp, WP_BUS_UPDT_RD_BUFF[3],"WP_BUS_UPDT_RD_BUFF_3");

sc_trace(fp, WP_BUS_RD_INX,"WP_BUS_RD_INX");
sc_trace(fp, GB_RW_COT,"GB_RW_COT");


}

Results: if you want to comiple the whole platfrom, you need download testbench and slave model in here.

2010年6月17日 星期四

AMBA 4 ARM

Purpose : 在過去幾年內最紅的話題 ”ARM”, 少了 x86 複雜的架構, 利用簡化的指令集跟有效率的系統分析. 在 Embedded System 上 有很好的 Power 跟 Performance 優勢. 且設計者可以輕易的 Put IP 到整體的 Platform 上, 做 whole chip 的驗證, 最後透過 Performance or Power Monitor 的分析, 讓系統能達到 High Performance and Low Power 的功效. 不僅加速設計的流程也降低設計的複雜度 底下我們用 ARM BUS system 當我們的模擬環境. ARM BUS 主要分成 High Performance Bus (AHB), Low Perfotmace Bus(APB). 有點像 PCI Bus 跟 ISC Bus. 中間透過 Bridge 來連接高速跟慢速的Interface. 可參考 AMBA™ Specification CoreLink System IP & Design Tools for AMBA 有詳細的說明 ARM bus Protocol 主要透過兩個 Transaction Phase 來達到 Pipeline 的效果 Step 1. Address Phase Address 主要是選擇現在要 Access 的記憶體區塊, 可能是 RAM, ROM or Slave ... Step 2. Data Phase 等我們要 Access 的區塊確定後, 再針對這個區塊做 Data Access的動作. 當然這之中要可以 support burst or error handle ... ref: from ARM AMBA 2.0

2010年6月16日 星期三

handshake 4 Different Clock Domain pt2

Hi all, this is our testbench for handshake 4 Different Clock Domain. if you don't know it, you can review our previous posted "handshake 4 Different Clock Domain pt1". t_ififo.h

#include <systemc.h>
#include <iostream>

using namespace std;

enum T_IFIFO_ST {
     T_IDLE = 0,
     T_GNT  = 1,
     T_Write= 2,
};

SC_MODULE(t_ififo) {

  sc_out<bool> T_Rst;
  
  sc_out<bool> T_Read_En;
  sc_out<int> T_Read_Dt;
  sc_in<bool> T_Read_Clk;
  sc_out<bool> T_Read_Req;
  sc_in<bool> T_Read_Gnt;

  sc_in<bool>   T_Write_En;
  sc_in<int> T_Write_Dt;
  sc_in<bool> T_Write_Clk;
  sc_in<bool>   T_Write_Req;
  sc_out<bool>  T_Write_Gnt;

  sc_signal<int> T_Cur_ST;
  sc_signal<int> T_Nxt_ST;

 SC_CTOR(t_ififo){
   SC_THREAD(TST_PRO_RD);
   dont_initialize(); 
   sensitive << T_Read_Clk.pos();

   SC_METHOD(TST_PRO_WT);
   dont_initialize();
   sensitive << T_Rst; 
   sensitive << T_Write_Clk.pos();

   SC_METHOD(TST_PRO_WT_DO);
   dont_initialize();
   sensitive << T_Cur_ST; 
   sensitive << T_Write_Req;
   sensitive << T_Write_En;
 
   SC_METHOD(TST_PRO_WT_OT);
   dont_initialize();
   sensitive << T_Write_Clk.pos(); 

   SC_METHOD(TST_PRO_WT_DP);
   dont_initialize();
   sensitive << T_Write_Clk.pos(); 
   
   TST_VCD_Dump(); 
 };
 
 void TST_PRO_RD();
 void TST_2_OT( bool t, bool e, int d, bool r); 
 
 void TST_PRO_WT();
 void TST_PRO_WT_DO();
 void TST_PRO_WT_OT();
 void TST_PRO_WT_DP();
 void TST_VCD_Dump();
};

t_fifio.cpp

#include "t_ififo.h"

void t_ififo::TST_PRO_RD() {
  
 TST_2_OT(false, false, 21,  true);
 wait();
 TST_2_OT(false, true,  21,  true);
 wait();

 //Reset
 cout << "Send Reset ...\n" <<endl; 
 TST_2_OT(true, false,  21,  false);
 wait();
 wait();
 wait();
 wait();


 // release Reset
 TST_2_OT(false, false,  21,  false);
 wait();

for(int i=1; i < 21; i++){
 //Request
 cout << "Send Request ...\n" <<endl;
 while( T_Read_Gnt.read() != true ){
  TST_2_OT(false, false,  21,  true);
  wait();
 }


 //release Reguest
   TST_2_OT(false, false,  21,  false);
   wait();
 
// Data
  cout << "Send Data ...\t"<< i <<endl;

   TST_2_OT(false, true,  i,  false);
   wait();
// release Data 
   TST_2_OT(false, false,  i,  false);
   wait();
}

}

void t_ififo::TST_2_OT( bool t, bool e, int d, bool r) {
  T_Rst.write(t);
  T_Read_En.write(e);
  T_Read_Dt.write(d);
  T_Read_Req.write(r);
}


void t_ififo::TST_PRO_WT(){
  sc_int<32> Tmp_Cur_ST = T_Cur_ST.read();
  sc_int<32> Tmp_Nxt_ST = T_Nxt_ST.read();
  
  Tmp_Cur_ST = ( T_Rst.read()== true )? T_IDLE : Tmp_Nxt_ST;
  T_Cur_ST.write(Tmp_Cur_ST);
}

void t_ififo::TST_PRO_WT_DO(){
  sc_int<32> Tmp_Cur_ST = T_Cur_ST.read();
  sc_int<32> Tmp_Nxt_ST = T_Nxt_ST.read();
 
  switch(Tmp_Cur_ST){
   case T_IDLE : Tmp_Nxt_ST = ( T_Write_Req.read()==true )? T_GNT : T_IDLE;  break; 
   case T_GNT  : Tmp_Nxt_ST = T_Write;                                       break;
   case T_Write: Tmp_Nxt_ST = ( T_Write_En.read() ==true )? T_IDLE: T_Write; break;
   default     : Tmp_Nxt_ST = T_IDLE;                                        break;
  }  

  T_Nxt_ST.write(Tmp_Nxt_ST);
}

void t_ififo::TST_PRO_WT_OT(){
  sc_int<32> Tmp_Cur_ST = T_Cur_ST.read();
  sc_int<32> Tmp_Nxt_ST = T_Nxt_ST.read();
 
   switch(Tmp_Cur_ST){
    case T_IDLE : T_Write_Gnt.write(false); break; 
    case T_GNT  : T_Write_Gnt.write(true);  break;
    case T_Write: T_Write_Gnt.write(false); break;
  }
}

void t_ififo::TST_PRO_WT_DP(){
  if(T_Write_En.read()==true){
    cout<<"FeedBack::\t"<< T_Write_Dt.read() << endl;
  }
}

void t_ififo::TST_VCD_Dump() {
sc_trace_file *fp = sc_create_vcd_trace_file("t_ififo_file");
((vcd_trace_file*)fp)->sc_set_vcd_time_unit(-9);

sc_trace(fp, T_Rst,"T_Rst");
sc_trace(fp, T_Write_En,"T_Write_En");
sc_trace(fp, T_Write_Dt,"T_Write_Dt");
sc_trace(fp, T_Write_Clk,"T_Write_Clk");
sc_trace(fp, T_Write_Req,"T_Write_Req");
sc_trace(fp, T_Write_Gnt,"T_Write_Gnt");
sc_trace(fp, T_Cur_ST,"T_Cur_ST");
sc_trace(fp, T_Nxt_ST,"T_Nxt_ST");


}
main.cpp


#include <systemc.h>
#include "ififo.h"
#include "t_ififo.h"

int sc_main (int argc , char *argv[]) {

  sc_signal<bool>  S_Rst;
  sc_signal<bool>  S_Read_En;
  sc_signal<int>   S_Read_Dt;
  sc_signal<bool>  S_Read_Req;
  sc_signal<bool>  S_Read_Gnt;

  sc_signal<bool>  S_Write_En;
  sc_signal<int>   S_Write_Dt;
  sc_signal<bool>  S_Write_Req;
  sc_signal<bool>  S_Write_Gnt;


 // sc_clock S_Read_Clk; 

 sc_clock S_Read_Clk("S_Read_Clk", 10, SC_NS, 0.5, 0.0, SC_NS);
 sc_clock S_Write_Clk("S_Write_Clk", 42, SC_NS, 0.5, 0.0, SC_NS);
  
  ififo            ififo_ptr("ififo");
  ififo_ptr.Rst(S_Rst);

  ififo_ptr.Read_Clk(S_Read_Clk); 
  ififo_ptr.Read_En(S_Read_En);
  ififo_ptr.Read_Dt(S_Read_Dt);
  ififo_ptr.Read_Req(S_Read_Req);
  ififo_ptr.Read_Gnt(S_Read_Gnt);

  ififo_ptr.Write_Clk(S_Write_Clk);
  ififo_ptr.Write_Req(S_Write_Req);
  ififo_ptr.Write_Gnt(S_Write_Gnt);
  ififo_ptr.Write_En(S_Write_En);
  ififo_ptr.Write_Dt(S_Write_Dt);

 
  t_ififo            t_ififo_ptr("t_ififo");
  t_ififo_ptr.T_Rst(S_Rst);

  t_ififo_ptr.T_Read_Clk(S_Read_Clk); 
  t_ififo_ptr.T_Read_En(S_Read_En);
  t_ififo_ptr.T_Read_Dt(S_Read_Dt);
  t_ififo_ptr.T_Read_Req(S_Read_Req);
  t_ififo_ptr.T_Read_Gnt(S_Read_Gnt);

  t_ififo_ptr.T_Write_Clk(S_Write_Clk);
  t_ififo_ptr.T_Write_Req(S_Write_Req);
  t_ififo_ptr.T_Write_Gnt(S_Write_Gnt);
  t_ififo_ptr.T_Write_En(S_Write_En);
  t_ififo_ptr.T_Write_Dt(S_Write_Dt);


sc_trace_file *fp = sc_create_vcd_trace_file("wave_file");
sc_trace(fp, S_Rst,"S_Rst");
sc_start(1000, SC_NS);
sc_close_vcd_trace_file(fp);   
  
return 0; 

}
compiler
g++ -Wall -g -c -I$(YourSystemC)/include/ ififo.cpp  t_ififo.cpp  main.cpp

g++  -Wall -DSC_INCLUDE_FX -O3   -o fifo ififo.o t_ififo.o main.o  -L$(YourSystemC)/lib-linux -lsystemc -lm

./fifo
or you can download all files in here

handshake 4 Different Clock Domain pt1

Hi all, this is a sample case for "Different Clock domain data transition" in SystemC cycle accurate mode, we use the basic way such as "Ask and wait for response", that we call "Request and Grant", "Request" means asking the server to get the property, "Response" means waiting for the server to get the property. and then we add lock function in our design to avoid the dead lock read/write at same time. but in this case only single transition, you can remodel it to burst mode supported like AHB/APB format. waveform view @ gtkwave below is our target design, if you want to run it, you should prepare our testbench in it. ififo.h


#include <systemc.h>
#define BUFDEP 6

enum iFIFO_ST {
 RD_IDLE =0,
 RD_GANT =1,
 RD_READ =2,
 WT_IDLE =3,
 WT_REQ  =4,
 WT_WRITE=5,
};


SC_MODULE(ififo) {

 sc_in<bool> Rst;

 sc_in<bool> Read_En;
 sc_in<int> Read_Dt;
 sc_in<bool> Read_Clk;
 sc_in<bool> Read_Req;
 sc_out<bool> Read_Gnt;


 sc_out<bool> Write_En;
 sc_out<int> Write_Dt;
 sc_in<bool> Write_Clk;
 sc_out<bool>  Write_Req;
 sc_in<bool>   Write_Gnt;

 sc_signal<int>   iBuff[BUFDEP];
 sc_signal<bool>  iBuff_Full; 
 sc_signal<int>   iBuff_Inx;
 sc_signal<bool>  iBuff_Emty;
 sc_signal<int>   iBuff_RD_TMP;
 sc_signal<int>   iBuff_WT_TMP;

 sc_signal<bool>  iBuff_WT_En; 
 sc_signal<int>   Cur_RD_ST;
 sc_signal<int>   Nxt_RD_ST;

 sc_signal<int>   Cur_WT_ST;
 sc_signal<int>   Nxt_WT_ST;

 sc_signal<bool>  Read_Lock;
 sc_signal<bool>  Write_Lock;

 SC_CTOR(ififo)
 {
     SC_METHOD(PRO_RD_ST);
     dont_initialize();
     sensitive << Rst;
     sensitive << Read_Clk.pos();
    
     SC_METHOD(PRO_RD_ST_DO);
     dont_initialize();
     sensitive << Cur_RD_ST;     
     sensitive << Read_Req;
     sensitive << iBuff_Full;     
     sensitive << Read_En;
     sensitive << Write_Lock;

     SC_METHOD(PRO_RD_ST_OT);
     dont_initialize();
     sensitive << Cur_RD_ST;
     sensitive << iBuff_Full;
     sensitive << Read_En;     

     SC_METHOD(PRO_iBuff);
     dont_initialize();
     sensitive << iBuff_Inx;
     sensitive << Rst;

     SC_METHOD(PRO_RW_TRS);
     dont_initialize();
     sensitive << Rst;     
     sensitive << Cur_RD_ST;     
     sensitive << Read_En;
     sensitive << Cur_WT_ST;
     sensitive << iBuff_WT_En;      

     SC_METHOD(PRO_WT_ST);
     dont_initialize();
     sensitive << Rst;    
     sensitive << Write_Clk.pos();

     SC_METHOD(PRO_WT_ST_DO);
     dont_initialize();
     sensitive << Cur_WT_ST;
     sensitive << iBuff_Emty;
     sensitive << Write_Gnt;
     sensitive << Read_Lock;
 
     SC_METHOD(PRO_WT_ST_OT);
     dont_initialize();
     sensitive << Cur_WT_ST;

     SC_METHOD(PRO_RW_LOCK);
     dont_initialize();
     sensitive << Cur_RD_ST;
     sensitive << Cur_WT_ST;

     VCD_DUMP();    

     };

 void PRO_RD_ST();
 void PRO_RD_ST_DO();
 void PRO_RD_ST_OT();
 void PRO_iBuff();
 void PRO_RW_TRS();

 void PRO_WT_ST();
 void PRO_WT_ST_DO();
 void PRO_WT_ST_OT();
 void PRO_RW_LOCK();

 void VCD_DUMP();

};
ififo.cpp


#include "ififo.h"

//========================================
// Read Part Start
//========================================
void ififo::PRO_RD_ST(){

sc_int<32>  Tmp_Cur_ST = Cur_RD_ST.read();
sc_int<32> Tmp_Nxt_ST = Nxt_RD_ST.read();

Tmp_Cur_ST = ( Rst.read() == true )?  RD_IDLE : Tmp_Nxt_ST;
Cur_RD_ST.write(Tmp_Cur_ST);
   
}

void ififo::PRO_RD_ST_DO(){

sc_int<32>  Tmp_Cur_ST = Cur_RD_ST.read();
sc_int<32>     Tmp_Nxt_ST = Nxt_RD_ST.read();

  switch (Tmp_Cur_ST) {
     case RD_IDLE : Tmp_Nxt_ST =  ( Read_Req.read()   == true && Write_Lock.read() == false )? RD_GANT : RD_IDLE;  break;
     case RD_GANT : Tmp_Nxt_ST =  ( iBuff_Full.read() == true                               )? RD_IDLE : RD_READ;  break;
     case RD_READ : Tmp_Nxt_ST =  ( Read_En.read()    == true                               )? RD_IDLE : RD_READ;  break; 
//      default      : Tmp_Nxt_ST =  RD_IDLE;  break;
 }

 Nxt_RD_ST.write(Tmp_Nxt_ST);
}

void ififo::PRO_RD_ST_OT(){

sc_int<32>  Tmp_Cur_ST = Cur_RD_ST.read();
sc_int<32>     Tmp_Nxt_ST = Nxt_RD_ST.read();
sc_int<32>     Tmp_iBuff_RD;

  switch(Tmp_Cur_ST) {
     case RD_IDLE :                                Read_Gnt.write(false);                        break;
     case RD_GANT :  ( iBuff_Full.read()== true )? Read_Gnt.write(false): Read_Gnt.write(true);  break;
     case RD_READ :                                Read_Gnt.write(false);                        break;
 }

}

void ififo::PRO_iBuff(){

sc_int<32>    Tmp_iBuff_Inx = iBuff_Inx.read();

 (Tmp_iBuff_Inx == BUFDEP )? iBuff_Full.write(true) : iBuff_Full.write(false) ;
 (Tmp_iBuff_Inx == 0      )? iBuff_Emty.write(true) : iBuff_Emty.write(false) ;
}

//=====================================
//Read Part end
//=====================================

void ififo::PRO_RW_LOCK(){
    Read_Lock.write(false);
    Write_Lock.write(false);

sc_int<32>    Tmp_RD_Cur_ST = Cur_RD_ST.read();
sc_int<32>    Tmp_WT_Cur_ST = Cur_WT_ST.read();

      if( Cur_WT_ST == WT_REQ  || Cur_WT_ST == WT_WRITE ){  Write_Lock.write(true); }
 else if( Cur_RD_ST == RD_GANT || Cur_RD_ST == RD_READ  ){  Read_Lock.write(true);  }

}

void ififo::PRO_RW_TRS(){
sc_int<32>    Tmp_iBuff_Inx = iBuff_Inx.read();
sc_int<32>    Tmp_iBuff_RD  = Read_Dt.read();
sc_int<32>    Tmp_iBuff_WT  = iBuff_WT_TMP.read();
sc_int<32>    Tmp_RD_Cur_ST = Cur_RD_ST.read();
sc_int<32>    Tmp_WT_Cur_ST = Cur_WT_ST.read();
sc_int<32>    Tmp_iBuff;
int i;

 if( Rst.read()==true ){
       iBuff_Inx.write(0);   

 } else {
           if( Read_En.read()== true && Tmp_RD_Cur_ST == RD_READ ){
               iBuff[Tmp_iBuff_Inx].write(Tmp_iBuff_RD);
               Tmp_iBuff_Inx++;
               iBuff_Inx.write(Tmp_iBuff_Inx);                 

   }
     if( iBuff_WT_En.read()== true && Tmp_WT_Cur_ST == WT_WRITE ){
               Tmp_iBuff_WT = iBuff[0].read();
               iBuff_WT_TMP.write(Tmp_iBuff_WT);

              for(i=0; i<BUFDEP-1; i++ ){      
                     Tmp_iBuff = iBuff[i+1].read();
                     iBuff[i].write(Tmp_iBuff); 
              }
                 Tmp_iBuff_Inx--;
                 iBuff_Inx.write(Tmp_iBuff_Inx);                 
   }
 }
}


//===================================
// Write Part end
//===================================
void ififo::PRO_WT_ST(){

sc_int<32>  Tmp_Cur_ST = Cur_WT_ST.read();
sc_int<32> Tmp_Nxt_ST = Nxt_WT_ST.read();

Tmp_Cur_ST = ( Rst.read() == true )?  WT_IDLE : Tmp_Nxt_ST;
Cur_WT_ST.write(Tmp_Cur_ST);

}

void ififo::PRO_WT_ST_DO(){

sc_int<32>  Tmp_Cur_ST = Cur_WT_ST.read();
sc_int<32>     Tmp_Nxt_ST = Nxt_WT_ST.read();

  switch (Tmp_Cur_ST) {
     case WT_IDLE : Tmp_Nxt_ST =  ( iBuff_Emty.read() == true || Read_Lock.read()== true  )? WT_IDLE : WT_REQ;   break;
     case WT_REQ  : Tmp_Nxt_ST =  ( Write_Gnt.read()  == true                             )? WT_WRITE: WT_REQ;   break;
     case WT_WRITE: Tmp_Nxt_ST =  WT_IDLE;  break; 
 //    default      : Tmp_Nxt_ST =  WT_IDLE;  break;
 }

 Nxt_WT_ST.write(Tmp_Nxt_ST);
}


void ififo::PRO_WT_ST_OT(){
sc_int<32>  Tmp_Cur_ST = Cur_WT_ST.read();
sc_int<32>     Tmp_Nxt_ST = Nxt_WT_ST.read();
sc_int<32>     Tmp_iBuff_WT = iBuff_WT_TMP.read();

  switch (Tmp_Cur_ST) {
     case WT_IDLE : Write_En.write(false); iBuff_WT_En.write(false); Write_Dt.write(0);            Write_Req.write(false);  break;
     case WT_REQ  : Write_En.write(false); iBuff_WT_En.write(false); Write_Dt.write(0);            Write_Req.write(true);   break;
     case WT_WRITE: Write_En.write(true);  iBuff_WT_En.write(true);  Write_Dt.write(Tmp_iBuff_WT); Write_Req.write(false);  break; 
 }

}

void ififo::VCD_DUMP(){
sc_trace_file *fp = sc_create_vcd_trace_file("ififo_file");
((vcd_trace_file*)fp)->sc_set_vcd_time_unit(-9);

sc_trace(fp, Rst,"Rst");
sc_trace(fp, Read_En,"Read_En");
sc_trace(fp, Read_Dt,"Read_Dt");
sc_trace(fp, Read_Clk,"Read_Clk");
sc_trace(fp, Read_Req,"Read_Req");
sc_trace(fp, Read_Gnt,"Read_Gnt");
sc_trace(fp, iBuff_Full,"iBuff_Full");
sc_trace(fp, iBuff_Inx,"iBuff_Inx");
sc_trace(fp, iBuff_Emty,"iBuff_Emty");
sc_trace(fp, Cur_RD_ST,"Cur_RD_ST");
sc_trace(fp, Nxt_RD_ST,"Nxt_RD_ST");
sc_trace(fp, iBuff_RD_TMP,"iBuff_RD_TMP");
sc_trace(fp, Write_En,"Write_En");
sc_trace(fp, Write_Dt,"Write_Dt");
sc_trace(fp, Write_Clk,"Write_Clk");
sc_trace(fp, Write_Req,"Write_Req");
sc_trace(fp, Write_Gnt,"Write_Gnt");
sc_trace(fp, iBuff_Emty,"iBuff_Emty");
sc_trace(fp, iBuff_WT_En,"iBuff_WT_En");
sc_trace(fp, iBuff_WT_TMP,"iBuff_WT_TMP");
sc_trace(fp, Cur_WT_ST,"Cur_WT_ST");
sc_trace(fp, Nxt_WT_ST,"Nxt_WT_ST");
sc_trace(fp, Read_Lock,"Read_Lock");
sc_trace(fp, Write_Lock,"Write_Lock");
sc_trace(fp, iBuff[0],"iBuff_0");
sc_trace(fp, iBuff[1],"iBuff_1");
sc_trace(fp, iBuff[2],"iBuff_2");

}

2010年6月15日 星期二

peak power

pic Ref: http://en.wikipedia.org/wiki/Power_(physics) purpose: 利用 Power Model 算出 peak power value. 避免 Test Vector 在測試的過程中瞬間 power 過大,讓chip 燒毀. 在power monitor part2 中我們算出 Pin 腳的 transition total count, 再把 back end 所抽出來的 R, C, L 值代入 power model 中, 就可大概算出 power 的 total 值, 之後再藉由每個 peak 值來分析 Vector 所消耗的 peak power 跟 Vector 所佔有的 coverage 是否足夠到我們所要的目標. solutions: Step 1. 分析 Vector, 判斷是 function vector/ ATPG vector. 如果是 function vector, 就可針對 function vector 所測試的部份做分析, 因為function vector 是對 chip 內的 function 做驗證, 試著分析每支 function vector 的相依性找出相關和不相關的部份.假設在 T+n 支 vector 上發現有 peak power 過大的問題, 但在 T+1 支 vector 卻已測過相同的部份且 coverage 還不錯, 就可試著把 T+n 的 Vector 拿掉 peak power 的部份. 可加快測試的速度跟power 的消耗. Step 2. 分解 Vector,把 Vector 猜解成多支 Vectors .可減少 Peak Power 的消耗,相對的測試時間較長. Step 3. 改變 Vector 的順序, 在 Vector 測試的流程中, Coverage 會慢慢趨於一個飽和值, 可藉由 Vector 分析其特性曲線跟 Peak Power 的關係 PS: 一般會發生 peak power 過大的問題都來自 ATPG Vector,因為 ATPG 是亂數產生, 沒有 Test 特定的部位, 所以會造成額外的 power 消耗, 但如果是以 Testing 的角度來看,如果能測到更多的 faults, 用 test time 跟 power 來交換應該也是值得的....

2010年6月13日 星期日

power management 4 Linux

Propose : 在 low power design 上, "Power Management" 佔了很重要的地位. 利用 Power ON/OFF 來開關 Devices, 讓沒有在 work 的 devices 能進入 "Sleep" or "Shutdown" Mode... ,而這些判斷機制主要是透過上層的 software 演算法來決策. 因為過度的 ON/OFF 會消耗 "switch power", 讓電容不斷的 charge and discharge 導致不必要的 Power 消耗, 有時甚至比待機時候還來的耗電. 所以在 Power Management software design 上, 透過 control signal 打給底層的 hardware, 讓 hardware 有 state 上的變化, 再藉由每個不同的 state 來 define devices 的 on/off. Target : 用 c++ 來模擬 Power Management 的 hardware mode. 底下我們用 Linux 的 Power Management 來當例子. Ref: state define and detail info Linux power management other Refs : Android Power Management Power Planning power_man.h


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <list>

using namespace std;

enum PWSTATE {
 PW_RUN  =0,
 PW_STANDBY =1,
 PW_SLEEP =2,
 PW_SHUTDOWN =3,
 PW_NOP  =4,
};

enum PWSWITCH {
 ON =0,
 OFF =1,
 SLEEP =2,
 LOW =3,
};

enum PWERROR {
 CUR2NXT_OK =0,
 CUR2NXT_ERR  =1,
 CUR2PUT_OK =2,
 CUR2PUT_ERR =3,
};

template<class T>
class Power_Man_IN {

public:
        T       ReBoot;
        T       Activity;
        T       InActivity;
        T       ShutDown;
        T       CLK;
 T Button;
};

template<class T>
class Power_Man_OT {

public:
       T   CPU;
       T   LCD;
       T   Keys;
       T   Audio;
}; 

class Power_Man {

public:  
  Power_Man_IN<int8_t> PW_MN_IN_Pt;
  Power_Man_OT<int8_t> PW_MN_OT_Pt;

  list<Power_Man_IN<int8_t> > TST_VEC_LIST;  
  
  int8_t Cur_ST;
  int8_t Nxt_ST;
 
  void SET2PW_MN_IN(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b);
  void SET2PW_MN_OT(int8_t c,int8_t l,int8_t k,int8_t a);
  int8_t PRO2PW_MN();
  int8_t Put2OutREG();

  void DisPlaySET2PW_MN_IN();
  void DisPlaySET2PW_MN_OT();

//================================
// Test Bench 
//================================
  void SET_TEST_VECTOR(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b);
  void SET_TEST_LIST();
};
power_man.cpp

 
//#include <systemc.h>
#include "power_man.h"

void Power_Man::SET_TEST_VECTOR(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b){
  Power_Man_IN<int8_t> *VECPt = new Power_Man_IN<int8_t>;
    VECPt->ReBoot = r;
    VECPt->Activity = a;
    VECPt->InActivity = i;
    VECPt->ShutDown = s;
    VECPt->CLK  = c;
    VECPt->Button = b;
  
    TST_VEC_LIST.push_back(*VECPt);

  delete VECPt;
 }

//====================================
// Write your Test Bench here
//====================================
void Power_Man::SET_TEST_LIST(){

Cur_ST = PW_NOP;
Nxt_ST = PW_NOP;

SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);
// Set to  Run ST
SET_TEST_VECTOR(ON,  OFF, OFF, OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);

// Set to STANDBY
SET_TEST_VECTOR(OFF, OFF, ON,  OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);

}


void Power_Man::SET2PW_MN_IN(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b){
 PW_MN_IN_Pt.ReBoot  = r;
 PW_MN_IN_Pt.Activity = a;
 PW_MN_IN_Pt.InActivity = i;
 PW_MN_IN_Pt.ShutDown = s;
 PW_MN_IN_Pt.CLK  = c;
 PW_MN_IN_Pt.Button = b;
}

void Power_Man::SET2PW_MN_OT(int8_t c,int8_t l,int8_t k,int8_t a){
 PW_MN_OT_Pt.CPU  = c;
 PW_MN_OT_Pt.LCD  = l;
 PW_MN_OT_Pt.Keys = k;
 PW_MN_OT_Pt.Audio = a;
}

int8_t Power_Man::PRO2PW_MN(){
 
 switch(Cur_ST){
 case PW_RUN : Nxt_ST = (PW_MN_IN_Pt.InActivity == ON )? PW_STANDBY  :
       (PW_MN_IN_Pt.ShutDown   == ON )? PW_SHUTDOWN : PW_RUN;       break;
 case PW_STANDBY : Nxt_ST = (PW_MN_IN_Pt.InActivity == ON )? PW_SLEEP    :
                                   (PW_MN_IN_Pt.Activity   == ON )? PW_RUN      : PW_STANDBY;   break; 
 case PW_SLEEP : Nxt_ST = (PW_MN_IN_Pt.Activity   == ON )? PW_RUN      : PW_SLEEP;     break;
 case PW_SHUTDOWN: Nxt_ST = (PW_MN_IN_Pt.Button     == ON )? PW_RUN      : PW_SHUTDOWN;  break;
 case PW_NOP : Nxt_ST = (PW_MN_IN_Pt.ReBoot     == ON )? PW_RUN      : PW_NOP; break;
 default:                return   CUR2NXT_ERR;  break;
        }
     
      Cur_ST = Nxt_ST;

 return CUR2NXT_OK;
}  

int8_t Power_Man::Put2OutREG(){
 switch(Cur_ST){
 case PW_RUN : SET2PW_MN_OT(ON,   ON,  ON,  ON ); break;
 case PW_STANDBY : SET2PW_MN_OT(LOW,  OFF, ON,  ON ); break;
 case PW_SLEEP : SET2PW_MN_OT(SLEEP,OFF, OFF, OFF); break;
 case PW_SHUTDOWN: SET2PW_MN_OT(SLEEP,OFF, OFF, OFF); break;
 case PW_NOP : SET2PW_MN_OT(OFF,  OFF, OFF, OFF); break;
 default:                       return  CUR2PUT_ERR; break;
 }

return CUR2PUT_OK;
}

void Power_Man::DisPlaySET2PW_MN_IN(){
int8_t r = PW_MN_IN_Pt.ReBoot;  
int8_t a = PW_MN_IN_Pt.Activity; 
int8_t i = PW_MN_IN_Pt.InActivity; 
int8_t s = PW_MN_IN_Pt.ShutDown; 
int8_t c = PW_MN_IN_Pt.CLK;
int8_t  b = PW_MN_IN_Pt.Button;

cout<<"CTL\t"<<"CLK:\t"<<int(c)<<"\tREBT:\t"<<int(r)<<"\tACT:\t"<<int(a)<<"\tINACT:\t"<<int(i)<<"\tSHTDN:\t"<<int(s)<<"\tBUTTON:\t"<<int(b)<<endl;  
}

void Power_Man::DisPlaySET2PW_MN_OT(){
int8_t c = PW_MN_OT_Pt.CPU;
int8_t l = PW_MN_OT_Pt.LCD;
int8_t k = PW_MN_OT_Pt.Keys;
int8_t a = PW_MN_OT_Pt.Audio;

cout<<"PUT\t"<<"CPU:\t"<<int(c)<<"\tLCD:\t"<<int(l)<<"\tKEYS:\t"<<int(k)<<"\tAUDIO:\t"<<int(a)<<endl;

}



int main() {

_List_iterator<Power_Man_IN<int8_t> > it;

Power_Man *PW_MN_Pt = new Power_Man;

PW_MN_Pt->SET_TEST_LIST();

for(it=PW_MN_Pt->TST_VEC_LIST.begin(); it!=PW_MN_Pt->TST_VEC_LIST.end(); it++){

if( PW_MN_Pt->Put2OutREG()!= CUR2PUT_OK ){
  cout<<"CUR2PUT Error"<<endl; return -1; }

  PW_MN_Pt->DisPlaySET2PW_MN_OT();
  
  int8_t r = it->ReBoot;
  int8_t a = it->Activity;
  int8_t i = it->InActivity;
  int8_t s = it->ShutDown;
  int8_t c = it->CLK;
  int8_t b = it->Button;

  PW_MN_Pt->SET2PW_MN_IN( r, a, i, s, c, b);
  PW_MN_Pt->DisPlaySET2PW_MN_IN();

if( PW_MN_Pt->PRO2PW_MN()!= CUR2NXT_OK ){
 cout<<"CUR2NXT Error"<<endl; return -1; }


}

delete PW_MN_Pt;

return 0;
}
Results: PUT CPU: 1 LCD: 1 KEYS: 1 AUDIO: 1 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 1 LCD: 1 KEYS: 1 AUDIO: 1 CTL CLK: 1 REBT: 0 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 0 LCD: 0 KEYS: 0 AUDIO: 0 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 0 LCD: 0 KEYS: 0 AUDIO: 0 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 0 LCD: 0 KEYS: 0 AUDIO: 0 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 0 SHTDN: 1 BUTTON: 1 PUT CPU: 3 LCD: 1 KEYS: 0 AUDIO: 0 PS:目前只有考慮 CPU, LCD, KEYS, AUDIO 的 control. 當然你也可以自己 define 所要 control 的 devices download : http://sites.google.com/site/funningboy/c/power_man.cpp?attredirects=0&d=1 http://sites.google.com/site/funningboy/c/power_man.h?attredirects=0&d=1

2010年6月12日 星期六

power monitor part2

power monitor part1 中, 我們介紹過 "要如何取得 dynamic Power" 的方式. 底下就用 Systemc 2.0 中 examples/sysc/fir 當例子. 可參考 SystemC 安裝 fir_data.h
#include <power.h>

SC_MODULE(fir_data) {
   
  sc_in<bool>      reset;
  sc_in<unsigned>  state_out;
  sc_in<int>       sample;
  sc_out<int>      result;
  sc_out<bool>     output_data_ready;
  
  sc_int<19> acc;
  sc_int<8> shift[16];
  sc_int<9> coefs[16];

// power 4 sc_in<int>sample 
      TopCss<int> sample_ptr;
      int cur_sample;
      int pre_sample;
 
  SC_CTOR(fir_data)
    { 
      SC_METHOD(entry);
      dont_initialize();
      sensitive << reset;
      sensitive << state_out;
      sensitive << sample;
#include "fir_const.h"

//=================================
// sample signal Dynamic model
//=================================

      SC_METHOD(sample_DyPW);
      dont_initialize();
      sensitive << sample;
      sensitive << reset;
    
      cur_sample =0;
      pre_sample =0; 
   };

  void entry();
  void sample_DyPW();
};
fir_data.cpp
#include <systemc.h>
#include "fir_data.h"

void fir_data::entry()
{
  int state;
  sc_int<8> sample_tmp;

  // reset functionality
  if(reset.read()==true) {
    sample_tmp   = 0;
    acc = 0;
    for (int i=0; i<=15; i++) 
      shift[i] = 0;
  }

  // default settings
  result.write(0); 
  output_data_ready.write(false);
  state = state_out.read();
#ifdef DEBUG
  // cout << "Data debug : " << " " << state << " " << acc << " " << " at time " << sc_time_stamp() << endl;
  cout << "Data debug : " << " " << state << " " << acc << " " << " at time " << sc_time_stamp().to_double() << endl;
  for(int i=15; i>=0; i--) {
    cout << "Data debug : shift(" << i << ") " << shift[i] << endl;
  }; 
#endif

  // cycle behavior could be as well a case statement
  switch (state) {
  case 1 :
    sample_tmp = sample.read();
    acc = sample_tmp*coefs[0];
    acc += shift[14]* coefs[15];
    acc += shift[13]*coefs[14];
    acc += shift[12]*coefs[13];
    acc += shift[11]*coefs[12];
    break; 
  case 2 : 
    acc += shift[10]*coefs[11];
    acc += shift[9]*coefs[10];
    acc += shift[8]*coefs[9];
    acc += shift[7]*coefs[8];
    break; 
  case 3 : 
    acc += shift[6]*coefs[7];
    acc += shift[5]*coefs[6];
    acc += shift[4]*coefs[5];
    acc += shift[3]*coefs[4];
    break; 
  case 4 : 
    acc += shift[2]*coefs[3];
    acc += shift[1]*coefs[2];
    acc += shift[0]*coefs[1];
    for(int i=14; i>=0; i--) {
      shift[i+1] = shift[i];
    }; 
    shift[0] = sample.read();
    result.write((int)acc); 
    output_data_ready.write(true);
    break;
  default :
    cout << "Information : Reset state" << endl;
  }
} 


void fir_data::sample_DyPW(){

  if(reset.read()){
   sample_ptr.SetSignalDef("sample",0,0,IN);  
  cur_sample=0; pre_sample=0; } 
   
    cur_sample = sample.read();
 
    sample_ptr.UpdateSignalDef("sample",pre_sample,cur_sample,IN);
   int c = sample_ptr.CalDymPower("sample");
   
   cout <<"sample cur counts::\t"<< c << endl; 
   pre_sample = cur_sample; 
  
}
Results: Display : -16 at time 33000 Stimuli : 3 at time 39000 sample cur counts:: 1 Display : -13 at time 43000 Stimuli : 4 at time 49000 sample cur counts:: 3 Display : 6 at time 53000 Stimuli : 5 at time 59000 sample cur counts:: 1 最後把 cur counts 加總, 就可以算得 total counts

power monitor part1

Propose : 一般在 Testing 時, 除了 Test Vector (function) 的正確性外, 還要考量 Power 的問題. 如果 Power 過大, 會導致 VDD short 讓電路燒毀, 或者 VDD 供壓不穩造成 function fail. 雖然能透過加大 VDD 的電壓 or 把 Power supply 的 Metal line 變寬... 但總體而言,會浪費不必要的Power消耗. Target : 用簡單的 Power 分析, 在不違背 Test Vector function 正確性下, 大概算出sample 的次數, 之後再帶入 Power model 就可評估出這支 Vector 的 rough Power. Ref: Power Format
Here are the differences between Static and Dynamic Power Analysis:

SPA and DPA

SPA uses average current to calculate IR drop
while DPA uses Peak value of current at any time to calculate the same.
SPA considers Power to Gnd n/w as resistive while DPA considers it as R and C.

Vstatic = I * R

V(t)dyn = I(t) * R + L di/dt

where t- time
    R- resistance
    L - inductance
底下用個簡單的 sample 來測量 Dynamic Power sample的次數. 可得 N(sample counts)*V(t)dyn = total Dynamic Power

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <list>
//#include <util.h>

using namespace std;

enum SIGNALTYPE {
 IN =0,
 OUT =1,
 INOUT =2,
 REG =3,
 FIFO =4,
 BUFF =5,
};



template<class T>
class SignalCss
{
public:
 T PreSignal;
 T CurSignal;
 string Name;
 SIGNALTYPE Type;
};

template<class T>
class TopCss 
{
public:
 SignalCss<T> b;
 list<SignalCss<T> > SignalList;

void SetSignalDef(string n, T pre, T Cur, SIGNALTYPE s);
void DisplaySignal(string n);
int  CalDymPower(string n);

};

//=============================
// insert 2 SignalList
//=============================
template<class T>
void TopCss<T>::SetSignalDef(string n, T pre, T Cur, SIGNALTYPE s){

SignalCss<T> *b = new SignalCss<T>;
b->PreSignal = pre;
b->CurSignal = Cur;
b->Name      = n;
b->Type      = s;
 
SignalList.push_back(*b);
delete b;
}

//===============================
// Display func
//===============================
template<class T>
void TopCss<T>::DisplaySignal(string n){

_List_iterator<SignalCss<T> > it;

for(it=SignalList.begin(); it!=SignalList.end(); it++){
    if( n.compare(it->Name)==0 )
 cout<<"NM::\t"<<it->Name<<"\tTP::\t"<<it->Type<<"\tPre::\t"<<it->PreSignal<<"\tCur::\t"<<it->CurSignal<<endl;
 }

}

//================================
// calculate dynamic power
//================================
template<class T>
int TopCss<T>::CalDymPower(string n){
T c;
int i=0;

_List_iterator<SignalCss<T> > it;
 
for(it=SignalList.begin(); it!=SignalList.end(); it++){
    if( n.compare(it->Name)==0 ){
 c = (it->PreSignal)^(it->CurSignal);
        
 while(c!=0){
  (c % 2 ==0)? i=i : i++;
  c = c>>1;
 }
 return i; 
     }
}
return 0;
}

int main(int argc, char* argv[]){
int8_t a;
TopCss<int> *tp = new TopCss<int>;

tp->SetSignalDef("RX",3,5,IN);
cout<< tp->CalDymPower("RX");

//tp->DisplaySignal("clk");

return 0;
}

PS: 當然也可以寫成 Verilog code 包在 Test bench 下來測. code download: http://sites.google.com/site/funningboy/c/power.cpp?attredirects=0&d=1

2010年6月9日 星期三

PCI driver 4 Linux kernel case study

http://lwn.net/Kernel/LDD3/ http://dev.firnow.com/course/6_system/linux/Linuxjs/2008720/133589.html Linux kernel api http://vovo2000.com/type-lab/linux/kernel-api/linux-kernel-api.html Linux kernel build tutorial http://www.kroah.com/lkn/

2010年6月8日 星期二

CPU test flow

在CPU 的 test_flow中,大概分成底下部份 1. AC/DC Test 確保沒有短路或者漏電的問題造成Power Supply不穩... 2. Function Test 用Function Vector(PLL test, TX/RX...)來測試 3. Cache test 用BIST測, 如果有row/column fail, 可用 Cache repair的機制來修補. 4. bin class. 分出CPU的等級 所以不管是那種Test, 都要打vector到TX, 接收RX的 Data來判斷 Fail/OK. 底下就寫了個簡單的 Test-Vector Generator. step1. 打Config Cycle, 確定 Mode selection. step2. 打Vector到TX, 抓RX的訊號. PS: 這只是Emulator, 離實際 Platform上的實現還有一段距離. 底下是 Physical Platform 下要考慮的因素 1. sample ratio 2. package size (Byte/Bit...) 3. latency ... 可以參考print port control UART/RS232

#include < stdio.h>
#include < stdlib.h>
#include < util.h>

#ifdef DEBUG
int  VIA_DEBUG =1;
#else
int VIA_DEBUG =0;
#endif
//==================================
//Hash Definition
//==================================
enum TSTLIST {
 TST_VECTOR_1 =0,
 TST_VECTOR_2 =1,
 TST_VECTOR_3 =2,
};


enum ERRORLIST {
 OUT_POWER =0,
 OUT_FREQ =1,
 OUT_THEM =2, 
 OUT_BOOL =3,
};

//==================================
//THEM[31:20], FREQ[19:8], POWER[7:0]
//==================================
enum CONFIGREG {
 POWER_TAG =8,
 FREQ_TAG =12,
 THEM_TAG =12,
};

//===================================
// Range Definition
//===================================
#define MAX_POWER 5 
#define MIN_POWER 1
#define MAX_FREQ 1000
#define MIN_FREQ 20
#define MAX_THEM 50
#define MIN_THEM 2


struct Supply {
 char* Name_Supply;  //Name  Test_Vector Name;
 int Power_Supply;  //Power  Supply unit in voltage(.v)
 int Freq_Supply;  //Frequency Supply unit in Mhz
 int Them_Supply;  //Thermal  Supply unit in .c
} SPLY_TSTLIST[] = {
 {"TST_VECTOR_1", 2, 500, 30 },
 {"TST_VECTOR_2", 3, 500, 30 },
 {"TST_VECTOR_3", 3, 400, 28 },
};

//===================================
// TEST Vector Support
//===================================

struct Vector {
 char*  Name_Vector;
 char* v; 
} VECT_TSTLIST[] = {
 {"TST_VECTOR_1", "0101 0100 0010 0110 0101 0100 0010 0110" },
 {"TST_VECTOR_2", "0101 0111 0010 0010 0101 0111 0010 0010" },
 {"TST_VECTOR_2", "0101 0110 1010 0110 0101 0110 1010 0110" },
};

#define ON "1" 
#define OFF "0"
#define HZ "Z"
#define HX "X"
//===================================
//TESTER Definition
//===================================
struct TESTER {
 char*  Name_TESTER;
 char* CLK;
 char* RST;
 char* VAL;
 char* TX;
 char* RX;

} OUR_TESTER = { "VIA_TST", OFF, OFF, OFF, OFF, OFF }; 

//===================================
//
//===================================
struct Detect {
 char*  Name_Detect;
 int Power_Detect;
 
};


int ERROR_HANDLE(int a, int i){
 switch(a){
   case 0 : printf("Please Check Power_Supply at V-%d\n", i); return -1; break;
   case 1 : printf("Please Check Freq_Supply  at V-%d\n", i); return -1; break;
   case 2 : printf("Please Check Them_Supply  at V-%d\n", i); return -1; break;
   case 3 : printf("Please Check Test Vector  at V-%d\n", i); return -1; break;
  default : return 0; break; 
 }
return 0;
}



int SETREG(int p, int f, int t ){

     if( p < MIN_POWER || p > MAX_POWER) { return OUT_POWER; }
     if( f < MIN_FREQ  || f > MAX_FREQ ) { return OUT_FREQ;  }
     if( t < MIN_THEM  || t > MAX_THEM ) { return OUT_THEM;  }
      
     return  t << (POWER_TAG + FREQ_TAG) + f << (FREQ_TAG) + p;
  }


void Set2TESTER(char* c, char* r, char* v,char* t){
OUR_TESTER.CLK = c;
OUR_TESTER.RST = r;
OUR_TESTER.TX  = t;
OUR_TESTER.VAL = v;
}

char* Put2TESTER() {
char* c = OUR_TESTER.CLK;
char* s = OUR_TESTER.RST;
char* v = OUR_TESTER.VAL;
char* t = OUR_TESTER.TX;

OUR_TESTER.RX = "1";

char* r = OUR_TESTER.RX;
printf ("CLK:%2s, RST:%2s,VAL: %2s, TX:%2s, RX:%2s\n",c,s,v,t,r);
return r;
}


void Set2TSTVector(int a,int i){
char* v = VECT_TSTLIST[i].v;

 Set2TESTER(ON, OFF, OFF, OFF);
 Put2TESTER();

while( (*v++)!='\0'){
       ((*v)==' ')?  : 
 ((*v)=='0')? Set2TESTER(OFF, OFF, ON, OFF) : Set2TESTER(OFF, OFF, ON, ON);
 Put2TESTER();

 ((*v)==' ')?  : 
 ((*v)=='0')? Set2TESTER(ON, OFF, ON, OFF) : Set2TESTER(ON, OFF, ON, ON);
 Put2TESTER();

 }
 Set2TESTER(OFF, OFF, OFF, OFF);
 Put2TESTER();

}

void Set2Config(int a,int i){
    char* t = int2bin(a);

    if(VIA_DEBUG) printf("Config Vector (%d) :: %s\n",i,t);

 Set2TESTER(ON, OFF, OFF, OFF);
 Put2TESTER();

while( (*t++)!= '\0'){
 ((*t)=='0')? Set2TESTER(OFF, OFF, ON, OFF) : Set2TESTER(OFF, OFF, ON, ON);
 Put2TESTER();
    
 ((*t)=='0')? Set2TESTER(ON, OFF, ON, OFF) : Set2TESTER(ON, OFF, ON, ON);
  Put2TESTER();
    }


 Set2TESTER(OFF, OFF, OFF, OFF);
 Put2TESTER();
}

void Set2Ini(int a,int i){
int j;
 
 Set2TESTER(OFF, ON, OFF, OFF);
 Put2TESTER();
 
   for( j=0; j<=3; j++){
 Set2TESTER(ON, ON, OFF, OFF);
 Put2TESTER();

 (j==3)? Set2TESTER(OFF, OFF, OFF, OFF) : Set2TESTER(OFF, ON, OFF, OFF);

 Put2TESTER();
   }
}

int main() {
int i,a;


for(i=0; i<sizeof(SPLY_TSTLIST)/sizeof(SPLY_TSTLIST[0]); i++){
//Step.1 initial 
Set2Ini(a,i);

//Step.2 Set Config REG
a = SETREG(SPLY_TSTLIST[i].Power_Supply, SPLY_TSTLIST[i].Freq_Supply, SPLY_TSTLIST[i].Them_Supply);
if (ERROR_HANDLE(a,i)== -1) return -1;

Set2Config(a,i);

//Step.3 Set Test Vector
Set2TSTVector(a,i);


//printf("%d\n",a);
}

return 0;
}

2010年6月6日 星期日

COMPUTEX @ Taipei

小弟有榮幸參與這次的COMPUTEX,看到台灣在軟體跟硬體上不斷的創新跟研發所付出的心力,在此先感謝各位 "RD" 們的辛勞...因為我也是RD,能夠感受到時間上迫切的壓力.... 當然在今年的主軸還是圍繞在 touch screen, 3D vision,and disc storage 上面. touch screen: 最火紅的應該就是現在最流行的 panel PC, 走簡單輕巧路線, 甩掉過去 notebook 那種又重又待機時間短的現象. 再結合 APP store 這種趨勢應該是跑不掉, 連 Intel 都跳進去了. 看來未來真的是 "軟體硬體通吃" 才會有市場吧. 不過最後還是以提供 Service 為最後目標. Refs: Intel App Center apple App store 3D vision: 拜3D電影所賜,今年還真是每家要打上 "3D" 這個 Mark 就對了. 雖然我個人不看好這塊市場, 看個電視還要戴個眼鏡爾且又有距離限制.... 還是等能夠裸眼的 3D 電視吧, 不然剛過的 CRT 革命 又要再 革命一次嘛... 除非你口袋夠深, 不然還看不到迫切的需要. disc storage: 主打 USB3.0 跟 SSD.... USB3.0 spec 最後獻上 小弟公司的產品 1. ARM + Android 1.6 platform 2. VIA Netbook Ref http://www.liliputing.com/2010/06/the-via-netbooks-of-computex-2010-video.html