⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c_slave.v

📁 I2c中通信的从机发送和接收信息的Verilog程序测试模块
💻 V
📖 第 1 页 / 共 2 页
字号:
    4'd2: sda_out = out_reg[5];
    4'd3: sda_out = out_reg[4];
    4'd4: sda_out = out_reg[3];
    4'd5: sda_out = out_reg[2];
    4'd6: sda_out = out_reg[1];
    4'd7: sda_out = out_reg[0];
   default: sda_out = out_reg[0];
  endcase

//----------------------------------------



//----------------------------------------
// Input De-Mux

always @ (posedge clk or negedge rst_l)
 begin 
 
 if (!rst_l) begin 
   in_reg <= 8'h00;
 end
 else if (in_reg_enable) begin 
   case (bit_counter)
    3'd0: in_reg[7] <= sda_reg_delayed;
    3'd1: in_reg[6] <= sda_reg_delayed;
    3'd2: in_reg[5] <= sda_reg_delayed;
    3'd3: in_reg[4] <= sda_reg_delayed;
    3'd4: in_reg[3] <= sda_reg_delayed;
    3'd5: in_reg[2] <= sda_reg_delayed;
    3'd6: in_reg[1] <= sda_reg_delayed;
    3'd7: in_reg[0] <= sda_reg_delayed;
  endcase
 end
 else begin 
   in_reg <= in_reg;
 end

end

//----------------------------------------


//----------------------------------------
// I2C Slave State Machine

always @ (posedge clk or negedge rst_l)
  begin 
  if (!rst_l) begin 
      current_state <= #1 idle;
   end
  else begin 
      
    case (current_state)
      idle: begin 
              if (start_detect && scl) begin 
                current_state <= #1 start;
              end
              else begin 
                current_state <= #1 idle;
                in_reg_enable <= #1 0;
              end
            end
      start: begin 
 
              if (start_detect && scl) begin 
                current_state <= #1 start;
              end
        
              if (stop_detect && scl) begin 
                current_state <= #1 idle;
              end
              
              else if (scl_pulse) begin                 
                  bit_counter <= #1 0;
                  in_reg_enable <= #1 1;
              end                 
              else if (in_reg_enable ) begin 
                  in_reg_enable = #1 0; 
                  bit_counter = #1 bit_counter + 1;
                  current_state = #1 address;
                  // clear all the address hit flags
                  hit_7 <= #1 0;
                  hit_10_upper <= #1 0;
                  hit_10_lower <= #1 0;
                  word_add_flag <= #1 0;
                  ack_flag <= #1 0;
              end
             end        
      address: begin 
        
                if (start_detect && scl) begin 
                  current_state <= #1 start;
                end
        
                else if (stop_detect && scl) begin 
                  current_state <= #1 idle;
                end
 
                else if (scl_pulse && (bit_counter <= 8)) begin                 
                  in_reg_enable <= #1 1;
                end  
        
                else if (in_reg_enable) begin 
                  in_reg_enable <= #1 0; 
                  bit_counter <= #1 bit_counter + 1;
                  current_state <= #1 address;
                end
        
                else if (bit_counter == 8 && address_mode == `seven_bit) begin 
                  // determine if r or w and set r_w_bit
                  if (in_reg[7:1] == address_reg_7) begin 
                    r_w_bit <= #1 in_reg[0];
                    current_state <= #1 ack;
                    hit_7 <= #1 1;
                    ack_flag <= #1 0; // used in ack state
                  end
                  else begin 
                    // the address is not for this slave                     
                    sda_out <= #1 1'b1;
                    current_state <= #1 idle;
                  end
                end
        
            // check if upper address byte is a hit in 10 bit addressing
                else if (bit_counter == 8 && address_mode == `ten_bit && hit_10_upper == 0)
                begin 
                  // first time checking upper hit
                  if (in_reg[7:1] == address_reg_10_upper) begin 
                    r_w_bit <= #1 in_reg[0];
                    current_state <= #1 ack;
                    hit_10_upper <= #1 1;
                    ack_flag <= #1 0; // used in ack state
                    if (in_reg[0] == 1'b0) begin 
                      temp_add_upper <= #1 in_reg[7:1];
                      read_10_flag <= #1 0; // clear
                      end
                    else if ((in_reg[0] === 1'b1) && (temp_add_upper === in_reg[7:1]) && (temp_add_lower === address_reg_10_lower) )
                    begin 
                      // This flag is set because the last 10 bit addressing 
                      // mode write was for this slave, so this read only 
                      // requires a match of the first byte of addressing
                      read_10_flag <= #1 1; // set            
                    end
                  end 
                  else begin 
                    // the address is not for this slave
                    sda_out <= #1 1'b1;
                    current_state <= #1 idle;
                    temp_add_upper = in_reg[7:1]; // holds value of last
                                                  // upper add
                    read_10_flag <= #1 0; // clear
                  end
                end 
        
          // check if lower address byte is a hit in 10 bit addressing
                else if (bit_counter == 8 && address_mode==`ten_bit && hit_10_upper == 1)
                begin
                  // is the lower address a hit?
                  if (in_reg[7:0] == address_reg_10_lower) begin 
                    current_state <= #1 ack;
                    hit_10_lower <= #1 1;
                    ack_flag <= #1 0; // used in ack state
                    temp_add_lower <= #1 in_reg[7:0];
                  end
                  else begin 
                    // the address is not for this slave
                    sda_out <= #1 1'b1;
                    current_state <= #1 idle;
                    temp_add_lower <= #1 in_reg[7:0];
                  end 
                end   
               end

 
      ack:  begin 
              // starts with scl high
        
        // if we get a start goto start
              if (start_detect && scl) begin 
                  current_state <= #1 start;
                end
        
        // if there is a stop goto idle
              else if (stop_detect && scl) begin 
                  current_state <= #1 idle;
              end       
        
        // if there is an address hit acknowledge the address 
              else if ((hit_7 || hit_10_upper || hit_10_lower) && scl_neg_pulse && !ack_flag) begin 
                 out_en <= #tdh 1; // turn on OE
                 ack_flag <= #1 1;
              end
        
        
        // once the acknowledge is presented turn off the OE
        // print the address, and goto address or data depending on
        // addressing mode
              else if ((hit_7 || hit_10_upper || hit_10_lower) && scl_neg_pulse  && ack_flag ) begin 
                 out_en <= #tdh 0; // #1 0; // turn off OE
                 bit_counter <= #1 4'b0;
                 
                 if (hit_10_upper && !hit_10_lower) begin 
                  $display($time, " %m << 10 bit addressing Upper address is %b >>", in_reg);
                  if (read_10_flag == 1'b0) begin 
                    current_state <= #1 address;
                  end
                  else if (read_10_flag === 1'b1) begin 
                    // going to the data state because a read in 10 bit
                    // addressing only requires a hit on the upper address if
                    // the last write was a hit.
                    current_state <= #1 data;
                  end
                 end
        
                 else if (hit_7 || hit_10_lower) begin 
                  // hit_10_lower or hit_7 
                  current_state <= #1 data;
                  if (hit_10_lower) begin 
                   $display($time, " %m << 10 bit addressing Lower address is %b >>", in_reg);
                  end
                  else if (hit_7) begin 
                   $display($time, " %m << 7 bit addressing & address is %b >>", in_reg);
                  end
                end              
 
              end //((hit_7 || hit_10_upper || hit_10_lower) && scl_neg_pulse  && ack_flag ) begin



          // if there is no hit, return to idle
              else  if (!hit_7 && !hit_10_upper && !hit_10_lower) begin 
                 // no_ack
                 out_en = #1 1'b0;
                 bit_counter <= #1 4'b0;
                 current_state <= #1 idle;
                end
            end
 
      data: begin 
 
              // starts with scl low
              if (start_detect && scl) begin 
                  current_state <= #1 start;
                end
        
              else if (stop_detect && scl) begin 
                current_state <= #1 idle;
              end       
               // write data
              else begin // outer else
                if (!r_w_bit && scl_pulse && (bit_counter <= 8) ) begin 
                   // write
                  in_reg_enable <= #1 1;
                end  
                else if (!r_w_bit && in_reg_enable && (bit_counter <= 8)) begin 
                  // write more
                  in_reg_enable <= #1 0; 
                  bit_counter <= #1 bit_counter + 1;
                  current_state <= #1 data;
                end
                else if (!r_w_bit && (bit_counter == 8)) begin 
                   // write last bit
                   in_reg_enable <= #1 0; // disable
                   current_state <= #1 data_ack;
                   ack_flag <= #1 0; // used in data_ack state
                   if (!word_add_flag) begin 
                     word_address <= #1 in_reg;
                     word_add_flag <= #1 1; // set the flag
                   end
                   else begin 
                     mem[word_address] <= #1 in_reg;
                     word_address <= #1 word_address + 1;
                   end
                 end
                 // read data
                else if (r_w_bit && (bit_counter == 0) && !scl_neg_pulse) begin 
                   // read first bit of word
                   // scl is low at start of read
                   out_en <=#tdh 1; // turn on OE
                   out_reg <= #tdh mem[word_address];  
                 end
                else if (r_w_bit && (bit_counter < 7) && scl_neg_pulse) begin 
                    // set up next bit
                    bit_counter <= #tdh bit_counter + 1; 
                 end
                else if (r_w_bit && (bit_counter == 7) && scl_neg_pulse) begin 
                  // we already output the last bit
                  bit_counter <= #tdh 0; 
                  out_en <= #tdh 0; // turn off OE
                  word_address <= #1 word_address + 1;
                  current_state <= #1 data_ack;
                  ack_flag <= #1 0; // used in data_ack state
                 end
              end // outer else
            end // end data phase
 
 data_ack: begin 

              if (start_detect && scl) begin 
                  current_state <= #1 start;
                end
 
              else if (stop_detect && scl) begin 
                  current_state <= #1 idle;
              end
              
           // starts with scl high on write
              else if ( !r_w_bit && scl_neg_pulse && !ack_flag) begin 
                 $display($time, " %m << Slave Data Received on write is %b >>", in_reg);
                 out_en <= #10 1; // turn on OE
                 sda_out <= #20 0; // sda is 0 so ack
                 ack_flag <= #1 1;
              end
              else if ( !r_w_bit && scl_neg_pulse  && ack_flag ) begin 
                 out_en <= #10 0; // turn off OE
                 sda_out <= #20 1; // sda is becomes a Z
                 bit_counter <= #1 4'b0;
                 current_state <= #1 data; 
              end
        
            // starts with scl low on read
                else if (r_w_bit && scl_pulse) begin 
                   // check sda for ack now
                   $display($time, " %m << Slave Data transmitted on read is %b >>", out_reg);
                   if (!sda) begin 
                     next_state <= #1 data;
                     bit_counter <= #1 4'b0;
                     $display($time, " %m Master ACK'd on a Data Read, returning to Data "); 
                     ack_flag <= #1 1;
                   end
                   else if (sda) begin 
                     $display($time, " %m No ACK on a Data Read, returning to Idle ");
                     next_state <= #1 idle;
                     ack_flag <= #1 1;
                   end
                 end
                else if (r_w_bit && scl_neg_pulse) begin 
                  current_state <= #1 next_state;
                end
      end
 
      default: begin 
                if (start_detect && scl) begin 
                  current_state <= #1 start;
                end
                else if (stop_detect && scl) begin 
                  current_state <= #1 idle;
                end
                else begin 
                  current_state <= #1 idle;
                  $display($time, " %m Something is broken is the SM returning to idle");
                end
               end // end of default
    endcase
 
    end // end of else
 
  end // end of always


                
endmodule                                    

//------------------------------- E O F ------------------------------------- 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -