福野泰介の一日一創 - create every day

24KBに、ギリギリまで詰め込んだOS、IchigoJam BASIC。でも、もうちょっとだけ改善したい!

ということで、気になっていた4KBのRAM、特にスタックの使い方にメスをいれてみました。

普段使うMacやWindowsやLinuxに組み込まれている、怪しいアプリに大事な情報をアクセスさせないための基本機能。 RAM(LPC1114FDH28では4KB)の範囲を超えると一般保護違反として、例外「HaldFault」が発生します。

プログラマーなら押さえておきたい、基本データ構造のひとつ、後入れ先出し(LIFO)のスタック。 IchigoJamのCPU、LPC1114のアーキテクチャ、Cortex-M0のスタックは、使うほどにアドレスが小さい方向に動いていきます。 現状のIchigoJamの実装では、スタックがどのくらい使われるかはBASICで記述する数式に依存するので、超えないように時々監視しながら、Comprex expression エラーを出しています。ただ、やり口、速度面、プログラム量の面で、ちょっと不格好な点、実は気にしていました。

そこで今回、スタックの領域を一般的なRAMの後ろではなく、先頭側におき、RAMの領域を超えた際に発生する例外をうまいこと使おうという作戦。


ということで、まずはミニマムに実験! 再帰呼び出しでスタックを使い切ったら、soft_entryからリスタート!成功です。 スタート直後、わざとROM領域に書き込もうとして、例外を発生させ、スタックポインタを初期化してスタートする雛形ができました。

#include "LPC1100.h" static inline void led(int n) { GPIO1MASKED[1 << 5] = n << 5; } static inline void wait(int n) { for (volatile int i = 0; i < 50000 * n; i++); } void job(int n) { for (;;) { led(1); wait(1); led(0); wait(1); job(n++); // 再帰でstack溢れ -> HardFault -> soft_entry } } void soft_entry() { // ここからリスタートする wait(10); job(0); } void main() { // Reset_Handlerから呼び出される IOCON_PIO1_5 = 0x000000d0; GPIO1DIR = 1 << 5; *(char*)0 = 0; // アクセス違反 -> HaldFault -> soft_entry } void HardFault_Hander() { // 一般保護違反 RAMの範囲を超えたアクセスなど uint32_t* sp; // = 0x10000000 + 1024 - 32 __asm( "mov r1, #1\n" "mov %0, r1\n" "lsl %0, %0, #18\n" "add %0, %0, r1\n" "lsl %0, %0, #10\n" "sub %0, %0, #32\n" "mov sp, %0\n" : "=r" (sp) ); *(sp + 6) = (uint32_t)(void*)soft_entry; // set PC *(sp + 7) = (1 << 24); // need to set PSR, Thumb mode }

スタックを使い切ってしまっているので、通常の割り込み時にセットされているはずのデータはありません。なので、スタックを初期化して、復帰用のデータを捏造しています。 副次的に、Armマシン語でミスした際にも、復帰できる確率が上がって、よりプログラミングを楽しめるかも!? IchigoJamへの組み込み、がんばります。
はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

子供も大人も楽しい学びの場、地域ICTクラブ!
入り口は広くやさしく、でも、とんでもなく深く広いIT/プログラミングの世界、じっくりみんなで楽しみましょう!


今年の福井こどもプログラミング協議会、ますます楽しくなりそうです!
Thanks: 蕎麦と旨酒と 亀蔵 - 福井県鯖江市

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY 福野泰介 - Taisuke Fukuno / @taisukef / アイコン画像 / プロフィール画像