// Example code for an AHBLite System-on-Chip // Iain McNally // ECS, University of Soutampton // // This module is an AHB-Lite Slave containing three read-only locations // // Number of addressable locations : 3 // Size of each addressable location : 16 bits // Supported transfer sizes : Half Word // Alignment of base address : Double Word aligned // // Address map : // Base addess + 0 : // Read Switches Entered via Button[0] // Base addess + 2 : // Read Switches Entered via Button[1] // Base addess + 4 : // Read Status of Switches Entered via Buttons // // Bits within status register : // Bit 1 DataValid[1] // (data has been entered via Button[1] // this status bit is cleared when this data is read by the bus master) // Bit 0 DataValid[0] // (data has been entered via Button[0] // this status bit is cleared when this data is read by the bus master) // For simplicity, this interface supports only 16-bit transfers // since there are only 16 switches. module ahb_switches( // AHB Global Signals input HCLK, input HRESETn, // AHB Signals from Master to Slave input [31:0] HADDR, // With this interface HADDR is ignored input [31:0] HWDATA, input [2:0] HSIZE, input [1:0] HTRANS, input HWRITE, input HREADY, input HSEL, // AHB Signals from Slave to Master output logic [31:0] HRDATA, output HREADYOUT, //Non-AHB Signals input [15:0] Switches, input [1:0] Buttons ); timeunit 1ns; timeprecision 100ps; // AHB transfer codes needed in this module localparam No_Transfer = 2'b0; // Storage for two different switch values logic [15:0] SwitchData[0:1]; // Storage for status bits logic [1:0] DataValid; // last_buttons is used for simple edge detection logic [1:0] last_buttons; //control signals are stored in registers logic read_enable; logic [1:0] half_word_address; logic [15:0] Status; //Update the SwitchData values only when the appropriate button is pressed always_ff @(posedge HCLK, negedge HRESETn) if ( ! HRESETn ) begin SwitchData[0] <= '0; SwitchData[1] <= '0; last_buttons <= '0; DataValid <= 0; end else begin if ( Buttons[0] && !last_buttons[0] ) begin SwitchData[0] <= Switches; DataValid[0] <= 1; end else if ( read_enable && ( half_word_address == 0 ) ) begin DataValid[0] <= 0; end if ( Buttons[1] && !last_buttons[1] ) begin SwitchData[1] <= Switches; DataValid[1] <= 1; end else if ( read_enable && ( half_word_address == 1 ) ) begin DataValid[1] <= 0; end last_buttons <= Buttons; end //Generate the control signals in the address phase always_ff @(posedge HCLK, negedge HRESETn) if ( ! HRESETn ) begin read_enable <= '0; half_word_address <= '0; end else if ( HREADY && HSEL && (HTRANS != No_Transfer) ) begin read_enable <= ! HWRITE; half_word_address <= HADDR[2:1]; end else begin read_enable <= '0; half_word_address <= '0; end //Act on control signals in the data phase // define the bits in the status register assign Status = { 14'd0, DataValid}; //read always_comb if ( ! read_enable ) // (output of zero when not enabled for read is not necessary // but may help with debugging) HRDATA = '0; else case (half_word_address) // ensure that half-word data is correctly aligned 0 : HRDATA = { 16'd0, SwitchData[0] }; 1 : HRDATA = { SwitchData[1], 16'd0 }; 2 : HRDATA = { 16'd0, Status }; // unused address - returns zero default : HRDATA = '0; endcase //Transfer Response assign HREADYOUT = '1; //Single cycle Write & Read. Zero Wait state operations endmodule