Z80アセンブラでFizzBuzz
レジスタ内容をダンプするシステムコール云々などと言ってましたが、もうちょっと複雑なアセンブラの動作確認がどうしてもしたくなって、BUSRQしてRAMを見にいく方法をさくっと試してみました。
今回のプログラムは遂にLチカを卒業して、FizzBuzzをやってみます。RAMに1からカウントアップする数字を書いていって、
としつつ100(0x64)まで数えます。
STACK: equ 0xf000 org 0x0000 ld sp,STACK ; Turn off LED ld a,0 out 0,a ; Do FizzBuzz ld b,100 ld hl,0xc000 call FIZBUZ ; Turn on LED ld a,1 out 0,a halt ; FizzBuzz counter ; [parameters] ; B -- a number upto which you want to play FizzBuzz ; HL -- starting address to record the result ; [result] ; The counted numbers are recorded in RAM from HL. FIZBUZ: ld a,0 _LOOP: inc a ; Is A divisible by 15? ld d,0x0f call CANDIV jp nz,_DIV3 ld c,0xfb ; Let's say FIZZBUZZ! jp _DUMP ; Is A divisible by 3? _DIV3: ld d,0x03 call CANDIV jp nz,_DIV5 ld c,0xff ; Let's say FIZZ! jp _DUMP ; Is A divisible by 5? _DIV5: ld d,0x05 call CANDIV jp nz,_NOP ld c,0xbb ; Let's say BUZZ! jp _DUMP _NOP: ld c,a ; Say it as it is. _DUMP: ld (hl),c inc hl djnz _LOOP ret ; CANDIV tests if A is divisible by D. ; [parameters] ; A -- dividend ; D -- divisor ; [result] ; F -- Z == 1 if divisible CANDIV: ld e,a _SUB: sub d jr z,_EXIT jp nc,_SUB _EXIT: ld a,e ret
どうってことない処理ですが、CANDIV(割り切れるか?)の実装はちょっと時間かかりました。 はじめは % (mod演算)を実装しようとしてたんですね。 すると余りを出すのに、ボローが出たら除数を足すか、計算過程を1回分キャッシュするかというわちゃっとした解法しかすぐに浮かばなくて悩みました。 でもよく考えたら「割り切れるかどうか」だけ分かればいいので、Aがゼロになるかボローが出るかを見るだけでいいですよね。 これならまぁ、正解に近い感じがします。
さて、上記コードをアセンブルして実行すると0xc000番地からFizzBuzzの結果が書き込まれるはずです。 前回までは「アセンブルした機械語をArduinoファームウェアのソースにuint8の配列として埋め込む」という原始的な方法でプログラミングしていましたが、 今回はCUIソフトも作ったので、転送→実行→停止→確認がPC側から全部行えるようになりました。
以下、その操作ログです。
$ ./loader.rb requesting connection.. connected! MAX_BLOCK_SIZE: 96 erasing RAM data...done in 0.10248114200021519 sec. cmd?> wfile fizzbuzz.rom programming the romfile...done in 0.012214564000259998 sec. reading back the romfile to verify...done in 0.020541404000141483 sec. SUCCEEDED!! dumped the readback image to "_fizzbuzz.rom" cmd?> reset let the board...GO! cmd?> busrq requesting bus control...accepted! cmd?> dump c000 100 01 02 ff 04 bb ff 07 08 ff bb 0b ff 0d 0e fb 10 11 ff 13 bb ff 16 17 ff bb 1a ff 1c 1d fb 1f 20 ff 22 bb ff 25 26 ff bb 29 ff 2b 2c fb 2e 2f ff 31 bb ff 34 35 ff bb 38 ff 3a 3b fb 3d 3e ff 40 bb ff 43 44 ff bb 47 ff 49 4a fb 4c 4d ff 4f bb ff 52 53 ff bb 56 ff 58 59 fb 5b 5c ff 5e bb ff 61 62 ff bb cmd?> exit $
GOOD!