mirror of
https://github.com/irmen/prog8.git
synced 2024-06-13 09:29:34 +00:00
inline asm and fixed c64 libs
This commit is contained in:
parent
263b197fec
commit
529c525081
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
/.idea/
|
||||
**/.idea/
|
||||
/build/
|
||||
/dist/
|
||||
/output/
|
||||
|
|
|
@ -1,54 +1,26 @@
|
|||
%option enable_floats
|
||||
%import c64utils
|
||||
|
||||
~ main $c800 {
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
memory ubyte mub = $c400
|
||||
memory ubyte mub2 = $c401
|
||||
memory uword muw = $c500
|
||||
memory uword muw2 = $c502
|
||||
memory byte mb = $c000
|
||||
memory word mw = $c002
|
||||
|
||||
|
||||
byte b = -100
|
||||
ubyte ub = $c4
|
||||
ubyte ub2 = $c4
|
||||
uword uw = $c500
|
||||
uword uw2 = $c502
|
||||
word ww = -30000
|
||||
|
||||
float f1 = 1.23456
|
||||
float f2 = -999.999e22
|
||||
float f3 = -999.999e22
|
||||
float f4 = -999.999e22
|
||||
|
||||
str s1 = "hallo"
|
||||
str_p s2 = "hallo p"
|
||||
str_s s3 = "hallo s"
|
||||
str_ps s4 = "hallo ps"
|
||||
|
||||
byte[4] array1 = -99
|
||||
ubyte[4] array2 = 244
|
||||
word[4] array3 = -999
|
||||
uword[4] array4 = 44444
|
||||
float[4] array5 = [11.11, 22.22, 33.33, 44.44]
|
||||
byte[3,7] matrix1 = [1,-2,3,-4,5,-6,1,-2,3,-4,5,-6,1,-2,3,-4,5,-6,22,33,44]
|
||||
ubyte[3,7] matrix2 = [11,22,33,44,55,66, 11,22,33,44,55,66, 11,22,33,44,55,66, 55,66,77]
|
||||
|
||||
const ubyte screen_color = 9
|
||||
const ubyte border_color = 2
|
||||
const ubyte cursor_color = 7
|
||||
memory ubyte screen = $d021
|
||||
memory ubyte border = $d020
|
||||
memory ubyte cursor = 646
|
||||
|
||||
screen = screen_color
|
||||
border = border_color
|
||||
cursor = cursor_color
|
||||
return
|
||||
|
||||
sub nested () {
|
||||
byte b
|
||||
uword uw
|
||||
}
|
||||
}
|
||||
|
||||
sub second() {
|
||||
byte b
|
||||
uword uw
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
~ block2 $c000 {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -486,7 +486,7 @@ class AstChecker(private val namespace: INameScope,
|
|||
if(directive.parent !is Module) err("this directive may only occur at module level")
|
||||
if(directive.args.size!=1 || directive.args[0].name==null)
|
||||
err("invalid import directive, expected module name argument")
|
||||
if(directive.args[0].name == (directive.parent as Module).name)
|
||||
if(directive.args[0].name == (directive.parent as? Module)?.name)
|
||||
err("invalid import directive, cannot import itself")
|
||||
}
|
||||
"%breakpoint" -> {
|
||||
|
|
|
@ -199,9 +199,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||
prog.line(subroutine.position)
|
||||
// note: the caller has already written the arguments into the subroutine's parameter variables.
|
||||
translate(subroutine.statements)
|
||||
} else {
|
||||
throw CompilerException("kernel subroutines (with memory address and no body) are not supported by StackVM: $subroutine")
|
||||
}
|
||||
} else if(subroutine.isNotEmpty())
|
||||
throw CompilerException("kernel subroutines (with memory address) can't have a body: $subroutine")
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
||||
|
@ -237,7 +236,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||
is RepeatLoop -> translate(stmt)
|
||||
is AnonymousScope -> translate(stmt)
|
||||
is Directive, is VarDecl, is Subroutine -> {} // skip this, already processed these.
|
||||
is InlineAssembly -> throw CompilerException("inline assembly is not supported by the StackVM")
|
||||
is InlineAssembly -> translate(stmt)
|
||||
else -> TODO("translate statement $stmt to stackvm")
|
||||
}
|
||||
}
|
||||
|
@ -390,6 +389,10 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||
}
|
||||
}
|
||||
|
||||
private fun translate(stmt: InlineAssembly) {
|
||||
prog.instr(Opcode.INLINE_ASSEMBLY, callLabel = stmt.assembly)
|
||||
}
|
||||
|
||||
private fun translate(stmt: Continue) {
|
||||
prog.line(stmt.position)
|
||||
if(continueStmtLabelStack.empty())
|
||||
|
|
|
@ -226,7 +226,8 @@ enum class Opcode {
|
|||
NOP, // do nothing
|
||||
BREAKPOINT, // breakpoint
|
||||
TERMINATE, // end the program
|
||||
LINE // track source file line number
|
||||
LINE, // track source file line number
|
||||
INLINE_ASSEMBLY // container to hold inline raw assembly code
|
||||
}
|
||||
|
||||
val opcodesWithVarArgument = setOf(
|
||||
|
|
|
@ -49,7 +49,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||
}
|
||||
}
|
||||
|
||||
private fun out(str: String) = output.println(str)
|
||||
private fun out(str: String?) = output.println(str)
|
||||
|
||||
fun compileToAssembly(): AssemblyProgram {
|
||||
println("\nGenerating assembly code from intermediate code... ")
|
||||
|
@ -58,7 +58,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||
output = File("${program.name}.asm").printWriter()
|
||||
output.use {
|
||||
header()
|
||||
for(block in program.blocks)
|
||||
for(block in program.blocks) // todo sort by address (if specified) (blocks w/o address go LAST)
|
||||
block2asm(block)
|
||||
}
|
||||
|
||||
|
@ -108,10 +108,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||
out("\t.null $9e, format(' %d ', _prog8_entrypoint), $3a, $8f, ' prog8 by idj'")
|
||||
out("+\t.word 0")
|
||||
out("_prog8_entrypoint\t; assembly code starts here\n")
|
||||
out("\tjsr c64utils.init_system")
|
||||
}
|
||||
options.output == OutputType.PRG -> {
|
||||
out("; ---- program without sys call ----")
|
||||
out("* = ${program.loadAddress.toHex()}\n")
|
||||
out("\tjsr c64utils.init_system")
|
||||
}
|
||||
options.output == OutputType.RAW -> {
|
||||
out("; ---- raw assembler program ----")
|
||||
|
@ -119,10 +121,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||
}
|
||||
}
|
||||
|
||||
out("\tlda #0")
|
||||
out("\ttay")
|
||||
out("\ttax")
|
||||
out("\tdex\t; init estack pointer to \$ff")
|
||||
out("\tldx #\$ff\t; init estack pointer")
|
||||
out("\tclc")
|
||||
out("\tjmp main.start\t; jump to program entrypoint")
|
||||
out("")
|
||||
|
@ -621,6 +620,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||
}
|
||||
pushFloat(ins.arg!!.integerValue().toHex())
|
||||
}
|
||||
Opcode.INLINE_ASSEMBLY -> out(ins.callLabel) // All of the inline assembly is stored in the calllabel property.
|
||||
else-> TODO("asm for $ins")
|
||||
// Opcode.POP_MEM_B -> TODO()
|
||||
// Opcode.POP_MEM_UB -> TODO()
|
||||
|
|
|
@ -84,6 +84,8 @@ fun executeImportDirective(import: Directive, importedFrom: Path): Module? {
|
|||
if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null)
|
||||
throw SyntaxError("invalid import directive", import.position)
|
||||
val moduleName = import.args[0].name!!
|
||||
if("$moduleName.p8" == import.position.file)
|
||||
throw SyntaxError("cannot import self", import.position)
|
||||
if(importedModules.containsKey(moduleName))
|
||||
return null
|
||||
|
||||
|
|
|
@ -1363,6 +1363,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||
P_carry = evalstack.pop().asBooleanValue
|
||||
P_irqd = evalstack.pop().asBooleanValue
|
||||
}
|
||||
Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code")
|
||||
//else -> throw VmExecutionException("unimplemented opcode: ${ins.opcode}")
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
memory byte SFDX = $cb ; current key pressed (matrix value) (updated by IRQ)
|
||||
|
||||
memory byte COLOR = $0286 ; cursor color
|
||||
memory byte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
|
||||
memory byte HIBASE = $0288 ; screen base address / 256 (hi-byte of screen memory address)
|
||||
memory word CINV = $0314 ; IRQ vector
|
||||
memory word NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
|
||||
memory word RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
|
||||
memory word IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
|
||||
memory word NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
|
||||
memory word RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
|
||||
memory word IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
|
||||
|
||||
memory byte[40, 25] Screen = $0400 ; default character screen matrix
|
||||
memory byte[40, 25] Colors = $d800 ; character screen colors
|
||||
|
@ -110,22 +110,22 @@
|
|||
; note: for subtraction and division, the left operand is in fac2, the right operand in fac1.
|
||||
|
||||
; checked functions below:
|
||||
asmsub MOVFM (mflpt: word @ AY) -> clobbers(A,Y) -> () = $bba2 ; load mflpt value from memory in A/Y into fac1
|
||||
asmsub MOVFM (mflpt: uword @ AY) -> clobbers(A,Y) -> () = $bba2 ; load mflpt value from memory in A/Y into fac1
|
||||
asmsub FREADMEM () -> clobbers(A,Y) -> () = $bba6 ; load mflpt value from memory in $22/$23 into fac1
|
||||
asmsub CONUPK (mflpt: word @ AY) -> clobbers(A,Y) -> () = $ba8c ; load mflpt value from memory in A/Y into fac2
|
||||
asmsub CONUPK (mflpt: uword @ AY) -> clobbers(A,Y) -> () = $ba8c ; load mflpt value from memory in A/Y into fac2
|
||||
asmsub FAREADMEM () -> clobbers(A,Y) -> () = $ba90 ; load mflpt value from memory in $22/$23 into fac2
|
||||
asmsub MOVFA () -> clobbers(A,X) -> () = $bbfc ; copy fac2 to fac1
|
||||
asmsub MOVAF () -> clobbers(A,X) -> () = $bc0c ; copy fac1 to fac2 (rounded)
|
||||
asmsub MOVEF () -> clobbers(A,X) -> () = $bc0f ; copy fac1 to fac2
|
||||
asmsub FTOMEMXY (mflpt: word @ XY) -> clobbers(A,Y) -> () = $bbd4 ; store fac1 to memory X/Y as 5-byte mflpt
|
||||
asmsub FTOMEMXY (mflpt: uword @ XY) -> clobbers(A,Y) -> () = $bbd4 ; store fac1 to memory X/Y as 5-byte mflpt
|
||||
|
||||
; fac1-> signed word in Y/A (might throw ILLEGAL QUANTITY)
|
||||
; (use c64flt.FTOSWRDAY to get A/Y output; lo/hi switched to normal order)
|
||||
asmsub FTOSWORDYA () -> clobbers(X) -> (byte @ Y, byte @ A) = $b1aa
|
||||
asmsub FTOSWORDYA () -> clobbers(X) -> (ubyte @ Y, ubyte @ A) = $b1aa
|
||||
|
||||
; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15)
|
||||
; (use c64flt.GETADRAY to get A/Y output; lo/hi switched to normal order)
|
||||
asmsub GETADR () -> clobbers(X) -> (byte @ Y, byte @ A) = $b7f7
|
||||
asmsub GETADR () -> clobbers(X) -> (ubyte @ Y, ubyte @ A) = $b7f7
|
||||
|
||||
asmsub QINT () -> clobbers(A,X,Y) -> () = $bc9b ; fac1 -> 4-byte signed integer in 98-101 ($62-$65), with the MSB FIRST.
|
||||
asmsub AYINT () -> clobbers(A,X,Y) -> () = $b1bf ; fac1-> signed word in 100-101 ($64-$65) MSB FIRST. (might throw ILLEGAL QUANTITY)
|
||||
|
@ -136,41 +136,41 @@ asmsub AYINT () -> clobbers(A,X,Y) -> () = $b1bf ; fac1-> signed word in 100
|
|||
; there is also c64flt.FREADS32 that reads from 98-101 ($62-$65) MSB FIRST
|
||||
; there is also c64flt.FREADUS32 that reads from 98-101 ($62-$65) MSB FIRST
|
||||
; there is also c64flt.FREADS24AXY that reads signed int24 into fac1 from A/X/Y (lo/mid/hi bytes)
|
||||
asmsub GIVAYF (lo: byte @ Y, hi: byte @ A) -> clobbers(A,X,Y) -> () = $b391
|
||||
asmsub GIVAYF (lo: ubyte @ Y, hi: ubyte @ A) -> clobbers(A,X,Y) -> () = $b391
|
||||
|
||||
asmsub FREADUY (ubyte: byte @ Y) -> clobbers(A,X,Y) -> () = $b3a2 ; 8 bit unsigned Y -> float in fac1
|
||||
asmsub FREADSA (sbyte: byte @ A) -> clobbers(A,X,Y) -> () = $bc3c ; 8 bit signed A -> float in fac1
|
||||
asmsub FREADSTR (length: byte @ A) -> clobbers(A,X,Y) -> () = $b7b5 ; str -> fac1, $22/23 must point to string, A=string length
|
||||
asmsub FREADUY (unsigned: ubyte @ Y) -> clobbers(A,X,Y) -> () = $b3a2 ; 8 bit unsigned Y -> float in fac1
|
||||
asmsub FREADSA (signed: ubyte @ A) -> clobbers(A,X,Y) -> () = $bc3c ; 8 bit signed A -> float in fac1
|
||||
asmsub FREADSTR (length: ubyte @ A) -> clobbers(A,X,Y) -> () = $b7b5 ; str -> fac1, $22/23 must point to string, A=string length
|
||||
asmsub FPRINTLN () -> clobbers(A,X,Y) -> () = $aabc ; print string of fac1, on one line (= with newline)
|
||||
asmsub FOUT () -> clobbers(X) -> (word @ AY) = $bddd ; fac1 -> string, address returned in AY ($0100)
|
||||
asmsub FOUT () -> clobbers(X) -> (uword @ AY) = $bddd ; fac1 -> string, address returned in AY ($0100)
|
||||
|
||||
asmsub FADDH () -> clobbers(A,X,Y) -> () = $b849 ; fac1 += 0.5, for rounding- call this before INT
|
||||
asmsub MUL10 () -> clobbers(A,X,Y) -> () = $bae2 ; fac1 *= 10
|
||||
asmsub DIV10 () -> clobbers(A,X,Y) -> () = $bafe ; fac1 /= 10 , CAUTION: result is always positive!
|
||||
asmsub FCOMP (mflpt: word @ AY) -> clobbers(X,Y) -> (byte @ A) = $bc5b ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
|
||||
asmsub FCOMP (mflpt: uword @ AY) -> clobbers(X,Y) -> (ubyte @ A) = $bc5b ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
|
||||
|
||||
asmsub FADDT () -> clobbers(A,X,Y) -> () = $b86a ; fac1 += fac2
|
||||
asmsub FADD (mflpt: word @ AY) -> clobbers(A,X,Y) -> () = $b867 ; fac1 += mflpt value from A/Y
|
||||
asmsub FADD (mflpt: uword @ AY) -> clobbers(A,X,Y) -> () = $b867 ; fac1 += mflpt value from A/Y
|
||||
asmsub FSUBT () -> clobbers(A,X,Y) -> () = $b853 ; fac1 = fac2-fac1 mind the order of the operands
|
||||
asmsub FSUB (mflpt: word @ AY) -> clobbers(A,X,Y) -> () = $b850 ; fac1 = mflpt from A/Y - fac1
|
||||
asmsub FSUB (mflpt: uword @ AY) -> clobbers(A,X,Y) -> () = $b850 ; fac1 = mflpt from A/Y - fac1
|
||||
asmsub FMULTT () -> clobbers(A,X,Y) -> () = $ba2b ; fac1 *= fac2
|
||||
asmsub FMULT (mflpt: word @ AY) -> clobbers(A,X,Y) -> () = $ba28 ; fac1 *= mflpt value from A/Y
|
||||
asmsub FMULT (mflpt: uword @ AY) -> clobbers(A,X,Y) -> () = $ba28 ; fac1 *= mflpt value from A/Y
|
||||
asmsub FDIVT () -> clobbers(A,X,Y) -> () = $bb12 ; fac1 = fac2/fac1 mind the order of the operands
|
||||
asmsub FDIV (mflpt: word @ AY) -> clobbers(A,X,Y) -> () = $bb0f ; fac1 = mflpt in A/Y / fac1
|
||||
asmsub FDIV (mflpt: uword @ AY) -> clobbers(A,X,Y) -> () = $bb0f ; fac1 = mflpt in A/Y / fac1
|
||||
asmsub FPWRT () -> clobbers(A,X,Y) -> () = $bf7b ; fac1 = fac2 ** fac1
|
||||
asmsub FPWR (mflpt: word @ AY) -> clobbers(A,X,Y) -> () = $bf78 ; fac1 = fac2 ** mflpt from A/Y
|
||||
asmsub FPWR (mflpt: uword @ AY) -> clobbers(A,X,Y) -> () = $bf78 ; fac1 = fac2 ** mflpt from A/Y
|
||||
|
||||
asmsub NOTOP () -> clobbers(A,X,Y) -> () = $aed4 ; fac1 = NOT(fac1)
|
||||
asmsub INT () -> clobbers(A,X,Y) -> () = $bccc ; INT() truncates, use FADDH first to round instead of trunc
|
||||
asmsub LOG () -> clobbers(A,X,Y) -> () = $b9ea ; fac1 = LN(fac1) (natural log)
|
||||
asmsub SGN () -> clobbers(A,X,Y) -> () = $bc39 ; fac1 = SGN(fac1), result of SIGN (-1, 0 or 1)
|
||||
asmsub SIGN () -> clobbers() -> (byte @ A) = $bc2b ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
|
||||
asmsub SIGN () -> clobbers() -> (ubyte @ A) = $bc2b ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
|
||||
asmsub ABS () -> clobbers() -> () = $bc58 ; fac1 = ABS(fac1)
|
||||
asmsub SQR () -> clobbers(A,X,Y) -> () = $bf71 ; fac1 = SQRT(fac1)
|
||||
asmsub EXP () -> clobbers(A,X,Y) -> () = $bfed ; fac1 = EXP(fac1) (e ** fac1)
|
||||
asmsub NEGOP () -> clobbers(A) -> () = $bfb4 ; switch the sign of fac1
|
||||
asmsub RND () -> clobbers(A,X,Y) -> () = $e097 ; fac1 = RND() (use RNDA instead)
|
||||
asmsub RNDA (acc: byte @ A) -> clobbers(A,X,Y) -> () = $e09a ; fac1 = RND(A)
|
||||
asmsub RNDA (acc: ubyte @ A) -> clobbers(A,X,Y) -> () = $e09a ; fac1 = RND(A)
|
||||
asmsub COS () -> clobbers(A,X,Y) -> () = $e264 ; fac1 = COS(fac1)
|
||||
asmsub SIN () -> clobbers(A,X,Y) -> () = $e26b ; fac1 = SIN(fac1)
|
||||
asmsub TAN () -> clobbers(A,X,Y) -> () = $e2b4 ; fac1 = TAN(fac1)
|
||||
|
@ -195,41 +195,41 @@ asmsub CINT () -> clobbers(A,X,Y) -> () = $FF81 ; (alias: SCINIT) initial
|
|||
asmsub IOINIT () -> clobbers(A, X) -> () = $FF84 ; initialize I/O devices (CIA, SID, IRQ)
|
||||
asmsub RAMTAS () -> clobbers(A,X,Y) -> () = $FF87 ; initialize RAM, tape buffer, screen
|
||||
asmsub RESTOR () -> clobbers(A,X,Y) -> () = $FF8A ; restore default I/O vectors
|
||||
asmsub VECTOR (dir: byte @ Pc, userptr: word @ XY) -> clobbers(A,Y) -> () = $FF8D ; read/set I/O vector table
|
||||
asmsub SETMSG (value: byte @ A) -> clobbers() -> () = $FF90 ; set Kernal message control flag
|
||||
asmsub SECOND (address: byte @ A) -> clobbers(A) -> () = $FF93 ; (alias: LSTNSA) send secondary address after LISTEN
|
||||
asmsub TKSA (address: byte @ A) -> clobbers(A) -> () = $FF96 ; (alias: TALKSA) send secondary address after TALK
|
||||
asmsub MEMTOP (dir: byte @ Pc, address: word @ XY) -> clobbers() -> (word @ XY) = $FF99 ; read/set top of memory pointer
|
||||
asmsub MEMBOT (dir: byte @ Pc, address: word @ XY) -> clobbers() -> (word @ XY) = $FF9C ; read/set bottom of memory pointer
|
||||
asmsub VECTOR (dir: ubyte @ Pc, userptr: uword @ XY) -> clobbers(A,Y) -> () = $FF8D ; read/set I/O vector table
|
||||
asmsub SETMSG (value: ubyte @ A) -> clobbers() -> () = $FF90 ; set Kernal message control flag
|
||||
asmsub SECOND (address: ubyte @ A) -> clobbers(A) -> () = $FF93 ; (alias: LSTNSA) send secondary address after LISTEN
|
||||
asmsub TKSA (address: ubyte @ A) -> clobbers(A) -> () = $FF96 ; (alias: TALKSA) send secondary address after TALK
|
||||
asmsub MEMTOP (dir: ubyte @ Pc, address: uword @ XY) -> clobbers() -> (uword @ XY) = $FF99 ; read/set top of memory pointer
|
||||
asmsub MEMBOT (dir: ubyte @ Pc, address: uword @ XY) -> clobbers() -> (uword @ XY) = $FF9C ; read/set bottom of memory pointer
|
||||
asmsub SCNKEY () -> clobbers(A,X,Y) -> () = $FF9F ; scan the keyboard
|
||||
asmsub SETTMO (timeout: byte @ A) -> clobbers() -> () = $FFA2 ; set time-out flag for IEEE bus
|
||||
asmsub ACPTR () -> clobbers() -> (byte @ A) = $FFA5 ; (alias: IECIN) input byte from serial bus
|
||||
asmsub CIOUT (databyte: byte @ A) -> clobbers() -> () = $FFA8 ; (alias: IECOUT) output byte to serial bus
|
||||
asmsub SETTMO (timeout: ubyte @ A) -> clobbers() -> () = $FFA2 ; set time-out flag for IEEE bus
|
||||
asmsub ACPTR () -> clobbers() -> (ubyte @ A) = $FFA5 ; (alias: IECIN) input byte from serial bus
|
||||
asmsub CIOUT (databyte: ubyte @ A) -> clobbers() -> () = $FFA8 ; (alias: IECOUT) output byte to serial bus
|
||||
asmsub UNTLK () -> clobbers(A) -> () = $FFAB ; command serial bus device to UNTALK
|
||||
asmsub UNLSN () -> clobbers(A) -> () = $FFAE ; command serial bus device to UNLISTEN
|
||||
asmsub LISTEN (device: byte @ A) -> clobbers(A) -> () = $FFB1 ; command serial bus device to LISTEN
|
||||
asmsub TALK (device: byte @ A) -> clobbers(A) -> () = $FFB4 ; command serial bus device to TALK
|
||||
asmsub READST () -> clobbers() -> (byte @ A) = $FFB7 ; read I/O status word
|
||||
asmsub SETLFS (logical: byte @ A, device: byte @ X, address: byte @ Y) -> clobbers() -> () = $FFBA ; set logical file parameters
|
||||
asmsub SETNAM (namelen: byte @ A, filename: word @ XY) -> clobbers() -> () = $FFBD ; set filename parameters
|
||||
asmsub LISTEN (device: ubyte @ A) -> clobbers(A) -> () = $FFB1 ; command serial bus device to LISTEN
|
||||
asmsub TALK (device: ubyte @ A) -> clobbers(A) -> () = $FFB4 ; command serial bus device to TALK
|
||||
asmsub READST () -> clobbers() -> (ubyte @ A) = $FFB7 ; read I/O status word
|
||||
asmsub SETLFS (logical: ubyte @ A, device: ubyte @ X, address: ubyte @ Y) -> clobbers() -> () = $FFBA ; set logical file parameters
|
||||
asmsub SETNAM (namelen: ubyte @ A, filename: uword @ XY) -> clobbers() -> () = $FFBD ; set filename parameters
|
||||
asmsub OPEN () -> clobbers(A,X,Y) -> () = $FFC0 ; (via 794 ($31A)) open a logical file
|
||||
asmsub CLOSE (logical: byte @ A) -> clobbers(A,X,Y) -> () = $FFC3 ; (via 796 ($31C)) close a logical file
|
||||
asmsub CHKIN (logical: byte @ X) -> clobbers(A,X) -> () = $FFC6 ; (via 798 ($31E)) define an input channel
|
||||
asmsub CHKOUT (logical: byte @ X) -> clobbers(A,X) -> () = $FFC9 ; (via 800 ($320)) define an output channel
|
||||
asmsub CLOSE (logical: ubyte @ A) -> clobbers(A,X,Y) -> () = $FFC3 ; (via 796 ($31C)) close a logical file
|
||||
asmsub CHKIN (logical: ubyte @ X) -> clobbers(A,X) -> () = $FFC6 ; (via 798 ($31E)) define an input channel
|
||||
asmsub CHKOUT (logical: ubyte @ X) -> clobbers(A,X) -> () = $FFC9 ; (via 800 ($320)) define an output channel
|
||||
asmsub CLRCHN () -> clobbers(A,X) -> () = $FFCC ; (via 802 ($322)) restore default devices
|
||||
asmsub CHRIN () -> clobbers(Y) -> (byte @ A) = $FFCF ; (via 804 ($324)) input a character (for keyboard, read a whole line from the screen) A=byte read.
|
||||
asmsub CHROUT (char: byte @ A) -> clobbers() -> () = $FFD2 ; (via 806 ($326)) output a character
|
||||
asmsub LOAD (verify: byte @ A, address: word @ XY) -> clobbers() -> (byte @Pc, byte @ A, byte @ X, byte @ Y) = $FFD5 ; (via 816 ($330)) load from device
|
||||
asmsub SAVE (zp_startaddr: byte @ A, endaddr: word @ XY) -> clobbers() -> (byte @ Pc, byte @ A) = $FFD8 ; (via 818 ($332)) save to a device
|
||||
asmsub SETTIM (low: byte @ A, middle: byte @ X, high: byte @ Y) -> clobbers() -> () = $FFDB ; set the software clock
|
||||
asmsub RDTIM () -> clobbers() -> (byte @ A, byte @ X, byte @ Y) = $FFDE ; read the software clock
|
||||
asmsub STOP () -> clobbers(A,X) -> (byte @ Pz, byte @ Pc) = $FFE1 ; (via 808 ($328)) check the STOP key
|
||||
asmsub GETIN () -> clobbers(X,Y) -> (byte @ A) = $FFE4 ; (via 810 ($32A)) get a character
|
||||
asmsub CHRIN () -> clobbers(Y) -> (ubyte @ A) = $FFCF ; (via 804 ($324)) input a character (for keyboard, read a whole line from the screen) A=byte read.
|
||||
asmsub CHROUT (char: ubyte @ A) -> clobbers() -> () = $FFD2 ; (via 806 ($326)) output a character
|
||||
asmsub LOAD (verify: ubyte @ A, address: uword @ XY) -> clobbers() -> (ubyte @Pc, ubyte @ A, ubyte @ X, ubyte @ Y) = $FFD5 ; (via 816 ($330)) load from device
|
||||
asmsub SAVE (zp_startaddr: ubyte @ A, endaddr: uword @ XY) -> clobbers() -> (ubyte @ Pc, ubyte @ A) = $FFD8 ; (via 818 ($332)) save to a device
|
||||
asmsub SETTIM (low: ubyte @ A, middle: ubyte @ X, high: ubyte @ Y) -> clobbers() -> () = $FFDB ; set the software clock
|
||||
asmsub RDTIM () -> clobbers() -> (ubyte @ A, ubyte @ X, ubyte @ Y) = $FFDE ; read the software clock
|
||||
asmsub STOP () -> clobbers(A,X) -> (ubyte @ Pz, ubyte @ Pc) = $FFE1 ; (via 808 ($328)) check the STOP key
|
||||
asmsub GETIN () -> clobbers(X,Y) -> (ubyte @ A) = $FFE4 ; (via 810 ($32A)) get a character
|
||||
asmsub CLALL () -> clobbers(A,X) -> () = $FFE7 ; (via 812 ($32C)) close all files
|
||||
asmsub UDTIM () -> clobbers(A,X) -> () = $FFEA ; update the software clock
|
||||
asmsub SCREEN () -> clobbers() -> (byte @ X, byte @ Y) = $FFED ; read number of screen rows and columns
|
||||
asmsub PLOT (dir: byte @ Pc, col: byte @ Y, row: byte @ X) -> clobbers() -> (byte @ X, byte @ Y) = $FFF0 ; read/set position of cursor on screen
|
||||
asmsub IOBASE () -> clobbers() -> (byte @ X, byte @ Y) = $FFF3 ; read base address of I/O devices
|
||||
asmsub SCREEN () -> clobbers() -> (ubyte @ X, ubyte @ Y) = $FFED ; read number of screen rows and columns
|
||||
asmsub PLOT (dir: ubyte @ Pc, col: ubyte @ Y, row: ubyte @ X) -> clobbers() -> (ubyte @ X, ubyte @ Y) = $FFF0 ; read/set position of cursor on screen
|
||||
asmsub IOBASE () -> clobbers() -> (ubyte @ X, ubyte @ Y) = $FFF3 ; read base address of I/O devices
|
||||
|
||||
; ---- end of C64 kernal routines ----
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ asmsub init_system () -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub byte2decimal (ubyte: byte @ A) -> clobbers() -> (byte @ Y, byte @ X, byte @ A) {
|
||||
asmsub byte2decimal (value: ubyte @ A) -> clobbers() -> (ubyte @ Y, ubyte @ X, ubyte @ A) {
|
||||
; ---- A to decimal string in Y/X/A (100s in Y, 10s in X, 1s in A)
|
||||
%asm {{
|
||||
ldy #$2f
|
||||
|
@ -60,7 +60,7 @@ asmsub byte2decimal (ubyte: byte @ A) -> clobbers() -> (byte @ Y, byte @ X, by
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub byte2hex (ubyte: byte @ A) -> clobbers(A) -> (byte @ X, byte @ Y) {
|
||||
asmsub byte2hex (value: ubyte @ A) -> clobbers(A) -> (ubyte @ X, ubyte @ Y) {
|
||||
; ---- A to hex string in XY (first hex char in X, second hex char in Y)
|
||||
%asm {{
|
||||
pha
|
||||
|
@ -77,13 +77,13 @@ asmsub byte2hex (ubyte: byte @ A) -> clobbers(A) -> (byte @ X, byte @ Y) {
|
|||
tax
|
||||
rts
|
||||
|
||||
hex_digits .str "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||
hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
str word2hex_output = "1234" ; 0-terminated, to make printing easier
|
||||
asmsub word2hex (dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub word2hex (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- convert 16 bit word in X/Y into 4-character hexadecimal string into memory 'word2hex_output'
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP2
|
||||
|
@ -99,8 +99,8 @@ asmsub word2hex (dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
byte[3] word2bcd_bcdbuff = [0, 0, 0]
|
||||
asmsub word2bcd (dataword: word @ XY) -> clobbers(A,X) -> () {
|
||||
ubyte[3] word2bcd_bcdbuff = [0, 0, 0]
|
||||
asmsub word2bcd (dataword: uword @ XY) -> clobbers(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
|
||||
|
@ -137,8 +137,8 @@ asmsub word2bcd (dataword: word @ XY) -> clobbers(A,X) -> () {
|
|||
}
|
||||
|
||||
|
||||
byte[5] word2decimal_output = 0
|
||||
asmsub word2decimal (dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
ubyte[5] word2decimal_output = 0
|
||||
asmsub word2decimal (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- convert 16 bit word in X/Y into decimal string into memory 'word2decimal_output'
|
||||
%asm {{
|
||||
jsr word2bcd
|
||||
|
@ -202,7 +202,7 @@ asmsub FREADUS32 () -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub FREADS24AXY (lo: byte @ A, mid: byte @ X, hi: byte @ Y) -> clobbers(A,X,Y) -> () {
|
||||
asmsub FREADS24AXY (lo: ubyte @ A, mid: ubyte @ X, hi: ubyte @ Y) -> clobbers(A,X,Y) -> () {
|
||||
; ---- fac1 = signed int24 (A/X/Y contain lo/mid/hi bytes)
|
||||
; note: there is no FREADU24AXY (unsigned), use FREADUS32 instead.
|
||||
%asm {{
|
||||
|
@ -219,7 +219,7 @@ asmsub FREADS24AXY (lo: byte @ A, mid: byte @ X, hi: byte @ Y) -> clobbers(A,X
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub GIVUAYF (uword: word @ AY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub GIVUAYF (value: uword @ AY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
|
||||
%asm {{
|
||||
sty $62
|
||||
|
@ -230,7 +230,7 @@ asmsub GIVUAYF (uword: word @ AY) -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub GIVAYFAY (sword: word @ AY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub GIVAYFAY (value: uword @ AY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- signed 16 bit word in A/Y (lo/hi) to float in fac1
|
||||
%asm {{
|
||||
sta c64.SCRATCH_ZP1
|
||||
|
@ -240,7 +240,7 @@ asmsub GIVAYFAY (sword: word @ AY) -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub FTOSWRDAY () -> clobbers(X) -> (word @ AY) {
|
||||
asmsub FTOSWRDAY () -> clobbers(X) -> (uword @ AY) {
|
||||
; ---- fac1 to signed word in A/Y
|
||||
%asm {{
|
||||
jsr c64.FTOSWORDYA ; note the inverse Y/A order
|
||||
|
@ -251,7 +251,7 @@ asmsub FTOSWRDAY () -> clobbers(X) -> (word @ AY) {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub GETADRAY () -> clobbers(X) -> (word @ AY) {
|
||||
asmsub GETADRAY () -> clobbers(X) -> (uword @ AY) {
|
||||
; ---- fac1 to unsigned word in A/Y
|
||||
%asm {{
|
||||
jsr c64.GETADR ; this uses the inverse order, Y/A
|
||||
|
@ -263,7 +263,7 @@ asmsub GETADRAY () -> clobbers(X) -> (word @ AY) {
|
|||
}
|
||||
|
||||
|
||||
asmsub copy_mflt (source: word @ XY) -> clobbers(A,Y) -> () {
|
||||
asmsub copy_mflt (source: uword @ XY) -> clobbers(A,Y) -> () {
|
||||
; ---- copy a 5 byte MFLT floating point variable to another place
|
||||
; input: X/Y = source address, c64.SCRATCH_ZPWORD1 = destination address
|
||||
%asm {{
|
||||
|
@ -289,7 +289,7 @@ asmsub copy_mflt (source: word @ XY) -> clobbers(A,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub float_add_one (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub float_add_one (mflt: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- add 1 to the MFLT pointed to by X/Y. Clobbers A, X, Y
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP1
|
||||
|
@ -305,7 +305,7 @@ asmsub float_add_one (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub float_sub_one (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub float_sub_one (mflt: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- subtract 1 from the MFLT pointed to by X/Y. Clobbers A, X, Y
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP1
|
||||
|
@ -322,7 +322,7 @@ asmsub float_sub_one (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub float_add_SW1_to_XY (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub float_add_SW1_to_XY (mflt: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- add MFLT pointed to by SCRATCH_ZPWORD1 to the MFLT pointed to by X/Y. Clobbers A, X, Y
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP1
|
||||
|
@ -338,7 +338,7 @@ asmsub float_add_SW1_to_XY (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
|||
}}
|
||||
}
|
||||
|
||||
asmsub float_sub_SW1_from_XY (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub float_sub_SW1_from_XY (mflt: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- subtract MFLT pointed to by SCRATCH_ZPWORD1 from the MFLT pointed to by X/Y. Clobbers A, X, Y
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP1
|
||||
|
@ -363,7 +363,7 @@ asmsub float_sub_SW1_from_XY (mflt: word @ XY) -> clobbers(A,X,Y) -> () {
|
|||
; ---- this block contains (character) Screen and text I/O related functions ----
|
||||
|
||||
|
||||
asmsub clear_screen (char: byte @ A, color: byte @ Y) -> clobbers() -> () {
|
||||
asmsub clear_screen (char: ubyte @ A, color: ubyte @ Y) -> clobbers() -> () {
|
||||
; ---- clear the character screen with the given fill character and character color.
|
||||
; (assumes screen is at $0400, could be altered in the future with self-modifying code)
|
||||
; @todo some byte var to set the SCREEN ADDR HI BYTE
|
||||
|
@ -393,7 +393,7 @@ _loop lda #0
|
|||
}
|
||||
|
||||
|
||||
asmsub scroll_left_full (alsocolors: byte @ Pc) -> clobbers(A, X, Y) -> () {
|
||||
asmsub scroll_left_full (alsocolors: ubyte @ Pc) -> clobbers(A, X, Y) -> () {
|
||||
; ---- scroll the whole screen 1 character to the left
|
||||
; contents of the rightmost column are unchanged, you should clear/refill this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
|
@ -452,7 +452,7 @@ _scroll_screen ; scroll the screen memory
|
|||
}
|
||||
|
||||
|
||||
asmsub scroll_right_full (alsocolors: byte @ Pc) -> clobbers(A,X) -> () {
|
||||
asmsub scroll_right_full (alsocolors: ubyte @ Pc) -> clobbers(A,X) -> () {
|
||||
; ---- scroll the whole screen 1 character to the right
|
||||
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
|
@ -503,7 +503,7 @@ _scroll_screen ; scroll the screen memory
|
|||
}
|
||||
|
||||
|
||||
asmsub scroll_up_full (alsocolors: byte @ Pc) -> clobbers(A,X) -> () {
|
||||
asmsub scroll_up_full (alsocolors: ubyte @ Pc) -> clobbers(A,X) -> () {
|
||||
; ---- scroll the whole screen 1 character up
|
||||
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
|
@ -554,7 +554,7 @@ _scroll_screen ; scroll the screen memory
|
|||
}
|
||||
|
||||
|
||||
asmsub scroll_down_full (alsocolors: byte @ Pc) -> clobbers(A,X) -> () {
|
||||
asmsub scroll_down_full (alsocolors: ubyte @ Pc) -> clobbers(A,X) -> () {
|
||||
; ---- scroll the whole screen 1 character down
|
||||
; contents of the top row are unchanged, you should refill/clear this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
|
@ -606,7 +606,7 @@ _scroll_screen ; scroll the screen memory
|
|||
|
||||
|
||||
|
||||
asmsub print_string (address: word @ XY) -> clobbers(A,Y) -> () {
|
||||
asmsub print_string (address: uword @ XY) -> clobbers(A,Y) -> () {
|
||||
; ---- print null terminated string from X/Y
|
||||
; note: the compiler contains an optimization that will replace
|
||||
; a call to this subroutine with a string argument of just one char,
|
||||
|
@ -625,7 +625,7 @@ asmsub print_string (address: word @ XY) -> clobbers(A,Y) -> () {
|
|||
}
|
||||
|
||||
|
||||
asmsub print_pstring (address: word @ XY) -> clobbers(A,X) -> (byte @ Y) {
|
||||
asmsub print_pstring (address: uword @ XY) -> clobbers(A,X) -> (ubyte @ Y) {
|
||||
; ---- print pstring (length as first byte) from X/Y, returns str len in Y
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP1
|
||||
|
@ -644,36 +644,7 @@ asmsub print_pstring (address: word @ XY) -> clobbers(A,X) -> (byte @ Y) {
|
|||
}
|
||||
|
||||
|
||||
asmsub print_pimmediate () -> clobbers() -> () {
|
||||
; ---- print pstring in memory immediately following the subroutine fast call instruction
|
||||
; note that the clobbered registers (A,X,Y) are not listed ON PURPOSE
|
||||
%asm {{
|
||||
tsx
|
||||
lda $102,x
|
||||
tay ; put high byte in y
|
||||
lda $101,x
|
||||
tax ; and low byte in x.
|
||||
inx
|
||||
bne +
|
||||
iny
|
||||
+ jsr print_pstring ; print string in XY, returns string length in y.
|
||||
tya
|
||||
tsx
|
||||
clc
|
||||
adc $101,x ; add content of 1st (length) byte to return addr.
|
||||
bcc + ; if that made the low byte roll over to 00,
|
||||
inc $102,x ; then increment the high byte too.
|
||||
+ clc
|
||||
adc #1 ; now add 1 for the length byte itself.
|
||||
sta $101,x
|
||||
bne + ; if that made it (the low byte) roll over to 00,
|
||||
inc $102,x ; increment the high byte of the return addr too.
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
asmsub print_byte_decimal0 (ubyte: byte @ A) -> clobbers(A,X,Y) -> () {
|
||||
asmsub print_byte_decimal0 (value: ubyte @ A) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the byte in A in decimal form, with left padding 0s (3 positions total)
|
||||
%asm {{
|
||||
jsr byte2decimal
|
||||
|
@ -688,7 +659,7 @@ asmsub print_byte_decimal0 (ubyte: byte @ A) -> clobbers(A,X,Y) -> () {
|
|||
}
|
||||
|
||||
|
||||
asmsub print_byte_decimal (ubyte: byte @ A) -> clobbers(A,X,Y) -> () {
|
||||
asmsub print_byte_decimal (value: ubyte @ A) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the byte in A in decimal form, without left padding 0s
|
||||
%asm {{
|
||||
jsr byte2decimal
|
||||
|
@ -709,7 +680,7 @@ _print_tens txa
|
|||
}
|
||||
|
||||
|
||||
asmsub print_byte_hex (prefix: byte @ Pc, ubyte: byte @ A) -> clobbers(A,X,Y) -> () {
|
||||
asmsub print_byte_hex (prefix: ubyte @ Pc, value: ubyte @ A) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the byte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||
%asm {{
|
||||
bcc +
|
||||
|
@ -726,7 +697,7 @@ asmsub print_byte_hex (prefix: byte @ Pc, ubyte: byte @ A) -> clobbers(A,X,Y)
|
|||
}
|
||||
|
||||
|
||||
asmsub print_word_hex (prefix: byte @ Pc, dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub print_word_hex (prefix: ubyte @ Pc, dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the (unsigned) word in X/Y in hexadecimal form (4 digits)
|
||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||
%asm {{
|
||||
|
@ -740,8 +711,9 @@ asmsub print_word_hex (prefix: byte @ Pc, dataword: word @ XY) -> clobbers(A,X,
|
|||
}
|
||||
|
||||
|
||||
asmsub print_word_decimal0 (dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub print_word_decimal0 (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the (unsigned) word in X/Y in decimal form, with left padding 0s (5 positions total)
|
||||
; @todo shorter in loop form?
|
||||
%asm {{
|
||||
jsr word2decimal
|
||||
lda word2decimal_output
|
||||
|
@ -758,7 +730,7 @@ asmsub print_word_decimal0 (dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
|||
}
|
||||
|
||||
|
||||
asmsub print_word_decimal (dataword: word @ XY) -> clobbers(A,X,Y) -> () {
|
||||
asmsub print_word_decimal (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
|
||||
; ---- print the word in X/Y in decimal form, without left padding 0s
|
||||
%asm {{
|
||||
jsr word2decimal
|
||||
|
@ -791,8 +763,8 @@ _pr_decimal
|
|||
}
|
||||
|
||||
|
||||
asmsub input_chars (buffer: word @ AX) -> clobbers(A) -> (byte @ Y) {
|
||||
; ---- Input a string (max. 80 chars) from the keyboard.
|
||||
asmsub input_chars (buffer: uword @ AX) -> clobbers(A) -> (ubyte @ Y) {
|
||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length.
|
||||
; It assumes the keyboard is selected as I/O channel!!
|
||||
|
||||
%asm {{
|
||||
|
@ -813,48 +785,3 @@ asmsub input_chars (buffer: word @ AX) -> clobbers(A) -> (byte @ Y) {
|
|||
}
|
||||
|
||||
} ; ---- end block c64scr
|
||||
|
||||
|
||||
|
||||
;asmsub memcopy_basic () -> clobbers(A,X,Y) -> () {
|
||||
; ; ---- copy a memory block by using a BASIC ROM routine
|
||||
; ; it calls a function from the basic interpreter, so:
|
||||
; ; - BASIC ROM must be banked in
|
||||
; ; - the source block must be readable (so no RAM hidden under BASIC, Kernal, or I/O)
|
||||
; ; - the target block must be writable (so no RAM hidden under I/O)
|
||||
; ; higher addresses are copied first, so:
|
||||
; ; - moving data to higher addresses works even if areas overlap
|
||||
; ; - moving data to lower addresses only works if areas do not overlap
|
||||
; %asm {{
|
||||
; lda #<src_start
|
||||
; ldx #>src_start
|
||||
; sta $5f
|
||||
; stx $60
|
||||
; lda #<src_end
|
||||
; ldx #>src_end
|
||||
; sta $5a
|
||||
; stx $5b
|
||||
; lda #<(target_start + src_end - src_start)
|
||||
; ldx #>(target_start + src_end - src_start)
|
||||
; sta $58
|
||||
; stx $59
|
||||
; jmp $a3bf
|
||||
; }
|
||||
;}
|
||||
|
||||
; macro version of the above memcopy_basic routine:
|
||||
; MACRO PARAMS src_start, src_end, target_start
|
||||
; lda #<src_start
|
||||
; ldx #>src_start
|
||||
; sta $5f
|
||||
; stx $60
|
||||
; lda #<src_end
|
||||
; ldx #>src_end
|
||||
; sta $5a
|
||||
; stx $5b
|
||||
; lda #<(target_start + src_end - src_start)
|
||||
; ldx #>(target_start + src_end - src_start)
|
||||
; sta $58
|
||||
; stx $59
|
||||
; jsr $a3bf
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user