pyz80 (2)

なんでこんなに z80 してるのか自分でも不思議。ただ、python な 1854 行のソースコードz80アセンブラが書けてるというのも色々な意味で不思議。
とりあえず命令コードの一覧をググりつつ、LD な命令について確認してみた。

まず、LD な op コードをナニしている手続きの最初らへんが以下。

def op_LD(p,opargs):
    check_args(opargs,2)
    arg1,arg2 = opargs.split(',',1)
    
    prefix, rr1 = double(arg1)
    if rr1 != '':
        prefix2, rr2 = double(arg2)
        if rr1==3 and rr2==2:
            instr = prefix
            instr.append(0xf9)
            dump(instr)
            return len(instr)

check_args で opargs の要素数 (?) のチェック (詳細略しますが、ここでは 2 つでないと翻訳は途中で終わり) をしてそれぞれを arg1 と arg2 に格納してます。多値を戻しておりますな。
で、上記引用の一番下のブロックですが、

F9 LD SP,HL

な命令にあたります。その所以は double という手続きを見れば分かります。

def double(arg, allow_af_instead_of_sp=0, allow_af_alt=0, allow_index=1):
# decode double register [bc, de, hl, sp][ix,iy] --special:  af af'
    double_mapping = {'BC':([],0), 'DE':([],1), 'HL':([],2), 'SP':([],3), 'IX':([0xdd],2), 'IY':([0xfd],2), 'AF':([],5), "AF'":([],4) }
    rr = double_mapping.get(arg.strip().upper(),([],''))
    if (rr[1]==3) and allow_af_instead_of_sp:
        rr = ([],'')
    if rr[1]==5:
        if allow_af_instead_of_sp:
            rr = ([],3)
        else:
            rr = ([],'')
    if (rr[1]==4) and not allow_af_alt:
        rr = ([],'')
    
    if (rr[0] != []) and not allow_index:
        rr = ([],'')
    
    return rr

double_mapping という辞書がなかなかポイント高い。if 文で微妙な処理をしてますが、ここではスルーします。python 的には

    rr = double_mapping.get(arg.strip().upper(),([],''))

は arg.strip().upper() な key が無ければ ([],'') を rr に格納、という事か。ちなみに rr2 に 2 が格納されるケイスとしては

  • 'HL':([],2)
  • 'IX':([0xdd],2)
  • 'IY':([0xfd],2)

というナニ。ですが、ざくっと一覧見た限りでは SP に LD する命令としては一つしか無い模様。で、以降のブロックですが rr1 が double なレジスタである、なブロックの続きとしてまず以下。

        match = re.search("\A\s*\(\s*(.*)\s*\)\s*\Z", arg2)
        if match:
            # ld rr, (nn)
            if p==2:
                nn = parse_expression(match.group(1),word=1)
            else:
                nn = 0
            instr = prefix
            if rr1==2:
                instr.extend([0x2a, nn%256, nn/256])
            else:
                instr.extend([0xed, 0x4b + 16*rr1, nn%256, nn/256])
            dump(instr)
            return len (instr)

おそらく arg2 の中身が (hoge) かどうか、な判定をしてる模様。そうであった場合は

            # ld rr, (nn)

というパターンな命令である、と。ここで rr1 が 2 の場合ですが

  • 'HL':([],2)
    • ([0x2a, nn%256, nn/256])
  • 'IX':([0xdd],2)
    • ([0xdd, 0x2a, nn%256, nn/256])
  • 'IY':([0xfd],2)
    • ([0xfd, 0x2a, nn%256, nn/256])

という形になるんかな。これはなかなか見事。あと、2 以外の場合どうなるか、というと

  • 'BC':([],0)
    • ([0xed, 0x4b, nn%256, nn/256])
  • 'DE':([],1)
    • ([0xed, 0x5b, nn%256, nn/256])
  • 'SP':([],3)
    • ([0xed, 0x7b, nn%256, nn/256])

というパターンがある模様。16*rr1 というのがなかなか凄い。なんでこんなに都合良い形でインストラクションが用意されているのかな。
あと何故に nn を 256 で割った余りと商なの? って思ったら 16 bits なアドレスをこーゆー形 (8bits なソレの組) で表現しているのか、と。

ちょっと休憩

というか、pass 1 とか 2 の意味が理解できてないので確認できたら別途、という事にて。