mirror of
https://github.com/irmen/prog8.git
synced 2025-01-14 01:29:55 +00:00
cx16 assembler was moved into its own github repo
This commit is contained in:
parent
b270f6f713
commit
c328e9018c
@ -72,7 +72,7 @@ io_error:
|
|||||||
str list_filename = "?" * 32
|
str list_filename = "?" * 32
|
||||||
|
|
||||||
|
|
||||||
; ----- get a list of files (uses iteration functions internally -----
|
; ----- get a list of files (uses iteration functions internally) -----
|
||||||
|
|
||||||
sub list_files(ubyte drivenumber, uword pattern_ptr, uword name_ptrs, ubyte max_names) -> ubyte {
|
sub list_files(ubyte drivenumber, uword pattern_ptr, uword name_ptrs, ubyte max_names) -> ubyte {
|
||||||
; -- fill the array 'name_ptrs' with (pointers to) the names of the files requested.
|
; -- fill the array 'name_ptrs' with (pointers to) the names of the files requested.
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
all: perfecthash.c opcodes.asm
|
|
||||||
|
|
||||||
perfecthash.c: gen_opcodes.py
|
|
||||||
python gen_opcodes.py --mnemlist | gperf --no-strlen --null-strings -7 -C -D -E -m 100 > perfecthash.c
|
|
||||||
|
|
||||||
opcodes.asm: gen_opcodes.py
|
|
||||||
python gen_opcodes.py --parser > opcodes.asm
|
|
||||||
|
|
@ -1,733 +0,0 @@
|
|||||||
%target cx16
|
|
||||||
%import textio
|
|
||||||
%import diskio
|
|
||||||
%import string
|
|
||||||
%import test_stack
|
|
||||||
%zeropage basicsafe
|
|
||||||
%option no_sysinit
|
|
||||||
|
|
||||||
; raw file loading of the large assembly file $c000-$ffff: 372 jiffies
|
|
||||||
; time loading and actually processing it: 700 jiffies
|
|
||||||
|
|
||||||
main {
|
|
||||||
|
|
||||||
sub start() {
|
|
||||||
txt.print("\ncommander-x16 65c02 file based assembler.\n\nfilename or enter for interactive: ")
|
|
||||||
|
|
||||||
str filename = "?" * 20
|
|
||||||
if txt.input_chars(filename)
|
|
||||||
file_input(filename)
|
|
||||||
else
|
|
||||||
user_input()
|
|
||||||
|
|
||||||
cx16.rombank(4) ; switch back to basic rom
|
|
||||||
|
|
||||||
test_stack.test()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub user_input() {
|
|
||||||
txt.lowercase()
|
|
||||||
parser.print_emit_bytes = true
|
|
||||||
parser.program_counter = $4000
|
|
||||||
txt.print("\nEmpty line to stop.\n")
|
|
||||||
repeat {
|
|
||||||
ubyte input_length = 0
|
|
||||||
txt.chrout('A')
|
|
||||||
txt.print_uwhex(parser.program_counter, 1)
|
|
||||||
txt.print(": ")
|
|
||||||
; simulate user always having at least one space at the start
|
|
||||||
parser.input_line[0] = ' '
|
|
||||||
input_length = txt.input_chars(&parser.input_line+1)
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
if not input_length {
|
|
||||||
txt.print("exit\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if not parser.process_line()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
parser.done()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub file_input(uword filename) {
|
|
||||||
parser.print_emit_bytes = false
|
|
||||||
ubyte success = false
|
|
||||||
|
|
||||||
txt.print("\nreading ")
|
|
||||||
txt.print(filename)
|
|
||||||
txt.spc()
|
|
||||||
|
|
||||||
cx16.rombank(0) ; switch to kernal rom for faster file i/o
|
|
||||||
|
|
||||||
if diskio.f_open(8, filename) {
|
|
||||||
c64.SETTIM(0,0,0)
|
|
||||||
uword line=0
|
|
||||||
repeat {
|
|
||||||
void diskio.f_readline(parser.input_line)
|
|
||||||
line++
|
|
||||||
|
|
||||||
if not lsb(line)
|
|
||||||
txt.chrout('.')
|
|
||||||
|
|
||||||
if not parser.process_line() {
|
|
||||||
txt.print("\nerror. last line was ")
|
|
||||||
txt.print_uw(line)
|
|
||||||
txt.print(": ")
|
|
||||||
txt.print(parser.word_addrs[0])
|
|
||||||
if parser.word_addrs[1] {
|
|
||||||
txt.spc()
|
|
||||||
txt.print(parser.word_addrs[1])
|
|
||||||
}
|
|
||||||
if parser.word_addrs[2] {
|
|
||||||
txt.spc()
|
|
||||||
txt.print(parser.word_addrs[2])
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if c64.READST() {
|
|
||||||
success = c64.READST()&64==64 ; end of file?
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if c64.STOP2() {
|
|
||||||
txt.print("?break\n")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diskio.f_close()
|
|
||||||
parser.done()
|
|
||||||
|
|
||||||
if success
|
|
||||||
print_summary(line, parser.pc_min, parser.pc_max)
|
|
||||||
} else {
|
|
||||||
txt.print(diskio.status(8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub print_summary(uword lines, uword start_address, uword end_address) {
|
|
||||||
txt.print("\n\nstart address: ")
|
|
||||||
txt.print_uwhex(start_address, 1)
|
|
||||||
txt.print("\n end address: ")
|
|
||||||
txt.print_uwhex(end_address, 1)
|
|
||||||
txt.print("\n lines: ")
|
|
||||||
txt.print_uw(lines)
|
|
||||||
|
|
||||||
txt.print("\n time (sec): ")
|
|
||||||
uword current_time = c64.RDTIM16()
|
|
||||||
uword secs = current_time / 60
|
|
||||||
current_time = (current_time - secs*60)*1000/60
|
|
||||||
txt.print_uw(secs)
|
|
||||||
txt.chrout('.')
|
|
||||||
if current_time<10
|
|
||||||
txt.chrout('0')
|
|
||||||
if current_time<100
|
|
||||||
txt.chrout('0')
|
|
||||||
txt.print_uw(current_time)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parser {
|
|
||||||
; byte counts per address mode id:
|
|
||||||
ubyte[17] operand_size = [$ff, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2]
|
|
||||||
|
|
||||||
str input_line = "?" * 160
|
|
||||||
uword[3] word_addrs
|
|
||||||
uword program_counter = $ffff
|
|
||||||
ubyte print_emit_bytes
|
|
||||||
uword pc_min = $ffff
|
|
||||||
uword pc_max = $0000
|
|
||||||
|
|
||||||
sub process_line() -> ubyte {
|
|
||||||
string.lower(input_line)
|
|
||||||
preprocess_assignment_spacing()
|
|
||||||
split_input()
|
|
||||||
|
|
||||||
if word_addrs[1] and @(word_addrs[1])=='='
|
|
||||||
return do_assign()
|
|
||||||
else
|
|
||||||
return do_label_andor_instr()
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
sub done() {
|
|
||||||
if program_counter>pc_max
|
|
||||||
pc_max = program_counter
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_assign() -> ubyte {
|
|
||||||
; target is in word_addrs[0], value is in word_addrs[2] ('=' is in word_addrs[1])
|
|
||||||
if not word_addrs[2] {
|
|
||||||
txt.print("?syntax error\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
ubyte valid_operand=false
|
|
||||||
if @(word_addrs[2])=='*' {
|
|
||||||
cx16.r15 = program_counter
|
|
||||||
valid_operand = true
|
|
||||||
} else {
|
|
||||||
ubyte nlen = conv.any2uword(word_addrs[2])
|
|
||||||
valid_operand = nlen and @(word_addrs[2]+nlen)==0
|
|
||||||
}
|
|
||||||
|
|
||||||
if valid_operand {
|
|
||||||
if string.compare(word_addrs[0], "*")==0 {
|
|
||||||
program_counter = cx16.r15
|
|
||||||
txt.print("\n* = ")
|
|
||||||
txt.print_uwhex(program_counter, true)
|
|
||||||
txt.nl()
|
|
||||||
if program_counter<pc_min
|
|
||||||
pc_min = program_counter
|
|
||||||
if program_counter>pc_max
|
|
||||||
pc_max = program_counter
|
|
||||||
} else {
|
|
||||||
symbols.setvalue(word_addrs[0], cx16.r15)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
txt.print("?invalid operand\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_label_andor_instr() -> ubyte {
|
|
||||||
uword label_ptr = 0
|
|
||||||
uword instr_ptr = 0
|
|
||||||
uword operand_ptr = 0
|
|
||||||
ubyte starts_with_whitespace = input_line[0]==' ' or input_line[0]==9 or input_line[0]==160
|
|
||||||
|
|
||||||
if word_addrs[2] {
|
|
||||||
label_ptr = word_addrs[0]
|
|
||||||
instr_ptr = word_addrs[1]
|
|
||||||
operand_ptr = word_addrs[2]
|
|
||||||
} else if word_addrs[1] {
|
|
||||||
if starts_with_whitespace {
|
|
||||||
instr_ptr = word_addrs[0]
|
|
||||||
operand_ptr = word_addrs[1]
|
|
||||||
} else {
|
|
||||||
label_ptr = word_addrs[0]
|
|
||||||
instr_ptr = word_addrs[1]
|
|
||||||
}
|
|
||||||
} else if word_addrs[0] {
|
|
||||||
if starts_with_whitespace
|
|
||||||
instr_ptr = word_addrs[0]
|
|
||||||
else
|
|
||||||
label_ptr = word_addrs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if label_ptr {
|
|
||||||
uword lastlabelchar = label_ptr + string.length(label_ptr)-1
|
|
||||||
if @(lastlabelchar) == ':'
|
|
||||||
@(lastlabelchar) = 0
|
|
||||||
if instructions.match(label_ptr) {
|
|
||||||
txt.print("?label cannot be a mnemonic\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
symbols.setvalue(label_ptr, program_counter)
|
|
||||||
}
|
|
||||||
if instr_ptr {
|
|
||||||
if @(instr_ptr)=='.'
|
|
||||||
return process_assembler_directive(instr_ptr, operand_ptr)
|
|
||||||
|
|
||||||
return assemble_instruction(instr_ptr, operand_ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true ; empty line
|
|
||||||
}
|
|
||||||
|
|
||||||
sub assemble_instruction(uword instr_ptr, uword operand_ptr) -> ubyte {
|
|
||||||
uword instruction_info_ptr = instructions.match(instr_ptr)
|
|
||||||
if instruction_info_ptr {
|
|
||||||
; we got a mnemonic match, now process the operand (and its value, if applicable, into cx16.r15)
|
|
||||||
ubyte addr_mode = parse_operand(operand_ptr)
|
|
||||||
|
|
||||||
if addr_mode {
|
|
||||||
ubyte opcode = instructions.opcode(instruction_info_ptr, addr_mode)
|
|
||||||
if_cc {
|
|
||||||
; most likely an invalid instruction BUT could also be a branchin instruction
|
|
||||||
; that needs its "absolute" operand recalculated as relative.
|
|
||||||
ubyte retry = false
|
|
||||||
when addr_mode {
|
|
||||||
instructions.am_Abs -> {
|
|
||||||
if @(instr_ptr)=='b' {
|
|
||||||
addr_mode = instructions.am_Rel
|
|
||||||
if not calc_relative_branch_into_r14()
|
|
||||||
return false
|
|
||||||
cx16.r15 = cx16.r14
|
|
||||||
retry = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
instructions.am_Imp -> {
|
|
||||||
addr_mode = instructions.am_Acc
|
|
||||||
retry = true
|
|
||||||
}
|
|
||||||
instructions.am_Izp -> {
|
|
||||||
addr_mode = instructions.am_Ind
|
|
||||||
retry = true
|
|
||||||
}
|
|
||||||
instructions.am_Zp -> {
|
|
||||||
addr_mode = instructions.am_Abs
|
|
||||||
retry = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if retry
|
|
||||||
opcode = instructions.opcode(instruction_info_ptr, addr_mode)
|
|
||||||
|
|
||||||
if not opcode {
|
|
||||||
txt.print("?invalid instruction\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if addr_mode==instructions.am_Zpr {
|
|
||||||
; instructions like BBR4 $zp,$aaaa (dual-operand)
|
|
||||||
uword comma = string.find(operand_ptr,',')
|
|
||||||
if comma {
|
|
||||||
comma++
|
|
||||||
cx16.r13 = cx16.r15
|
|
||||||
if parse_operand(comma) {
|
|
||||||
program_counter++
|
|
||||||
if not calc_relative_branch_into_r14()
|
|
||||||
return false
|
|
||||||
program_counter--
|
|
||||||
cx16.r15 = (cx16.r14 << 8) | lsb(cx16.r13)
|
|
||||||
} else {
|
|
||||||
txt.print("?invalid operand\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
txt.print("?invalid operand\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ubyte num_operand_bytes = operand_size[addr_mode]
|
|
||||||
if print_emit_bytes {
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uwhex(program_counter, 1)
|
|
||||||
txt.print(" ")
|
|
||||||
}
|
|
||||||
emit(opcode)
|
|
||||||
if num_operand_bytes==1 {
|
|
||||||
emit(lsb(cx16.r15))
|
|
||||||
} else if num_operand_bytes == 2 {
|
|
||||||
emit(lsb(cx16.r15))
|
|
||||||
emit(msb(cx16.r15))
|
|
||||||
}
|
|
||||||
if print_emit_bytes
|
|
||||||
txt.nl()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
txt.print("?invalid operand\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
txt.print("?invalid instruction\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
sub calc_relative_branch_into_r14() -> ubyte {
|
|
||||||
cx16.r14 = cx16.r15 - program_counter - 2
|
|
||||||
if msb(cx16.r14) {
|
|
||||||
if cx16.r14 < $ff80 {
|
|
||||||
txt.print("?branch out of range\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else if cx16.r14 > $007f {
|
|
||||||
txt.print("?branch out of range\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
sub parse_operand(uword operand_ptr) -> ubyte {
|
|
||||||
; parses the operand. Returns 2 things:
|
|
||||||
; - addressing mode id as result value or 0 (am_Invalid) when error
|
|
||||||
; - operand numeric value in cx16.r15 (if applicable)
|
|
||||||
|
|
||||||
ubyte @zp firstchr = @(operand_ptr)
|
|
||||||
ubyte parsed_len
|
|
||||||
when firstchr {
|
|
||||||
0 -> return instructions.am_Imp
|
|
||||||
'#' -> {
|
|
||||||
; lda #$99 Immediate
|
|
||||||
operand_ptr++
|
|
||||||
parsed_len = conv.any2uword(operand_ptr)
|
|
||||||
if parsed_len {
|
|
||||||
operand_ptr += parsed_len
|
|
||||||
if @(operand_ptr)==0
|
|
||||||
return instructions.am_Imm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'a' -> {
|
|
||||||
if not @(operand_ptr+1)
|
|
||||||
return instructions.am_Acc ; Accumulator - no value.
|
|
||||||
|
|
||||||
; TODO its a symbol/label, immediate or indexed addressing
|
|
||||||
txt.print("TODO symbol: ")
|
|
||||||
txt.print(operand_ptr)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
'(' -> {
|
|
||||||
; various forms of indirect
|
|
||||||
operand_ptr++
|
|
||||||
parsed_len = conv.any2uword(operand_ptr)
|
|
||||||
if parsed_len {
|
|
||||||
operand_ptr+=parsed_len
|
|
||||||
if msb(cx16.r15) {
|
|
||||||
; absolute indirects
|
|
||||||
if str_is1(operand_ptr, ')')
|
|
||||||
return instructions.am_Ind
|
|
||||||
if str_is3(operand_ptr, ",x)")
|
|
||||||
return instructions.am_IaX
|
|
||||||
} else {
|
|
||||||
; zero page indirects
|
|
||||||
if str_is1(operand_ptr, ')')
|
|
||||||
return instructions.am_Izp
|
|
||||||
if str_is3(operand_ptr, ",x)")
|
|
||||||
return instructions.am_IzX
|
|
||||||
if str_is3(operand_ptr, "),y")
|
|
||||||
return instructions.am_IzY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'$', '%', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> {
|
|
||||||
; address optionally followed by ,x or ,y or ,address
|
|
||||||
parsed_len = conv.any2uword(operand_ptr)
|
|
||||||
if parsed_len {
|
|
||||||
operand_ptr += parsed_len
|
|
||||||
if msb(cx16.r15) {
|
|
||||||
; absolute or abs indirects
|
|
||||||
if @(operand_ptr)==0
|
|
||||||
return instructions.am_Abs
|
|
||||||
if str_is2(operand_ptr, ",x")
|
|
||||||
return instructions.am_AbsX
|
|
||||||
if str_is2(operand_ptr, ",y")
|
|
||||||
return instructions.am_AbsY
|
|
||||||
} else {
|
|
||||||
; zero page or zp indirects
|
|
||||||
if @(operand_ptr)==0
|
|
||||||
return instructions.am_Zp
|
|
||||||
if str_is2(operand_ptr, ",x")
|
|
||||||
return instructions.am_ZpX
|
|
||||||
if str_is2(operand_ptr, ",y")
|
|
||||||
return instructions.am_ZpY
|
|
||||||
if @(operand_ptr)==',' {
|
|
||||||
; assume BBR $zp,$aaaa or BBS $zp,$aaaa
|
|
||||||
return instructions.am_Zpr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instructions.am_Invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
sub process_assembler_directive(uword directive, uword operand) -> ubyte {
|
|
||||||
; we only recognise .byte right now
|
|
||||||
if string.compare(directive, ".byte")==0 {
|
|
||||||
if operand {
|
|
||||||
ubyte length
|
|
||||||
length = conv.any2uword(operand)
|
|
||||||
if length {
|
|
||||||
if msb(cx16.r15) {
|
|
||||||
txt.print("?byte value too large\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if print_emit_bytes {
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uwhex(program_counter, 1)
|
|
||||||
txt.print(" ")
|
|
||||||
}
|
|
||||||
emit(lsb(cx16.r15))
|
|
||||||
operand += length
|
|
||||||
while @(operand)==',' {
|
|
||||||
operand++
|
|
||||||
length = conv.any2uword(operand)
|
|
||||||
if not length
|
|
||||||
break
|
|
||||||
if msb(cx16.r15) {
|
|
||||||
txt.print("?byte value too large\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
emit(lsb(cx16.r15))
|
|
||||||
operand += length
|
|
||||||
}
|
|
||||||
if print_emit_bytes
|
|
||||||
txt.nl()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txt.print("?syntax error\n")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub str_is1(uword st @R0, ubyte char @A) clobbers(Y) -> ubyte @A {
|
|
||||||
%asm {{
|
|
||||||
cmp (cx16.r0)
|
|
||||||
bne +
|
|
||||||
ldy #1
|
|
||||||
lda (cx16.r0),y
|
|
||||||
bne +
|
|
||||||
lda #1
|
|
||||||
rts
|
|
||||||
+ lda #0
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub str_is2(uword st @R0, uword compare @AY) clobbers(Y) -> ubyte @A {
|
|
||||||
%asm {{
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
sty P8ZP_SCRATCH_W1+1
|
|
||||||
ldy #0
|
|
||||||
jmp str_is3._is_2_entry
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub str_is3(uword st @R0, uword compare @AY) clobbers(Y) -> ubyte @A {
|
|
||||||
%asm {{
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
sty P8ZP_SCRATCH_W1+1
|
|
||||||
lda (cx16.r0)
|
|
||||||
cmp (P8ZP_SCRATCH_W1)
|
|
||||||
bne +
|
|
||||||
ldy #1
|
|
||||||
_is_2_entry
|
|
||||||
lda (cx16.r0),y
|
|
||||||
cmp (P8ZP_SCRATCH_W1),y
|
|
||||||
bne +
|
|
||||||
iny
|
|
||||||
lda (cx16.r0),y
|
|
||||||
cmp (P8ZP_SCRATCH_W1),y
|
|
||||||
bne +
|
|
||||||
iny
|
|
||||||
lda (cx16.r0),y
|
|
||||||
bne +
|
|
||||||
lda #1
|
|
||||||
rts
|
|
||||||
+ lda #0
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub emit(ubyte value) {
|
|
||||||
@(program_counter) = value
|
|
||||||
program_counter++
|
|
||||||
|
|
||||||
if print_emit_bytes {
|
|
||||||
txt.print_ubhex(value, 0)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub dummy(uword operand_ptr) -> uword {
|
|
||||||
uword a1=rndw()
|
|
||||||
uword a6=a1+operand_ptr
|
|
||||||
return a6
|
|
||||||
}
|
|
||||||
|
|
||||||
sub split_input() {
|
|
||||||
; first strip the input string of extra whitespace and comments
|
|
||||||
ubyte copying_word = false
|
|
||||||
ubyte word_count
|
|
||||||
ubyte @zp char_idx = 0
|
|
||||||
|
|
||||||
word_addrs[0] = 0
|
|
||||||
word_addrs[1] = 0
|
|
||||||
word_addrs[2] = 0
|
|
||||||
|
|
||||||
ubyte @zp char
|
|
||||||
for char in input_line {
|
|
||||||
when char {
|
|
||||||
' ', 9, 160 -> {
|
|
||||||
if copying_word
|
|
||||||
input_line[char_idx] = 0; terminate word
|
|
||||||
copying_word = false
|
|
||||||
}
|
|
||||||
';', 0 -> {
|
|
||||||
; terminate line on comment char or end-of-string
|
|
||||||
break
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
if not copying_word {
|
|
||||||
if word_count==3
|
|
||||||
break
|
|
||||||
word_addrs[word_count] = &input_line + char_idx
|
|
||||||
word_count++
|
|
||||||
}
|
|
||||||
copying_word = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char_idx++
|
|
||||||
}
|
|
||||||
|
|
||||||
char = input_line[char_idx]
|
|
||||||
if char==' ' or char==9 or char==160 or char==';'
|
|
||||||
input_line[char_idx] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
sub debug_print_words() { ; TODO remove
|
|
||||||
txt.print("(debug:) words: ")
|
|
||||||
uword word_ptr
|
|
||||||
for word_ptr in word_addrs {
|
|
||||||
txt.chrout('[')
|
|
||||||
txt.print(word_ptr)
|
|
||||||
txt.print("] ")
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub preprocess_assignment_spacing() {
|
|
||||||
if not string.find(input_line, '=')
|
|
||||||
return
|
|
||||||
|
|
||||||
; split the line around the '='
|
|
||||||
str input_line2 = "?" * 40
|
|
||||||
uword src = &input_line
|
|
||||||
uword dest = &input_line2
|
|
||||||
ubyte @zp cc
|
|
||||||
for cc in input_line {
|
|
||||||
if cc=='=' {
|
|
||||||
@(dest) = ' '
|
|
||||||
dest++
|
|
||||||
@(dest) = '='
|
|
||||||
dest++
|
|
||||||
cc = ' '
|
|
||||||
}
|
|
||||||
@(dest) = cc
|
|
||||||
dest++
|
|
||||||
}
|
|
||||||
@(dest)=0
|
|
||||||
void string.copy(input_line2, src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
symbols {
|
|
||||||
sub setvalue(uword symbolname_ptr, uword value) {
|
|
||||||
txt.print("symbol: ")
|
|
||||||
txt.print(symbolname_ptr)
|
|
||||||
txt.chrout('=')
|
|
||||||
txt.print_uwhex(value, true)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions {
|
|
||||||
const ubyte am_Invalid = 0
|
|
||||||
const ubyte am_Imp = 1
|
|
||||||
const ubyte am_Acc = 2
|
|
||||||
const ubyte am_Imm = 3
|
|
||||||
const ubyte am_Zp = 4
|
|
||||||
const ubyte am_ZpX = 5
|
|
||||||
const ubyte am_ZpY = 6
|
|
||||||
const ubyte am_Rel = 7
|
|
||||||
const ubyte am_Abs = 8
|
|
||||||
const ubyte am_AbsX = 9
|
|
||||||
const ubyte am_AbsY = 10
|
|
||||||
const ubyte am_Ind = 11
|
|
||||||
const ubyte am_IzX = 12
|
|
||||||
const ubyte am_IzY = 13
|
|
||||||
const ubyte am_Zpr = 14
|
|
||||||
const ubyte am_Izp = 15
|
|
||||||
const ubyte am_IaX = 16
|
|
||||||
|
|
||||||
; TODO: explore (benchmark) hash based matchers. Faster (although the bulk of the time is not in the mnemonic matching)? Less memory?
|
|
||||||
|
|
||||||
asmsub match(uword mnemonic_ptr @AY) -> uword @AY {
|
|
||||||
; -- input: mnemonic_ptr in AY, output: pointer to instruction info structure or $0000 in AY
|
|
||||||
%asm {{
|
|
||||||
phx
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
sty P8ZP_SCRATCH_W1+1
|
|
||||||
lda (P8ZP_SCRATCH_W1)
|
|
||||||
and #$7f ; lowercase
|
|
||||||
pha
|
|
||||||
ldy #1
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
sta cx16.r4 ; fourth letter in R4 (only exists for the few 4-letter mnemonics)
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
sta cx16.r5 ; fifth letter in R5 (should always be zero or whitespace for a valid mnemonic)
|
|
||||||
pla
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
jsr get_opcode_info
|
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub opcode(uword instr_info_ptr @AY, ubyte addr_mode @X) clobbers(X) -> ubyte @A, ubyte @Pc {
|
|
||||||
; -- input: instruction info struct ptr @AY, desired addr_mode @X
|
|
||||||
; output: opcode @A, valid @carrybit
|
|
||||||
%asm {{
|
|
||||||
cpy #0
|
|
||||||
beq _not_found
|
|
||||||
sta P8ZP_SCRATCH_W2
|
|
||||||
sty P8ZP_SCRATCH_W2+1
|
|
||||||
stx cx16.r5
|
|
||||||
|
|
||||||
; debug result address
|
|
||||||
;sec
|
|
||||||
;jsr txt.print_uwhex
|
|
||||||
;lda #13
|
|
||||||
;jsr c64.CHROUT
|
|
||||||
|
|
||||||
lda (P8ZP_SCRATCH_W2)
|
|
||||||
beq _multi_addrmodes
|
|
||||||
ldy #1
|
|
||||||
lda (P8ZP_SCRATCH_W2),y
|
|
||||||
cmp cx16.r5 ; check single possible addr.mode
|
|
||||||
bne _not_found
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W2),y ; get opcode
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
|
|
||||||
_not_found lda #0
|
|
||||||
clc
|
|
||||||
rts
|
|
||||||
|
|
||||||
_multi_addrmodes
|
|
||||||
ldy cx16.r5
|
|
||||||
lda (P8ZP_SCRATCH_W2),y ; check opcode for addr.mode
|
|
||||||
bne _valid
|
|
||||||
; opcode $00 usually means 'invalid' but for "brk" it is actually valid so check for "brk"
|
|
||||||
lda (P8ZP_SCRATCH_W1)
|
|
||||||
and #$7f ; lowercase
|
|
||||||
cmp #'b'
|
|
||||||
bne _not_found
|
|
||||||
ldy #1
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
cmp #'r'
|
|
||||||
bne _not_found
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
cmp #'k'
|
|
||||||
bne _not_found
|
|
||||||
lda #0
|
|
||||||
_valid sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
%asminclude "opcodes.asm", ""
|
|
||||||
}
|
|
@ -1,167 +0,0 @@
|
|||||||
%target cx16
|
|
||||||
%import test_stack
|
|
||||||
%import textio
|
|
||||||
%zeropage basicsafe
|
|
||||||
%option no_sysinit
|
|
||||||
|
|
||||||
|
|
||||||
main {
|
|
||||||
|
|
||||||
sub start() {
|
|
||||||
txt.print("\nassembler benchmark - tree match routine\n")
|
|
||||||
|
|
||||||
benchmark.benchmark()
|
|
||||||
|
|
||||||
test_stack.test()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmark {
|
|
||||||
sub benchmark() {
|
|
||||||
str[20] mnemonics = ["lda", "ldx", "ldy", "jsr", "bcs", "rts", "lda", "ora", "and", "eor", "wai", "nop", "wai", "nop", "wai", "nop", "wai", "nop", "wai", "nop"]
|
|
||||||
ubyte[20] modes = [3, 4, 8, 8, 7, 1, 12, 13, 5, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
|
||||||
uword valid = 0
|
|
||||||
|
|
||||||
const uword iterations = 40000 / len(mnemonics)
|
|
||||||
const uword amount = iterations * len(mnemonics)
|
|
||||||
|
|
||||||
txt.print("matching ")
|
|
||||||
txt.print_uw(amount)
|
|
||||||
txt.print(" mnemonics")
|
|
||||||
|
|
||||||
c64.SETTIM(0,0,0)
|
|
||||||
|
|
||||||
uword total = 0
|
|
||||||
repeat iterations {
|
|
||||||
if lsb(total)==0
|
|
||||||
txt.chrout('.')
|
|
||||||
ubyte idx
|
|
||||||
for idx in 0 to len(mnemonics)-1 {
|
|
||||||
uword instr_info = instructions.match(mnemonics[idx])
|
|
||||||
ubyte opcode = instructions.opcode(instr_info, modes[idx])
|
|
||||||
if_cs
|
|
||||||
valid++
|
|
||||||
total++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uword current_time = c64.RDTIM16()
|
|
||||||
txt.print("\nvalid: ")
|
|
||||||
txt.print_uw(valid)
|
|
||||||
txt.print("\ninvalid: ")
|
|
||||||
txt.print_uw(amount-valid)
|
|
||||||
txt.print("\ntotal: ")
|
|
||||||
txt.print_uw(total)
|
|
||||||
txt.print("\n\nseconds:")
|
|
||||||
uword secs = current_time / 60
|
|
||||||
current_time = (current_time - secs*60)*1000/60
|
|
||||||
txt.print_uw(secs)
|
|
||||||
txt.chrout('.')
|
|
||||||
if current_time<10
|
|
||||||
txt.chrout('0')
|
|
||||||
if current_time<100
|
|
||||||
txt.chrout('0')
|
|
||||||
txt.print_uw(current_time)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions {
|
|
||||||
asmsub match(uword mnemonic_ptr @AY) -> uword @AY {
|
|
||||||
; -- input: mnemonic_ptr in AY, output: pointer to instruction info structure or $0000 in AY
|
|
||||||
%asm {{
|
|
||||||
phx
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
sty P8ZP_SCRATCH_W1+1
|
|
||||||
ldy #0
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
sta cx16.r4 ; fourth letter in R4 (only exists for the few 4-letter mnemonics)
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
sta cx16.r5 ; fifth letter in R5 (should always be zero or whitespace for a valid mnemonic)
|
|
||||||
pla
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
jsr get_opcode_info
|
|
||||||
plx
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub opcode(uword instr_info_ptr @AY, ubyte addr_mode @X) clobbers(X) -> ubyte @A, ubyte @Pc {
|
|
||||||
; -- input: instruction info struct ptr @AY, desired addr_mode @X
|
|
||||||
; output: opcode @A, valid @carrybit
|
|
||||||
%asm {{
|
|
||||||
cpy #0
|
|
||||||
beq _not_found
|
|
||||||
sta P8ZP_SCRATCH_W2
|
|
||||||
sty P8ZP_SCRATCH_W2+1
|
|
||||||
stx cx16.r15
|
|
||||||
|
|
||||||
; debug result address
|
|
||||||
;sec
|
|
||||||
;jsr txt.print_uwhex
|
|
||||||
;lda #13
|
|
||||||
;jsr c64.CHROUT
|
|
||||||
|
|
||||||
ldy #0
|
|
||||||
lda (P8ZP_SCRATCH_W2),y
|
|
||||||
beq _multi_addrmodes
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W2),y
|
|
||||||
cmp cx16.r15 ; check single possible addr.mode
|
|
||||||
bne _not_found
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W2),y ; get opcode
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
|
|
||||||
_not_found lda #0
|
|
||||||
clc
|
|
||||||
rts
|
|
||||||
|
|
||||||
_multi_addrmodes
|
|
||||||
ldy cx16.r15
|
|
||||||
lda (P8ZP_SCRATCH_W2),y ; check opcode for addr.mode
|
|
||||||
bne _valid
|
|
||||||
; opcode $00 usually means 'invalid' but for "brk" it is actually valid so check for "brk"
|
|
||||||
ldy #0
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
cmp #'b'
|
|
||||||
bne _not_found
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
cmp #'r'
|
|
||||||
bne _not_found
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W1),y
|
|
||||||
and #$7f ; lowercase
|
|
||||||
cmp #'k'
|
|
||||||
bne _not_found
|
|
||||||
lda #0
|
|
||||||
_valid sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
%asminclude "opcodes.asm", ""
|
|
||||||
}
|
|
@ -1,506 +0,0 @@
|
|||||||
import sys
|
|
||||||
from collections import Counter
|
|
||||||
from enum import IntEnum
|
|
||||||
|
|
||||||
|
|
||||||
class AddrMode(IntEnum):
|
|
||||||
Imp = 1,
|
|
||||||
Acc = 2,
|
|
||||||
Imm = 3,
|
|
||||||
Zp = 4,
|
|
||||||
ZpX = 5,
|
|
||||||
ZpY = 6,
|
|
||||||
Rel = 7,
|
|
||||||
Abs = 8,
|
|
||||||
AbsX = 9,
|
|
||||||
AbsY = 10,
|
|
||||||
Ind = 11,
|
|
||||||
IzX = 12,
|
|
||||||
IzY = 13,
|
|
||||||
Zpr = 14,
|
|
||||||
Izp = 15,
|
|
||||||
IaX = 16
|
|
||||||
|
|
||||||
|
|
||||||
AllInstructions = [
|
|
||||||
(0x00, "brk", AddrMode.Imp),
|
|
||||||
(0x01, "ora", AddrMode.IzX),
|
|
||||||
(0x02, "nop", AddrMode.Imm),
|
|
||||||
(0x03, "nop", AddrMode.Imp),
|
|
||||||
(0x04, "tsb", AddrMode.Zp),
|
|
||||||
(0x05, "ora", AddrMode.Zp),
|
|
||||||
(0x06, "asl", AddrMode.Zp),
|
|
||||||
(0x07, "rmb0", AddrMode.Zp),
|
|
||||||
(0x08, "php", AddrMode.Imp),
|
|
||||||
(0x09, "ora", AddrMode.Imm),
|
|
||||||
(0x0a, "asl", AddrMode.Acc),
|
|
||||||
(0x0b, "nop", AddrMode.Imp),
|
|
||||||
(0x0c, "tsb", AddrMode.Abs),
|
|
||||||
(0x0d, "ora", AddrMode.Abs),
|
|
||||||
(0x0e, "asl", AddrMode.Abs),
|
|
||||||
(0x0f, "bbr0", AddrMode.Zpr),
|
|
||||||
(0x10, "bpl", AddrMode.Rel),
|
|
||||||
(0x11, "ora", AddrMode.IzY),
|
|
||||||
(0x12, "ora", AddrMode.Izp),
|
|
||||||
(0x13, "nop", AddrMode.Imp),
|
|
||||||
(0x14, "trb", AddrMode.Zp),
|
|
||||||
(0x15, "ora", AddrMode.ZpX),
|
|
||||||
(0x16, "asl", AddrMode.ZpX),
|
|
||||||
(0x17, "rmb1", AddrMode.Zp),
|
|
||||||
(0x18, "clc", AddrMode.Imp),
|
|
||||||
(0x19, "ora", AddrMode.AbsY),
|
|
||||||
(0x1a, "inc", AddrMode.Acc),
|
|
||||||
(0x1b, "nop", AddrMode.Imp),
|
|
||||||
(0x1c, "trb", AddrMode.Abs),
|
|
||||||
(0x1d, "ora", AddrMode.AbsX),
|
|
||||||
(0x1e, "asl", AddrMode.AbsX),
|
|
||||||
(0x1f, "bbr1", AddrMode.Zpr),
|
|
||||||
(0x20, "jsr", AddrMode.Abs),
|
|
||||||
(0x21, "and", AddrMode.IzX),
|
|
||||||
(0x22, "nop", AddrMode.Imm),
|
|
||||||
(0x23, "nop", AddrMode.Imp),
|
|
||||||
(0x24, "bit", AddrMode.Zp),
|
|
||||||
(0x25, "and", AddrMode.Zp),
|
|
||||||
(0x26, "rol", AddrMode.Zp),
|
|
||||||
(0x27, "rmb2", AddrMode.Zp),
|
|
||||||
(0x28, "plp", AddrMode.Imp),
|
|
||||||
(0x29, "and", AddrMode.Imm),
|
|
||||||
(0x2a, "rol", AddrMode.Acc),
|
|
||||||
(0x2b, "nop", AddrMode.Imp),
|
|
||||||
(0x2c, "bit", AddrMode.Abs),
|
|
||||||
(0x2d, "and", AddrMode.Abs),
|
|
||||||
(0x2e, "rol", AddrMode.Abs),
|
|
||||||
(0x2f, "bbr2", AddrMode.Zpr),
|
|
||||||
(0x30, "bmi", AddrMode.Rel),
|
|
||||||
(0x31, "and", AddrMode.IzY),
|
|
||||||
(0x32, "and", AddrMode.Izp),
|
|
||||||
(0x33, "nop", AddrMode.Imp),
|
|
||||||
(0x34, "bit", AddrMode.ZpX),
|
|
||||||
(0x35, "and", AddrMode.ZpX),
|
|
||||||
(0x36, "rol", AddrMode.ZpX),
|
|
||||||
(0x37, "rmb3", AddrMode.Zp),
|
|
||||||
(0x38, "sec", AddrMode.Imp),
|
|
||||||
(0x39, "and", AddrMode.AbsY),
|
|
||||||
(0x3a, "dec", AddrMode.Acc),
|
|
||||||
(0x3b, "nop", AddrMode.Imp),
|
|
||||||
(0x3c, "bit", AddrMode.AbsX),
|
|
||||||
(0x3d, "and", AddrMode.AbsX),
|
|
||||||
(0x3e, "rol", AddrMode.AbsX),
|
|
||||||
(0x3f, "bbr3", AddrMode.Zpr),
|
|
||||||
(0x40, "rti", AddrMode.Imp),
|
|
||||||
(0x41, "eor", AddrMode.IzX),
|
|
||||||
(0x42, "nop", AddrMode.Imm),
|
|
||||||
(0x43, "nop", AddrMode.Imp),
|
|
||||||
(0x44, "nop", AddrMode.Zp),
|
|
||||||
(0x45, "eor", AddrMode.Zp),
|
|
||||||
(0x46, "lsr", AddrMode.Zp),
|
|
||||||
(0x47, "rmb4", AddrMode.Zp),
|
|
||||||
(0x48, "pha", AddrMode.Imp),
|
|
||||||
(0x49, "eor", AddrMode.Imm),
|
|
||||||
(0x4a, "lsr", AddrMode.Acc),
|
|
||||||
(0x4b, "nop", AddrMode.Imp),
|
|
||||||
(0x4c, "jmp", AddrMode.Abs),
|
|
||||||
(0x4d, "eor", AddrMode.Abs),
|
|
||||||
(0x4e, "lsr", AddrMode.Abs),
|
|
||||||
(0x4f, "bbr4", AddrMode.Zpr),
|
|
||||||
(0x50, "bvc", AddrMode.Rel),
|
|
||||||
(0x51, "eor", AddrMode.IzY),
|
|
||||||
(0x52, "eor", AddrMode.Izp),
|
|
||||||
(0x53, "nop", AddrMode.Imp),
|
|
||||||
(0x54, "nop", AddrMode.ZpX),
|
|
||||||
(0x55, "eor", AddrMode.ZpX),
|
|
||||||
(0x56, "lsr", AddrMode.ZpX),
|
|
||||||
(0x57, "rmb5", AddrMode.Zp),
|
|
||||||
(0x58, "cli", AddrMode.Imp),
|
|
||||||
(0x59, "eor", AddrMode.AbsY),
|
|
||||||
(0x5a, "phy", AddrMode.Imp),
|
|
||||||
(0x5b, "nop", AddrMode.Imp),
|
|
||||||
(0x5c, "nop", AddrMode.Abs),
|
|
||||||
(0x5d, "eor", AddrMode.AbsX),
|
|
||||||
(0x5e, "lsr", AddrMode.AbsX),
|
|
||||||
(0x5f, "bbr5", AddrMode.Zpr),
|
|
||||||
(0x60, "rts", AddrMode.Imp),
|
|
||||||
(0x61, "adc", AddrMode.IzX),
|
|
||||||
(0x62, "nop", AddrMode.Imm),
|
|
||||||
(0x63, "nop", AddrMode.Imp),
|
|
||||||
(0x64, "stz", AddrMode.Zp),
|
|
||||||
(0x65, "adc", AddrMode.Zp),
|
|
||||||
(0x66, "ror", AddrMode.Zp),
|
|
||||||
(0x67, "rmb6", AddrMode.Zp),
|
|
||||||
(0x68, "pla", AddrMode.Imp),
|
|
||||||
(0x69, "adc", AddrMode.Imm),
|
|
||||||
(0x6a, "ror", AddrMode.Acc),
|
|
||||||
(0x6b, "nop", AddrMode.Imp),
|
|
||||||
(0x6c, "jmp", AddrMode.Ind),
|
|
||||||
(0x6d, "adc", AddrMode.Abs),
|
|
||||||
(0x6e, "ror", AddrMode.Abs),
|
|
||||||
(0x6f, "bbr6", AddrMode.Zpr),
|
|
||||||
(0x70, "bvs", AddrMode.Rel),
|
|
||||||
(0x71, "adc", AddrMode.IzY),
|
|
||||||
(0x72, "adc", AddrMode.Izp),
|
|
||||||
(0x73, "nop", AddrMode.Imp),
|
|
||||||
(0x74, "stz", AddrMode.ZpX),
|
|
||||||
(0x75, "adc", AddrMode.ZpX),
|
|
||||||
(0x76, "ror", AddrMode.ZpX),
|
|
||||||
(0x77, "rmb7", AddrMode.Zp),
|
|
||||||
(0x78, "sei", AddrMode.Imp),
|
|
||||||
(0x79, "adc", AddrMode.AbsY),
|
|
||||||
(0x7a, "ply", AddrMode.Imp),
|
|
||||||
(0x7b, "nop", AddrMode.Imp),
|
|
||||||
(0x7c, "jmp", AddrMode.IaX),
|
|
||||||
(0x7d, "adc", AddrMode.AbsX),
|
|
||||||
(0x7e, "ror", AddrMode.AbsX),
|
|
||||||
(0x7f, "bbr7", AddrMode.Zpr),
|
|
||||||
(0x80, "bra", AddrMode.Rel),
|
|
||||||
(0x81, "sta", AddrMode.IzX),
|
|
||||||
(0x82, "nop", AddrMode.Imm),
|
|
||||||
(0x83, "nop", AddrMode.Imp),
|
|
||||||
(0x84, "sty", AddrMode.Zp),
|
|
||||||
(0x85, "sta", AddrMode.Zp),
|
|
||||||
(0x86, "stx", AddrMode.Zp),
|
|
||||||
(0x87, "smb0", AddrMode.Zp),
|
|
||||||
(0x88, "dey", AddrMode.Imp),
|
|
||||||
(0x89, "bit", AddrMode.Imm),
|
|
||||||
(0x8a, "txa", AddrMode.Imp),
|
|
||||||
(0x8b, "nop", AddrMode.Imp),
|
|
||||||
(0x8c, "sty", AddrMode.Abs),
|
|
||||||
(0x8d, "sta", AddrMode.Abs),
|
|
||||||
(0x8e, "stx", AddrMode.Abs),
|
|
||||||
(0x8f, "bbs0", AddrMode.Zpr),
|
|
||||||
(0x90, "bcc", AddrMode.Rel),
|
|
||||||
(0x91, "sta", AddrMode.IzY),
|
|
||||||
(0x92, "sta", AddrMode.Izp),
|
|
||||||
(0x93, "nop", AddrMode.Imp),
|
|
||||||
(0x94, "sty", AddrMode.ZpX),
|
|
||||||
(0x95, "sta", AddrMode.ZpX),
|
|
||||||
(0x96, "stx", AddrMode.ZpY),
|
|
||||||
(0x97, "smb1", AddrMode.Zp),
|
|
||||||
(0x98, "tya", AddrMode.Imp),
|
|
||||||
(0x99, "sta", AddrMode.AbsY),
|
|
||||||
(0x9a, "txs", AddrMode.Imp),
|
|
||||||
(0x9b, "nop", AddrMode.Imp),
|
|
||||||
(0x9c, "stz", AddrMode.Abs),
|
|
||||||
(0x9d, "sta", AddrMode.AbsX),
|
|
||||||
(0x9e, "stz", AddrMode.AbsX),
|
|
||||||
(0x9f, "bbs1", AddrMode.Zpr),
|
|
||||||
(0xa0, "ldy", AddrMode.Imm),
|
|
||||||
(0xa1, "lda", AddrMode.IzX),
|
|
||||||
(0xa2, "ldx", AddrMode.Imm),
|
|
||||||
(0xa3, "nop", AddrMode.Imp),
|
|
||||||
(0xa4, "ldy", AddrMode.Zp),
|
|
||||||
(0xa5, "lda", AddrMode.Zp),
|
|
||||||
(0xa6, "ldx", AddrMode.Zp),
|
|
||||||
(0xa7, "smb2", AddrMode.Zp),
|
|
||||||
(0xa8, "tay", AddrMode.Imp),
|
|
||||||
(0xa9, "lda", AddrMode.Imm),
|
|
||||||
(0xaa, "tax", AddrMode.Imp),
|
|
||||||
(0xab, "nop", AddrMode.Imp),
|
|
||||||
(0xac, "ldy", AddrMode.Abs),
|
|
||||||
(0xad, "lda", AddrMode.Abs),
|
|
||||||
(0xae, "ldx", AddrMode.Abs),
|
|
||||||
(0xaf, "bbs2", AddrMode.Zpr),
|
|
||||||
(0xb0, "bcs", AddrMode.Rel),
|
|
||||||
(0xb1, "lda", AddrMode.IzY),
|
|
||||||
(0xb2, "lda", AddrMode.Izp),
|
|
||||||
(0xb3, "nop", AddrMode.Imp),
|
|
||||||
(0xb4, "ldy", AddrMode.ZpX),
|
|
||||||
(0xb5, "lda", AddrMode.ZpX),
|
|
||||||
(0xb6, "ldx", AddrMode.ZpY),
|
|
||||||
(0xb7, "smb3", AddrMode.Zp),
|
|
||||||
(0xb8, "clv", AddrMode.Imp),
|
|
||||||
(0xb9, "lda", AddrMode.AbsY),
|
|
||||||
(0xba, "tsx", AddrMode.Imp),
|
|
||||||
(0xbb, "nop", AddrMode.Imp),
|
|
||||||
(0xbc, "ldy", AddrMode.AbsX),
|
|
||||||
(0xbd, "lda", AddrMode.AbsX),
|
|
||||||
(0xbe, "ldx", AddrMode.AbsY),
|
|
||||||
(0xbf, "bbs3", AddrMode.Zpr),
|
|
||||||
(0xc0, "cpy", AddrMode.Imm),
|
|
||||||
(0xc1, "cmp", AddrMode.IzX),
|
|
||||||
(0xc2, "nop", AddrMode.Imm),
|
|
||||||
(0xc3, "nop", AddrMode.Imp),
|
|
||||||
(0xc4, "cpy", AddrMode.Zp),
|
|
||||||
(0xc5, "cmp", AddrMode.Zp),
|
|
||||||
(0xc6, "dec", AddrMode.Zp),
|
|
||||||
(0xc7, "smb4", AddrMode.Zp),
|
|
||||||
(0xc8, "iny", AddrMode.Imp),
|
|
||||||
(0xc9, "cmp", AddrMode.Imm),
|
|
||||||
(0xca, "dex", AddrMode.Imp),
|
|
||||||
(0xcb, "wai", AddrMode.Imp),
|
|
||||||
(0xcc, "cpy", AddrMode.Abs),
|
|
||||||
(0xcd, "cmp", AddrMode.Abs),
|
|
||||||
(0xce, "dec", AddrMode.Abs),
|
|
||||||
(0xcf, "bbs4", AddrMode.Zpr),
|
|
||||||
(0xd0, "bne", AddrMode.Rel),
|
|
||||||
(0xd1, "cmp", AddrMode.IzY),
|
|
||||||
(0xd2, "cmp", AddrMode.Izp),
|
|
||||||
(0xd3, "nop", AddrMode.Imp),
|
|
||||||
(0xd4, "nop", AddrMode.ZpX),
|
|
||||||
(0xd5, "cmp", AddrMode.ZpX),
|
|
||||||
(0xd6, "dec", AddrMode.ZpX),
|
|
||||||
(0xd7, "smb5", AddrMode.Zp),
|
|
||||||
(0xd8, "cld", AddrMode.Imp),
|
|
||||||
(0xd9, "cmp", AddrMode.AbsY),
|
|
||||||
(0xda, "phx", AddrMode.Imp),
|
|
||||||
(0xdb, "stp", AddrMode.Imp),
|
|
||||||
(0xdc, "nop", AddrMode.Abs),
|
|
||||||
(0xdd, "cmp", AddrMode.AbsX),
|
|
||||||
(0xde, "dec", AddrMode.AbsX),
|
|
||||||
(0xdf, "bbs5", AddrMode.Zpr),
|
|
||||||
(0xe0, "cpx", AddrMode.Imm),
|
|
||||||
(0xe1, "sbc", AddrMode.IzX),
|
|
||||||
(0xe2, "nop", AddrMode.Imm),
|
|
||||||
(0xe3, "nop", AddrMode.Imp),
|
|
||||||
(0xe4, "cpx", AddrMode.Zp),
|
|
||||||
(0xe5, "sbc", AddrMode.Zp),
|
|
||||||
(0xe6, "inc", AddrMode.Zp),
|
|
||||||
(0xe7, "smb6", AddrMode.Zp),
|
|
||||||
(0xe8, "inx", AddrMode.Imp),
|
|
||||||
(0xe9, "sbc", AddrMode.Imm),
|
|
||||||
(0xea, "nop", AddrMode.Imp),
|
|
||||||
(0xeb, "nop", AddrMode.Imp),
|
|
||||||
(0xec, "cpx", AddrMode.Abs),
|
|
||||||
(0xed, "sbc", AddrMode.Abs),
|
|
||||||
(0xee, "inc", AddrMode.Abs),
|
|
||||||
(0xef, "bbs6", AddrMode.Zpr),
|
|
||||||
(0xf0, "beq", AddrMode.Rel),
|
|
||||||
(0xf1, "sbc", AddrMode.IzY),
|
|
||||||
(0xf2, "sbc", AddrMode.Izp),
|
|
||||||
(0xf3, "nop", AddrMode.Imp),
|
|
||||||
(0xf4, "nop", AddrMode.ZpX),
|
|
||||||
(0xf5, "sbc", AddrMode.ZpX),
|
|
||||||
(0xf6, "inc", AddrMode.ZpX),
|
|
||||||
(0xf7, "smb7", AddrMode.Zp),
|
|
||||||
(0xf8, "sed", AddrMode.Imp),
|
|
||||||
(0xf9, "sbc", AddrMode.AbsY),
|
|
||||||
(0xfa, "plx", AddrMode.Imp),
|
|
||||||
(0xfb, "nop", AddrMode.Imp),
|
|
||||||
(0xfc, "nop", AddrMode.AbsX),
|
|
||||||
(0xfd, "sbc", AddrMode.AbsX),
|
|
||||||
(0xfe, "inc", AddrMode.AbsX),
|
|
||||||
(0xff, "bbs7", AddrMode.Zpr)
|
|
||||||
]
|
|
||||||
|
|
||||||
# NOP is weird, it is all over the place.
|
|
||||||
# For the 'common' immediate NOP, keep only the $EA opcode (this was the original NOP on the 6502)
|
|
||||||
Instructions = [ins for ins in AllInstructions if ins[1] != "nop"] + [(0xea, "nop", AddrMode.Imp)]
|
|
||||||
|
|
||||||
|
|
||||||
InstructionsByName = {}
|
|
||||||
for ins in Instructions:
|
|
||||||
if ins[1] not in InstructionsByName:
|
|
||||||
InstructionsByName[ins[1]] = {ins[2]: ins[0]}
|
|
||||||
else:
|
|
||||||
InstructionsByName[ins[1]][ins[2]] = ins[0]
|
|
||||||
|
|
||||||
InstructionsByMode = {}
|
|
||||||
for ins in Instructions:
|
|
||||||
if ins[2] not in InstructionsByMode:
|
|
||||||
InstructionsByMode[ins[2]] = [(ins[1], ins[0])]
|
|
||||||
else:
|
|
||||||
InstructionsByMode[ins[2]].append((ins[1], ins[0]))
|
|
||||||
|
|
||||||
|
|
||||||
def generate_mnemonics_parser():
|
|
||||||
print("; generated by opcodes.py")
|
|
||||||
print("; addressing modes:")
|
|
||||||
for mode in AddrMode:
|
|
||||||
print(";", mode.value, "=", mode.name)
|
|
||||||
print()
|
|
||||||
|
|
||||||
print("""
|
|
||||||
.enc "petscii" ;define an ascii to petscii encoding
|
|
||||||
.cdef " @", 32 ;characters
|
|
||||||
.cdef "AZ", $c1
|
|
||||||
.cdef "az", $41
|
|
||||||
.cdef "[[", $5b
|
|
||||||
.cdef "]]", $5d
|
|
||||||
.edef "<nothing>", [];replace with no bytes
|
|
||||||
""")
|
|
||||||
|
|
||||||
for instr in sorted(InstructionsByName.items()):
|
|
||||||
print("i_" + instr[0] + ":\n\t.byte ", end="")
|
|
||||||
if len(instr[1]) == 1:
|
|
||||||
# many instructions have just 1 addressing mode, save space for those
|
|
||||||
info = instr[1].popitem()
|
|
||||||
print("1,", info[0].value,",", info[1])
|
|
||||||
else:
|
|
||||||
print("0, ", end='')
|
|
||||||
mode_opcodes = []
|
|
||||||
for mode in AddrMode:
|
|
||||||
if mode in instr[1]:
|
|
||||||
mode_opcodes.append(instr[1][mode])
|
|
||||||
else:
|
|
||||||
mode_opcodes.append(0)
|
|
||||||
print(",".join(str(o) for o in mode_opcodes), end="")
|
|
||||||
print()
|
|
||||||
|
|
||||||
def determine_mnemonics():
|
|
||||||
mnemonics = list(sorted(set(ins[1] for ins in Instructions)))
|
|
||||||
|
|
||||||
# opcodes histogram (ordered by occurrence) (in kernal + basic roms of the c64):
|
|
||||||
opcode_occurrences = [
|
|
||||||
(32, 839), (133, 502), (165, 488), (0, 429), (208, 426), (169, 390), (76, 324), (240, 322), (2, 314), (160, 245),
|
|
||||||
(96, 228), (3, 201), (1, 191), (255, 186), (144, 182), (170, 175), (162, 169), (177, 165), (104, 159), (164, 158),
|
|
||||||
(132, 157), (201, 156), (72, 151), (141, 150), (200, 146), (173, 144), (166, 139), (176, 139), (16, 138),
|
|
||||||
(134, 138), (73, 127), (24, 119), (101, 113), (69, 109), (13, 107), (34, 104), (145, 103), (4, 102), (168, 101),
|
|
||||||
(221, 98), (230, 93), (48, 91), (189, 87), (41, 86), (6, 86), (9, 86), (8, 85), (79, 85), (138, 80), (10, 80),
|
|
||||||
(7, 79), (185, 77), (56, 75), (44, 75), (78, 74), (105, 73), (5, 73), (174, 73), (220, 71), (198, 69), (232, 69),
|
|
||||||
(36, 69), (202, 67), (152, 67), (95, 67), (100, 65), (102, 65), (247, 65), (188, 64), (136, 64), (84, 64),
|
|
||||||
(122, 62), (128, 61), (80, 61), (186, 60), (82, 59), (97, 58), (15, 57), (70, 57), (229, 56), (19, 55), (40, 54),
|
|
||||||
(183, 54), (65, 54), (233, 53), (180, 53), (12, 53), (171, 53), (197, 53), (83, 52), (248, 52), (112, 51),
|
|
||||||
(237, 51), (89, 50), (11, 50), (158, 50), (74, 49), (224, 48), (20, 47), (238, 47), (108, 46), (234, 46),
|
|
||||||
(251, 46), (254, 46), (184, 45), (14, 44), (163, 44), (226, 43), (211, 43), (88, 43), (98, 42), (17, 42),
|
|
||||||
(153, 42), (243, 41), (228, 41), (99, 41), (253, 41), (209, 41), (187, 39), (123, 39), (67, 39), (196, 38),
|
|
||||||
(68, 38), (35, 38), (172, 38), (175, 38), (161, 38), (85, 38), (191, 37), (113, 37), (182, 37), (151, 37),
|
|
||||||
(71, 36), (181, 35), (214, 35), (121, 35), (157, 35), (178, 35), (77, 35), (42, 34), (212, 33), (18, 33),
|
|
||||||
(127, 33), (241, 33), (21, 33), (249, 32), (23, 31), (245, 30), (142, 30), (55, 29), (140, 29), (46, 29),
|
|
||||||
(192, 29), (179, 29), (252, 29), (115, 29), (22, 29), (43, 28), (215, 28), (45, 28), (246, 28), (38, 28),
|
|
||||||
(86, 27), (225, 27), (25, 26), (239, 26), (58, 26), (167, 26), (147, 26), (217, 26), (149, 25), (30, 25),
|
|
||||||
(206, 25), (28, 24), (47, 24), (37, 24), (155, 24), (129, 23), (148, 23), (111, 23), (29, 23), (39, 23),
|
|
||||||
(51, 22), (193, 22), (236, 22), (120, 22), (64, 22), (204, 21), (210, 21), (244, 21), (52, 21), (66, 21),
|
|
||||||
(114, 20), (250, 20), (106, 20), (93, 19), (199, 19), (218, 19), (154, 19), (205, 19), (50, 19), (159, 19),
|
|
||||||
(194, 19), (49, 19), (190, 19), (103, 18), (216, 18), (213, 18), (107, 18), (131, 18), (63, 18), (94, 18),
|
|
||||||
(91, 17), (242, 17), (109, 17), (53, 16), (227, 16), (139, 16), (31, 16), (75, 16), (60, 16), (195, 15),
|
|
||||||
(231, 15), (62, 15), (59, 15), (87, 14), (207, 14), (27, 14), (90, 14), (110, 13), (223, 13), (57, 13),
|
|
||||||
(118, 12), (26, 12), (203, 12), (81, 12), (156, 12), (54, 12), (235, 12), (146, 11), (135, 11), (126, 11),
|
|
||||||
(150, 11), (130, 11), (143, 10), (61, 10), (219, 10), (124, 9), (222, 9), (125, 9), (119, 7), (137, 7),
|
|
||||||
(33, 7), (117, 5), (92, 4), (116, 3)
|
|
||||||
]
|
|
||||||
|
|
||||||
cnt = Counter()
|
|
||||||
for opcode, amount in opcode_occurrences:
|
|
||||||
cnt[AllInstructions[opcode][1]] += amount
|
|
||||||
cnt["nop"] = 13
|
|
||||||
cnt["tsb"] = 13
|
|
||||||
|
|
||||||
four_letter_mnemonics = list(sorted([ins[1] for ins in AllInstructions if len(ins[1])>3]))
|
|
||||||
for ins4 in four_letter_mnemonics:
|
|
||||||
del cnt[ins4]
|
|
||||||
cnt[ins4] = 1
|
|
||||||
mnem2 = [c[0] for c in cnt.most_common()]
|
|
||||||
if len(mnem2)!=len(mnemonics):
|
|
||||||
raise ValueError("mnem count mismatch")
|
|
||||||
return mnem2
|
|
||||||
|
|
||||||
mnemonics = determine_mnemonics()
|
|
||||||
|
|
||||||
def first_letters():
|
|
||||||
firstletters = {m[0]: 0 for m in mnemonics}
|
|
||||||
return firstletters.keys()
|
|
||||||
|
|
||||||
def second_letters(firstletter):
|
|
||||||
secondletters = {m[1]: 0 for m in mnemonics if m[0] == firstletter}
|
|
||||||
return secondletters.keys()
|
|
||||||
|
|
||||||
def third_letters(firstletter, secondletter):
|
|
||||||
thirdletters = {m[2]: 0 for m in mnemonics if m[0] == firstletter and m[1] == secondletter}
|
|
||||||
return thirdletters.keys()
|
|
||||||
|
|
||||||
def fourth_letters(firstletter, secondletter, thirdletter):
|
|
||||||
longmnem = [m for m in mnemonics if len(m) > 3]
|
|
||||||
fourthletters = {m[3]: 0 for m in longmnem if m[0] == firstletter and m[1] == secondletter and m[2] == thirdletter}
|
|
||||||
return fourthletters.keys()
|
|
||||||
|
|
||||||
def make_tree():
|
|
||||||
tree = {}
|
|
||||||
for first in first_letters():
|
|
||||||
tree[first] = {
|
|
||||||
secondletter: {
|
|
||||||
thirdletter: {
|
|
||||||
fourthletter: {}
|
|
||||||
for fourthletter in fourth_letters(first, secondletter, thirdletter)
|
|
||||||
}
|
|
||||||
for thirdletter in third_letters(first, secondletter)
|
|
||||||
}
|
|
||||||
for secondletter in second_letters(first)
|
|
||||||
}
|
|
||||||
return tree
|
|
||||||
|
|
||||||
tree = make_tree()
|
|
||||||
|
|
||||||
print("get_opcode_info .proc")
|
|
||||||
print("_mnem_fourth_letter = cx16.r4")
|
|
||||||
print("_mnem_fifth_letter = cx16.r5")
|
|
||||||
for first in tree:
|
|
||||||
print(" cmp #'%s'" % first)
|
|
||||||
print(" bne _not_%s" % first)
|
|
||||||
for second in tree[first]:
|
|
||||||
print(" cpx #'%s'" % second)
|
|
||||||
print(" bne _not_%s%s" % (first,second))
|
|
||||||
for third in tree[first][second]:
|
|
||||||
print(" cpy #'%s'" % third)
|
|
||||||
print(" bne _not_%s%s%s" % (first, second, third))
|
|
||||||
fourth = tree[first][second][third]
|
|
||||||
if fourth:
|
|
||||||
if "".join(fourth.keys()) != "01234567":
|
|
||||||
raise ValueError("fourth", fourth.keys())
|
|
||||||
print(" bra _check_%s%s%s" % (first, second, third))
|
|
||||||
else:
|
|
||||||
print(" lda _mnem_fourth_letter") # check that the fourth letter is not present
|
|
||||||
print(" bne _invalid")
|
|
||||||
print(" lda #<i_%s%s%s" % (first, second, third))
|
|
||||||
print(" ldy #>i_%s%s%s" % (first, second, third))
|
|
||||||
print(" rts")
|
|
||||||
print("_not_%s%s%s:" % (first, second, third))
|
|
||||||
print("_not_%s%s:" % (first, second))
|
|
||||||
print("_not_%s:" % first)
|
|
||||||
print("_invalid:")
|
|
||||||
print(" lda #0")
|
|
||||||
print(" ldy #0")
|
|
||||||
print(" rts")
|
|
||||||
|
|
||||||
# the 4-letter mnemonics are:
|
|
||||||
# smb[0-7]
|
|
||||||
# bbr[0-7]
|
|
||||||
# rmb[0-7]
|
|
||||||
# bbs[0-7]
|
|
||||||
for fourlettermnemonic in ["smb", "bbr", "rmb", "bbs"]:
|
|
||||||
print("_check_%s" % fourlettermnemonic)
|
|
||||||
print(" lda #<_tab_%s" % fourlettermnemonic)
|
|
||||||
print(" ldy #>_tab_%s" % fourlettermnemonic)
|
|
||||||
print(""" sta P8ZP_SCRATCH_W2
|
|
||||||
sty P8ZP_SCRATCH_W2+1
|
|
||||||
bra _check4""")
|
|
||||||
|
|
||||||
print("""_check4
|
|
||||||
lda _mnem_fourth_letter
|
|
||||||
cmp #'0'
|
|
||||||
bcc _invalid
|
|
||||||
cmp #'8'
|
|
||||||
bcs _invalid
|
|
||||||
lda _mnem_fifth_letter ; must have no fifth letter
|
|
||||||
bne _invalid
|
|
||||||
lda _mnem_fourth_letter
|
|
||||||
sec
|
|
||||||
sbc #'0'
|
|
||||||
asl a
|
|
||||||
tay
|
|
||||||
lda (P8ZP_SCRATCH_W2),y
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda (P8ZP_SCRATCH_W2),y
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
rts""")
|
|
||||||
|
|
||||||
for fourlettermnemonic in ["smb", "bbr", "rmb", "bbs"]:
|
|
||||||
print("_tab_%s" % fourlettermnemonic)
|
|
||||||
for ii in "01234567":
|
|
||||||
print(" .word i_%s%s" % (fourlettermnemonic, ii))
|
|
||||||
|
|
||||||
print(" .pend")
|
|
||||||
|
|
||||||
|
|
||||||
def generate_mnem_list():
|
|
||||||
for m in sorted(InstructionsByName):
|
|
||||||
print(m.upper())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__=="__main__":
|
|
||||||
if sys.argv[1]=="--mnemlist":
|
|
||||||
generate_mnem_list()
|
|
||||||
elif sys.argv[1]=="--parser":
|
|
||||||
generate_mnemonics_parser()
|
|
||||||
else:
|
|
||||||
print("invalid arg")
|
|
@ -1,17 +0,0 @@
|
|||||||
import re
|
|
||||||
|
|
||||||
hashcode = open("perfecthash.c", "rt").read()
|
|
||||||
|
|
||||||
entries = hashcode.split("wordlist")[1].split("{")[1].split("}")[0].strip().split(",")
|
|
||||||
|
|
||||||
max_hash_value = int(re.search(r"MAX_HASH_VALUE = (\d+)", hashcode).group(1))
|
|
||||||
|
|
||||||
if len(entries) != max_hash_value+1:
|
|
||||||
raise ValueError("inconsistent number of entries parsed")
|
|
||||||
|
|
||||||
|
|
||||||
entries = [e.strip() for e in entries]
|
|
||||||
entries = [None if e.endswith('0') else e.strip('"') for e in entries]
|
|
||||||
|
|
||||||
for ix, entry in enumerate(entries):
|
|
||||||
print(ix, entry or "-")
|
|
@ -1,152 +0,0 @@
|
|||||||
|
|
||||||
def in_word_set(string: str) -> bool:
|
|
||||||
length = len(string)
|
|
||||||
|
|
||||||
wordlist = [
|
|
||||||
"PHP",
|
|
||||||
"ROR",
|
|
||||||
"STP",
|
|
||||||
"RTS",
|
|
||||||
"RTI",
|
|
||||||
"TXS",
|
|
||||||
"PHY",
|
|
||||||
"TRB",
|
|
||||||
"EOR",
|
|
||||||
"STY",
|
|
||||||
"PHX",
|
|
||||||
"TSB",
|
|
||||||
"TAY",
|
|
||||||
"STX",
|
|
||||||
"BRK",
|
|
||||||
"LSR",
|
|
||||||
"TAX",
|
|
||||||
"TSX",
|
|
||||||
"PHA",
|
|
||||||
"PLP",
|
|
||||||
"BRA",
|
|
||||||
"STA",
|
|
||||||
"ROL",
|
|
||||||
"BCS",
|
|
||||||
"SEI",
|
|
||||||
"TXA",
|
|
||||||
"LDY",
|
|
||||||
"PLY",
|
|
||||||
"INY",
|
|
||||||
"LDX",
|
|
||||||
"PLX",
|
|
||||||
"NOP",
|
|
||||||
"INX",
|
|
||||||
"CLI",
|
|
||||||
"ASL",
|
|
||||||
"SBC",
|
|
||||||
"BMI",
|
|
||||||
"LDA",
|
|
||||||
"PLA",
|
|
||||||
"ORA",
|
|
||||||
"BNE",
|
|
||||||
"ADC",
|
|
||||||
"BBS7",
|
|
||||||
"BBR7",
|
|
||||||
"CMP",
|
|
||||||
"CPY",
|
|
||||||
"INC",
|
|
||||||
"SEC",
|
|
||||||
"BCC",
|
|
||||||
"CPX",
|
|
||||||
"BPL",
|
|
||||||
"DEY",
|
|
||||||
"TYA",
|
|
||||||
"CLV",
|
|
||||||
"DEX",
|
|
||||||
"CLC",
|
|
||||||
"BBS6",
|
|
||||||
"BBR6",
|
|
||||||
"BBS5",
|
|
||||||
"BBR5",
|
|
||||||
"SMB7",
|
|
||||||
"RMB7",
|
|
||||||
"STZ",
|
|
||||||
"SED",
|
|
||||||
"BBS4",
|
|
||||||
"BBR4",
|
|
||||||
"DEC",
|
|
||||||
"BBS3",
|
|
||||||
"BBR3",
|
|
||||||
"BBS2",
|
|
||||||
"BBR2",
|
|
||||||
"AND",
|
|
||||||
"CLD",
|
|
||||||
"BBS1",
|
|
||||||
"BBR1",
|
|
||||||
"BEQ",
|
|
||||||
"SMB6",
|
|
||||||
"RMB6",
|
|
||||||
"SMB5",
|
|
||||||
"RMB5",
|
|
||||||
"BBS0",
|
|
||||||
"BBR0",
|
|
||||||
"BVS",
|
|
||||||
"WAI",
|
|
||||||
"SMB4",
|
|
||||||
"RMB4",
|
|
||||||
"JSR",
|
|
||||||
"SMB3",
|
|
||||||
"RMB3",
|
|
||||||
"SMB2",
|
|
||||||
"RMB2",
|
|
||||||
"BIT",
|
|
||||||
"SMB1",
|
|
||||||
"RMB1",
|
|
||||||
"SMB0",
|
|
||||||
"RMB0",
|
|
||||||
"BVC",
|
|
||||||
"JMP"
|
|
||||||
]
|
|
||||||
|
|
||||||
lookup = [
|
|
||||||
-1, 0, -1, 1, 2, 3, -1, 4, 5, 6, 7, 8, 9, 10,
|
|
||||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
|
||||||
25, 26, 27, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
|
|
||||||
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, -1, 50,
|
|
||||||
51, 52, -1, 53, 54, 55, -1, 56, 57, 58, 59, -1, 60, 61,
|
|
||||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, -1, 72, 73, 74,
|
|
||||||
75, 76, 77, 78, 79, 80, 81, 82, -1, 83, 84, 85, 86, 87,
|
|
||||||
88, 89, 90, 91, -1, -1, 92, 93, -1, -1, -1, -1, -1, 94,
|
|
||||||
95, -1, -1, -1, -1, 96, -1, -1, -1, -1, -1, -1, -1, 97
|
|
||||||
]
|
|
||||||
|
|
||||||
asso_values = [
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 73, 66,
|
|
||||||
61, 59, 56, 49, 47, 30, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 10, 3, 13, 23, 9,
|
|
||||||
25, 126, 126, 1, 90, 7, 12, 22, 35, 23,
|
|
||||||
0, 28, 1, 0, 4, 4, 12, 88, 6, 4,
|
|
||||||
33, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
|
|
||||||
126, 126, 126, 126, 126, 126, 126, 126, 126
|
|
||||||
]
|
|
||||||
|
|
||||||
print(len(lookup))
|
|
||||||
print(len(asso_values))
|
|
||||||
|
|
||||||
def hash(string: str, length: len) -> int:
|
|
||||||
return asso_values[ord(string[2])] + \
|
|
||||||
asso_values[ord(string[1])+1] + \
|
|
||||||
asso_values[ord(string[0])] + \
|
|
||||||
asso_values[ord(string[length - 1])]
|
|
||||||
|
|
||||||
MAX_HASH_VALUE = 125
|
|
||||||
|
|
||||||
if 3<=length<=4:
|
|
||||||
key = hash(string, length)
|
|
||||||
if key <= MAX_HASH_VALUE:
|
|
||||||
index = lookup[key]
|
|
||||||
if index>=0:
|
|
||||||
word = wordlist[index]
|
|
||||||
return word==string
|
|
||||||
return False
|
|
@ -1,72 +0,0 @@
|
|||||||
; program to test the loading speed
|
|
||||||
|
|
||||||
.cpu "65c02"
|
|
||||||
*=$0801
|
|
||||||
; 10 sys 2061
|
|
||||||
.byte $0b, $08, $0a, $00, $9e, $32, $30, $36
|
|
||||||
.byte $31, $00, $00, $00
|
|
||||||
|
|
||||||
start
|
|
||||||
|
|
||||||
stz $9f60 ; switch to kernal bank for faster i/o
|
|
||||||
phx
|
|
||||||
|
|
||||||
ldx #<_filename
|
|
||||||
ldy #>_filename
|
|
||||||
lda #10
|
|
||||||
jsr $FFBD ; SETNAM
|
|
||||||
jmp _go
|
|
||||||
_filename
|
|
||||||
.text "romdis.asm"
|
|
||||||
|
|
||||||
_go
|
|
||||||
lda #0
|
|
||||||
tax
|
|
||||||
tay
|
|
||||||
jsr $FFDB ; SETTIM 0,0,0
|
|
||||||
|
|
||||||
lda #1
|
|
||||||
ldx #8
|
|
||||||
ldy #0
|
|
||||||
jsr $FFBA ; SETLFS 1,8,0
|
|
||||||
jsr $FFC0 ; OPEN
|
|
||||||
ldx #1
|
|
||||||
jsr $FFC6 ; CHKIN, use #1 as output channel
|
|
||||||
;lda #'.'
|
|
||||||
;jsr $FFD2 ; CHROUT
|
|
||||||
|
|
||||||
; load the file ....
|
|
||||||
_loop
|
|
||||||
jsr $ffb7 ;READST
|
|
||||||
bne _eof
|
|
||||||
jsr $FFCF ;CHRIN
|
|
||||||
sta $02 ; store...
|
|
||||||
jmp _loop
|
|
||||||
|
|
||||||
_eof
|
|
||||||
; close stuff
|
|
||||||
jsr $FFCC ;CLRCHN
|
|
||||||
lda #1
|
|
||||||
jsr $FFC3 ;CLOSE
|
|
||||||
|
|
||||||
lda #4
|
|
||||||
sta $9f60
|
|
||||||
|
|
||||||
; print the time taken
|
|
||||||
jsr $FFDE ; RDTIM -> A,X,Y
|
|
||||||
tay
|
|
||||||
txa
|
|
||||||
jsr $fe03 ; GIVAYF
|
|
||||||
jsr $fe81 ; FOUT
|
|
||||||
sta 2
|
|
||||||
sty 3
|
|
||||||
ldy #0
|
|
||||||
_printlp
|
|
||||||
lda (2),y
|
|
||||||
beq _endstr
|
|
||||||
jsr $FFD2 ; CHROUT
|
|
||||||
iny
|
|
||||||
bne _printlp
|
|
||||||
_endstr
|
|
||||||
plx
|
|
||||||
rts
|
|
Loading…
x
Reference in New Issue
Block a user