branch と daa 以外は大体調べました。長いので 0x20 ごとに区切ります。
- op: opcode
- name: 基本 6809 と同じだが、独自拡張はMAMEの物だったりそれを改称したもの
- mode: addressing mode
- inh: inherent
- ind: indexed
- r8: relative signed 8bit
- r16: relative 16bit
- ~: 命令読み込み後に動くまでの待ちクロック数
- operation/note: 動作および補足
- [address]: address の data を読み込む
- [address].w: address の data と address + 1 の data を読み込み bigendian 16bit として扱う
- ; 命令実行 + clock 消費 (だと思う)
- , 並列命令実行
- 各演算子は 6809 addressing > Verilog Bitslice > C の優先度で同じ (6809 addressing の s++ は C では s += 2であり、C の s++ は s += 1 だから 6809 addressing を使う)
- A - imm など = がついていない -, & は比較して CC だけに反映
0x00-0x1f
op name mode ~ |operation/note ---------------------------------- 00 sres inh 2 |dp = 0, pc = [0xfffe].w (nmi許可は変更しない) 01 sync inh ? |wait interrupt 02 snmi inh 5 |pushs all; pc = [0xfffc].w (lds しなくても動く) 03 sfirq inh 3 |pushs cc,pc; pc = [0xfff6].w 04 sirq inh 5 |pushs all; pc = [0xfff8].w 05 sync? 06 sync? 07 sync? 08 leax ind 4 |x = ea 09 leay ind 4 |y = ea 0a leau ind 4 |u = ea 0b leas ind 4 |s = ea (nmi許可は変更しない) 0c pushs imm 5*|[-s] = x/y/u/pc lo->hi; [-s] = cc/a/b/dp.hi; 0d pushu imm 5*|[-u] = x/y/s/pc lo->hi; [-u] = cc/a/b/dp.hi; 0e pulls imm 5*|[s+]=pc/u/y/x hi->lo; [s+] = dp.hi/b/a/cc (nmi許可は変更しない) 0f pullu imm 5*|[u+]=pc/s/y/x hi->lo; [u+] = dp.hi/b/a/cc 10 lda imm 1 |a = imm 11 ldb imm 1 |b = imm 12 lda ind 0 |a = [ea] 13 ldb ind 0 |b = [ea] 14 adda imm 0 |a += imm 15 addb imm 0 |b += imm 16 adda imm 0 |a += [ea] 17 addb imm 0 |b += [ea] 18 adca imm 0 |a += imm + c 19 adcb imm 0 |b += imm + c 1a adca ind 0 |a += [ea] + c 1b adcb ind 0 |b += [ea] + c 1c suba imm 0 |a -= imm 1d subb imm 0 |b -= imm 1e suba ind 0 |a -= [ea] 1f subb ind 0 |b -= [ea]
- 未判明の 00 から 07 はソフトウェア割り込み関連です。
- snmi, sirq, sfirq は PC が increment されないバグがあるようで実用には向いていません.
- lea の indexed は ea が [ea] にならないので mode を別の扱いで考え直そうと思います。
- push の register は下位 byte -> 上位 byte の順に書く
- push と pull の計算数は複雑で別項を末尾に設けました。
0x20-0x3f
op name mode ~ |operation/note ---------------------------------- 20 sbca imm 0 |a -= imm + c 21 sbcb imm 0 |b -= imm + c 22 sbca ind 0 |a += [ea] + c 23 sbcb ind 0 |b += [ea] + c 24 anda imm 1 |a &= imm 25 andb imm 1 |b &= imm 26 anda ind 1 |a &= [ea] 27 andb ind 1 |b &= [ea] 28 bita imm 1 |a & imm 29 bitb imm 1 |b & imm 2a bita ind 1 |a & [ea] 2b bitb ind 1 |b & [ea] 2c eora imm 1 |a ^= imm 2d eorb imm 1 |b ^= imm 2e eora ind 1 |a ^= [ea] 2f eorb ind 1 |b ^= [ea] 30 ora imm 1 |a |= imm 31 orb imm 1 |b |= imm 32 ora ind 1 |a |= [ea] 33 orb ind 1 |b |= [ea] 34 cmpa imm 0 |a - imm 35 cmpb imm 0 |b - imm 36 cmpa ind 0 |a - [ea] 37 cmpb ind 0 |b - [ea] 38 ldp imm 1 |p = imm (setlines から改称) 39 ldp ind 1 |p = [ea](setlines から改称) 3a sta ind 1 |[ea] = a 3b stb ind 1 |[ea] = b 3c andcc imm 1 |cc &= imm 3d orcc imm 1 |cc |= imm 3e (exg) imm 0 ;imm bit7 == 0 exg / bit7 == 1 tfr 3f (tfr) imm 0 ;0x3e と同じ
- P は回路図上 A23:16 に反映される 8bit レジスタ (勝手に名前を付けた)
- 0x3e, 0x3f
- imm の bit7 で operation が決まり、 opcode の違いはないようです.
0x40-0x5f
op name mode ~ |operation/note ---------------------------------- 40 ldd imm 0 |d = imm 41 ldd ind 0 |d = [ea].w 42 ldx imm 0 |x = imm 43 ldx ind 0 |x = [ea].w 44 ldy imm 0 |y = imm 45 ldy ind 0 |y = [ea].w 46 ldu imm 0 |u = imm 47 ldu ind 0 |u = [ea].w 48 lds imm 0 |s = imm, nmiflag = 1 49 lds ind 0 |s = [ea].w, nmiflag = 1 4a cmpd imm 1 |d - imm 4b cmpd ind 0 |d - [ea].w 4c cmpx imm 0 |x - imm 4d cmpx ind 0 |x - [ea].w 4e cmpy imm 0 |y - imm 4f cmpy ind 0 |y - [ea].w 50 cmpu imm 0 |u - imm 51 cmpu ind 0 |u - [ea].w 52 cmps imm 0 |s - imm 53 cmps ind 0 |s - [ea].w 54 addd imm 1 |d += imm 55 addd ind 0 |d += [ea].w 56 subd imm 1 |d -= imm 57 subd ind 0 |d -= [ea].w 58 std ind 1 |[ea].w = d 59 stx ind 1 |[ea].w = x 5a sty ind 1 |[ea].w = y 5b stu ind 1 |[ea].w = u 5c sts ind 1 |[ea].w = s 5d swi inh 5*|pushs all; pc = [0xfffa].w 5e swi2 inh 4*|pushs all; pc = [0xfff4].w 5f swi3 inh 4*|pushs all; pc = [0xfff2].w
- cmpd が何故か他の cmp とくらべて 1 clock 遅いです。
- swi, swi2, swi3 については pushs の動作をしますのでさらに pushs の clock 数の特殊な計算が正確な値になります。
0x60-0x7f
branch ですが、 brn, lbrn を調査しただけなので今日の時点では記載しません。
0x80-0x9f
op name mode ~ |operation/note ---------------------------------- 80 clra inh 0 |a = 0 81 clrb inh 0 |b = 0 82 clr ind 1 |[ea] = 0 83 coma inh 0 |a = ~a 84 comb inh 0 |b = ~b 85 com ind 0 |temp = [ea]; [ea] = ~temp 86 nega inh 1 |a = -a 87 negb inh 1 |b = -b 88 neg ind 1 |temp = [ea]; [ea] = -temp 89 inca inh 0 |a += 1 8a incb inh 0 |b += 1 8b inc ind 0 |temp = [ea]; [ea] = temp + 1 8c deca inh 0 |a -= 1 8d decb inh 0 |b -= 1 8e dec ind 0 |temp = [ea]; [ea] = temp - 1 8f rts inh 2 |pc = [s++].w 90 tsta inh 0 |a - 0 91 tstb inh 0 |b - 0 92 tst ind 0 |temp = [ea]; temp - 0 93 lsra inh 0 |a = {1'b0, a[7:1]} 94 lsrb inh 0 |b = {1'b0, b[7:1]} 95 lsr ind 0 |temp = [ea]; [ea] = {1'b0, temp[7:1]} 96 rora inh 0 |a = {c, a[7:1]} 97 rorb inh 0 |b = {c, b[7:1]} 98 ror ind 0 |temp = [ea]; [ea] = {c, temp[7:1]} 99 asra inh 0 |a = {a[7], a[7:1}} 9a asrb inh 0 |b = {b[7], b[7:1]} 9b asr ind 0 |temp = [ea]; [ea] = {temp[7], temp[7:1]} 9c asla inh 0 |a = {a[6:0], 1'b0} 9d aslb inh 0 |b = {b[6:0], 1'b0} 9e asl ind 0 |temp = [ea]; [ea] = {temp[6:0], 1'b0} 9f rti inh 2*|pulls all / pulls cc,pc
- MAME のコードで未確認となっていましたが動作は合っていました。
- rti は pulls を内部実行するので clock の計算が特殊です。
0xa0-0xb7
op name mode ~ |operation/note ---------------------------------- a0 rola inh 0 |a = {a[6:0], c} a1 rolb inh 0 |b = {b[6:0], c} a2 rol ind 0 |temp = [ea]; [ea] = {temp; [6:0], c} a3 lsrw ind 2 |temp = [ea].w; [ea].w = {1'b0, temp[15:1]} a4 rorw ind 2 |temp = [ea].w; [ea].w = {c, temp[15:1]} a5 asrw ind 2 |temp = [ea].w; [ea].w = {temp[15], temp[15:1]} a6 aslw ind 0 |temp = [ea].w; [ea].w = {temp[14:0], 1'b0} a7 rolw ind 0 |temp = [ea].w; [ea].w = {temp[14:0], c} a8 jmp ind 1 |pc = ea a9 jsr ind 1 |[-s] = pc.lo; [-s] = pc.hi; pc = ea aa bsr r8 3 |[-s] = pc.lo; [-s] = pc.hi; pc += signed(rel) ab lbsr r16 1 |[-s] = pc.lo; [-s] = pc.hi; pc += rel.w ac dbbne r8? 2*|b-=1; if(b != 0) pc += signed(rel) else pc += 1 ad dxbne r8? 2*|x-=1; if(x != 0) pc += signed(rel) else pc += 1 ae nop inh 0 |(nothing) af sync inh ? |wait interrupt b0 abx inh 0 |x += {8'h00, b} b1 daa inh ? |(あとで調べる) b2 sex inh 0 |D = signed(B) b3 mul inh 12 |D = a * b b4 lmul inh 18 |temp = x * y; x = temp[31:16], y = temp[15:0] b5 div inh 18 |(b != 0 の場合) x = x / b, b = x %b |(b == 0 の場合) x = 0xffff, b = 0xff b6 bmove inh 2 |nn: [x+] = [y+], u-=1; bne nn b7 move inh 2 |[x+] = [y+], u-=1;
- jmp, jsr も lea 同様 ea を直接使う addressing です。
- 右シフト命令: byte order の都合で待ちが発生するので左シフトと比べて 2clock 必要なようです。
- ac, ad: 名前が長いので勝手にかえました。動作は同じです。
- b == 0 の場合、何故か pc が1つ余計に進むようです.(?)
- branch すると + 1 clock です。
- af: sync で重複命令です。いまのところの調査で 6809 にある命令で見つかっていないのが CWAI です。リストアップした sync のどれかが CWAI かもしれませんが、 IRQ を発生させて確認しているはずです。
- b1: daa は計測時間が複雑なので後日全通り調べます。
- b5: div で除数に 0 をいれても例外ジャンプは発生せずに X と B の全ビットが1に埋まりました。
- b6: Z80 でいうところの ldir に相当しますが、 opcode の読み直しがなく src read と dest write を順番に繰り返します。
0xb8- 以降
052001 では不可解な動作をしますので、不正な命令なようです。ただし、 053248 では使われている命令が多数有ります。
そもそもこの CPU を調査しようとしたきっかけが 0xb8 の lsrd と名前を仕えられている命令でした。他のシフト/ローテート命令は1回の動作ですが、これは a の数だけシフトすることを見つけました。
ですので 052001 でこれらが動かなくてちょっと残念です。
push/pull の clock 数の計算方法
immediate で各 bit が 1 になっているかで待ちが 5 から 13, 追加参照バイト数は 12 から 0 になります。
- immediate を読んでから 3 clock の待ちが発生します
- その後 1bit ずつ bit を参照します。
- bit が 0 の場合は何もしないので 1 clock の待ち
- bit が 1 の場合は push か pull をするので 1 か 2 byte のメモリアクセスが発生しますが、待ちはなくなります。
- 8bit 参照後に復帰までに 2 clock の待ちが発生します。