下記のサイトに、同一プログラムを各種CPUで書いた比較記事が掲載されている。MC6800だとどうなるか、PRNG(擬似乱数)プログラムを書いてみた。
- Getting a Decent and Fast PRNG Out of an 8-Bit Chip | Bumbershoot Software
- Comparing an LZ4 Decompressor on Four Legacy CPUs | Bumbershoot Software
お題:擬似乱数プログラム
周期が 2^32-1 である擬似乱数を作成するコードである。Cで書くと下記の通り。0は生成されないので要注意。
uint16_t rnd_xorshift_32() { static uint16_t x=1,y=1; uint16_t t=(x^(x<<5)); x=y; return y=(y^(y>>1))^(t^(t>>3)); }
素直にMC6800で書いてみる
chibiccから関数として呼べる形で書いてみた。変数がxx,yy,ttなのは、x がレジスタ名と衝突して使えなかったから(as6800の制限)。
メモリを節約するために x/y/zにはインデックスレジスタ経由でアクセスしているが、ダイレクトページが使えるなら その方が早い。
40命令、62バイトである。データ部分が別に6バイト。
.data xyt: .word 1 .word 1 .word 0 xx .equ 0 yy .equ 2 tt .equ 4 .code .export _asm_xorshift_32 _asm_xorshift_32: ldx #xyt ; t = x^(x<<5); ldab xx+1,x ldaa xx,x aslb rola aslb rola aslb rola aslb rola aslb rola eorb xx+1,x eora xx,x ; t = t^(t>>3); stab tt+1,x staa tt,x lsra rorb lsra rorb lsra rorb eorb tt+1,x eora tt,x stab tt+1,x staa tt,x ; x = y ldab yy+1,x ldaa yy,x stab xx+1,x staa xx,x ; tmp = y^(y>>1); lsra rorb eorb yy+1,x eora yy,x ; y = tmp ^ t; eorb tt+1,x eora tt,x stab yy+1,x staa yy,x rts
6502版と比べてみる
6502版では、x<<5 と t>>3 はループで書かれている。6502でアキュムレータは1つしかなく、残り8bitはメモリシフトを使っている。
メモリシフトに絶対アドレッシングを使うので、1bitシフトするのに4バイト使う(lsr / ror _x)。
ループのために(ldx #$03 … dex / bne _lp2)の5バイトを使っても元が取れる。
MC6800では16bit数値のシフトは lsra / rorb の2バイトで足りるし、ループに6バイト使う。元が取れないので、素直にシフト命令を並べている。
もうちょっとだけ短くする
x<<5 の部分は ほんの少しだけ短くできる。左に5bitシフトする代わりに、右に3bitシフトすれば良い。
一見すると最後に入れ替えが必要に思えるが、最初にAccABに読み込むときに逆に読んでおけば良い。
右からキャリーに溢れた1bitを回収するのと 下位ビットを0クリアする処理が必要。2命令・1バイトだけ小さくなる(38命令、61バイト)。
ldab xx,x ldaa xx+1,x lsrb rora rorb rora rorb rora rorb andb #$e0
もっと小さくできるだろうか?

コメント