052001 operation 一覧

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 の待ちが発生します。