#/usr/bin/env perl -w

# create i8080 instruction table
# containing (low-byte) FLASH pointers
# to assembly snippets in the emulator

# must be regenerated when recompiling the emulator

# this is a workaround for a limitation in avr-as,
# since avr-as does not support pm_lo8(sym) for data symbols

use strict;
use warnings;
use v5.010;

my @instrs = (
    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 00       : NOP
    [ "fetch_dir16", "exec_nop",   "store_bc",   10 ], # 01 nn nn : LXI B, d16
    [ "fetch_a",     "exec_nop",   "store_mbc",   7 ], # 02       : STAX B
    [ "fetch_bc",    "exec_inc16", "store_bc",    5 ], # 03       : INX B
    [ "fetch_b",     "exec_inc",   "store_b",     5 ], # 04       : INR B
    [ "fetch_b",     "exec_dec",   "store_b",     5 ], # 05       : DCR B
    [ "fetch_dir8",  "exec_nop",   "store_b",     7 ], # 06 nn    : MVI B, d8
    [ "fetch_nop",   "exec_rlca",  "store_nop",   4 ], # 07       : RLC
    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 08       : *NOP
    [ "fetch_bc",    "exec_addhl", "store_nop",  10 ], # 09       : DAD B
    [ "fetch_mbc",   "exec_nop",   "store_a",     7 ], # 0a       : LDAX B
    [ "fetch_bc",    "exec_dec16", "store_bc",    5 ], # 0b       : DCX B
    [ "fetch_c",     "exec_inc",   "store_c",     5 ], # 0c       : INR C
    [ "fetch_c",     "exec_dec",   "store_c",     5 ], # 0d       : DCR C
    [ "fetch_dir8",  "exec_nop",   "store_c",     7 ], # 0e nn    : MVI C, d8
    [ "fetch_nop",   "exec_rrca",  "store_nop",   4 ], # 0f       : RRC

    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 10       : *NOP
    [ "fetch_dir16", "exec_nop",   "store_de",   10 ], # 11 nn nn : LXI D, d16
    [ "fetch_a",     "exec_nop",   "store_mde",   7 ], # 12       : STAX D
    [ "fetch_de",    "exec_inc16", "store_de",    5 ], # 13       : INX D
    [ "fetch_d",     "exec_inc",   "store_d",     5 ], # 14       : INR D
    [ "fetch_d",     "exec_dec",   "store_d",     5 ], # 15       : DCR D
    [ "fetch_dir8",  "exec_nop",   "store_d",     7 ], # 16 nn    : MVI D, d8
    [ "fetch_nop",   "exec_rla",   "store_nop",   4 ], # 17       : RAL
    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 18       : *NOP
    [ "fetch_de",    "exec_addhl", "store_nop",  10 ], # 19       : DAD D
    [ "fetch_mde",   "exec_nop",   "store_a",     7 ], # 1a       : LDAX D
    [ "fetch_de",    "exec_dec16", "store_de",    5 ], # 1b       : DCX D
    [ "fetch_e",     "exec_inc",   "store_e",     5 ], # 1c       : INR E
    [ "fetch_e",     "exec_dec",   "store_e",     5 ], # 1d       : DCR E
    [ "fetch_dir8",  "exec_nop",   "store_e",     7 ], # 1e nn    : MVI E, d8
    [ "fetch_nop",   "exec_rra",   "store_nop",   4 ], # 1f       : RAR

    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 20       : *NOP
    [ "fetch_dir16", "exec_nop",   "store_hl",   10 ], # 21 nn nn : LXI H, d16
    [ "fetch_dir16", "exec_sthl",  "store_nop",  16 ], # 22 nn nn : SHLD a16
    [ "fetch_hl",    "exec_inc16", "store_hl",    5 ], # 23       : INX H
    [ "fetch_h",     "exec_inc",   "store_h",     5 ], # 24       : INR H
    [ "fetch_h",     "exec_dec",   "store_h",     5 ], # 25       : DCR H
    [ "fetch_dir8",  "exec_nop",   "store_h",     7 ], # 26 nn    : MVI H, d8
    [ "fetch_a",     "exec_da",    "store_a",     4 ], # 27       : DAA
    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 28       : *NOP
    [ "fetch_hl",    "exec_addhl", "store_nop",  10 ], # 29       : DAD H
    [ "fetch_dir16", "exec_rmem16","store_hl",   16 ], # 2a nn nn : LHLD a16
    [ "fetch_hl",    "exec_dec16", "store_hl",    5 ], # 2b       : DCX H
    [ "fetch_l",     "exec_inc",   "store_l",     5 ], # 2c       : INR L
    [ "fetch_l",     "exec_dec",   "store_l",     5 ], # 2d       : DCR L
    [ "fetch_dir8",  "exec_nop",   "store_l",     7 ], # 2e nn    : MVI L, d8
    [ "fetch_nop",   "exec_cpla",  "store_nop",   4 ], # 2f       : CMA

    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 30       : *NOP
    [ "fetch_dir16", "exec_nop",   "store_sp",   10 ], # 31 nn nn : LXI SP, d16
    [ "fetch_dir16", "exec_nop",   "store_ma",   13 ], # 32 nn nn : STA a16
    [ "fetch_sp",    "exec_inc16", "store_sp",    5 ], # 33       : INX SP
    [ "fetch_mhl",   "exec_inc",   "store_mhl",  10 ], # 34       : INR M
    [ "fetch_mhl",   "exec_dec",   "store_mhl",  10 ], # 35       : DCR M
    [ "fetch_dir8",  "exec_nop",   "store_mhl",  10 ], # 36 nn    : MVI M, d8
    [ "fetch_nop",   "exec_scf",   "store_nop",   4 ], # 37       : STC
    [ "fetch_nop",   "exec_nop",   "store_nop",   4 ], # 38       : *NOP
    [ "fetch_sp",    "exec_addhl", "store_nop",  10 ], # 39       : DAD SP
    [ "fetch_dir16", "exec_rmem8", "store_a",    13 ], # 3a nn nn : LDA a16
    [ "fetch_sp",    "exec_dec16", "store_sp",    5 ], # 3b       : DCX SP
    [ "fetch_a",     "exec_inc",   "store_a",     5 ], # 3c       : INR A
    [ "fetch_a",     "exec_dec",   "store_a",     5 ], # 3d       : DCR A
    [ "fetch_dir8",  "exec_nop",   "store_a",     7 ], # 3e nn    : MVI A, d8
    [ "fetch_nop",   "exec_ccf",   "store_nop",   4 ], # 3f       : CMC

    [ "fetch_b",     "exec_nop",   "store_b",     5 ], # 40       : MOV B, B
    [ "fetch_c",     "exec_nop",   "store_b",     5 ], # 41       : MOV B, C
    [ "fetch_d",     "exec_nop",   "store_b",     5 ], # 42       : MOV B, D
    [ "fetch_e",     "exec_nop",   "store_b",     5 ], # 43       : MOV B, E
    [ "fetch_h",     "exec_nop",   "store_b",     5 ], # 44       : MOV B, H
    [ "fetch_l",     "exec_nop",   "store_b",     5 ], # 45       : MOV B, L
    [ "fetch_mhl",   "exec_nop",   "store_b",     7 ], # 46       : MOV B, M
    [ "fetch_a",     "exec_nop",   "store_b",     5 ], # 47       : MOV B, A
    [ "fetch_b",     "exec_nop",   "store_c",     5 ], # 48       : MOV C, B
    [ "fetch_c",     "exec_nop",   "store_c",     5 ], # 49       : MOV C, C
    [ "fetch_d",     "exec_nop",   "store_c",     5 ], # 4a       : MOV C, D
    [ "fetch_e",     "exec_nop",   "store_c",     5 ], # 4b       : MOV C, E
    [ "fetch_h",     "exec_nop",   "store_c",     5 ], # 4c       : MOV C, H
    [ "fetch_l",     "exec_nop",   "store_c",     5 ], # 4d       : MOV C, L
    [ "fetch_mhl",   "exec_nop",   "store_c",     7 ], # 4e       : MOV C, M
    [ "fetch_a",     "exec_nop",   "store_c",     5 ], # 4f       : MOV C, A

    [ "fetch_b",     "exec_nop",   "store_d",     5 ], # 50       : MOV D, B
    [ "fetch_c",     "exec_nop",   "store_d",     5 ], # 51       : MOV D, C
    [ "fetch_d",     "exec_nop",   "store_d",     5 ], # 52       : MOV D, D
    [ "fetch_e",     "exec_nop",   "store_d",     5 ], # 53       : MOV D, E
    [ "fetch_h",     "exec_nop",   "store_d",     5 ], # 54       : MOV D, H
    [ "fetch_l",     "exec_nop",   "store_d",     5 ], # 55       : MOV D, L
    [ "fetch_mhl",   "exec_nop",   "store_d",     7 ], # 56       : MOV D, M
    [ "fetch_a",     "exec_nop",   "store_d",     5 ], # 57       : MOV D, A
    [ "fetch_b",     "exec_nop",   "store_e",     5 ], # 58       : MOV E, B
    [ "fetch_c",     "exec_nop",   "store_e",     5 ], # 59       : MOV E, C
    [ "fetch_d",     "exec_nop",   "store_e",     5 ], # 5a       : MOV E, D
    [ "fetch_e",     "exec_nop",   "store_e",     5 ], # 5b       : MOV E, E
    [ "fetch_h",     "exec_nop",   "store_e",     5 ], # 5c       : MOV E, H
    [ "fetch_l",     "exec_nop",   "store_e",     5 ], # 5d       : MOV E, L
    [ "fetch_mhl",   "exec_nop",   "store_e",     7 ], # 5e       : MOV E, M
    [ "fetch_a",     "exec_nop",   "store_e",     5 ], # 5f       : MOV E, A

    [ "fetch_b",     "exec_nop",   "store_h",     5 ], # 60       : MOV H, B
    [ "fetch_c",     "exec_nop",   "store_h",     5 ], # 61       : MOV H, C
    [ "fetch_d",     "exec_nop",   "store_h",     5 ], # 62       : MOV H, D
    [ "fetch_e",     "exec_nop",   "store_h",     5 ], # 63       : MOV H, E
    [ "fetch_h",     "exec_nop",   "store_h",     5 ], # 64       : MOV H, H
    [ "fetch_l",     "exec_nop",   "store_h",     5 ], # 65       : MOV H, L
    [ "fetch_mhl",   "exec_nop",   "store_h",     7 ], # 66       : MOV H, M
    [ "fetch_a",     "exec_nop",   "store_h",     5 ], # 67       : MOV H, A
    [ "fetch_b",     "exec_nop",   "store_l",     5 ], # 68       : MOV L, B
    [ "fetch_c",     "exec_nop",   "store_l",     5 ], # 69       : MOV L, C
    [ "fetch_d",     "exec_nop",   "store_l",     5 ], # 6a       : MOV L, D
    [ "fetch_e",     "exec_nop",   "store_l",     5 ], # 6b       : MOV L, E
    [ "fetch_h",     "exec_nop",   "store_l",     5 ], # 6c       : MOV L, H
    [ "fetch_l",     "exec_nop",   "store_l",     5 ], # 6d       : MOV L, L
    [ "fetch_mhl",   "exec_nop",   "store_l",     7 ], # 6e       : MOV L, M
    [ "fetch_a",     "exec_nop",   "store_l",     5 ], # 6f       : MOV L, A

    [ "fetch_b",     "exec_nop",   "store_mhl",   7 ], # 70       : MOV M, B
    [ "fetch_c",     "exec_nop",   "store_mhl",   7 ], # 71       : MOV M, C
    [ "fetch_d",     "exec_nop",   "store_mhl",   7 ], # 72       : MOV M, D
    [ "fetch_e",     "exec_nop",   "store_mhl",   7 ], # 73       : MOV M, E
    [ "fetch_h",     "exec_nop",   "store_mhl",   7 ], # 74       : MOV M, H
    [ "fetch_l",     "exec_nop",   "store_mhl",   7 ], # 75       : MOV M, L
    [ "fetch_nop",   "exec_hlt",   "store_nop",   7 ], # 76       : HLT
    [ "fetch_a",     "exec_nop",   "store_mhl",   7 ], # 77       : MOV M, A
    [ "fetch_b",     "exec_nop",   "store_a",     5 ], # 78       : MOV A, B
    [ "fetch_c",     "exec_nop",   "store_a",     5 ], # 79       : MOV A, C
    [ "fetch_d",     "exec_nop",   "store_a",     5 ], # 7a       : MOV A, D
    [ "fetch_e",     "exec_nop",   "store_a",     5 ], # 7b       : MOV A, E
    [ "fetch_h",     "exec_nop",   "store_a",     5 ], # 7c       : MOV A, H
    [ "fetch_l",     "exec_nop",   "store_a",     5 ], # 7d       : MOV A, L
    [ "fetch_mhl",   "exec_nop",   "store_a",     7 ], # 7e       : MOV A, M
    [ "fetch_a",     "exec_nop",   "store_a",     5 ], # 7f       : MOV A, A

    [ "fetch_b",     "exec_adda",  "store_nop",   4 ], # 80       : ADD B
    [ "fetch_c",     "exec_adda",  "store_nop",   4 ], # 81       : ADD C
    [ "fetch_d",     "exec_adda",  "store_nop",   4 ], # 82       : ADD D
    [ "fetch_e",     "exec_adda",  "store_nop",   4 ], # 83       : ADD E
    [ "fetch_h",     "exec_adda",  "store_nop",   4 ], # 84       : ADD H
    [ "fetch_l",     "exec_adda",  "store_nop",   4 ], # 85       : ADD L
    [ "fetch_mhl",   "exec_adda",  "store_nop",   7 ], # 86       : ADD M
    [ "fetch_a",     "exec_adda",  "store_nop",   4 ], # 87       : ADD A
    [ "fetch_b",     "exec_adca",  "store_nop",   4 ], # 88       : ADC B
    [ "fetch_c",     "exec_adca",  "store_nop",   4 ], # 89       : ADC C
    [ "fetch_d",     "exec_adca",  "store_nop",   4 ], # 8a       : ADC D
    [ "fetch_e",     "exec_adca",  "store_nop",   4 ], # 8b       : ADC E
    [ "fetch_h",     "exec_adca",  "store_nop",   4 ], # 8c       : ADC H
    [ "fetch_l",     "exec_adca",  "store_nop",   4 ], # 8d       : ADC L
    [ "fetch_mhl",   "exec_adca",  "store_nop",   7 ], # 8e       : ADC M
    [ "fetch_a",     "exec_adca",  "store_nop",   4 ], # 8f       : ADC A

    [ "fetch_b",     "exec_suba",  "store_nop",   4 ], # 90       : SUB B
    [ "fetch_c",     "exec_suba",  "store_nop",   4 ], # 91       : SUB C
    [ "fetch_d",     "exec_suba",  "store_nop",   4 ], # 92       : SUB D
    [ "fetch_e",     "exec_suba",  "store_nop",   4 ], # 93       : SUB E
    [ "fetch_h",     "exec_suba",  "store_nop",   4 ], # 94       : SUB H
    [ "fetch_l",     "exec_suba",  "store_nop",   4 ], # 95       : SUB L
    [ "fetch_mhl",   "exec_suba",  "store_nop",   7 ], # 96       : SUB M
    [ "fetch_a",     "exec_suba",  "store_nop",   4 ], # 97       : SUB A
    [ "fetch_b",     "exec_sbca",  "store_nop",   4 ], # 98       : SBB B
    [ "fetch_c",     "exec_sbca",  "store_nop",   4 ], # 99       : SBB C
    [ "fetch_d",     "exec_sbca",  "store_nop",   4 ], # 9a       : SBB D
    [ "fetch_e",     "exec_sbca",  "store_nop",   4 ], # 9b       : SBB E
    [ "fetch_h",     "exec_sbca",  "store_nop",   4 ], # 9c       : SBB H
    [ "fetch_l",     "exec_sbca",  "store_nop",   4 ], # 9d       : SBB L
    [ "fetch_mhl",   "exec_sbca",  "store_nop",   7 ], # 9e       : SBB M
    [ "fetch_a",     "exec_sbca",  "store_nop",   4 ], # 9f       : SBB A

    [ "fetch_b",     "exec_anda",  "store_nop",   4 ], # a0       : ANA B
    [ "fetch_c",     "exec_anda",  "store_nop",   4 ], # a1       : ANA C
    [ "fetch_d",     "exec_anda",  "store_nop",   4 ], # a2       : ANA D
    [ "fetch_e",     "exec_anda",  "store_nop",   4 ], # a3       : ANA E
    [ "fetch_h",     "exec_anda",  "store_nop",   4 ], # a4       : ANA H
    [ "fetch_l",     "exec_anda",  "store_nop",   4 ], # a5       : ANA L
    [ "fetch_mhl",   "exec_anda",  "store_nop",   7 ], # a6       : ANA M
    [ "fetch_a",     "exec_anda",  "store_nop",   4 ], # a7       : ANA A
    [ "fetch_b",     "exec_xora",  "store_nop",   4 ], # a8       : XRA B
    [ "fetch_c",     "exec_xora",  "store_nop",   4 ], # a9       : XRA C
    [ "fetch_d",     "exec_xora",  "store_nop",   4 ], # aa       : XRA D
    [ "fetch_e",     "exec_xora",  "store_nop",   4 ], # ab       : XRA E
    [ "fetch_h",     "exec_xora",  "store_nop",   4 ], # ac       : XRA H
    [ "fetch_l",     "exec_xora",  "store_nop",   4 ], # ad       : XRA L
    [ "fetch_mhl",   "exec_xora",  "store_nop",   7 ], # ae       : XRA M
    [ "fetch_a",     "exec_xora",  "store_nop",   4 ], # af       : XRA A

    [ "fetch_b",     "exec_ora",   "store_nop",   4 ], # b0       : ORA B
    [ "fetch_c",     "exec_ora",   "store_nop",   4 ], # b1       : ORA C
    [ "fetch_d",     "exec_ora",   "store_nop",   4 ], # b2       : ORA D
    [ "fetch_e",     "exec_ora",   "store_nop",   4 ], # b3       : ORA E
    [ "fetch_h",     "exec_ora",   "store_nop",   4 ], # b4       : ORA H
    [ "fetch_l",     "exec_ora",   "store_nop",   4 ], # b5       : ORA L
    [ "fetch_mhl",   "exec_ora",   "store_nop",   7 ], # b6       : ORA M
    [ "fetch_a",     "exec_ora",   "store_nop",   4 ], # b7       : ORA A
    [ "fetch_b",     "exec_cpa",   "store_nop",   4 ], # b8       : CMP B
    [ "fetch_c",     "exec_cpa",   "store_nop",   4 ], # b9       : CMP C
    [ "fetch_d",     "exec_cpa",   "store_nop",   4 ], # ba       : CMP D
    [ "fetch_e",     "exec_cpa",   "store_nop",   4 ], # bb       : CMP E
    [ "fetch_h",     "exec_cpa",   "store_nop",   4 ], # bc       : CMP H
    [ "fetch_l",     "exec_cpa",   "store_nop",   4 ], # bd       : CMP L
    [ "fetch_mhl",   "exec_cpa",   "store_nop",   7 ], # be       : CMP M
    [ "fetch_a",     "exec_cpa",   "store_nop",   4 ], # bf       : CMP A

    [ "fetch_nop",   "exec_ifnz",  "store_ret",   5 ], # c0       : RNZ
    [ "fetch_nop",   "exec_pop",   "store_bc",   10 ], # c1       : POP B
    [ "fetch_dir16", "exec_ifnz",  "store_pc",   10 ], # c2 nn nn : JNZ a16
    [ "fetch_dir16", "exec_nop",   "store_pc",   10 ], # c3 nn nn : JMP a16
    [ "fetch_dir16", "exec_ifnz",  "store_call", 11 ], # c4 nn nn : CNZ a16
    [ "fetch_bc",    "exec_push",  "store_nop",  11 ], # c5       : PUSH B
    [ "fetch_dir8",  "exec_adda",  "store_nop",   7 ], # c6 nn    : ADI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # c7       : RST 0
    [ "fetch_nop",   "exec_ifz",   "store_ret",   5 ], # c8       : RZ
    [ "fetch_nop",   "exec_nop",   "store_ret",  10 ], # c9       : RET
    [ "fetch_dir16", "exec_ifz",   "store_pc",   10 ], # ca nn nn : JZ a16
    [ "fetch_dir16", "exec_nop",   "store_pc",   10 ], # cb nn nn : *JMP a16
    [ "fetch_dir16", "exec_ifz",   "store_call", 11 ], # cc nn nn : CZ a16
    [ "fetch_dir16", "exec_nop",   "store_call", 17 ], # cd nn nn : CALL a16
    [ "fetch_dir8",  "exec_adca",  "store_nop",   7 ], # ce nn    : ACI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # cf       : RST 1

    [ "fetch_nop",   "exec_ifnc",  "store_ret",   5 ], # d0       : RNC
    [ "fetch_nop",   "exec_pop",   "store_de",   10 ], # d1       : POP D
    [ "fetch_dir16", "exec_ifnc",  "store_pc",   10 ], # d2 nn nn : JNC a16
    [ "fetch_dir8",  "exec_outa",  "store_nop",  10 ], # d3 nn    : OUT d8
    [ "fetch_dir16", "exec_ifnc",  "store_call", 11 ], # d4 nn nn : CNC a16
    [ "fetch_de",    "exec_push",  "store_nop",  11 ], # d5       : PUSH D
    [ "fetch_dir8",  "exec_suba",  "store_nop",   7 ], # d6 nn    : SUI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # d7       : RST 2
    [ "fetch_nop",   "exec_ifc",   "store_ret",   5 ], # d8       : RC
    [ "fetch_nop",   "exec_nop",   "store_ret",  10 ], # d9       : *RET
    [ "fetch_dir16", "exec_ifc",   "store_pc",   10 ], # da nn nn : JC a16
    [ "fetch_dir8",  "exec_ina",   "store_nop",  10 ], # db nn    : IN d8
    [ "fetch_dir16", "exec_ifc",   "store_call", 11 ], # dc nn nn : CC a16
    [ "fetch_dir16", "exec_nop",   "store_call", 17 ], # dd nn nn : *CALL a16
    [ "fetch_dir8",  "exec_sbca",  "store_nop",   7 ], # de nn    : SBI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # df       : RST 3

    [ "fetch_nop",   "exec_ifpo",  "store_ret",   5 ], # e0       : RPO
    [ "fetch_nop",   "exec_pop",   "store_hl",   10 ], # e1       : POP H
    [ "fetch_dir16", "exec_ifpo",  "store_pc",   10 ], # e2 nn nn : JPO a16
    [ "fetch_msp",   "exec_exhl",  "store_msp",  18 ], # e3       : XTHL
    [ "fetch_dir16", "exec_ifpo",  "store_call", 11 ], # e4 nn nn : CPO a16
    [ "fetch_hl",    "exec_push",  "store_nop",  11 ], # e5       : PUSH H
    [ "fetch_dir8",  "exec_anda",  "store_nop",   7 ], # e6 nn    : ANI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # e7       : RST 4
    [ "fetch_nop",   "exec_ifpe",  "store_ret",   5 ], # e8       : RPE
    [ "fetch_hl",    "exec_nop",   "store_pc",    5 ], # e9       : PCHL
    [ "fetch_dir16", "exec_ifpe",  "store_pc",   10 ], # ea nn nn : JPE a16
    [ "fetch_de",    "exec_exhl",  "store_de",    5 ], # eb       : XCHG
    [ "fetch_dir16", "exec_ifpe",  "store_call", 11 ], # ec nn nn : CPE a16
    [ "fetch_dir16", "exec_nop",   "store_call", 17 ], # ed nn nn : *CALL a16
    [ "fetch_dir8",  "exec_xora",  "store_nop",   7 ], # ee nn    : XRI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # ef       : RST 5

    [ "fetch_nop",   "exec_ifp",   "store_ret",   5 ], # f0       : RP
    [ "fetch_nop",   "exec_pop",   "store_af",   10 ], # f1       : POP PSW
    [ "fetch_dir16", "exec_ifp",   "store_pc",   10 ], # f2 nn nn : JP a16
    [ "fetch_nop",   "exec_di",    "store_nop",   4 ], # f3       : DI
    [ "fetch_dir16", "exec_ifp",   "store_call", 11 ], # f4 nn nn : CP a16
    [ "fetch_af",    "exec_push",  "store_nop",  11 ], # f5       : PUSH PSW
    [ "fetch_dir8",  "exec_ora",   "store_nop",   7 ], # f6 nn    : ORI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # f7       : RST 6
    [ "fetch_nop",   "exec_ifm",   "store_ret",   5 ], # f8       : RM
    [ "fetch_hl",    "exec_nop",   "store_sp",    5 ], # f9       : SPHL
    [ "fetch_dir16", "exec_ifm",   "store_pc",   10 ], # fa nn nn : JM a16
    [ "fetch_nop",   "exec_ei",    "store_nop",   4 ], # fb       : EI
    [ "fetch_dir16", "exec_ifm",   "store_call", 11 ], # fc nn nn : CM a16
    [ "fetch_dir16", "exec_nop",   "store_call", 17 ], # fd nn nn : *CALL a16
    [ "fetch_dir8",  "exec_cpa",   "store_nop",   7 ], # fe nn    : CPI d8
    [ "fetch_rst",   "exec_nop",   "store_call", 11 ], # ff       : RST 7
);

my @flags = (
	0x46, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x02, 0x06, 0x06, 0x02, 0x06, 0x02, 0x02, 0x06,
	0x06, 0x02, 0x02, 0x06, 0x02, 0x06, 0x06, 0x02,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x86, 0x82, 0x82, 0x86, 0x82, 0x86, 0x86, 0x82,
	0x82, 0x86, 0x86, 0x82, 0x86, 0x82, 0x82, 0x86,
);

sub reloc {
	my $arg  = shift;
	my $addr = hex($arg) / 2;
	my $val  = substr(sprintf("%2x", $addr), -2);
	return $val;
}

sub gen_instr_table {
	# read symbol table
	my $symlist = `avr-nm $ARGV[0]` or die "Can't get symbol list";
	my $syms = {};
	foreach (split /^/, $symlist) {
		chomp;
		next unless /^(.*) . (.*)$/;
		my ($addr, $symb) = ($1, $2);
		$syms->{$symb} = $addr;
	}

	# print header
	print <<"EOF";
\n; *************************
; * INSTRUCTION TABLE
; *   must be page-aligned
; *************************
.balign 512
.global instr_table
instr_table:
EOF

	# print low byte of symbol flash address
	for my $i (@instrs) {
		my @bytes = (
			reloc($syms->{$i->[0]}),	# fetch
			reloc($syms->{$i->[1]}),	# exec
			reloc($syms->{$i->[2]}),	# store
			$i->[3],
		);
		print sprintf("\t.byte 0x%s, 0x%s, 0x%s, %2d",
			$bytes[2], $bytes[1], $bytes[0], $bytes[3]);
		print sprintf("\t; %s, %s, %s\n",
			$i->[2], $i->[1], $i->[0]);
	}

	# print footer
	print <<'EOF';
instr_table_end:
EOF
}

sub gen_flags_table {
	# print header
	print <<"EOF";
\n; *************************
; * FLAG TABLE
; *   must be page-aligned
; *************************
.balign 256
.global flag_table
flag_table:
EOF

	# print flag values
	for my $idx (0 .. $#flags/8) {
		print sprintf("\t.byte 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
			@flags[8 * $idx .. 8 * $idx + 7]);
	}

	# print footer
	print <<'EOF';
flag_table_end:
EOF
}

sub main {
	print <<'EOF';
; i8080 tables
; AUTO-GENERATED, DO NOT EDIT
; RE-GENERATE AFTER BUILDING EMULATOR
EOF

	gen_instr_table();
	gen_flags_table();
}

main()
