Akses perangkat keras

Akses perangkat keras melalui klausul address, variabel volatile, dan interrupt.

Daftar isi

Sistem tertanam tidak selalu berkomunikasi dengan lingkungan luarnya melalui pemanggilan fungsi. Sebagian besar komunikasi terjadi melalui pembacaan dan penulisan pada alamat memori tertentu yang terhubung langsung ke perangkat keras, misalnya register status sebuah sensor. Topik ini membahas tiga mekanisme bahasa untuk keperluan itu, yaitu klausul address yang menempatkan objek pada alamat tertentu, pragma Volatile dan Atomic yang menjamin setiap akses benar-benar dilakukan, serta penanganan interrupt melalui protected procedure. Setelah topik ini diselesaikan, pola akses register perangkat dan handler interrupt dapat dikenali beserta batas penerapannya pada host.

Klausul address dan atribut Address#

Setiap objek pada program Ada memiliki lokasi memori yang dapat dibaca melalui atribut ‘Address, dan hasilnya bertipe System.Address. Klausul address bekerja pada arah sebaliknya, yaitu menetapkan lokasi tertentu untuk sebuah objek. Bentuk umumnya adalah for Nama'Address use ekspresi_alamat, dan kompilator menempatkan objek tersebut tepat pada alamat yang dinyatakan. Pada target tertanam, ekspresi alamat biasanya berupa konstanta yang dinyatakan dalam dokumen perangkat keras.

Mekanisme klausul address dapat diperagakan dengan aman pada host karena alamatnya diambil dari variabel biasa, bukan dari perangkat. Program berikut menumpangkan satu nama baru pada variabel yang sudah ada, sehingga kedua nama mengacu pada lokasi memori yang sama.

ada tumpang_alamat.adb
with Ada.Text_IO;
with System;
use type System.Address;

procedure Tumpang_Alamat is
   Suhu  : Integer := 21;
   Alias : Integer;
   for Alias'Address use Suhu'Address;
begin
   Alias := 42;
   Ada.Text_IO.Put_Line ("Suhu  = " & Integer'Image (Suhu));
   Ada.Text_IO.Put_Line ("Alias = " & Integer'Image (Alias));
   Ada.Text_IO.Put_Line ("alamat sama = "
      & Boolean'Image (Alias'Address = Suhu'Address));
end Tumpang_Alamat;
bash
# kompilasi program
gnatmake -q tumpang_alamat.adb
# jalankan program
./tumpang_alamat
text Keluaran
Suhu  =  42
Alias =  42
alamat sama = TRUE

Penulisan melalui Alias benar-benar mengubah Suhu, dan perbandingan kedua atribut ‘Address menghasilkan TRUE secara deterministik. Pola penumpangan ini juga menjadi cara memahami register perangkat, yaitu satu lokasi memori yang dilihat dari dua sisi, satu sisi dari program dan satu sisi dari perangkat keras. Pada target nyata, objek tidak lagi dideklarasikan sebagai variabel biasa dan alamatnya diganti dengan konstanta perangkat, sedangkan cara kerja klausul address tetap sama.

Variabel volatile dan pragma Atomic#

Register perangkat keras dapat berubah tanpa sepengetahuan alur program, misalnya ketika perangkat memperbarui statusnya sendiri. Tanpa petunjuk tambahan, kompilator boleh menyimpan hasil pembacaan pertama ke dalam register mesin dan melewati pembacaan berikutnya, sehingga perubahan dari perangkat tidak pernah terlihat. Pengoptimalan semacam itu dicegah oleh pragma Volatile, sedangkan pragma Atomic menambah jaminan bahwa setiap pembacaan dan penulisan berlangsung sebagai satu operasi yang tidak terpecah. Pada Ada 2022, keduanya juga dapat ditulis sebagai aspek pada deklarasi objek.

ada Contoh: register sensor tiruan pada alamat tetap
-- tidak-dijalankan
with System.Storage_Elements;

package Register_Sensor is
   type Bait_Status is mod 2**8;

   Status_Perangkat : Bait_Status;
   for Status_Perangkat'Address use
      System.Storage_Elements.To_Address (16#A000#);
   pragma Volatile (Status_Perangkat);
   pragma Atomic (Status_Perangkat);
end Register_Sensor;

Fragmen di atas menggambarkan pola lengkapnya, yaitu tipe modular berukuran 8 bit, klausul address menuju alamat sensor, dan dua pragma pengendali akses. Tipe modular dipilih agar ukurannya tepat satu bait, sebagaimana lebar register status sensor pada umumnya. Alamat 16#A000# adalah contoh alamat perangkat pada target tertanam dan tidak ada pada peta memori host, sehingga fragmen ini tidak dijalankan di sandbox.

Penanganan interrupt#

Interrupt adalah sinyal yang dikirim perangkat keras kepada prosesor untuk meminta penanganan segera, misalnya saat bacaan sensor baru siap. Bahasa menyediakan penanganan interrupt melalui protected procedure yang dilindungi oleh runtime, sehingga badan handler tidak dapat disisipi oleh protected action lain dan tidak boleh melakukan operasi yang memblokir. Pragma Attach_Handler mengaitkan handler tersebut dengan interrupt tertentu, sedangkan daftar nama interrupt pada suatu target disediakan oleh package Ada.Interrupts.Names.

ada Contoh: protected procedure sebagai handler interrupt
-- tidak-dijalankan
with Ada.Interrupts.Names;

package Bacaan_Baru is
   protected Pengolah is
      pragma Attach_Handler (Tangani, Ada.Interrupts.Names.SIGUSR1);

      procedure Tangani;
      function Bacaan_Terbaru return Integer;
   private
      Bacaan : Integer := 0;
   end Pengolah;
end Bacaan_Baru;

Nama SIGUSR1 pada contoh berasal dari package Ada.Interrupts.Names yang isinya berbeda untuk setiap target, dan target tertanam biasanya menyediakan nama nomor IRQ perangkatnya sendiri. Prosedur Tangani dipanggil oleh runtime setiap kali interrupt tersebut terjadi, sedangkan fungsi Bacaan_Terbaru memberi task lain cara membaca hasilnya dengan aman. Perlindungan pada protected object memastikan data Bacaan tidak pernah terbaca dalam keadaan setengah diperbarui.

Kesalahan umum#

Empat kekeliruan berikut paling sering muncul saat akses perangkat keras dipraktikkan.

  • Melupakan pragma Volatile pada register perangkat. Kompilator menganggap nilai objek hanya berubah melalui kode program, sehingga pembacaan berulang disederhanakan menjadi satu pembacaan. Tambahkan pragma Volatile, atau aspek Volatile => True, pada setiap objek yang dibagikan dengan perangkat keras.
  • Menaruh pekerjaan berat di dalam handler interrupt. Handler berjalan di luar jadwal biasa dan tidak boleh menunggu apa pun, sehingga pekerjaan yang panjang menunda seluruh sistem. Catat data pada handler, lalu proses hasilnya pada task biasa.
  • Mengasumsikan ukuran objek tanpa menetapkannya. Klausul address menempatkan objek pada alamat yang dinyatakan, tetapi tidak mengubah ukurannya, dan ketidakcocokan ukuran dengan register menghasilkan bacaan yang bergeser. Tetapkan ukurannya dengan tipe yang tepat, misalnya tipe modular 8 bit untuk register satu bait.
  • Menganggap pragma Volatile otomatis menjadikan akses atomik. Volatile hanya melarang pengoptimalan, sedangkan penulisan yang lebih lebar dari satu akses mesin masih dapat terpecah. Gunakan pragma Atomic untuk data yang harus terbaca utuh oleh perangkat atau task lain.

Ringkasan#

  • Klausul address menempatkan objek pada alamat tertentu, sedangkan atribut ‘Address membaca lokasi sebuah objek dengan tipe System.Address.
  • pragma Volatile melarang pengoptimalan pembacaan, dan pragma Atomic menjamin setiap akses berlangsung sebagai satu operasi.
  • Handler interrupt dinyatakan sebagai protected procedure yang dikaitkan dengan pragma Attach_Handler, dan nama interrupt disediakan oleh Ada.Interrupts.Names.
  • Contoh alamat perangkat dan handler interrupt bersifat konseptual pada host, karena alamat perangkat dan lingkungan interrupt hanya tersedia pada target tertanam.

Referensi#