mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
subroutines
This commit is contained in:
parent
37f049ee54
commit
63aa3cae8c
@ -229,14 +229,33 @@ class CodeGenerator:
|
|||||||
self.p("* = ${:04x}".format(block.address))
|
self.p("* = ${:04x}".format(block.address))
|
||||||
self.p("{:s}\t.proc\n".format(block.label))
|
self.p("{:s}\t.proc\n".format(block.label))
|
||||||
self.generate_block_vars(block)
|
self.generate_block_vars(block)
|
||||||
subroutines = list(block.symbols.iter_subroutines())
|
subroutines = list(sub for sub in block.symbols.iter_subroutines() if sub.address is not None)
|
||||||
if subroutines:
|
if subroutines:
|
||||||
self.p("\n; external subroutines")
|
self.p("\n; external subroutines")
|
||||||
for subdef in subroutines:
|
for subdef in subroutines:
|
||||||
|
assert subdef.sub_block is None
|
||||||
self.p("\t\t{:s} = {:s}".format(subdef.name, Parser.to_hex(subdef.address)))
|
self.p("\t\t{:s} = {:s}".format(subdef.name, Parser.to_hex(subdef.address)))
|
||||||
self.p("; end external subroutines")
|
self.p("; end external subroutines")
|
||||||
for stmt in block.statements:
|
for stmt in block.statements:
|
||||||
self.generate_statement(stmt)
|
self.generate_statement(stmt)
|
||||||
|
subroutines = list(sub for sub in block.symbols.iter_subroutines() if sub.address is None)
|
||||||
|
if subroutines:
|
||||||
|
self.p("\n; block subroutines")
|
||||||
|
for subdef in subroutines:
|
||||||
|
assert subdef.sub_block is not None
|
||||||
|
self.p("{:s}\t\t; src l. {:d}".format(subdef.name, subdef.sourceref.line))
|
||||||
|
params = ", ".join("{:s} -> {:s}".format(p[0] or "<unnamed>", p[1]) for p in subdef.parameters)
|
||||||
|
returns = ",".join(sorted(subdef.return_registers))
|
||||||
|
clobbers = ",".join(sorted(subdef.clobbered_registers))
|
||||||
|
self.p("\t\t; params: {}\n\t\t; returns: {} clobbers: {}"
|
||||||
|
.format(params or "-", returns or "-", clobbers or "-"))
|
||||||
|
cur_block = self.cur_block
|
||||||
|
self.cur_block = subdef.sub_block
|
||||||
|
for stmt in subdef.sub_block.statements:
|
||||||
|
self.generate_statement(stmt)
|
||||||
|
self.cur_block = cur_block
|
||||||
|
self.p("")
|
||||||
|
self.p("; end external subroutines")
|
||||||
self.p("\t.pend\n")
|
self.p("\t.pend\n")
|
||||||
|
|
||||||
def generate_block_vars(self, block: ParseResult.Block) -> None:
|
def generate_block_vars(self, block: ParseResult.Block) -> None:
|
||||||
|
@ -805,12 +805,10 @@ class Parser:
|
|||||||
raise self.PError("ZP block cannot contain code statements")
|
raise self.PError("ZP block cannot contain code statements")
|
||||||
self.prev_line()
|
self.prev_line()
|
||||||
self.cur_block.statements.append(self.parse_asm())
|
self.cur_block.statements.append(self.parse_asm())
|
||||||
continue
|
|
||||||
elif unstripped_line.startswith((" ", "\t")):
|
elif unstripped_line.startswith((" ", "\t")):
|
||||||
if is_zp_block:
|
if is_zp_block:
|
||||||
raise self.PError("ZP block cannot contain code statements")
|
raise self.PError("ZP block cannot contain code statements")
|
||||||
self.cur_block.statements.append(self.parse_statement(line))
|
self.cur_block.statements.append(self.parse_statement(line))
|
||||||
continue
|
|
||||||
elif line:
|
elif line:
|
||||||
if is_zp_block:
|
if is_zp_block:
|
||||||
raise self.PError("ZP block cannot contain code labels")
|
raise self.PError("ZP block cannot contain code labels")
|
||||||
@ -861,9 +859,10 @@ class Parser:
|
|||||||
r"\((?P<parameters>[\w\s:,]*)\)"
|
r"\((?P<parameters>[\w\s:,]*)\)"
|
||||||
r"\s*->\s*"
|
r"\s*->\s*"
|
||||||
r"\((?P<results>[\w\s?,]*)\)\s*"
|
r"\((?P<results>[\w\s?,]*)\)\s*"
|
||||||
r"\s+=\s+(?P<address>\S*)\s*$", line)
|
r"(?P<decltype>\s+=\s+(?P<address>\S*)|{)\s*$", line)
|
||||||
if not match:
|
if not match:
|
||||||
raise self.PError("invalid subx declaration")
|
raise self.PError("invalid subx declaration")
|
||||||
|
code_decl = match.group("decltype") == "{"
|
||||||
name, parameterlist, resultlist, address_str = \
|
name, parameterlist, resultlist, address_str = \
|
||||||
match.group("name"), match.group("parameters"), match.group("results"), match.group("address")
|
match.group("name"), match.group("parameters"), match.group("results"), match.group("address")
|
||||||
parameters = [(match.group("name"), match.group("target"))
|
parameters = [(match.group("name"), match.group("target"))
|
||||||
@ -875,12 +874,41 @@ class Parser:
|
|||||||
if len(all_paramnames) != len(set(all_paramnames)):
|
if len(all_paramnames) != len(set(all_paramnames)):
|
||||||
raise self.PError("duplicates in parameter names")
|
raise self.PError("duplicates in parameter names")
|
||||||
results = {match.group("name") for match in re.finditer(r"\s*(?P<name>(?:\w+)\??)\s*(?:,|$)", resultlist)}
|
results = {match.group("name") for match in re.finditer(r"\s*(?P<name>(?:\w+)\??)\s*(?:,|$)", resultlist)}
|
||||||
|
subroutine_block = None
|
||||||
|
if code_decl:
|
||||||
|
address = None
|
||||||
|
# parse the subroutine code lines (until the closing '}')
|
||||||
|
subroutine_block = ParseResult.Block(name, self.sourceref, self.cur_block.symbols)
|
||||||
|
current_block = self.cur_block
|
||||||
|
self.cur_block = subroutine_block
|
||||||
|
while True:
|
||||||
|
self._parse_comments()
|
||||||
|
line = self.next_line()
|
||||||
|
unstripped_line = line
|
||||||
|
line = line.strip()
|
||||||
|
if line == "}":
|
||||||
|
# subroutine end
|
||||||
|
break
|
||||||
|
if line.startswith(("subx ", "subx\t")):
|
||||||
|
raise self.PError("cannot nest subroutines")
|
||||||
|
elif line.startswith(("asm ", "asm\t")):
|
||||||
|
self.prev_line()
|
||||||
|
subroutine_block.statements.append(self.parse_asm())
|
||||||
|
elif unstripped_line.startswith((" ", "\t")):
|
||||||
|
subroutine_block.statements.append(self.parse_statement(line))
|
||||||
|
elif line:
|
||||||
|
self.parse_label(line)
|
||||||
|
else:
|
||||||
|
raise self.PError("missing } to close subroutine from line " + str(subroutine_block.sourceref.line))
|
||||||
|
self.cur_block = current_block
|
||||||
|
self.cur_block.sourceref = subroutine_block.sourceref
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
address = parse_expr_as_int(address_str, self.cur_block.symbols, self.ppsymbols, self.sourceref)
|
||||||
|
except ParseError:
|
||||||
|
raise self.PError("invalid subroutine address")
|
||||||
try:
|
try:
|
||||||
address = parse_expr_as_int(address_str, self.cur_block.symbols, self.ppsymbols, self.sourceref)
|
self.cur_block.symbols.define_sub(name, self.sourceref, parameters, results, address, subroutine_block)
|
||||||
except ParseError:
|
|
||||||
raise self.PError("invalid subroutine address")
|
|
||||||
try:
|
|
||||||
self.cur_block.symbols.define_sub(name, self.sourceref, parameters, results, address)
|
|
||||||
except SymbolError as x:
|
except SymbolError as x:
|
||||||
raise self.PError(str(x)) from x
|
raise self.PError(str(x)) from x
|
||||||
|
|
||||||
|
@ -167,9 +167,11 @@ class ConstantDef(SymbolDefinition):
|
|||||||
|
|
||||||
class SubroutineDef(SymbolDefinition):
|
class SubroutineDef(SymbolDefinition):
|
||||||
def __init__(self, blockname: str, name: str, sourceref: SourceRef,
|
def __init__(self, blockname: str, name: str, sourceref: SourceRef,
|
||||||
parameters: Sequence[Tuple[str, str]], returnvalues: Set[str], address: Optional[int]=None) -> None:
|
parameters: Sequence[Tuple[str, str]], returnvalues: Set[str],
|
||||||
|
address: Optional[int]=None, sub_block: Any=None) -> None:
|
||||||
super().__init__(blockname, name, sourceref, False)
|
super().__init__(blockname, name, sourceref, False)
|
||||||
self.address = address
|
self.address = address
|
||||||
|
self.sub_block = sub_block
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
self.input_registers = set() # type: Set[str]
|
self.input_registers = set() # type: Set[str]
|
||||||
self.return_registers = set() # type: Set[str]
|
self.return_registers = set() # type: Set[str]
|
||||||
@ -372,9 +374,10 @@ class SymbolTable:
|
|||||||
self.eval_dict = None
|
self.eval_dict = None
|
||||||
|
|
||||||
def define_sub(self, name: str, sourceref: SourceRef,
|
def define_sub(self, name: str, sourceref: SourceRef,
|
||||||
parameters: Sequence[Tuple[str, str]], returnvalues: Set[str], address: Optional[int]) -> None:
|
parameters: Sequence[Tuple[str, str]], returnvalues: Set[str],
|
||||||
|
address: Optional[int], sub_block: Any) -> None:
|
||||||
self.check_identifier_valid(name, sourceref)
|
self.check_identifier_valid(name, sourceref)
|
||||||
self.symbols[name] = SubroutineDef(self.name, name, sourceref, parameters, returnvalues, address)
|
self.symbols[name] = SubroutineDef(self.name, name, sourceref, parameters, returnvalues, address, sub_block)
|
||||||
|
|
||||||
def define_label(self, name: str, sourceref: SourceRef) -> None:
|
def define_label(self, name: str, sourceref: SourceRef) -> None:
|
||||||
self.check_identifier_valid(name, sourceref)
|
self.check_identifier_valid(name, sourceref)
|
||||||
|
122
lib/c64lib.ill
122
lib/c64lib.ill
@ -215,8 +215,8 @@ subx IOBASE () -> (X, Y) = $FFF3 ; read base addres
|
|||||||
|
|
||||||
; @todo use user-defined subroutines here to have param definitions
|
; @todo use user-defined subroutines here to have param definitions
|
||||||
|
|
||||||
; ---- fac1 = signed int32 from $62-$65 big endian (MSB FIRST)
|
subx FREADS32 () -> (A?, X?, Y?) {
|
||||||
FREADS32 ; () -> (A?, X?, Y?)
|
; ---- fac1 = signed int32 from $62-$65 big endian (MSB FIRST)
|
||||||
asm {
|
asm {
|
||||||
lda $62
|
lda $62
|
||||||
eor #$ff
|
eor #$ff
|
||||||
@ -225,19 +225,21 @@ FREADS32 ; () -> (A?, X?, Y?)
|
|||||||
ldx #$a0
|
ldx #$a0
|
||||||
jmp $bc4f
|
jmp $bc4f
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- fac1 = uint32 from $62-$65 big endian (MSB FIRST)
|
subx FREADUS32 () -> (A?, X?, Y?) {
|
||||||
FREADUS32 ; () -> (A?, X?, Y?)
|
; ---- fac1 = uint32 from $62-$65 big endian (MSB FIRST)
|
||||||
asm {
|
asm {
|
||||||
sec
|
sec
|
||||||
lda #0
|
lda #0
|
||||||
ldx #$a0
|
ldx #$a0
|
||||||
jmp $bc4f
|
jmp $bc4f
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- fac1 = signed int24 (A/X/Y contain lo/mid/hi bytes)
|
subx FREADS24AXY (lo: A, mid: X, hi: Y) -> (A?, X?, Y?) {
|
||||||
; note: there is no FREADU24AXY (unsigned), use FREADUS32 instead.
|
; ---- fac1 = signed int24 (A/X/Y contain lo/mid/hi bytes)
|
||||||
FREADS24AXY ; (lo: A, mid: X, hi: Y) -> (A?, X?, Y?)
|
; note: there is no FREADU24AXY (unsigned), use FREADUS32 instead.
|
||||||
asm {
|
asm {
|
||||||
sty $62
|
sty $62
|
||||||
stx $63
|
stx $63
|
||||||
@ -250,10 +252,10 @@ FREADS24AXY ; (lo: A, mid: X, hi: Y) -> (A?, X?, Y?)
|
|||||||
ldx #$98
|
ldx #$98
|
||||||
jmp $bc4f
|
jmp $bc4f
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
|
subx GIVUAYF (uword: AY) -> (A?, X?, Y?) {
|
||||||
GIVUAYF ; (uword: AY) -> (A?, X?, Y?)
|
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
|
||||||
asm {
|
asm {
|
||||||
sty $62
|
sty $62
|
||||||
sta $63
|
sta $63
|
||||||
@ -261,18 +263,20 @@ GIVUAYF ; (uword: AY) -> (A?, X?, Y?)
|
|||||||
sec
|
sec
|
||||||
jmp $bc49
|
jmp $bc49
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- signed 16 bit word in A/Y (lo/hi) to float in fac1
|
subx GIVAYFAY (sword: AY) -> (A?, X?, Y?) {
|
||||||
GIVAYFAY ; (sword: AY) -> (A?, X?, Y?)
|
; ---- signed 16 bit word in A/Y (lo/hi) to float in fac1
|
||||||
asm {
|
asm {
|
||||||
sta c64.SCRATCH_ZP1
|
sta c64.SCRATCH_ZP1
|
||||||
tya
|
tya
|
||||||
ldy c64.SCRATCH_ZP1
|
ldy c64.SCRATCH_ZP1
|
||||||
jmp c64.GIVAYF ; this uses the inverse order, Y/A
|
jmp c64.GIVAYF ; this uses the inverse order, Y/A
|
||||||
}
|
}
|
||||||
|
}
|
||||||
; ---- fac1 to signed word in A/Y
|
|
||||||
FTOSWRDAY ; () -> (A, Y, X?)
|
subx FTOSWRDAY () -> (A, Y, X?) {
|
||||||
|
; ---- fac1 to signed word in A/Y
|
||||||
asm {
|
asm {
|
||||||
jsr c64.FTOSWORDYA ; note the inverse Y/A order
|
jsr c64.FTOSWORDYA ; note the inverse Y/A order
|
||||||
sta c64.SCRATCH_ZP1
|
sta c64.SCRATCH_ZP1
|
||||||
@ -280,9 +284,10 @@ FTOSWRDAY ; () -> (A, Y, X?)
|
|||||||
ldy c64.SCRATCH_ZP1
|
ldy c64.SCRATCH_ZP1
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- fac1 to unsigned word in A/Y
|
subx GETADRAY () -> (A, Y, X?) {
|
||||||
GETADRAY ; () -> (A, Y, X?)
|
; ---- fac1 to unsigned word in A/Y
|
||||||
asm {
|
asm {
|
||||||
jsr c64.GETADR ; this uses the inverse order, Y/A
|
jsr c64.GETADR ; this uses the inverse order, Y/A
|
||||||
sta c64.SCRATCH_ZP1
|
sta c64.SCRATCH_ZP1
|
||||||
@ -290,10 +295,10 @@ GETADRAY ; () -> (A, Y, X?)
|
|||||||
ldy c64.SCRATCH_ZP1
|
ldy c64.SCRATCH_ZP1
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print null terminated string from X/Y
|
subx print_string (address: XY) -> (A?, Y?) {
|
||||||
print_string ; (address: XY) -> (A?, Y?)
|
; ---- print null terminated string from X/Y
|
||||||
asm {
|
asm {
|
||||||
stx c64.SCRATCH_ZP1
|
stx c64.SCRATCH_ZP1
|
||||||
sty c64.SCRATCH_ZP2
|
sty c64.SCRATCH_ZP2
|
||||||
@ -305,9 +310,10 @@ print_string ; (address: XY) -> (A?, Y?)
|
|||||||
bne -
|
bne -
|
||||||
+ rts
|
+ rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print pstring (length as first byte) from X/Y, returns str len in Y
|
subx print_pstring (address: XY) -> (A?, X?, Y) {
|
||||||
print_pstring ; (address: XY) -> (A?, X?, Y)
|
; ---- print pstring (length as first byte) from X/Y, returns str len in Y
|
||||||
asm {
|
asm {
|
||||||
stx c64.SCRATCH_ZP1
|
stx c64.SCRATCH_ZP1
|
||||||
sty c64.SCRATCH_ZP2
|
sty c64.SCRATCH_ZP2
|
||||||
@ -322,10 +328,11 @@ print_pstring ; (address: XY) -> (A?, X?, Y)
|
|||||||
bne -
|
bne -
|
||||||
+ rts ; output string length is in Y
|
+ rts ; output string length is in Y
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subx print_pimmediate () -> () {
|
||||||
; ---- print pstring in memory immediately following the fcall instruction (don't use call!)
|
; ---- print pstring in memory immediately following the subroutine fast call instruction
|
||||||
print_pimmediate
|
; note that the clobbered registers (A,X,Y) are not listed ON PURPOSE
|
||||||
asm {
|
asm {
|
||||||
tsx
|
tsx
|
||||||
lda $102,x
|
lda $102,x
|
||||||
@ -349,10 +356,10 @@ print_pimmediate
|
|||||||
inc $102,x ; increment the high byte of the return addr too.
|
inc $102,x ; increment the high byte of the return addr too.
|
||||||
+ rts
|
+ rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subx byte2decimal (ubyte: A) -> (Y, X, A) {
|
||||||
; ---- A to decimal string in Y/X/A (100s in Y, 10s in X, 1s in A)
|
; ---- A to decimal string in Y/X/A (100s in Y, 10s in X, 1s in A)
|
||||||
byte2decimal ; (ubyte: A) -> (Y, X, A)
|
|
||||||
asm {
|
asm {
|
||||||
ldy #$2f
|
ldy #$2f
|
||||||
ldx #$3a
|
ldx #$3a
|
||||||
@ -366,9 +373,10 @@ byte2decimal ; (ubyte: A) -> (Y, X, A)
|
|||||||
adc #$2f
|
adc #$2f
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- A to hex string in XY (first hex char in X, second hex char in Y)
|
subx byte2hex (ubyte: A) -> (X, Y, A?) {
|
||||||
byte2hex ; (ubyte: A) -> (X, Y, A?)
|
; ---- A to hex string in XY (first hex char in X, second hex char in Y)
|
||||||
asm {
|
asm {
|
||||||
pha
|
pha
|
||||||
and #$0f
|
and #$0f
|
||||||
@ -386,20 +394,19 @@ byte2hex ; (ubyte: A) -> (X, Y, A?)
|
|||||||
|
|
||||||
hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
; Convert an 16 bit binary value to BCD
|
|
||||||
;
|
|
||||||
; This function converts a 16 bit binary value in X/Y into a 24 bit BCD. It
|
|
||||||
; works by transferring one bit a time from the source and adding it
|
|
||||||
; into a BCD value that is being doubled on each iteration. As all the
|
|
||||||
; arithmetic is being done in BCD the result is a binary to decimal
|
|
||||||
; conversion.
|
|
||||||
|
|
||||||
var .array(3) word2bcd_bcdbuff
|
var .array(3) word2bcd_bcdbuff
|
||||||
|
subx word2bcd (address: XY) -> (A?, X?) {
|
||||||
word2bcd ; (address: XY) -> (A?, X?)
|
; Convert an 16 bit binary value to BCD
|
||||||
|
;
|
||||||
|
; This function converts a 16 bit binary value in X/Y into a 24 bit BCD. It
|
||||||
|
; works by transferring one bit a time from the source and adding it
|
||||||
|
; into a BCD value that is being doubled on each iteration. As all the
|
||||||
|
; arithmetic is being done in BCD the result is a binary to decimal
|
||||||
|
; conversion.
|
||||||
asm {
|
asm {
|
||||||
stx c64.SCRATCH_ZP1
|
stx c64.SCRATCH_ZP1
|
||||||
sty c64.SCRATCH_ZP2
|
sty c64.SCRATCH_ZP2
|
||||||
@ -426,12 +433,12 @@ word2bcd ; (address: XY) -> (A?, X?)
|
|||||||
cld ; back to binary
|
cld ; back to binary
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
; ---- convert 16 bit word in X/Y into decimal string into memory 'word2decimal_output'
|
|
||||||
var .array(5) word2decimal_output
|
var .array(5) word2decimal_output
|
||||||
|
subx word2decimal (address: XY) -> (A?, X?, Y?) {
|
||||||
word2decimal ; (address: XY) -> (A?, X?, Y?)
|
; ---- convert 16 bit word in X/Y into decimal string into memory 'word2decimal_output'
|
||||||
asm {
|
asm {
|
||||||
jsr word2bcd
|
jsr word2bcd
|
||||||
lda word2bcd_bcdbuff+2
|
lda word2bcd_bcdbuff+2
|
||||||
@ -459,9 +466,10 @@ word2decimal ; (address: XY) -> (A?, X?, Y?)
|
|||||||
iny
|
iny
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print the byte in A in decimal form, with left padding 0s (3 positions total)
|
subx print_byte_decimal0 (ubyte: A) -> (A?, X?, Y?) {
|
||||||
print_byte_decimal0 ; (ubyte: A) -> (A?, X?, Y?)
|
; ---- print the byte in A in decimal form, with left padding 0s (3 positions total)
|
||||||
asm {
|
asm {
|
||||||
jsr byte2decimal
|
jsr byte2decimal
|
||||||
pha
|
pha
|
||||||
@ -472,9 +480,10 @@ print_byte_decimal0 ; (ubyte: A) -> (A?, X?, Y?)
|
|||||||
pla
|
pla
|
||||||
jmp c64.CHROUT
|
jmp c64.CHROUT
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print the byte in A in decimal form, without left padding 0s
|
subx print_byte_decimal (ubyte: A) -> (A?, X?, Y?) {
|
||||||
print_byte_decimal ; (ubyte: A) -> (A?, X?, Y?)
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
asm {
|
asm {
|
||||||
jsr byte2decimal
|
jsr byte2decimal
|
||||||
pha
|
pha
|
||||||
@ -489,9 +498,10 @@ print_byte_decimal ; (ubyte: A) -> (A?, X?, Y?)
|
|||||||
+ pla
|
+ pla
|
||||||
jmp c64.CHROUT
|
jmp c64.CHROUT
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print the byte in A in hex form
|
subx print_byte_hex (ubyte: A) -> (A?, X?, Y?) {
|
||||||
print_byte_hex ; (ubyte: A) -> (A?, X?, Y?)
|
; ---- print the byte in A in hex form
|
||||||
asm {
|
asm {
|
||||||
jsr byte2hex
|
jsr byte2hex
|
||||||
txa
|
txa
|
||||||
@ -499,9 +509,11 @@ print_byte_hex ; (ubyte: A) -> (A?, X?, Y?)
|
|||||||
tya
|
tya
|
||||||
jmp c64.CHROUT
|
jmp c64.CHROUT
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print the word in X/Y in decimal form, with left padding 0s (5 positions total)
|
|
||||||
print_word_decimal0 ; (address: XY) -> (A?, X?, Y?)
|
subx print_word_decimal0 (address: XY) -> (A?, X?, Y?) {
|
||||||
|
; ---- print the word in X/Y in decimal form, with left padding 0s (5 positions total)
|
||||||
asm {
|
asm {
|
||||||
jsr word2decimal
|
jsr word2decimal
|
||||||
lda word2decimal_output
|
lda word2decimal_output
|
||||||
@ -515,9 +527,11 @@ print_word_decimal0 ; (address: XY) -> (A?, X?, Y?)
|
|||||||
lda word2decimal_output+4
|
lda word2decimal_output+4
|
||||||
jmp c64.CHROUT
|
jmp c64.CHROUT
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
; ---- print the word in X/Y in decimal form, without left padding 0s
|
|
||||||
print_word_decimal ; (address: XY) -> (A?, X? Y?)
|
subx print_word_decimal (address: XY) -> (A?, X? Y?) {
|
||||||
|
; ---- print the word in X/Y in decimal form, without left padding 0s
|
||||||
asm {
|
asm {
|
||||||
jsr word2decimal
|
jsr word2decimal
|
||||||
ldy #0
|
ldy #0
|
||||||
@ -547,3 +561,5 @@ _pr_decimal
|
|||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -336,15 +336,13 @@ proc_results = sequence of <register> names that specify in which register(s) th
|
|||||||
example: "subx CLOSE (logical: A) -> (A?, X?, Y?) $FFC3"
|
example: "subx CLOSE (logical: A) -> (A?, X?, Y?) $FFC3"
|
||||||
|
|
||||||
|
|
||||||
ISOLATION (register preservation when calling subroutines): @todo isolation
|
REGISTER PRESERVATION BLOCK: @todo (no)preserve
|
||||||
|
|
||||||
isolate [regs] { .... } that adds register preservation around the containing code default = all 3 regs, or specify which.
|
preserve [regs] { .... } adds register preservation around the containing code default = all 3 regs, or specify which.
|
||||||
fcall -> fastcall, doesn't do register preservations
|
nopreserve [regs] { .... } removes register preservation on all statements in the block that would otherwise have it.
|
||||||
call -> as before, alsways does it, even when already in isolate block
|
|
||||||
|
|
||||||
|
|
||||||
|
@todo document user defined subroutines
|
||||||
@todo user defined subroutines
|
|
||||||
|
|
||||||
|
|
||||||
SUBROUTINE CALLS
|
SUBROUTINE CALLS
|
||||||
|
@ -79,8 +79,33 @@ _loop block2.zpw1 ++
|
|||||||
return 155,2,%00000101 ; will end up in A, X, Y
|
return 155,2,%00000101 ; will end up in A, X, Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
~ block2 {
|
~ block2 {
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
subx memsub () -> () = $fff2
|
||||||
|
|
||||||
|
subx customsub (Y)->() {
|
||||||
|
|
||||||
|
asm {
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
lda #99
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
}
|
||||||
|
|
||||||
|
A=2
|
||||||
|
X=33
|
||||||
|
goto fidget.subroutine()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
somelabel1222
|
somelabel1222
|
||||||
|
customsub(2)
|
||||||
return
|
return
|
||||||
|
|
||||||
var zp1
|
var zp1
|
||||||
|
@ -60,8 +60,7 @@ start
|
|||||||
c64.CHROUT('0')
|
c64.CHROUT('0')
|
||||||
c64.CHROUT('1')
|
c64.CHROUT('1')
|
||||||
c64.CHROUT('2')
|
c64.CHROUT('2')
|
||||||
XY = hello
|
c64util.print_string(hello)
|
||||||
c64util.print_string()
|
|
||||||
goto c64.CHROUT('!')
|
goto c64.CHROUT('!')
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,52 +14,36 @@ start
|
|||||||
.ptext "hello-pimmediate!{cr}"
|
.ptext "hello-pimmediate!{cr}"
|
||||||
}
|
}
|
||||||
|
|
||||||
A = 19
|
c64util.print_byte_decimal0 ! (19)
|
||||||
c64util.print_byte_decimal0 ! ()
|
|
||||||
c64.CHROUT ! (13)
|
c64.CHROUT ! (13)
|
||||||
A = 19
|
c64util.print_byte_decimal ! (19)
|
||||||
c64util.print_byte_decimal ! ()
|
|
||||||
c64.CHROUT ! (13)
|
c64.CHROUT ! (13)
|
||||||
|
|
||||||
|
|
||||||
X = $01
|
c64util.print_word_decimal0 ! ($0102)
|
||||||
Y = $02
|
|
||||||
c64util.print_word_decimal0 ! ()
|
|
||||||
c64.CHROUT ! (13)
|
c64.CHROUT ! (13)
|
||||||
X = $01
|
c64util.print_word_decimal ! ($0102)
|
||||||
Y = $02
|
|
||||||
c64util.print_word_decimal ! ()
|
|
||||||
c64.CHROUT ! (13)
|
c64.CHROUT ! (13)
|
||||||
return
|
return
|
||||||
|
|
||||||
start2
|
start2
|
||||||
global2.make_screen_black()
|
global2.make_screen_black()
|
||||||
c64.CLEARSCR()
|
c64.CLEARSCR()
|
||||||
XY = greeting
|
c64util.print_string(greeting)
|
||||||
c64util.print_string()
|
c64util.print_pstring(p_greeting)
|
||||||
XY = p_greeting
|
c64util.print_byte_decimal(0)
|
||||||
c64util.print_pstring()
|
c64util.print_byte_hex(0)
|
||||||
A = 0
|
|
||||||
c64util.print_byte_decimal()
|
|
||||||
A = 0
|
|
||||||
c64util.print_byte_hex()
|
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
c64util.print_byte_decimal()
|
c64util.print_byte_decimal(13)
|
||||||
A = 13
|
c64util.print_byte_hex(13)
|
||||||
c64util.print_byte_hex()
|
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
A = 255
|
c64util.print_byte_decimal(255)
|
||||||
c64util.print_byte_decimal()
|
c64util.print_byte_hex(254)
|
||||||
A = 254
|
c64util.print_byte_hex(129)
|
||||||
c64util.print_byte_hex()
|
|
||||||
A = 129
|
|
||||||
c64util.print_byte_hex()
|
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
|
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
X = 1
|
c64util.print_word_decimal($0100)
|
||||||
Y = 0
|
|
||||||
c64util.print_word_decimal()
|
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user