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");


}