mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
fix function calls
This commit is contained in:
parent
13b4afdc35
commit
4d60506d0a
@ -71,9 +71,7 @@ statement :
|
||||
|
||||
labeldef : identifier ':' ;
|
||||
|
||||
call_location : integerliteral | identifier | scoped_identifier ;
|
||||
|
||||
unconditionaljump : 'goto' call_location ;
|
||||
unconditionaljump : 'goto' (integerliteral | identifier | scoped_identifier) ;
|
||||
|
||||
directive :
|
||||
directivename=('%output' | '%launcher' | '%zp' | '%address' | '%import' |
|
||||
@ -137,7 +135,7 @@ expression :
|
||||
|
||||
|
||||
functioncall :
|
||||
call_location '(' expression_list? ')'
|
||||
(identifier | scoped_identifier) '(' expression_list? ')'
|
||||
;
|
||||
|
||||
expression_list :
|
||||
@ -174,11 +172,17 @@ inlineasm : '%asm' INLINEASMBLOCK;
|
||||
|
||||
|
||||
subroutine :
|
||||
'sub' identifier '(' sub_params? ')' '->' '(' sub_returns? ')' '{' EOL
|
||||
'sub' identifier '(' sub_params? ')' '->' '(' sub_returns? ')' (sub_address | sub_body)
|
||||
;
|
||||
|
||||
sub_body :
|
||||
'{' EOL
|
||||
(statement | EOL) *
|
||||
'}' EOL
|
||||
;
|
||||
|
||||
sub_address : '=' integerliteral ;
|
||||
|
||||
sub_params : sub_param (',' sub_param)* ;
|
||||
|
||||
sub_param: identifier ':' register ;
|
||||
|
@ -7,6 +7,12 @@
|
||||
|
||||
A = "derp" * %000100
|
||||
|
||||
sub foo () -> () {
|
||||
A=99
|
||||
return 33
|
||||
X =33
|
||||
}
|
||||
|
||||
return 1+999
|
||||
%breakpoint
|
||||
%asminclude "derp", hopsa
|
||||
|
@ -97,7 +97,7 @@ fun discoverImportedModule(name: String, importedFrom: Path): Path {
|
||||
|
||||
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)
|
||||
throw SyntaxError("invalid import directive", import.position)
|
||||
val moduleName = import.args[0].name!!
|
||||
if(importedModules.containsKey(moduleName))
|
||||
return null
|
||||
|
@ -34,9 +34,9 @@ enum class Register {
|
||||
open class AstException(override var message: String) : Exception(message)
|
||||
class ExpressionException(override var message: String) : AstException(message)
|
||||
|
||||
class SyntaxError(override var message: String, val node: Node?) : AstException(message) {
|
||||
class SyntaxError(override var message: String, val position: Position?) : AstException(message) {
|
||||
fun printError() {
|
||||
val location = if(node?.position == null) "" else node.position.toString()
|
||||
val location = if(position == null) "" else position.toString()
|
||||
System.err.println("$location $message")
|
||||
}
|
||||
}
|
||||
@ -55,6 +55,8 @@ interface IAstProcessor {
|
||||
fun process(block: Block): IStatement
|
||||
fun process(decl: VarDecl): IStatement
|
||||
fun process(subroutine: Subroutine): IStatement
|
||||
fun process(jump: Jump): IStatement
|
||||
fun process(functionCall: FunctionCall): IExpression
|
||||
}
|
||||
|
||||
|
||||
@ -193,6 +195,14 @@ data class VarDecl(val type: VarDeclType,
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
val isScalar = arrayspec==null
|
||||
val isArray = arrayspec!=null && arrayspec.y==null
|
||||
val isMatrix = arrayspec?.y != null
|
||||
val arraySizeX : Int?
|
||||
get() = arrayspec?.x?.constValue()?.intvalue
|
||||
val arraySizeY : Int?
|
||||
get() = arrayspec?.y?.constValue()?.intvalue
|
||||
}
|
||||
|
||||
|
||||
@ -275,24 +285,24 @@ data class LiteralValue(val intvalue: Int? = null,
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
|
||||
fun asInt(): Int? {
|
||||
fun asInt(errorIfNotNumeric: Boolean=true): Int? {
|
||||
return when {
|
||||
intvalue!=null -> intvalue
|
||||
floatvalue!=null -> floatvalue.toInt()
|
||||
else -> {
|
||||
if(strvalue!=null || arrayvalue!=null)
|
||||
if((strvalue!=null || arrayvalue!=null) && errorIfNotNumeric)
|
||||
throw AstException("attempt to get int value from non-integer $this")
|
||||
else null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun asFloat(): Double? {
|
||||
fun asFloat(errorIfNotNumeric: Boolean=true): Double? {
|
||||
return when {
|
||||
floatvalue!=null -> floatvalue
|
||||
intvalue!=null -> intvalue.toDouble()
|
||||
else -> {
|
||||
if(strvalue!=null || arrayvalue!=null)
|
||||
if((strvalue!=null || arrayvalue!=null) && errorIfNotNumeric)
|
||||
throw AstException("attempt to get float value from non-integer $this")
|
||||
else null
|
||||
}
|
||||
@ -350,7 +360,7 @@ data class Identifier(val name: String, val scope: List<String>) : IExpression {
|
||||
}
|
||||
|
||||
override fun constValue(): LiteralValue? {
|
||||
// @todo should look up the identifier and return its value if that is a compile time const
|
||||
// @todo should look up the location and return its value if that is a compile time const
|
||||
return null
|
||||
}
|
||||
|
||||
@ -358,19 +368,6 @@ data class Identifier(val name: String, val scope: List<String>) : IExpression {
|
||||
}
|
||||
|
||||
|
||||
data class CallTarget(val address: Int?, val identifier: Identifier?) : Node {
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
identifier?.linkParents(this)
|
||||
}
|
||||
|
||||
fun process(processor: IAstProcessor) = this
|
||||
}
|
||||
|
||||
|
||||
data class PostIncrDecr(var target: AssignTarget, val operator: String) : IStatement {
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
@ -387,29 +384,26 @@ data class PostIncrDecr(var target: AssignTarget, val operator: String) : IState
|
||||
}
|
||||
|
||||
|
||||
data class Jump(var target: CallTarget) : IStatement {
|
||||
data class Jump(val address: Int?, val identifier: Identifier?) : IStatement {
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
target.linkParents(this)
|
||||
identifier?.linkParents(this)
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor): IStatement {
|
||||
target = target.process(processor)
|
||||
return this
|
||||
}
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
}
|
||||
|
||||
|
||||
data class FunctionCall(var target: CallTarget, var arglist: List<IExpression>) : IExpression {
|
||||
data class FunctionCall(var location: Identifier, var arglist: List<IExpression>) : IExpression {
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
target.linkParents(this)
|
||||
location.linkParents(this)
|
||||
arglist.forEach { it.linkParents(this) }
|
||||
}
|
||||
|
||||
@ -418,11 +412,7 @@ data class FunctionCall(var target: CallTarget, var arglist: List<IExpression>)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor): IExpression {
|
||||
target = target.process(processor)
|
||||
arglist = arglist.map{it.process(processor)}
|
||||
return this
|
||||
}
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
}
|
||||
|
||||
|
||||
@ -441,6 +431,7 @@ data class InlineAssembly(val assembly: String) : IStatement {
|
||||
data class Subroutine(val name: String,
|
||||
val parameters: List<SubroutineParameter>,
|
||||
val returnvalues: List<SubroutineReturnvalue>,
|
||||
val address: Int?,
|
||||
var statements: List<IStatement>) : IStatement {
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
@ -619,7 +610,13 @@ private fun il65Parser.InlineasmContext.toAst(withPosition: Boolean): IStatement
|
||||
|
||||
|
||||
private fun il65Parser.UnconditionaljumpContext.toAst(withPosition: Boolean): IStatement {
|
||||
val jump = Jump(call_location().toAst(withPosition))
|
||||
|
||||
val address = integerliteral()?.toAst()
|
||||
val identifier =
|
||||
if(identifier()!=null) identifier()?.toAst(withPosition)
|
||||
else scoped_identifier()?.toAst(withPosition)
|
||||
|
||||
val jump = Jump(address, identifier)
|
||||
jump.position = toPosition(withPosition)
|
||||
return jump
|
||||
}
|
||||
@ -636,7 +633,8 @@ private fun il65Parser.SubroutineContext.toAst(withPosition: Boolean) : Subrouti
|
||||
val sub = Subroutine(identifier().text,
|
||||
if(sub_params()==null) emptyList() else sub_params().toAst(withPosition),
|
||||
if(sub_returns()==null) emptyList() else sub_returns().toAst(withPosition),
|
||||
statement().map{ it.toAst(withPosition) })
|
||||
sub_address()?.integerliteral()?.toAst(),
|
||||
if(sub_body()==null) emptyList() else sub_body().statement().map {it.toAst(withPosition)})
|
||||
sub.position = toPosition(withPosition)
|
||||
return sub
|
||||
}
|
||||
@ -653,17 +651,6 @@ private fun il65Parser.Sub_returnsContext.toAst(withPosition: Boolean): List<Sub
|
||||
}
|
||||
|
||||
|
||||
private fun il65Parser.Call_locationContext.toAst(withPosition: Boolean) : CallTarget {
|
||||
val address = integerliteral()?.toAst()
|
||||
val identifier = identifier()
|
||||
val result =
|
||||
if(identifier!=null) CallTarget(address, identifier.toAst(withPosition))
|
||||
else CallTarget(address, scoped_identifier().toAst(withPosition))
|
||||
result.position = toPosition(withPosition)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private fun il65Parser.Assign_targetContext.toAst(withPosition: Boolean) : AssignTarget {
|
||||
val register = register()?.toAst()
|
||||
val identifier = identifier()
|
||||
@ -764,7 +751,7 @@ private fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpress
|
||||
|
||||
val funcall = functioncall()
|
||||
if(funcall!=null) {
|
||||
val location = funcall.call_location().toAst(withPosition)
|
||||
val location = funcall.identifier().toAst(withPosition)
|
||||
val fcall = if(funcall.expression_list()==null)
|
||||
FunctionCall(location, emptyList())
|
||||
else
|
||||
|
@ -1,6 +1,7 @@
|
||||
package il65.ast
|
||||
|
||||
import il65.ParsingFailedError
|
||||
import javax.xml.crypto.Data
|
||||
|
||||
|
||||
fun Module.checkValid() {
|
||||
@ -16,7 +17,6 @@ fun Module.checkValid() {
|
||||
|
||||
|
||||
class AstChecker : IAstProcessor {
|
||||
|
||||
private val checkResult: MutableList<SyntaxError> = mutableListOf()
|
||||
private val blockNames: HashMap<String, Position?> = hashMapOf()
|
||||
|
||||
@ -36,13 +36,24 @@ class AstChecker : IAstProcessor {
|
||||
return expr
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCall): IExpression {
|
||||
functionCall.arglist.map{it.process(this)}
|
||||
return functionCall
|
||||
}
|
||||
|
||||
override fun process(jump: Jump): IStatement {
|
||||
if(jump.address!=null && (jump.address < 0 || jump.address > 65535))
|
||||
checkResult.add(SyntaxError("jump address must be valid 0..\$ffff", jump.position))
|
||||
return jump
|
||||
}
|
||||
|
||||
override fun process(block: Block): IStatement {
|
||||
if(block.address!=null && (block.address<0 || block.address>65535)) {
|
||||
checkResult.add(SyntaxError("block memory address must be valid 0..\$ffff", block))
|
||||
checkResult.add(SyntaxError("block memory address must be valid 0..\$ffff", block.position))
|
||||
}
|
||||
val existing = blockNames[block.name]
|
||||
if(existing!=null) {
|
||||
checkResult.add(SyntaxError("block name conflict, first defined in ${existing.file} line ${existing.line}", block))
|
||||
checkResult.add(SyntaxError("block name conflict, first defined in ${existing.file} line ${existing.line}", block.position))
|
||||
} else {
|
||||
blockNames[block.name] = block.position
|
||||
}
|
||||
@ -55,7 +66,7 @@ class AstChecker : IAstProcessor {
|
||||
*/
|
||||
override fun process(subroutine: Subroutine): IStatement {
|
||||
fun err(msg: String) {
|
||||
checkResult.add(SyntaxError(msg, subroutine))
|
||||
checkResult.add(SyntaxError(msg, subroutine.position))
|
||||
}
|
||||
val uniqueNames = subroutine.parameters.map { it.name }.toSet()
|
||||
if(uniqueNames.size!=subroutine.parameters.size)
|
||||
@ -72,12 +83,15 @@ class AstChecker : IAstProcessor {
|
||||
// subroutine must contain at least one 'return' or 'goto'
|
||||
// (or if it has an asm block, that must contain a 'rts' or 'jmp')
|
||||
if(subroutine.statements.count { it is Return || it is Jump } == 0) {
|
||||
if(subroutine.address==null) {
|
||||
val amount = subroutine.statements
|
||||
.map {(it as InlineAssembly)?.assembly}
|
||||
.filter { it is InlineAssembly }
|
||||
.map {(it as InlineAssembly).assembly}
|
||||
.count { it.contains(" rts") || it.contains("\trts") ||
|
||||
it.contains(" jmp") || it.contains("\tjmp")}
|
||||
if(amount==0)
|
||||
if(amount==0 )
|
||||
err("subroutine must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
}
|
||||
}
|
||||
|
||||
return subroutine
|
||||
@ -88,7 +102,7 @@ class AstChecker : IAstProcessor {
|
||||
*/
|
||||
override fun process(decl: VarDecl): IStatement {
|
||||
fun err(msg: String) {
|
||||
checkResult.add(SyntaxError(msg, decl))
|
||||
checkResult.add(SyntaxError(msg, decl.position))
|
||||
}
|
||||
when(decl.type) {
|
||||
VarDeclType.VAR, VarDeclType.CONST -> {
|
||||
@ -97,38 +111,12 @@ class AstChecker : IAstProcessor {
|
||||
err("need a compile-time constant initializer value")
|
||||
decl.value !is LiteralValue ->
|
||||
err("need a compile-time constant initializer value, found: ${decl.value!!::class.simpleName}")
|
||||
else -> {
|
||||
val value = decl.value as LiteralValue
|
||||
when (decl.datatype) {
|
||||
DataType.FLOAT -> {
|
||||
val number = value.asFloat()
|
||||
if (number == null)
|
||||
err("need a const float initializer value")
|
||||
else if (number > 1.7014118345e+38 || number < -1.7014118345e+38)
|
||||
err("floating point value out of range for MFLPT format")
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val number = value.asInt()
|
||||
if (number == null)
|
||||
err("need a const integer initializer value")
|
||||
else if (number < 0 || number > 255)
|
||||
err("value out of range for unsigned byte")
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val number = value.asInt()
|
||||
if (number == null)
|
||||
err("need a const integer initializer value")
|
||||
else if (number < 0 || number > 65535)
|
||||
err("value out of range for unsigned word")
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
val str = value.strvalue
|
||||
if (str == null)
|
||||
err("need a const string initializer value")
|
||||
else if (str.isEmpty() || str.length > 65535)
|
||||
err("string length must be 1..65535")
|
||||
}
|
||||
}
|
||||
decl.isScalar -> {
|
||||
checkConstInitializerValueScalar(decl)
|
||||
checkValueRange(decl.datatype, decl.value as LiteralValue, decl.position)
|
||||
}
|
||||
decl.isArray || decl.isMatrix -> {
|
||||
checkConstInitializerValueArray(decl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,12 +133,107 @@ class AstChecker : IAstProcessor {
|
||||
return decl
|
||||
}
|
||||
|
||||
|
||||
private fun checkConstInitializerValueArray(decl: VarDecl) {
|
||||
val value = decl.value as LiteralValue
|
||||
// init value should either be a scalar or an array with the same dimensions as the arrayspec.
|
||||
|
||||
if(decl.isArray) {
|
||||
if(value.arrayvalue==null) {
|
||||
checkValueRange(decl.datatype, value.constValue()!!, value.position)
|
||||
}
|
||||
else {
|
||||
if (value.arrayvalue.size != decl.arraySizeX)
|
||||
checkResult.add(SyntaxError("initializer array size mismatch (expecting ${decl.arraySizeX})", decl.position))
|
||||
else {
|
||||
value.arrayvalue.forEach {
|
||||
checkValueRange(decl.datatype, it.constValue()!!, it.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(decl.isMatrix) {
|
||||
if(value.arrayvalue==null) {
|
||||
checkValueRange(decl.datatype, value.constValue()!!, value.position)
|
||||
}
|
||||
else {
|
||||
if (value.arrayvalue.size != decl.arraySizeX!! * decl.arraySizeY!!)
|
||||
checkResult.add(SyntaxError("initializer array size mismatch (expecting ${decl.arraySizeX!! * decl.arraySizeY!!}", decl.position))
|
||||
else {
|
||||
value.arrayvalue.forEach {
|
||||
checkValueRange(decl.datatype, it.constValue()!!, it.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun checkValueRange(datatype: DataType, value: LiteralValue, position: Position?) {
|
||||
fun err(msg: String) {
|
||||
checkResult.add(SyntaxError(msg, position))
|
||||
}
|
||||
when (datatype) {
|
||||
DataType.FLOAT -> {
|
||||
val number = value.asFloat(false)
|
||||
if (number!=null && (number > 1.7014118345e+38 || number < -1.7014118345e+38))
|
||||
err("floating point value out of range for MFLPT format")
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val number = value.asInt(false)
|
||||
if (number!=null && (number < 0 || number > 255))
|
||||
err("value out of range for unsigned byte")
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val number = value.asInt(false)
|
||||
if (number!=null && (number < 0 || number > 65535))
|
||||
err("value out of range for unsigned word")
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
val str = value.strvalue
|
||||
if (str!=null && (str.isEmpty() || str.length > 65535))
|
||||
err("string length must be 1..65535")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun checkConstInitializerValueScalar(decl: VarDecl) {
|
||||
fun err(msg: String) {
|
||||
checkResult.add(SyntaxError(msg, decl.position))
|
||||
}
|
||||
val value = decl.value as LiteralValue
|
||||
when (decl.datatype) {
|
||||
DataType.FLOAT -> {
|
||||
val number = value.asFloat(false)
|
||||
if (number == null)
|
||||
err("need a const float initializer value")
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val number = value.asInt(false)
|
||||
if (number == null)
|
||||
err("need a const integer initializer value")
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val number = value.asInt(false)
|
||||
if (number == null)
|
||||
err("need a const integer initializer value")
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
val str = value.strvalue
|
||||
if (str == null)
|
||||
err("need a const string initializer value")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check the arguments of the directive
|
||||
*/
|
||||
override fun process(directive: Directive): IStatement {
|
||||
fun err(msg: String) {
|
||||
checkResult.add(SyntaxError(msg, directive))
|
||||
checkResult.add(SyntaxError(msg, directive.position))
|
||||
}
|
||||
when(directive.directive) {
|
||||
"%output" -> {
|
||||
|
@ -39,6 +39,15 @@ class AstOptimizer : IAstProcessor {
|
||||
return subroutine
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCall): IExpression {
|
||||
functionCall.arglist = functionCall.arglist.map{it.process(this)}
|
||||
return functionCall
|
||||
}
|
||||
|
||||
override fun process(jump: Jump): IStatement {
|
||||
return jump
|
||||
}
|
||||
|
||||
|
||||
override fun process(decl: VarDecl): IStatement {
|
||||
decl.value = decl.value?.process(this)
|
||||
|
@ -65,4 +65,12 @@ class ImportedAstChecker : IAstProcessor {
|
||||
return directive
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCall): IExpression {
|
||||
return functionCall
|
||||
}
|
||||
|
||||
override fun process(jump: Jump): IStatement {
|
||||
return jump
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
; ;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
%output enable_floats
|
||||
; todo %option enable_floats
|
||||
|
||||
|
||||
~ c64 {
|
||||
@ -172,7 +172,7 @@ sub SQR () -> (?) = $bf71 ; fac1 = SQRT(fac1)
|
||||
sub EXP () -> (?) = $bfed ; fac1 = EXP(fac1) (e ** fac1)
|
||||
sub NEGOP () -> (A?) = $bfb4 ; switch the sign of fac1
|
||||
sub RND () -> (?) = $e097 ; fac1 = RND() (use RNDA instead)
|
||||
sub RNDA (A) -> (?) = $e09a ; fac1 = RND(A)
|
||||
sub RNDA (acc: A) -> (?) = $e09a ; fac1 = RND(A)
|
||||
sub COS () -> (?) = $e264 ; fac1 = COS(fac1)
|
||||
sub SIN () -> (?) = $e26b ; fac1 = SIN(fac1)
|
||||
sub TAN () -> (?) = $e2b4 ; fac1 = TAN(fac1)
|
||||
@ -206,7 +206,7 @@ sub MEMBOT (dir: SC, address: XY) -> (XY) = $FF9C ; read/set bottom of memory
|
||||
sub SCNKEY () -> (?) = $FF9F ; scan the keyboard
|
||||
sub SETTMO (timeout: A) -> () = $FFA2 ; set time-out flag for IEEE bus
|
||||
sub ACPTR () -> (A) = $FFA5 ; (alias: IECIN) input byte from serial bus
|
||||
sub CIOUT (byte: A) -> () = $FFA8 ; (alias: IECOUT) output byte to serial bus
|
||||
sub CIOUT (databyte: A) -> () = $FFA8 ; (alias: IECOUT) output byte to serial bus
|
||||
sub UNTLK () -> (A?) = $FFAB ; command serial bus device to UNTALK
|
||||
sub UNLSN () -> (A?) = $FFAE ; command serial bus device to UNLISTEN
|
||||
sub LISTEN (device: A) -> (A?) = $FFB1 ; command serial bus device to LISTEN
|
||||
@ -269,7 +269,6 @@ sub init_system () -> (?) {
|
||||
}}
|
||||
}
|
||||
|
||||
%noreturn
|
||||
} ; ------ end of block c64
|
||||
|
||||
|
||||
@ -452,8 +451,6 @@ sub float_sub_SW1_from_XY (mflt: XY) -> (?) {
|
||||
}}
|
||||
}
|
||||
|
||||
%noreturn
|
||||
|
||||
} ; ------ end of block c64flt
|
||||
|
||||
|
||||
@ -743,8 +740,8 @@ hex_digits .str "0123456789abcdef" ; can probably be reused for other stuff as w
|
||||
}
|
||||
|
||||
|
||||
var str word2hex_output = "1234" ; 0-terminated, to make printing easier
|
||||
sub word2hex (word: XY) -> (?) {
|
||||
str word2hex_output = "1234" ; 0-terminated, to make printing easier
|
||||
sub word2hex (dataword: XY) -> (?) {
|
||||
; ---- convert 16 bit word in X/Y into 4-character hexadecimal string into memory 'word2hex_output'
|
||||
%asm {{
|
||||
stx c64.SCRATCH_ZP2
|
||||
@ -760,9 +757,8 @@ sub word2hex (word: XY) -> (?) {
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
var array(3) word2bcd_bcdbuff
|
||||
sub word2bcd (word: XY) -> (A?, X?) {
|
||||
byte[3] word2bcd_bcdbuff = [0, 0, 0]
|
||||
sub word2bcd (dataword: 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
|
||||
@ -799,8 +795,8 @@ sub word2bcd (word: XY) -> (A?, X?) {
|
||||
}
|
||||
|
||||
|
||||
var array(5) word2decimal_output
|
||||
sub word2decimal (word: XY) -> (?) {
|
||||
byte[5] word2decimal_output = 0
|
||||
sub word2decimal (dataword: XY) -> (?) {
|
||||
; ---- convert 16 bit word in X/Y into decimal string into memory 'word2decimal_output'
|
||||
%asm {{
|
||||
jsr word2bcd
|
||||
@ -955,7 +951,7 @@ sub print_byte_hex (prefix: SC, ubyte: A) -> (?) {
|
||||
}
|
||||
|
||||
|
||||
sub print_word_hex (prefix: SC, word: XY) -> (?) {
|
||||
sub print_word_hex (prefix: SC, dataword: XY) -> (?) {
|
||||
; ---- print the (unsigned) word in X/Y in hexadecimal form (4 digits)
|
||||
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||
%asm {{
|
||||
@ -969,7 +965,7 @@ sub print_word_hex (prefix: SC, word: XY) -> (?) {
|
||||
}
|
||||
|
||||
|
||||
sub print_word_decimal0 (word: XY) -> (?) {
|
||||
sub print_word_decimal0 (dataword: XY) -> (?) {
|
||||
; ---- print the (unsigned) word in X/Y in decimal form, with left padding 0s (5 positions total)
|
||||
%asm {{
|
||||
jsr word2decimal
|
||||
@ -987,7 +983,7 @@ sub print_word_decimal0 (word: XY) -> (?) {
|
||||
}
|
||||
|
||||
|
||||
sub print_word_decimal (word: XY) -> (A?, X?, Y?) {
|
||||
sub print_word_decimal (dataword: XY) -> (A?, X?, Y?) {
|
||||
; ---- print the word in X/Y in decimal form, without left padding 0s
|
||||
%asm {{
|
||||
jsr word2decimal
|
||||
@ -1041,8 +1037,6 @@ sub input_chars (buffer: AX) -> (A?, Y) {
|
||||
}}
|
||||
}
|
||||
|
||||
%noreturn
|
||||
|
||||
} ; ---- end block c64scr
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user