| 03a3459e Andy McCall |
1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
import re |
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
ACTN_KEY_STR = "action" |
| 20 |
CYCLES_KEY_STR = "cycles" |
| 21 |
MODE_KEY_STR = "mode" |
| 22 |
OPCODE_KEY_STR = "opcode" |
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
OPCODE_REGEX_STR = "^(?P<{actnCode}>\\w+)\\s+(?P<{addrMode}>\\w+)\\s+(?P<{mchnCycles}>\\d)\\s+\\$(?P<{opCode}>[0-9a-fA-F]+)$".format( |
| 27 |
actnCode=ACTN_KEY_STR, |
| 28 |
addrMode=MODE_KEY_STR, |
| 29 |
mchnCycles=CYCLES_KEY_STR, |
| 30 |
opCode=OPCODE_KEY_STR |
| 31 |
) |
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
ADDR_MODE_HEADER_C02 = "static void (*addrtable_c02[256])() = {" |
| 36 |
ACTN_CODE_HEADER_C02 = "static void (*optable_c02[256])() = {" |
| 37 |
MCHN_CYCLES_HEADER_C02 = "static const uint32_t ticktable_c02[256] = {" |
| 38 |
MNEMONICS_DISASSEM_HEADER_C02 = "static const char *mnemonics_c02[256] = {" |
| 39 |
ADDR_MODE_HEADER_C816 = "static void (*addrtable_c816[256])() = {" |
| 40 |
ACTN_CODE_HEADER_C816 = "static void (*optable_c816[256])() = {" |
| 41 |
MCHN_CYCLES_HEADER_C816 = "static const uint32_t ticktable_c816[256] = {" |
| 42 |
MNEMONICS_DISASSEM_HEADER_C816 = "static const char *mnemonics_c816[256] = {" |
| 43 |
TABLE_MAP = "/*{0:8}| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |{0:5}*/\n" |
| 44 |
|
| 45 |
|
| 46 |
|
| 47 |
EMPTY_NOP_ACTN = "nop" |
| 48 |
EMPTY_NOP_CYCLS = "1" |
| 49 |
EMPTY_NOP_MOD = "imp" |
| 50 |
OPCODE_ROW_LEN = 16 |
| 51 |
TOTAL_NUMBER_OPCODES = 2 ** 8 |
| 52 |
|
| 53 |
|
| 54 |
|
| 55 |
TABLES_HEADER_FNAME = "tables.h" |
| 56 |
MNEMONICS_DISASSEM_HEADER_FNAME = "mnemonics.h" |
| 57 |
OPCODES_6502_FNAME = "6502.opcodes" |
| 58 |
OPCODES_65c02_FNAME = "65c02.opcodes" |
| 59 |
OPCODES_65c816_FNAME = "65c816.opcodes" |
| 60 |
|
| 61 |
|
| 62 |
|
| 63 |
|
| 64 |
|
| 65 |
|
| 66 |
|
| 67 |
|
| 68 |
|
| 69 |
def loadSource(srcFile, opcodesList): |
| 70 |
|
| 71 |
fileLinesObject = open(srcFile).readlines() |
| 72 |
strippedOpcodeLines = [opcodeLine.strip() for opcodeLine in fileLinesObject if |
| 73 |
opcodeLine.strip() != "" and not opcodeLine.startswith(";")] |
| 74 |
|
| 75 |
|
| 76 |
for opcodeLine in strippedOpcodeLines: |
| 77 |
matchLine = re.match(OPCODE_REGEX_STR, opcodeLine) |
| 78 |
assert matchLine is not None, "Format {}".format(opcodeLine) |
| 79 |
|
| 80 |
opcode = int(matchLine.group(OPCODE_KEY_STR), 16) |
| 81 |
assert opcodesList[opcode] is None, "Duplicate {0:02x}".format(opcode) |
| 82 |
|
| 83 |
opcodesList[opcode] = { |
| 84 |
MODE_KEY_STR: matchLine.group(MODE_KEY_STR), |
| 85 |
ACTN_KEY_STR: matchLine.group(ACTN_KEY_STR), |
| 86 |
CYCLES_KEY_STR: matchLine.group(CYCLES_KEY_STR), |
| 87 |
OPCODE_KEY_STR: opcode |
| 88 |
} |
| 89 |
|
| 90 |
|
| 91 |
|
| 92 |
|
| 93 |
|
| 94 |
def fillNop(opcodesList): |
| 95 |
for i in range(0, TOTAL_NUMBER_OPCODES): |
| 96 |
if opcodesList[i] is None: |
| 97 |
opcodesList[i] = { |
| 98 |
MODE_KEY_STR: EMPTY_NOP_MOD, |
| 99 |
ACTN_KEY_STR: EMPTY_NOP_ACTN, |
| 100 |
CYCLES_KEY_STR: EMPTY_NOP_CYCLS, |
| 101 |
OPCODE_KEY_STR: i |
| 102 |
} |
| 103 |
|
| 104 |
|
| 105 |
|
| 106 |
|
| 107 |
|
| 108 |
def generateTable(hFileName, header, element, opcodesList): |
| 109 |
spacing = 5 |
| 110 |
hFileName.write("{}{}{}".format("\n", header, "\n")) |
| 111 |
hFileName.write(TABLE_MAP.format("", "")) |
| 112 |
for row in range(0, OPCODE_ROW_LEN): |
| 113 |
elements = ",".join( |
| 114 |
["{0:>9}".format(opcodesList[opcodeItem][element])[-spacing:] for opcodeItem in |
| 115 |
range(row * OPCODE_ROW_LEN, OPCODE_ROW_LEN * (row + 1))]) |
| 116 |
|
| 117 |
hFileName.write("/* {0:X} */ {3} {1}{2} /* {0:X} */\n".format( |
| 118 |
row, |
| 119 |
elements, |
| 120 |
" " if row == OPCODE_ROW_LEN - 1 else ",", |
| 121 |
" " if element == ACTN_KEY_STR else "") |
| 122 |
) |
| 123 |
hFileName.write("};\n") |
| 124 |
|
| 125 |
|
| 126 |
|
| 127 |
|
| 128 |
|
| 129 |
|
| 130 |
def generateList(hFileName, header, elements): |
| 131 |
hFileName.write("{}{}{}".format("\n", header, "\n")) |
| 132 |
for row in range(0, OPCODE_ROW_LEN): |
| 133 |
hFileName.write("\t// ${0:X}X\n".format(row)) |
| 134 |
|
| 135 |
for op in range(0, OPCODE_ROW_LEN): |
| 136 |
hFileName.write("\t/* ${0:X}{1:X} */ \"{2}\"{3}".format(row, op, elements[row * OPCODE_ROW_LEN + op], "" if row == OPCODE_ROW_LEN-1 and op == OPCODE_ROW_LEN-1 else ",\n")) |
| 137 |
|
| 138 |
hFileName.write("{}".format("" if row == OPCODE_ROW_LEN-1 else "\n")) |
| 139 |
hFileName.write("};\n") |
| 140 |
|
| 141 |
|
| 142 |
|
| 143 |
|
| 144 |
|
| 145 |
|
| 146 |
def convertMnemonic(opInfo): |
| 147 |
modeStr = { |
| 148 |
"imp": "", |
| 149 |
"imp8": "#$%02x", |
| 150 |
"imm8": "#$%02x", |
| 151 |
"immm": "#$%%0%hhux", |
| 152 |
"immx": "#$%%0%hhux", |
| 153 |
"imm16": "#$%04x", |
| 154 |
"zp": "$%02x", |
| 155 |
"rel": "$%02x", |
| 156 |
"rel16": "$%04x", |
| 157 |
"zprel": "$%02x, $%04x", |
| 158 |
"zpx": "$%02x,x", |
| 159 |
"zpy": "$%02x,y", |
| 160 |
"abso": "$%04x", |
| 161 |
"absx": "$%04x,x", |
| 162 |
"absy": "$%04x,y", |
| 163 |
"absl": "$%06x", |
| 164 |
"abslx": "$%06x,x", |
| 165 |
"aindl": "[$%04x]", |
| 166 |
"ainx": "($%04x,x)", |
| 167 |
"indy": "($%02x),y", |
| 168 |
"indly": "[$%02x],y", |
| 169 |
"indx": "($%02x,x)", |
| 170 |
"ind": "($%04x)", |
| 171 |
"ind0": "($%02x)", |
| 172 |
"ind0p": "($%02x)", |
| 173 |
"indl0": "[$%02x]", |
| 174 |
"acc": "a", |
| 175 |
"sr": "$%02x,S", |
| 176 |
"sridy": "($%02x,S),y", |
| 177 |
"bmv": "$%02x,$%02x", |
| 178 |
} |
| 179 |
return "{} {}".format(opInfo[ACTN_KEY_STR], modeStr[opInfo[MODE_KEY_STR]]) |
| 180 |
|
| 181 |
|
| 182 |
|
| 183 |
|
| 184 |
|
| 185 |
if __name__ == '__main__': |
| 186 |
opcodesList_c02 = [None] * TOTAL_NUMBER_OPCODES |
| 187 |
|
| 188 |
|
| 189 |
loadSource(OPCODES_6502_FNAME, opcodesList_c02) |
| 190 |
|
| 191 |
loadSource(OPCODES_65c02_FNAME, opcodesList_c02) |
| 192 |
|
| 193 |
opcodesList_c816 = [None] * TOTAL_NUMBER_OPCODES |
| 194 |
|
| 195 |
|
| 196 |
loadSource(OPCODES_6502_FNAME, opcodesList_c816) |
| 197 |
|
| 198 |
loadSource(OPCODES_65c816_FNAME, opcodesList_c816) |
| 199 |
|
| 200 |
|
| 201 |
fillNop(opcodesList_c02) |
| 202 |
fillNop(opcodesList_c816) |
| 203 |
|
| 204 |
|
| 205 |
with open(TABLES_HEADER_FNAME, "w") as output_h_file: |
| 206 |
output_h_file.write("/* Generated by buildtables.py */\n") |
| 207 |
generateTable(output_h_file, ADDR_MODE_HEADER_C02, MODE_KEY_STR, opcodesList_c02) |
| 208 |
generateTable(output_h_file, ADDR_MODE_HEADER_C816, MODE_KEY_STR, opcodesList_c816) |
| 209 |
generateTable(output_h_file, ACTN_CODE_HEADER_C02, ACTN_KEY_STR, opcodesList_c02) |
| 210 |
generateTable(output_h_file, ACTN_CODE_HEADER_C816, ACTN_KEY_STR, opcodesList_c816) |
| 211 |
generateTable(output_h_file, MCHN_CYCLES_HEADER_C02, CYCLES_KEY_STR, opcodesList_c02) |
| 212 |
generateTable(output_h_file, MCHN_CYCLES_HEADER_C816, CYCLES_KEY_STR, opcodesList_c816) |
| 213 |
|
| 214 |
|
| 215 |
mnemonics_c02 = [convertMnemonic(opcodesList_c02[x]) for x in range(0, TOTAL_NUMBER_OPCODES)] |
| 216 |
mnemonics_c816 = [convertMnemonic(opcodesList_c816[x]) for x in range(0, TOTAL_NUMBER_OPCODES)] |
| 217 |
with open(MNEMONICS_DISASSEM_HEADER_FNAME, "w") as output_h_file: |
| 218 |
output_h_file.write("/* Generated by buildtables.py */\n") |
| 219 |
generateList(output_h_file, MNEMONICS_DISASSEM_HEADER_C02, mnemonics_c02) |
| 220 |
generateList(output_h_file, MNEMONICS_DISASSEM_HEADER_C816, mnemonics_c816) |