Skip to content

Instantly share code, notes, and snippets.

@andrew-wilkes
Created March 25, 2024 13:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrew-wilkes/7ee58170750c6f66fd7809489f3ebeb4 to your computer and use it in GitHub Desktop.
Save andrew-wilkes/7ee58170750c6f66fd7809489f3ebeb4 to your computer and use it in GitHub Desktop.
6502 Assembler Code
func process_lines_pass1(lines):
var addr = 0
var line_num = 0
for line in lines:
line_num += 1
var label = ""
var directive = ""
var op_code = -1
var op_token = ""
var no_comment_line = remove_comment(line, ";")
if no_comment_line.length() < 1: continue
var tokens = no_comment_line.to_upper().split(" ", false)
var operand = ""
for token in tokens:
if token.ends_with(":"):
if token.length() < 2:
return format_error(line_num, "Invalid label")
label = token.left(-1)
# Assign initial value to label
labels[label] = addr
directive = "label"
continue
if token.begins_with("."):
directive = token.right(-1)
op_code = -2 # Don't evaluate next token as op code
continue
if op_code == -1:
op_token = token
op_code = -2 # Skip op code
directive = ""
continue
else:
operand += token
# Evaluate operand
if directive == "":
match operand:
"", "A":
addr += 1
_ when operand.begins_with("("):
if operand.ends_with("X)"):
addr += 2
elif operand.ends_with(")"):
addr += 3
else:
addr += 2
_ when op_token.begins_with("B"):
addr += 2
_ when get_number(operand) > 255:
addr += 3
_ when is_label(operand):
# A label that has a 16 bit value
addr += 3
_:
addr += 2
else:
match directive:
"ORG":
addr = get_number(operand)
if addr < 0:
return format_error(line_num, "Invalid .org value: " + operand)
if label != "":
labels[label] = addr
"DB":
var values = operand.split(",")
addr += values.size()
"DW":
var values = operand.split(",")
addr += 2 * values.size()
"DL":
var values = operand.split(",")
addr += 3 * values.size()
"DS":
addr += get_number(operand)
ordered_labels = labels.keys()
ordered_labels.sort()
ordered_labels.reverse()
return "ok"
func process_lines_pass2(lines):
list = []
var addr = 0
var line_num = 0
for line in lines:
line_num += 1
var list_line = ""
var num_bytes = 0
var mode = ""
var directive = ""
var op_code = -1
var op_token = ""
var no_comment_line = remove_comment(line, ";")
if no_comment_line.length() < 1:
list.append(line)
continue
var tokens = no_comment_line.to_upper().split(" ", false)
var operand = ""
for token in tokens:
if token.ends_with(":"):
mode = "label"
list_line = line
continue
if token.begins_with("."):
mode = "dir"
directive = token.right(-1)
op_code = -2 # Don't evaluate next token as op code
continue
if op_code == -1:
op_token = token
op_code = OP_CODES.find(op_token)
if op_code < 0:
return format_error(line_num, "Invalid op_code " + token)
else:
operand += token
# Evaluate operand
operand = replace_labels(operand)
var num: int = get_number(operand)
match mode:
"":
match operand:
"":
mode = "impl"
"A":
mode = "A"
_:
var last_chr = operand[-1]
match operand[0]:
"#":
mode = "#"
num_bytes = 1
"(":
num_bytes = 1
match last_chr:
")" when operand[-2] == "X":
mode = "X,ind"
"Y":
mode = "ind,Y"
_:
mode = "ind"
num_bytes = 2
_ when op_token.begins_with("B"):
mode = "rel"
num_bytes = 1
# Convert number to a relative offset
num = num - addr - 2
if num < 0: num = 256 + num
_ when num > 255:
num_bytes = 2
match last_chr:
"X":
mode = "abs,X"
"Y":
mode = "abs,Y"
_:
mode = "abs"
_:
num_bytes = 1
match last_chr:
"X":
mode = "zpg,X"
"Y":
mode = "zpg,Y"
_:
mode = "zpg"
bytes[addr] = MAP.find([op_token, mode])
list_line = "%04x : %02x" % [addr, bytes[addr]]
addr += 1
# Add bytes for number
if num_bytes > 0:
bytes[addr] = num & 0xff
list_line += "%02x" % bytes[addr]
addr += 1
if num_bytes == 2:
bytes[addr] = num / 256
list_line += "%02x" % bytes[addr]
addr += 1
list_line = list_line.rpad(16) + line
"dir":
match directive:
"ORG":
addr = get_number(operand)
list_line = "%04x = %s" % [addr, line]
"DB":
list_line = "%04x : " % addr
var values = operand.split(",")
for value in values:
var v = get_number(value) & 0xff
list_line += "%02x" % v
bytes[addr] = v
addr += 1
list_line = list_line.rpad(16) + line
"DW":
list_line = "%04x : " % addr
var values = operand.split(",")
for value in values:
num = get_number(value)
var v = num & 0xff
list_line += "%02x" % v
bytes[addr] = v
addr += 1
v = (num / 0x100) & 0xff
list_line += "%02x" % v
bytes[addr] = v
addr += 1
list_line = list_line.rpad(16) + line
"DL":
list_line = "%04x : " % addr
var values = operand.split(",")
for value in values:
num = get_number_from_text(value)
for n in 4:
var v = num & 0xff
list_line += "%02x" % v
bytes[addr] = v
num /= 0x100
addr += 1
list_line = list_line.rpad(16) + line
"DS":
list_line = ("%04x : " % addr).rpad(16) + line
addr += get_number(operand)
list.append(list_line)
return "ok"
@andrew-wilkes
Copy link
Author

The first pass' primary purpose is to set the values of the labels to address values. The .org directive needs an actual number though for its operand.
The second pass does everything else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment