module uart_apb_reg(
  apb_uart_paddr,
  apb_uart_penable,
  apb_uart_psel,
  apb_uart_pwdata,
  apb_uart_pwrite,
  ctrl_reg_busy,
  ctrl_reg_fe,
  ctrl_reg_iid,
  ctrl_reg_iid_vld,
  ctrl_reg_oe,
  ctrl_reg_pe,
  ctrl_reg_rbr_wdata,
  ctrl_reg_rbr_write_en,
  ctrl_reg_thr_read,
  ctrl_reg_thsr_empty,
  reg_ctrl_dllh_data,
  reg_ctrl_ier_enable,
  reg_ctrl_lcr_dls,
  reg_ctrl_lcr_eps,
  reg_ctrl_lcr_pen,
  reg_ctrl_lcr_stop,
  reg_ctrl_lcr_wen,
  reg_ctrl_rbr_vld,
  reg_ctrl_set_dllh_vld,
  reg_ctrl_thr_data,
  reg_ctrl_thr_vld,
  reg_ctrl_threint_en,
  rst_b,
  sys_clk,
  uart_apb_prdata,
  uart_vic_int
);

// &Ports; @23
input   [31:0]  apb_uart_paddr;       
input           apb_uart_penable;     
input           apb_uart_psel;        
input   [31:0]  apb_uart_pwdata;      
input           apb_uart_pwrite;      
input           ctrl_reg_busy;        
input           ctrl_reg_fe;          
input   [3 :0]  ctrl_reg_iid;         
input           ctrl_reg_iid_vld;     
input           ctrl_reg_oe;          
input           ctrl_reg_pe;          
input   [7 :0]  ctrl_reg_rbr_wdata;   
input           ctrl_reg_rbr_write_en; 
input           ctrl_reg_thr_read;    
input           ctrl_reg_thsr_empty;  
input           rst_b;                
input           sys_clk;              
output  [15:0]  reg_ctrl_dllh_data;   
output  [2 :0]  reg_ctrl_ier_enable;  
output  [1 :0]  reg_ctrl_lcr_dls;     
output          reg_ctrl_lcr_eps;     
output          reg_ctrl_lcr_pen;     
output          reg_ctrl_lcr_stop;    
output          reg_ctrl_lcr_wen;     
output          reg_ctrl_rbr_vld;     
output          reg_ctrl_set_dllh_vld; 
output  [7 :0]  reg_ctrl_thr_data;    
output          reg_ctrl_thr_vld;     
output          reg_ctrl_threint_en;  
output  [31:0]  uart_apb_prdata;      
output          uart_vic_int;         

// &Regs; @24
reg             iid_priv_vld;         
reg             iir_iid_clr_vld;      
reg     [7 :0]  uart_dlh;             
reg     [7 :0]  uart_dll;             
reg     [3 :0]  uart_ier;             
reg     [3 :0]  uart_iir_iid;         
reg     [4 :0]  uart_lcr;             
reg             uart_lcr_dlab;        
reg             uart_lsr_dr;          
reg             uart_lsr_fe;          
reg             uart_lsr_oe;          
reg             uart_lsr_pe;          
reg             uart_lsr_thre;        
reg     [7 :0]  uart_rbr;             
reg     [7 :0]  uart_reg_data_pre;    
reg     [7 :0]  uart_thr;             
reg             uart_usr;             
reg             uart_vic_int;         

// &Wires; @25
wire            ahb_iir_read_vld;     
wire            ahb_lsr_read_vld;     
wire            ahb_rbr_read_vld;     
wire            ahb_usr_read_vld;     
wire    [31:0]  apb_uart_paddr;       
wire            apb_uart_penable;     
wire            apb_uart_psel;        
wire    [31:0]  apb_uart_pwdata;      
wire            apb_uart_pwrite;      
wire            ctrl_reg_busy;        
wire            ctrl_reg_fe;          
wire    [3 :0]  ctrl_reg_iid;         
wire            ctrl_reg_iid_vld;     
wire            ctrl_reg_oe;          
wire            ctrl_reg_pe;          
wire    [7 :0]  ctrl_reg_rbr_wdata;   
wire            ctrl_reg_rbr_write_en; 
wire            ctrl_reg_thr_read;    
wire            ctrl_reg_thsr_empty;  
wire            dllh_en;              
wire    [7 :0]  endian_wdata;         
wire            iir_iid_write_vld;    
wire            rd_acc;               
wire    [15:0]  reg_ctrl_dllh_data;   
wire    [2 :0]  reg_ctrl_ier_enable;  
wire    [1 :0]  reg_ctrl_lcr_dls;     
wire            reg_ctrl_lcr_eps;     
wire            reg_ctrl_lcr_pen;     
wire            reg_ctrl_lcr_stop;    
wire            reg_ctrl_lcr_wen;     
wire            reg_ctrl_rbr_vld;     
wire            reg_ctrl_set_dllh_vld; 
wire    [7 :0]  reg_ctrl_thr_data;    
wire            reg_ctrl_thr_vld;     
wire            reg_ctrl_threint_en;  
wire            rst_b;                
wire            sys_clk;              
wire    [31:0]  uart_apb_prdata;      
wire            uart_dlh_wen;         
wire            uart_dll_wen;         
wire            uart_ier_wen;         
wire            uart_lcr_wen;         
wire            uart_lsr_temt;        
wire    [7 :0]  uart_reg_data;        
wire    [5 :0]  uart_reg_haddr;       
wire            uart_thr_wen;         
wire            wr_acc;               


parameter          RBR = 6'h00;
parameter          THR = 6'h00;
parameter          DLL = 6'h00;
parameter          DLH = 6'h01;
parameter          IER = 6'h01;
parameter          IIR = 6'h02;
parameter          LCR = 6'h03;
parameter          LSR = 6'h05;
parameter          USR = 6'h1f;

// &Force("bus","apb_uart_paddr",31,0); @37
// &Force("bus","apb_uart_pwdata",31,0); @38
// //&Force("output","uart_ahb_hready_resp"); @39

//==================================================================================
//             write register control signal
//==================================================================================
// define transfer type;
//parameter TRANS_NONSEQ  = 2'b10,
//          TRANS_SEQ     = 2'b11,
//          RESP_OKAY     = 2'b00,
//          RESP_ERROR    = 2'b01;
//assign acc_vld = ((ahb_uart_htrans[1:0] == TRANS_NONSEQ) 
//                 || (ahb_uart_htrans[1:0] == TRANS_SEQ))
//              && ahb_uart_hsel && uart_ahb_hready_resp;
//
//assign rd_acc_pre     = acc_vld && !ahb_uart_hwrite;
//assign wr_acc_pre = acc_vld && ahb_uart_hwrite;
//
//assign uart_ahb_hresp[1:0]  = RESP_OKAY;
//
//parameter S_WRITE   = 2'b10;
//parameter S_IDLE    = 2'b00;
//parameter S_READ    = 2'b01;
//parameter S_RAW     = 2'b11;
//
//always @(posedge sys_clk or negedge rst_b)
//begin
//  if(!rst_b)
//    cur_state[1:0] <= S_IDLE;
//  else
//    cur_state[1:0] <= next_state[1:0];
//end
//
//&CombBeg;
//next_state[1:0] = S_IDLE;
//rd_acc          = 1'b0;
//casez(cur_state[1:0])
//  S_IDLE, 
//  S_READ,
//  S_RAW: begin
//    if(rd_acc_pre)
//    begin
//      rd_acc          = 1'b1;
//      next_state[1:0] = S_READ;
//    end
//    else if(wr_acc_pre)
//      next_state[1:0] = S_WRITE;
//  end
//  S_WRITE: begin
//    if(rd_acc_pre)
//      next_state[1:0] = S_RAW;
//    else if(wr_acc_pre)
//      next_state[1:0] = S_WRITE;
//  end
//  default:next_state[1:0] = 2'bx;        
//endcase
//&CombEnd;
//
//assign wr_acc = (cur_state[1:0]  == S_WRITE); 
// //&Force("output","uart_ahb_hready_resp"); @97
//assign uart_ahb_hready_resp = ~(cur_state[1:0] == S_RAW);
//assign raw = (cur_state[2:0] == S_RAW);
//assign uart_reg_haddr[5:0] = (wr_acc || raw)
//                                         ? uart_addr_lat[5:0]
//                                         : ahb_uart_haddr[7:2];
//// latch address
//// for byte or half word operation, data needs to be swapped. 
//always @(posedge sys_clk or negedge rst_b)
//begin
//  if(!rst_b)
//   uart_addr_lat[5:0] <= 14'b0;
//  else if(uart_ahb_hready_resp)
//  begin
//    uart_addr_lat[5:0] <= ahb_uart_haddr[7:2];
//  end
//end


//assign endian_wdata[7:0]  = i_bigend_b ? ahb_uart_hwdata[7:0] : ahb_uart_hwdata[31:24];
// &Force("bus","ahb_uart_hwdata",31,0); @117
assign endian_wdata[7:0]  = apb_uart_pwdata[7:0];
assign wr_acc  = apb_uart_psel && apb_uart_pwrite && apb_uart_penable;
assign rd_acc  = apb_uart_psel && !apb_uart_pwrite && apb_uart_penable; 
assign uart_reg_haddr[5:0] = apb_uart_paddr[7:2];
//==================================================================================
//          ahb write the uart register
//==================================================================================
assign dllh_en      = !uart_usr && uart_lcr_dlab; 
assign uart_dll_wen = dllh_en && wr_acc && (uart_reg_haddr[5:0] == DLL);
assign uart_dlh_wen = dllh_en && wr_acc && (uart_reg_haddr[5:0] == DLH);
assign uart_thr_wen = !uart_lcr_dlab && wr_acc && (uart_reg_haddr[5:0] == THR);
assign uart_ier_wen = !uart_lcr_dlab && wr_acc && (uart_reg_haddr[5:0] == IER);
assign uart_lcr_wen = wr_acc && (uart_reg_haddr[5:0] == LCR);

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_dll[7:0] <= 8'h0;
  else if(uart_dll_wen)
    uart_dll[7:0] <= endian_wdata[7:0];
end

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_dlh[7:0] <= 8'h0;
  else if(uart_dlh_wen)
    uart_dlh[7:0] <= endian_wdata[7:0];
end

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_thr[7:0] <= 8'h0;
  else if(uart_thr_wen)
    uart_thr[7:0] <= endian_wdata[7:0];
end

  
always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_ier[3:0] <= 4'h0;
  else if(uart_ier_wen)
    uart_ier[3:0] <= endian_wdata[3:0] ;
end

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
  begin
    uart_lcr_dlab <= 1'b0;
    uart_lcr[4:0] <= 5'h0;
  end
  else if(uart_lcr_wen)
  begin
    uart_lcr_dlab <= endian_wdata[7];
    uart_lcr[4:0] <= endian_wdata[4:0] ;
  end
  else
  begin
    uart_lcr_dlab <= uart_lcr_dlab;
    uart_lcr[4:0] <= uart_lcr[4:0];
  end
end
//==================================================================================
//            ahb read the uart register
//==================================================================================
//always@(posedge sys_clk or negedge rst_b)
//begin
//  if(!rst_b)
//    uart_reg_data[7:0] <= 8'b0;
//  else if(rd_acc)
//    uart_reg_data[7:0] <= uart_reg_data_pre[7:0];
//end
assign uart_reg_data[7:0] = rd_acc ? uart_reg_data_pre[7:0] : 8'bx;
// &CombBeg; @194
always @( uart_dll[7:0]
       or uart_lsr_fe
       or uart_ier[2:0]
       or uart_dlh[7:0]
       or uart_lsr_oe
       or uart_iir_iid[3:0]
       or uart_rbr[7:0]
       or uart_lcr_dlab
       or uart_usr
       or uart_lsr_pe
       or uart_lsr_temt
       or uart_reg_haddr[5:0]
       or uart_lsr_thre
       or uart_lcr[4:0]
       or uart_lsr_dr)
begin
case(uart_reg_haddr[5:0])
  RBR: uart_reg_data_pre[7:0] = uart_lcr_dlab ? uart_dll[7:0] : uart_rbr[7:0];
  IER: uart_reg_data_pre[7:0] = uart_lcr_dlab ? uart_dlh[7:0] : {5'b0,uart_ier[2:0]}; 
  IIR: uart_reg_data_pre[7:0] = {4'b0,uart_iir_iid[3:0]};
  LCR: uart_reg_data_pre[7:0] = {uart_lcr_dlab,2'b0,uart_lcr[4:0]};
  LSR: uart_reg_data_pre[7:0] = {1'b0,uart_lsr_temt,uart_lsr_thre,1'b0,
                               uart_lsr_fe,uart_lsr_pe,uart_lsr_oe,uart_lsr_dr};
  USR: uart_reg_data_pre[7:0] = {6'b0,uart_usr};
  default:uart_reg_data_pre[7:0] = 8'b0;     
 endcase 
// &CombEnd; @205
end

//assign uart_ahb_hrdata[31:24] = i_bigend_b ? 8'b0 : uart_reg_data[7:0];
assign uart_apb_prdata[31:0]  = {24'b0,uart_reg_data[7:0]};
// &CombBeg; @209
always @( uart_iir_iid[3:0])
begin
casez(uart_iir_iid[3:0])
  4'b0010:uart_vic_int =1'b1;
  4'b0100:uart_vic_int =1'b1;
  4'b0110:uart_vic_int =1'b1;
  default: uart_vic_int = 1'b0;
endcase
// &CombEnd; @216
end
//==================================================================================
//             Interface with UART_CTRL
//==================================================================================
//==================================================================================
//          UART_CTRL write the uart register
//==================================================================================

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_rbr[7:0] <= 8'b0;
  else if(ctrl_reg_rbr_write_en)
    uart_rbr[7:0] <= ctrl_reg_rbr_wdata[7:0]; 
end


always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_iir_iid[3:0] <= 4'b0001;
  else if(iir_iid_write_vld)
    uart_iir_iid[3:0] <= ctrl_reg_iid[3:0];
  else if(iir_iid_clr_vld)
    uart_iir_iid[3:0] <= 4'b0001;
end

assign iir_iid_write_vld = ctrl_reg_iid_vld && iid_priv_vld;

// &CombBeg; @245
always @( uart_iir_iid[3:0]
       or ctrl_reg_iid[2:0])
begin
 casez(uart_iir_iid[3:0])
 4'b0001: iid_priv_vld = 1'b1;
 4'b0111: iid_priv_vld = 1'b1;
 4'b0010: iid_priv_vld = (ctrl_reg_iid[2] && !ctrl_reg_iid[0]) ? 1 : 0;
 4'b0100: iid_priv_vld = (ctrl_reg_iid[2:0] == 3'b110) ? 1 : 0;
 4'b0110: iid_priv_vld = 1'b0;
 default: iid_priv_vld = 1'b0;
 endcase
// &CombEnd; @254
end


// &CombBeg; @257
always @( ahb_rbr_read_vld
       or uart_iir_iid[3:0]
       or ahb_lsr_read_vld
       or uart_lsr_thre
       or ahb_iir_read_vld
       or ahb_usr_read_vld)
begin
 casez(uart_iir_iid[3:0])
  4'b0010: iir_iid_clr_vld = !uart_lsr_thre  || ahb_iir_read_vld;
  4'b0100: iir_iid_clr_vld = ahb_rbr_read_vld;
  4'b0110: iir_iid_clr_vld = ahb_lsr_read_vld;
  4'b0111: iir_iid_clr_vld = ahb_usr_read_vld;
  default: iir_iid_clr_vld = 1'b0;  
  endcase
// &CombEnd; @265
end

  
assign ahb_iir_read_vld = rd_acc && ( uart_reg_haddr[5:0] == IIR );
assign ahb_lsr_read_vld = rd_acc && ( uart_reg_haddr[5:0] == LSR );
assign ahb_usr_read_vld = rd_acc && ( uart_reg_haddr[5:0] == USR );
assign ahb_rbr_read_vld = rd_acc && !uart_lcr_dlab &&( uart_reg_haddr[5:0] == RBR);


always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
  begin
    uart_lsr_thre <= 1'b1;
  end
  else if(uart_thr_wen)
  begin
    uart_lsr_thre <= 1'b0;
  end
  else if(ctrl_reg_thr_read)  
  begin
    uart_lsr_thre <= 1'b1;
  end
end

assign uart_lsr_temt = ctrl_reg_thsr_empty && uart_lsr_thre;

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_lsr_dr <= 1'b0;
  else if(ctrl_reg_rbr_write_en && !uart_lsr_pe && !uart_lsr_fe)
    uart_lsr_dr <= 1'b1;
  else if(ahb_rbr_read_vld )
    uart_lsr_dr <= 1'b0;
end

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_lsr_fe <= 1'b0;
  else if(ctrl_reg_fe)
    uart_lsr_fe <= 1'b1;
  else if( ahb_lsr_read_vld )
    uart_lsr_fe <= 1'b0;
end
  
always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_lsr_pe <= 1'b0;
  else if(ctrl_reg_pe)
    uart_lsr_pe <= 1'b1;
  else if( ahb_lsr_read_vld )
    uart_lsr_pe <= 1'b0;
end
 
always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_lsr_oe <= 1'b0;
  else if(ctrl_reg_oe)
    uart_lsr_oe <= 1'b1;
  else if( ahb_lsr_read_vld )
    uart_lsr_oe <= 1'b0;
end

always @(posedge sys_clk or negedge rst_b)
begin
  if(!rst_b)
    uart_usr <= 1'b0;
  else if(ctrl_reg_busy)
    uart_usr <= 1'b1;
  else if(!ctrl_reg_busy)
    uart_usr <= 1'b0;
end
   
//==================================================================================
//             Interface with UART_CTRL
//==================================================================================
assign reg_ctrl_thr_vld         = !uart_lsr_thre;
assign reg_ctrl_thr_data[7:0]   = uart_thr[7:0];
assign reg_ctrl_ier_enable[2:0] = uart_ier[2:0];
assign reg_ctrl_dllh_data[15:0] = {uart_dlh[7:0],uart_dll[7:0]};
assign reg_ctrl_lcr_eps         = uart_lcr[4];
assign reg_ctrl_lcr_pen         = uart_lcr[3];
assign reg_ctrl_lcr_stop        = uart_lcr[2];
assign reg_ctrl_lcr_dls[1:0]    = uart_lcr[1:0];
assign reg_ctrl_rbr_vld         = uart_lsr_dr;
assign reg_ctrl_lcr_wen         = uart_lcr_wen;
assign reg_ctrl_set_dllh_vld    = uart_dlh_wen || uart_dll_wen;
assign reg_ctrl_threint_en      = uart_ier_wen && endian_wdata[1];

// &ModuleEnd;  @358
endmodule