Created
March 25, 2024 13:13
-
-
Save andrew-wilkes/7ee58170750c6f66fd7809489f3ebeb4 to your computer and use it in GitHub Desktop.
6502 Assembler Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.