mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +00:00
added clamp() builtin function and floats.clampf()
This commit is contained in:
parent
e243531dab
commit
b43223cb7a
@ -99,8 +99,10 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||
"lsb" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
|
||||
"msb" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
|
||||
"mkword" to FSignature(true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD),
|
||||
"min" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), null),
|
||||
"max" to FSignature(true, listOf(FParam("value", NumericDatatypesNoBool)), null),
|
||||
"clamp__byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE)), FParam("minimum", arrayOf(DataType.BYTE)), FParam("maximum", arrayOf(DataType.BYTE))), DataType.BYTE),
|
||||
"clamp__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE)), FParam("minimum", arrayOf(DataType.UBYTE)), FParam("maximum", arrayOf(DataType.UBYTE))), DataType.UBYTE),
|
||||
"clamp__word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD)), FParam("minimum", arrayOf(DataType.WORD)), FParam("maximum", arrayOf(DataType.WORD))), DataType.WORD),
|
||||
"clamp__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD)), FParam("minimum", arrayOf(DataType.UWORD)), FParam("maximum", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||
"min__byte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), DataType.BYTE),
|
||||
"min__ubyte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UBYTE)), FParam("val2", arrayOf(DataType.UBYTE))), DataType.UBYTE),
|
||||
"min__word" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.WORD)), FParam("val2", arrayOf(DataType.WORD))), DataType.WORD),
|
||||
|
@ -31,6 +31,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
"msb" -> funcMsb(fcall, resultToStack, resultRegister)
|
||||
"lsb" -> funcLsb(fcall, resultToStack, resultRegister)
|
||||
"mkword" -> funcMkword(fcall, resultToStack, resultRegister)
|
||||
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(fcall, resultToStack, resultRegister)
|
||||
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(fcall, resultToStack, resultRegister)
|
||||
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(fcall, resultToStack, resultRegister)
|
||||
"abs__byte", "abs__word", "abs__float" -> funcAbs(fcall, resultToStack, resultRegister, sscope)
|
||||
@ -860,6 +861,37 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcClamp(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
val signed = fcall.type in SignedDatatypes
|
||||
when(fcall.type) {
|
||||
in ByteDatatypes -> {
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W1+1", fcall.args[2].type) // maximum
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.A, signed) // value
|
||||
asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}")
|
||||
if(resultToStack) {
|
||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||
} else {
|
||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister!!, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||
assignAsmGen.assignRegisterByte(targetReg, CpuRegister.A, signed)
|
||||
}
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[1], "P8ZP_SCRATCH_W1", fcall.args[1].type) // minimum
|
||||
assignAsmGen.assignExpressionToVariable(fcall.args[2], "P8ZP_SCRATCH_W2", fcall.args[2].type) // maximum
|
||||
assignAsmGen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY, signed) // value
|
||||
asmgen.out(" jsr prog8_lib.func_clamp_${fcall.type.toString().lowercase()}")
|
||||
if(resultToStack) {
|
||||
asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex")
|
||||
} else {
|
||||
val targetReg = AsmAssignTarget.fromRegisters(resultRegister!!, signed, fcall.position, fcall.definingISub(), asmgen)
|
||||
assignAsmGen.assignRegisterpairWord(targetReg, RegisterOrPair.AY)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcMin(fcall: PtBuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
val signed = fcall.type in SignedDatatypes
|
||||
if(fcall.type in ByteDatatypes) {
|
||||
|
@ -38,6 +38,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
"pokew" -> funcPokeW(call)
|
||||
"pokemon" -> ExpressionCodeResult.EMPTY // easter egg function
|
||||
"mkword" -> funcMkword(call)
|
||||
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword" -> funcClamp(call)
|
||||
"min__byte", "min__ubyte", "min__word", "min__uword" -> funcMin(call)
|
||||
"max__byte", "max__ubyte", "max__word", "max__uword" -> funcMax(call)
|
||||
"sort" -> funcSort(call)
|
||||
@ -324,6 +325,42 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
return ExpressionCodeResult(result, IRDataType.WORD, lsbTr.resultReg, -1)
|
||||
}
|
||||
|
||||
private fun funcClamp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val type = irType(call.type)
|
||||
val valueTr = exprGen.translateExpression(call.args[0])
|
||||
val minimumTr = exprGen.translateExpression(call.args[1])
|
||||
val maximumTr = exprGen.translateExpression(call.args[2])
|
||||
result += valueTr.chunks
|
||||
result += minimumTr.chunks
|
||||
result += maximumTr.chunks
|
||||
if(type==IRDataType.FLOAT) {
|
||||
result += codeGen.makeSyscall(
|
||||
IMSyscall.CLAMP_FLOAT, listOf(
|
||||
valueTr.dt to valueTr.resultFpReg,
|
||||
minimumTr.dt to minimumTr.resultFpReg,
|
||||
maximumTr.dt to maximumTr.resultFpReg,
|
||||
), type to valueTr.resultFpReg
|
||||
)
|
||||
return ExpressionCodeResult(result, type, -1, valueTr.resultFpReg)
|
||||
} else {
|
||||
val syscall = when(call.type) {
|
||||
DataType.UBYTE -> IMSyscall.CLAMP_UBYTE
|
||||
DataType.BYTE -> IMSyscall.CLAMP_BYTE
|
||||
DataType.UWORD -> IMSyscall.CLAMP_UWORD
|
||||
DataType.WORD -> IMSyscall.CLAMP_WORD
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
result += codeGen.makeSyscall(syscall, listOf(
|
||||
valueTr.dt to valueTr.resultReg,
|
||||
minimumTr.dt to minimumTr.resultReg,
|
||||
maximumTr.dt to maximumTr.resultReg,
|
||||
), type to valueTr.resultReg
|
||||
)
|
||||
return ExpressionCodeResult(result, type, valueTr.resultReg, -1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcMin(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val type = irType(call.type)
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
|
@ -1212,7 +1212,7 @@ class IRCodeGen(
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result,
|
||||
IRInstruction(elseBranch, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = elseLabel),
|
||||
IRInstruction(elseBranch, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = elseLabel),
|
||||
null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
@ -1224,7 +1224,7 @@ class IRCodeGen(
|
||||
val afterIfLabel = createLabelName()
|
||||
addInstr(
|
||||
result,
|
||||
IRInstruction(elseBranch, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = afterIfLabel),
|
||||
IRInstruction(elseBranch, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = afterIfLabel),
|
||||
null
|
||||
)
|
||||
result += translateNode(ifElse.ifScope)
|
||||
|
@ -72,7 +72,24 @@ class VarConstantValueTypeAdjuster(private val program: Program, private val err
|
||||
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
||||
// choose specific builtin function for the given types
|
||||
val func = functionCallExpr.target.nameInSource
|
||||
if(func==listOf("min") || func==listOf("max")) {
|
||||
if(func==listOf("clamp")) {
|
||||
val t1 = functionCallExpr.args[0].inferType(program)
|
||||
if(t1.isKnown) {
|
||||
val replaceFunc: String
|
||||
if(t1.isBytes) {
|
||||
replaceFunc = if(t1.istype(DataType.BYTE)) "clamp__byte" else "clamp__ubyte"
|
||||
} else if(t1.isInteger) {
|
||||
replaceFunc = if(t1.istype(DataType.WORD)) "clamp__word" else "clamp__uword"
|
||||
} else {
|
||||
errors.err("clamp builtin not supported for floats, use floats.clamp", functionCallExpr.position)
|
||||
return noModifications
|
||||
}
|
||||
return listOf(IAstModification.SetExpression({functionCallExpr.target = it as IdentifierReference},
|
||||
IdentifierReference(listOf(replaceFunc), functionCallExpr.target.position),
|
||||
functionCallExpr))
|
||||
}
|
||||
}
|
||||
else if(func==listOf("min") || func==listOf("max")) {
|
||||
val t1 = functionCallExpr.args[0].inferType(program)
|
||||
val t2 = functionCallExpr.args[1].inferType(program)
|
||||
if(t1.isKnown && t2.isKnown) {
|
||||
|
@ -227,4 +227,13 @@ sub maxf(float f1, float f2) -> float {
|
||||
return f2
|
||||
}
|
||||
|
||||
|
||||
sub clampf(float value, float minimum, float maximum) -> float {
|
||||
if value>maximum
|
||||
value=maximum
|
||||
if value>minimum
|
||||
return value
|
||||
return minimum
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -555,3 +555,111 @@ func_pokew .proc
|
||||
sta (P8ZP_SCRATCH_W1),y
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
func_clamp_byte .proc
|
||||
; signed value in A, result in A
|
||||
; minimum in P8ZP_SCRATCH_W1
|
||||
; maximum in P8ZP_SCRATCH_W1+1
|
||||
tay
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_W1+1
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bmi +
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
tay
|
||||
jmp ++
|
||||
+ tya
|
||||
+ sec
|
||||
sbc P8ZP_SCRATCH_W1
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bmi +
|
||||
tya
|
||||
rts
|
||||
+ lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
func_clamp_ubyte .proc
|
||||
; value in A, result in A
|
||||
; minimum in P8ZP_SCRATCH_W1
|
||||
; maximum in P8ZP_SCRATCH_W1+1
|
||||
cmp P8ZP_SCRATCH_W1+1
|
||||
bcc +
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
+ cmp P8ZP_SCRATCH_W1
|
||||
bcc +
|
||||
rts
|
||||
+ lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_clamp_word .proc
|
||||
; signed value in AY, result in AY
|
||||
; minimum in P8ZP_SCRATCH_W1
|
||||
; maximum in P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
lda P8ZP_SCRATCH_W2
|
||||
cmp P8ZP_SCRATCH_B1
|
||||
tya
|
||||
sbc P8ZP_SCRATCH_REG
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bpl +
|
||||
lda P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
+ ldy P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
cmp P8ZP_SCRATCH_B1
|
||||
tya
|
||||
sbc P8ZP_SCRATCH_REG
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bpl +
|
||||
ldy P8ZP_SCRATCH_REG
|
||||
lda P8ZP_SCRATCH_B1
|
||||
rts
|
||||
+ ldy P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_clamp_uword .proc
|
||||
; value in AY, result in AY
|
||||
; minimum in P8ZP_SCRATCH_W1
|
||||
; maximum in P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
cpy P8ZP_SCRATCH_W2+1
|
||||
bcc ++
|
||||
bne +
|
||||
cmp P8ZP_SCRATCH_W2
|
||||
bcc ++
|
||||
+ beq +
|
||||
lda P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
+ ldy P8ZP_SCRATCH_REG
|
||||
lda P8ZP_SCRATCH_B1
|
||||
cpy P8ZP_SCRATCH_W1+1
|
||||
bcc ++
|
||||
bne +
|
||||
cmp P8ZP_SCRATCH_W1
|
||||
bcc ++
|
||||
+ beq +
|
||||
ldy P8ZP_SCRATCH_REG
|
||||
lda P8ZP_SCRATCH_B1
|
||||
rts
|
||||
+ ldy P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
|
||||
.pend
|
||||
|
@ -123,4 +123,13 @@ sub rndseedf(float seed) {
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
sub clampf(float value, float minimum, float maximum) -> float {
|
||||
if value<minimum
|
||||
value=minimum
|
||||
if value<maximum
|
||||
return value
|
||||
return maximum
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,10 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
|
||||
"lsb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x and 255).toDouble() } },
|
||||
"msb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
||||
"mkword" to ::builtinMkword,
|
||||
"clamp__ubyte" to ::builtinClampUByte,
|
||||
"clamp__byte" to ::builtinClampByte,
|
||||
"clamp__uword" to ::builtinClampUWord,
|
||||
"clamp__word" to ::builtinClampWord,
|
||||
"min__ubyte" to ::builtinMinUByte,
|
||||
"min__byte" to ::builtinMinByte,
|
||||
"min__uword" to ::builtinMinUWord,
|
||||
@ -245,3 +249,44 @@ private fun builtinMaxUWord(args: List<Expression>, position: Position, program:
|
||||
val result = max(val1.number.toInt(), val2.number.toInt())
|
||||
return NumericLiteral(DataType.UWORD, result.toDouble(), position)
|
||||
}
|
||||
|
||||
private fun builtinClampUByte(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
if(args.size!=3)
|
||||
throw SyntaxError("clamp requires 3 arguments", position)
|
||||
val value = args[0].constValue(program) ?: throw NotConstArgumentException()
|
||||
val minimum = args[1].constValue(program) ?: throw NotConstArgumentException()
|
||||
val maximum = args[2].constValue(program) ?: throw NotConstArgumentException()
|
||||
val result = min(max(value.number, minimum.number), maximum.number)
|
||||
return NumericLiteral(DataType.UBYTE, result, position)
|
||||
}
|
||||
|
||||
private fun builtinClampByte(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
if(args.size!=3)
|
||||
throw SyntaxError("clamp requires 3 arguments", position)
|
||||
val value = args[0].constValue(program) ?: throw NotConstArgumentException()
|
||||
val minimum = args[1].constValue(program) ?: throw NotConstArgumentException()
|
||||
val maximum = args[2].constValue(program) ?: throw NotConstArgumentException()
|
||||
val result = min(max(value.number, minimum.number), maximum.number)
|
||||
return NumericLiteral(DataType.BYTE, result, position)
|
||||
}
|
||||
|
||||
private fun builtinClampUWord(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
if(args.size!=3)
|
||||
throw SyntaxError("clamp requires 3 arguments", position)
|
||||
val value = args[0].constValue(program) ?: throw NotConstArgumentException()
|
||||
val minimum = args[1].constValue(program) ?: throw NotConstArgumentException()
|
||||
val maximum = args[2].constValue(program) ?: throw NotConstArgumentException()
|
||||
val result = min(max(value.number, minimum.number), maximum.number)
|
||||
return NumericLiteral(DataType.UWORD, result, position)
|
||||
}
|
||||
|
||||
private fun builtinClampWord(args: List<Expression>, position: Position, program: Program): NumericLiteral {
|
||||
if(args.size!=3)
|
||||
throw SyntaxError("clamp requires 3 arguments", position)
|
||||
val value = args[0].constValue(program) ?: throw NotConstArgumentException()
|
||||
val minimum = args[1].constValue(program) ?: throw NotConstArgumentException()
|
||||
val maximum = args[2].constValue(program) ?: throw NotConstArgumentException()
|
||||
val result = min(max(value.number, minimum.number), maximum.number)
|
||||
return NumericLiteral(DataType.WORD, result, position)
|
||||
}
|
||||
|
||||
|
@ -261,6 +261,9 @@ point variables. This includes ``print_f``, the routine used to print floating
|
||||
``maxf (x, y)``
|
||||
returns the largest of x and y.
|
||||
|
||||
``clampf (value, minimum, maximum)``
|
||||
returns the value restricted to the given minimum and maximum.
|
||||
|
||||
``print_f (x)``
|
||||
prints the floating point number x as a string.
|
||||
|
||||
|
@ -761,6 +761,10 @@ min (x, y)
|
||||
max (x, y)
|
||||
Returns the largest of x and y. Supported for integer types only, for floats use ``floats.maxf()`` instead.
|
||||
|
||||
clamp (value, minimum, maximum)
|
||||
Returns the value restricted to the given minimum and maximum.
|
||||
Supported for integer types only, for floats use ``floats.clampf()`` instead.
|
||||
|
||||
sgn (x)
|
||||
Get the sign of the value. Result is -1, 0 or 1 (negative, zero, positive).
|
||||
|
||||
|
@ -4,7 +4,8 @@ TODO
|
||||
For 9.0 major changes
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
- DONE: added 'cbm' block in the syslib module that now contains all CBM compatible kernal routines and variables
|
||||
- DONE: added min() max() builtin functions
|
||||
- DONE: added min(), max() builtin functions. For floats, use floats.minf() and floats.maxf().
|
||||
- DONE: added clamp(value, minimum, maximum) to restrict a value x to a minimum and maximum value. For floats, use floats.clampf(f, minv, maxv).
|
||||
- DONE: rename sqrt16() to just sqrt(), make it accept multiple numeric types including float. Removed floats.sqrt().
|
||||
- DONE: abs() now supports multiple datatypes including float. Removed floats.fabs().
|
||||
- DONE: divmod() now supports multiple datatypes. divmodw() has been removed.
|
||||
@ -13,7 +14,9 @@ For 9.0 major changes
|
||||
- DONE: for loops now skip the whole loop if from value already outside the loop range (this is what all other programming languages also do)
|
||||
- DONE: asmsub params or return values passed in cpu flags (like carry) now must be declared as booleans (previously ubyte was still accepted).
|
||||
|
||||
- once 9.0 is stable, upgrade other programs (assem, shell, etc) to it. + add migration guide to the manual.
|
||||
TODO: test min/max, floats.minf/maxf on all compiler targets
|
||||
|
||||
|
||||
- [much work:] add special (u)word array type (or modifier such as @fast? ) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing
|
||||
this is an enormous amout of work, if this type is to be treated equally as existing (u)word , because all expression / lookup / assignment routines need to know about the distinction....
|
||||
So maybe only allow the bare essentials? (store, get, bitwise operations?)
|
||||
|
@ -4,8 +4,8 @@ Upgrading from version 8
|
||||
|
||||
How to upgrade older programs written for Prog8 version 8 or earlier to version 9.
|
||||
|
||||
cx16diskio -> diskio
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
``cx16diskio`` is now just ``diskio``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``cx16diskio`` module is gone, just use ``diskio``. The drivenumber is no longer a parameter on all routines.
|
||||
|
||||
@ -16,8 +16,8 @@ The ``cx16diskio`` module is gone, just use ``diskio``. The drivenumber is no lo
|
||||
and then call the load routine normally.
|
||||
|
||||
|
||||
@Pc now ``bool``
|
||||
^^^^^^^^^^^^^^^^
|
||||
@Pc param and return value is now always ``bool``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Parameters and return values passed via the carry status flag (@Pc) now need to be declared as ``bool``.
|
||||
(Previously also ``ubyte`` was allowed but as the value is just a single bit, this wasn't really correct)
|
||||
|
||||
@ -52,10 +52,10 @@ divmod(), sqrt() and abs() builtin functions accept multiple data types
|
||||
- ``floats.fabs()`` and ``floats.sqrt()`` don't exist anymore, just use ``abs()`` and ``sqrt()`` they now accept floating point as well.
|
||||
|
||||
|
||||
min() and max() are new builtin functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
If you used symbols named ``min`` or ``max`` you have to choose a new name as these are now
|
||||
reserved for the two new builtin functions.
|
||||
min(), max() and clamp() are new builtin functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
If you used symbols named ``min`` or ``max`` or ``clamp``, you have to choose a new name as these are now
|
||||
reserved for these new builtin functions.
|
||||
Code that uses an if statement and a comparison to determine the greater or lesser of two values,
|
||||
can now be optimized by just using one of these new builtin functions.
|
||||
|
||||
For floats, use ``floats.minf()``, ``floats.maxf()`` and ``floats.clampf()``.
|
||||
|
@ -6,16 +6,42 @@ main {
|
||||
|
||||
sub start() {
|
||||
word ww = -1234
|
||||
uword uww = 1234
|
||||
float fl = 123.34
|
||||
byte bb = -99
|
||||
byte bb = -123
|
||||
ubyte ub = 123
|
||||
|
||||
txt.print_w(abs(ww))
|
||||
txt.print_w(clamp(ww, -2000, -500))
|
||||
txt.spc()
|
||||
txt.print_w(clamp(ww, -1000, -500))
|
||||
txt.spc()
|
||||
txt.print_w(clamp(ww, -2000, -1500))
|
||||
txt.nl()
|
||||
txt.print_b(abs(bb))
|
||||
txt.print_uw(clamp(uww, 500, 2000))
|
||||
txt.spc()
|
||||
txt.print_uw(clamp(uww, 500, 1000))
|
||||
txt.spc()
|
||||
txt.print_uw(clamp(uww, 1500, 2000))
|
||||
txt.nl()
|
||||
floats.print_f(abs(fl))
|
||||
|
||||
txt.print_b(clamp(bb, -127, -50))
|
||||
txt.spc()
|
||||
txt.print_b(clamp(bb, -100, -50))
|
||||
txt.spc()
|
||||
txt.print_b(clamp(bb, -127, -125))
|
||||
txt.nl()
|
||||
floats.print_f(sqrt(fl))
|
||||
txt.print_ub(clamp(ub, 50, 200))
|
||||
txt.spc()
|
||||
txt.print_ub(clamp(ub, 50, 100))
|
||||
txt.spc()
|
||||
txt.print_ub(clamp(ub, 150, 200))
|
||||
txt.nl()
|
||||
|
||||
floats.print_f(floats.clampf(fl, 50.0, 200.0))
|
||||
txt.spc()
|
||||
floats.print_f(floats.clampf(fl, 50.0, 100.0))
|
||||
txt.spc()
|
||||
floats.print_f(floats.clampf(fl, 150.0, 200.0))
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
@ -21,5 +21,10 @@ enum class IMSyscall(val number: Int) {
|
||||
COMPARE_STRINGS(0x100d),
|
||||
STRING_CONTAINS(0x100e),
|
||||
BYTEARRAY_CONTAINS(0x100f),
|
||||
WORDARRAY_CONTAINS(0x1010)
|
||||
WORDARRAY_CONTAINS(0x1010),
|
||||
CLAMP_UBYTE(0x1011),
|
||||
CLAMP_BYTE(0x1012),
|
||||
CLAMP_UWORD(0x1013),
|
||||
CLAMP_WORD(0x1014),
|
||||
CLAMP_FLOAT(0x1015)
|
||||
}
|
||||
|
@ -714,6 +714,13 @@ data class IRInstruction(
|
||||
}
|
||||
}
|
||||
}
|
||||
if(format.immediate) {
|
||||
if(opcode==Opcode.LOAD)
|
||||
require(immediate != null || immediateFp != null || labelSymbol!=null) { "missing immediate value or labelsymbol" }
|
||||
else
|
||||
require(immediate != null || immediateFp != null) { "missing immediate value" }
|
||||
}
|
||||
|
||||
reg1direction = format.reg1
|
||||
reg2direction = format.reg2
|
||||
fpReg1direction = format.fpReg1
|
||||
|
@ -14,7 +14,7 @@
|
||||
<keywords keywords="&;->;@;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%ir;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" />
|
||||
<keywords3 keywords="@requirezp;@shared;@zp;bool;byte;const;float;str;ubyte;uword;void;word" />
|
||||
<keywords4 keywords="abs;all;any;callfar;callram;callrom;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;sgn;sizeof;sort;sqrt;sqrt16;swap;|>" />
|
||||
<keywords4 keywords="abs;all;any;callfar;callram;callrom;clamp;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;sgn;sizeof;sort;sqrt;sqrt16;swap;|>" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
<mapping ext="p8" />
|
||||
|
@ -27,7 +27,7 @@
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
word uword
float
zp shared requirezp</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub romsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat unroll
break return goto</Keywords>
|
||||
<Keywords name="Keywords4">abs all any callfar cmp divmod len lsb lsl lsr memory mkword min max msb peek peekw poke pokew push pushw pop popw rsave rsavex rrestore rrestorex reverse rnd rndw rol rol2 ror ror2 sgn sizeof sort sqrtw swap</Keywords>
|
||||
<Keywords name="Keywords4">abs all any callfar clamp cmp divmod len lsb lsl lsr memory mkword min max msb peek peekw poke pokew push pushw pop popw rsave rsavex rrestore rrestorex reverse rnd rndw rol rol2 ror ror2 sgn sizeof sort sqrtw swap</Keywords>
|
||||
<Keywords name="Keywords5">true false
not and or xor
as to downto |></Keywords>
|
||||
<Keywords name="Keywords6"></Keywords>
|
||||
<Keywords name="Keywords7"></Keywords>
|
||||
|
@ -15,7 +15,7 @@ syn keyword prog8BuiltInFunc any all len reverse sort
|
||||
" Miscellaneous functions
|
||||
syn keyword prog8BuiltInFunc cmp divmod lsb msb mkword min max peek peekw poke pokew push pushw pop popw rsave rsavex rrestore rrestorex
|
||||
syn keyword prog8BuiltInFunc rol rol2 ror ror2 sizeof
|
||||
syn keyword prog8BuiltInFunc swap memory callfar
|
||||
syn keyword prog8BuiltInFunc swap memory callfar clamp
|
||||
|
||||
|
||||
" c64/floats.p8
|
||||
|
@ -3,6 +3,7 @@ package prog8.vm
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.intermediate.FunctionCallArgs
|
||||
import prog8.intermediate.IRDataType
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/*
|
||||
@ -82,7 +83,13 @@ enum class Syscall {
|
||||
RNDF,
|
||||
STRING_CONTAINS,
|
||||
BYTEARRAY_CONTAINS,
|
||||
WORDARRAY_CONTAINS;
|
||||
WORDARRAY_CONTAINS,
|
||||
CLAMP_BYTE,
|
||||
CLAMP_UBYTE,
|
||||
CLAMP_WORD,
|
||||
CLAMP_UWORD,
|
||||
CLAMP_FLOAT
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val VALUES = values()
|
||||
@ -413,6 +420,46 @@ object SysCalls {
|
||||
}
|
||||
returnValue(callspec.returns!!, 0u, vm)
|
||||
}
|
||||
Syscall.CLAMP_BYTE -> {
|
||||
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
|
||||
val value = (valueU as UByte).toByte().toInt()
|
||||
val minimum = (minimumU as UByte).toByte().toInt()
|
||||
val maximum = (maximumU as UByte).toByte().toInt()
|
||||
val result = min(max(value, minimum), maximum)
|
||||
returnValue(callspec.returns!!, result, vm)
|
||||
}
|
||||
Syscall.CLAMP_UBYTE -> {
|
||||
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
|
||||
val value = (valueU as UByte).toInt()
|
||||
val minimum = (minimumU as UByte).toInt()
|
||||
val maximum = (maximumU as UByte).toInt()
|
||||
val result = min(max(value, minimum), maximum)
|
||||
returnValue(callspec.returns!!, result, vm)
|
||||
}
|
||||
Syscall.CLAMP_WORD -> {
|
||||
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
|
||||
val value = (valueU as UShort).toShort().toInt()
|
||||
val minimum = (minimumU as UShort).toShort().toInt()
|
||||
val maximum = (maximumU as UShort).toShort().toInt()
|
||||
val result = min(max(value, minimum), maximum)
|
||||
returnValue(callspec.returns!!, result, vm)
|
||||
}
|
||||
Syscall.CLAMP_UWORD -> {
|
||||
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
|
||||
val value = (valueU as UShort).toInt()
|
||||
val minimum = (minimumU as UShort).toInt()
|
||||
val maximum = (maximumU as UShort).toInt()
|
||||
val result = min(max(value, minimum), maximum)
|
||||
returnValue(callspec.returns!!, result, vm)
|
||||
}
|
||||
Syscall.CLAMP_FLOAT -> {
|
||||
val (valueU, minimumU, maximumU) = getArgValues(callspec.arguments, vm)
|
||||
val value = (valueU as Float)
|
||||
val minimum = (minimumU as Float)
|
||||
val maximum = (maximumU as Float)
|
||||
val result = min(max(value, minimum), maximum)
|
||||
returnValue(callspec.returns!!, result, vm)
|
||||
}
|
||||
else -> throw AssemblyError("missing syscall ${call.name}")
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +118,11 @@ class VmProgramLoader {
|
||||
IMSyscall.STRING_CONTAINS.number -> Syscall.STRING_CONTAINS
|
||||
IMSyscall.BYTEARRAY_CONTAINS.number -> Syscall.BYTEARRAY_CONTAINS
|
||||
IMSyscall.WORDARRAY_CONTAINS.number -> Syscall.WORDARRAY_CONTAINS
|
||||
IMSyscall.CLAMP_BYTE.number -> Syscall.CLAMP_BYTE
|
||||
IMSyscall.CLAMP_UBYTE.number -> Syscall.CLAMP_UBYTE
|
||||
IMSyscall.CLAMP_WORD.number -> Syscall.CLAMP_WORD
|
||||
IMSyscall.CLAMP_UWORD.number -> Syscall.CLAMP_UWORD
|
||||
IMSyscall.CLAMP_FLOAT.number -> Syscall.CLAMP_FLOAT
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user