Dalam proses penulisan STM8uLoader bootloader untuk mikrokontroler STM8, menjadi perlu untuk mengukur kedalaman tumpukan.
Mari kita bertanya:
- Apa yang terjadi jika Anda mencoba mendorong lebih banyak informasi tentang tumpukan daripada dalamnya?
- Apa yang terjadi jika Anda mencoba mengekstrak lebih banyak informasi dari tumpukan daripada yang Anda tempatkan?
- Apa yang terjadi jika Anda menginisialisasi penunjuk tumpukan SP dengan alamat yang melampaui batas tumpukan?
Memori RAM dan kedalaman tumpukan dapat bervariasi untuk model STM8 yang berbeda.
Untuk penelitian ini, model STM8S103F3 dipilih.
Dokumentasi untuk STM8S103F3 menyediakan data berikut:
- tumpukan kedalaman 513 byte;
- saat reset, pointer SP diinisialisasi ke 0x03FF (RAM END);
- tumpukan tumbuh ke arah menurunnya alamat.
Perhitungan menunjukkan bahwa batas bawah tumpukan adalah:
0x03FF - 513 = 0x01FF
Untuk menembus batas ini, Anda perlu mendorong beberapa lebih dari 513 byte pada stack.
Isi tumpukan tidak menarik bagi kami. Cukup untuk mengetahui isi pointer ke tumpukan SP, yang harus berisi alamat sel memori RAM berikutnya yang tidak digunakan.
Kami akan secara berurutan menempatkan byte dengan perintah push apa saja (misalnya, tekan A) dan sebelum setiap langkah mengirim konten SPH tinggi dan byte SPL rendah dari penunjuk tumpukan SP ke UART.
Algoritma Prosedur:
1 Inisialisasi penunjuk tumpukan dengan nilai 0x03FF dan konfigurasikan UART;
2 Kami menunggu byte dari program terminal;
3 byte diterima;
4 Kirim konten pointer SP ke UART;
5 Kami mendorong isi baterai ke tumpukan dengan perintah push A;
6 Jika siklus pengiriman kurang dari 64, lanjutkan ke langkah 4;
7 Jika siklus pengiriman 64, lanjutkan ke langkah 2.
; UART 9600/8N1 mov UART1_BRR2, #$00 ; mov UART1_BRR1, #$0D ; / mov UART1_CR2, #%00001100 ; SP $03FF ldw X, #$03FF ; X <= RAM END ldw SP, X ; SP <= X ; wait_rx_byte: btjf UART1_SR, #5, wait_rx_byte ; ld A, UART1_DR ; bset PB_DDR,#5 bset PB_CR1,#5 ldw Y, #64 ; Y <= 64 stack_cycle: ldw X, SP ; X <= SP ; SPH UART ; rlwa X ; A <- XH <- XL <- A ld A, XH ; A <- XH ld UART1_DR, A ; UART1_DR <= A wait_tx_byte_XH: btjf UART1_SR, #7, wait_tx_byte_XH ; SPL UART ; rlwa X ; A <- XH <- XL <- A ld A, XL ; A <- XL ld UART1_DR, A ; UART1_DR <= A wait_tx_byte_XL: btjf UART1_SR, #7, wait_tx_byte_XL ; A push A ; M(SP
Kami mengamati bagaimana program terminal secara berurutan menerima isi dari penunjuk SP mulai dari 0x03FF:
03 FF 03 FE 03 FD 03 FC 03 FB 03 FA 03 F9 03 F8 03 F7 03 F6 03 F5 03 F4 03 F3 03 F2 03 F1 03 F0 03 EF 03 EE 03 ED 03 EC 03 EB 03 EA 03 E9 03 E8 03 E7 03 E6 03 E5 03 E4 03 E3 03 E2 03 E1 03 E0 03 DF 03 DE 03 DD 03 DC 03 DB 03 DA 03 D9 03 D8
Setelah nilai mencapai 0x01FF (batas tumpukan yang dihitung sebelumnya)
penunjuk SP lagi mengambil nilai 0x03FF (tumpukan ditutup dalam cincin)
dan mulai menimpa data tertua
02 0F 02 0E 02 0D 02 0C 02 0B 02 0A 02 09 02 08 02 07 02 06 02 05 02 04 02 03 02 02 02 01 02 00 01 FF 03 FF 03 FE 03 FD 03 FC 03 FB 03 FA 03 F9 03 F8 03 F7 03 F6 03 F5 03 F4 03 F3 03 F2 03 F1 03 F0 03 EF 03 EE 03 ED 03 EC 03 EB 03 EA 03 E9
Sekarang mari kita lihat bagaimana isi dari pointer SP berperilaku jika kita mencoba untuk mengambil konten dari stack tanpa batas.
Algoritma Prosedur:
1 Inisialisasi penunjuk tumpukan dengan nilai 0x03FF dan konfigurasikan UART;
2 Kami menunggu byte dari program terminal;
3 byte diterima;
4 Kami mengekstrak konten dari tumpukan dengan perintah "pop A" ke baterai;
5 Mengirim konten pointer SP ke UART;
6 Jika siklus pengiriman kurang dari 64, lanjutkan ke langkah 3;
7 Jika siklus pengiriman 64, lanjutkan ke langkah 2.
Butir 4 dan 5 dari algoritma dan perintah "push A" ditukar dengan perintah "pop A".
Terlepas dari kenyataan bahwa kami menginisialisasi pointer SP dengan nilai 0x03FF sudah setelah perintah pop A pertama, pointer mengambil nilai 0x01FF dan terus meningkat menuju 0x03FF.
01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 02 11 02 12 02 13 02 14 02 15 02 16 02 17 02 18 02 19 02 1A 02 1B 02 1C 02 1D 02 1E 02 1F 02 20 02 21 02 22 02 23 02 24 02 25 02 26
Mencapai nilai 0x03FF. setelah perintah pop A berikutnya, pointer kembali mengasumsikan nilai 0x01FF dan terus meningkat menuju 0x03FF.
03 EF 03 F0 03 F1 03 F2 03 F3 03 F4 03 F5 03 F6 03 F7 03 F8 03 F9 03 FA 03 FB 03 FC 03 FD 03 FE 03 FF 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10 02 11 02 12 02 13 02 14 02 15
Dalam arah yang berlawanan, dengan jumlah pop (w) instruksi yang berlebihan, stack juga ditutup dalam ring 513-byte.
Tumpukan di STM8S103F3 adalah linier sampai Anda memecahkan salah satu perbatasannya 0x01FF atau 0x03FF.
Segera setelah Anda melanggar salah satu batas, tumpukan menjadi cincin 513-byte.
Tidak masalah di mana di atas ring (di alamat 0x01FF ... 0x03FF) bagian atas / bawah tumpukan akan ditemukan, kita dapat menempatkan jumlah byte yang tidak terbatas pada tumpukan, tetapi kita dapat mengekstrak tidak lebih dari 513 byte yang tidak rusak (yang terbaru).
Sekarang stack dilokalkan pada 0x01FF ... 0x03FF, saatnya untuk memecah rentang itu ketika menginisialisasi pointer SP.
Pada langkah 1 dari prosedur pertama, kami mengganti nilai 0x03FF untuk menginisialisasi penunjuk SP dengan nilai 0x01FE.
Kami mengamati bagaimana tumpukan dari alamat 0x01FE mengarah ke penurunan alamat.
01 FE 01 FD 01 FC 01 FB 01 FA 01 F9 01 F8 01 F7 01 F6 01 F5 01 F4 01 F3 01 F2 01 F1 01 F0 01 EF 01 EE 01 ED 01 EC 01 EB 01 EA 01 E9 01 E8 01 E7 01 E6 01 E5 01 E4 01 E3 01 E2 01 E1 01 E0 01 DF 01 DE 01 DD 01 DC 01 DB 01 DA 01 D9 01 D8 01 D7
Setelah mencapai alamat 0x0000, tumpukan keluar dari memori RAM dan masuk ke sel memori FLASH yang tidak dapat diakses ke STM8S103F3.
00 16 00 15 00 14 00 13 00 12 00 11 00 10 00 0F 00 0E 00 0D 00 0C 00 0B 00 0A 00 09 00 08 00 07 00 06 00 05 00 04 00 03 00 02 00 01 00 00 FF FF FF FE FF FD FF FC FF FB FF FA FF F9 FF F8 FF F7 FF F6 FF F5 FF F4 FF F3 FF F2 FF F1 FF F0 FF EF
Tidak ada pembicaraan tentang panggilan subrutin atau interupsi setelah pointer keluar dari memori RAM. Benar, di suatu tempat di kedalaman tumpukan data yang paling "kuno" masih ada, yang beruntung disimpan dalam memori RAM.
Sekarang mari kita coba mengambil data dari tumpukan dengan inisialisasi "terlarang" (di luar kisaran 0x01FF ... 0x03FF) dari penunjuk SP.
Mari kita mulai dengan alamat di luar RAM. Pada langkah 1 dari prosedur kedua, kami mengganti nilai 0x03FF inisialisasi pointer SP dengan nilai 0xFFF8.
Kami mengamati bagaimana tumpukan masuk ke memori RAM.
FF E9 FF EA FF EB FF EC FF ED FF EE FF EF FF F0 FF F1 FF F2 FF F3 FF F4 FF F5 FF F6 FF F7 FF F8 FF F9 FF FA FF FB FF FC FF FD FF FE FF FF 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00 10
Melintasi batas bawah 0x01FF, tumpukan memasuki wilayahnya.
01 E9 01 EA 01 EB 01 EC 01 ED 01 EE 01 EF 01 F0 01 F1 01 F2 01 F3 01 F4 01 F5 01 F6 01 F7 01 F8 01 F9 01 FA 01 FB 01 FC 01 FD 01 FE 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F 02 10
Setelah mencapai alamat 0x03FF, tumpukan ditutup dalam sebuah cincin.
03 E9 03 EA 03 EB 03 EC 03 ED 03 EE 03 EF 03 F0 03 F1 03 F2 03 F3 03 F4 03 F5 03 F6 03 F7 03 F8 03 F9 03 FA 03 FB 03 FC 03 FD 03 FE 03 FF 01 FF 02 00 02 01 02 02 02 03 02 04 02 05 02 06 02 07 02 08 02 09 02 0A 02 0B 02 0C 02 0D 02 0E 02 0F
Kesimpulan:
Tumpukan di STM8S103F3 mampu melakukan tugasnya hanya dalam kisaran 0x01FF ... 0x03FF.
Untuk mendapatkan kedalaman linier terbesar, penunjuk tumpukan SP di STM8S103F3 harus diinisialisasi ke 0x03FF.
Tumpukan di STM8S103F3 linier sampai Anda memutuskan batas bawah 0x01FF.
Segera setelah Anda menembus batas bawah, tumpukan menjadi cincin 513-byte.