mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
push,pushw,pop and popw are no longer built-in functions but regular routines in sys
This commit is contained in:
parent
38a22fbc99
commit
0d44492086
@ -125,10 +125,6 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
|||||||
"pokew" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null),
|
"pokew" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null),
|
||||||
"pokef" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.FLOAT))), null),
|
"pokef" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.FLOAT))), null),
|
||||||
"pokemon" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
|
"pokemon" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
|
||||||
"pop" to FSignature(false, listOf(FParam("target", ByteDatatypes)), null),
|
|
||||||
"popw" to FSignature(false, listOf(FParam("target", WordDatatypes)), null),
|
|
||||||
"push" to FSignature(false, listOf(FParam("value", ByteDatatypes)), null),
|
|
||||||
"pushw" to FSignature(false, listOf(FParam("value", WordDatatypes)), null),
|
|
||||||
"rsave" to FSignature(false, emptyList(), null),
|
"rsave" to FSignature(false, emptyList(), null),
|
||||||
"rrestore" to FSignature(false, emptyList(), null),
|
"rrestore" to FSignature(false, emptyList(), null),
|
||||||
"memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
|
"memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||||
|
@ -3059,30 +3059,16 @@ $repeatLabel""")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun popCpuStack(dt: DataType, target: IPtVariable, scope: IPtSubroutine?) {
|
internal fun popCpuStack(dt: DataType) {
|
||||||
// note: because A is pushed first so popped last, saving A is often not required here.
|
|
||||||
val targetAsmSub = (target as PtNode).definingAsmSub()
|
|
||||||
if(targetAsmSub != null) {
|
|
||||||
val parameter = targetAsmSub.parameters.first { it.second.name==target.name }
|
|
||||||
popCpuStack(targetAsmSub, parameter.second, parameter.first)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val scopedName = when(target) {
|
|
||||||
is PtConstant -> target.scopedName
|
|
||||||
is PtMemMapped -> target.scopedName
|
|
||||||
is PtVariable -> target.scopedName
|
|
||||||
else -> throw AssemblyError("weird target var")
|
|
||||||
}
|
|
||||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, this, target.type, scope, target.position, variableAsmName = asmVariableName(scopedName))
|
|
||||||
if (dt in ByteDatatypes) {
|
if (dt in ByteDatatypes) {
|
||||||
out(" pla")
|
out(" pla")
|
||||||
assignRegister(RegisterOrPair.A, tgt)
|
} else if (dt in WordDatatypes) {
|
||||||
} else {
|
|
||||||
if (isTargetCpu(CpuType.CPU65c02))
|
if (isTargetCpu(CpuType.CPU65c02))
|
||||||
out(" ply | pla")
|
out(" ply | pla")
|
||||||
else
|
else
|
||||||
out(" pla | tay | pla")
|
out(" pla | tay | pla")
|
||||||
assignRegister(RegisterOrPair.AY, tgt)
|
} else {
|
||||||
|
throw AssemblyError("can't pop type $dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,24 +63,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
|||||||
asmgen.out(" pla")
|
asmgen.out(" pla")
|
||||||
}
|
}
|
||||||
"poke" -> throw AssemblyError("poke() should have been replaced by @()")
|
"poke" -> throw AssemblyError("poke() should have been replaced by @()")
|
||||||
"push" -> asmgen.pushCpuStack(DataType.UBYTE, fcall.args[0])
|
|
||||||
"pushw" -> asmgen.pushCpuStack(DataType.UWORD, fcall.args[0])
|
|
||||||
"pop" -> {
|
|
||||||
require(fcall.args[0] is PtIdentifier) {
|
|
||||||
"attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}"
|
|
||||||
}
|
|
||||||
val symbol = asmgen.symbolTable.lookup((fcall.args[0] as PtIdentifier).name)
|
|
||||||
val target = symbol!!.astNode as IPtVariable
|
|
||||||
asmgen.popCpuStack(DataType.UBYTE, target, fcall.definingISub())
|
|
||||||
}
|
|
||||||
"popw" -> {
|
|
||||||
require(fcall.args[0] is PtIdentifier) {
|
|
||||||
"attempt to pop a value into a differently typed variable, or in something else that isn't supported ${fcall.position}"
|
|
||||||
}
|
|
||||||
val symbol = asmgen.symbolTable.lookup((fcall.args[0] as PtIdentifier).name)
|
|
||||||
val target = symbol!!.astNode as IPtVariable
|
|
||||||
asmgen.popCpuStack(DataType.UWORD, target, fcall.definingISub())
|
|
||||||
}
|
|
||||||
"rsave" -> funcRsave()
|
"rsave" -> funcRsave()
|
||||||
"rrestore" -> funcRrestore()
|
"rrestore" -> funcRrestore()
|
||||||
"cmp" -> funcCmp(fcall)
|
"cmp" -> funcCmp(fcall)
|
||||||
|
@ -20,10 +20,6 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
"sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(call)
|
"sqrt__ubyte", "sqrt__uword", "sqrt__float" -> funcSqrt(call)
|
||||||
"divmod__ubyte" -> funcDivmod(call, IRDataType.BYTE)
|
"divmod__ubyte" -> funcDivmod(call, IRDataType.BYTE)
|
||||||
"divmod__uword" -> funcDivmod(call, IRDataType.WORD)
|
"divmod__uword" -> funcDivmod(call, IRDataType.WORD)
|
||||||
"pop" -> funcPop(call)
|
|
||||||
"popw" -> funcPopw(call)
|
|
||||||
"push" -> funcPush(call)
|
|
||||||
"pushw" -> funcPushw(call)
|
|
||||||
"rsave", "rrestore" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore
|
"rsave", "rrestore" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore
|
||||||
"callfar" -> funcCallfar(call)
|
"callfar" -> funcCallfar(call)
|
||||||
"call" -> funcCall(call)
|
"call" -> funcCall(call)
|
||||||
@ -278,44 +274,6 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun funcPop(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
|
||||||
val code = IRCodeChunk(null, null)
|
|
||||||
val reg = codeGen.registers.nextFree()
|
|
||||||
code += IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=reg)
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
|
||||||
result += assignRegisterTo(call.args.single(), reg)
|
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, reg, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun funcPopw(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
|
||||||
val code = IRCodeChunk(null, null)
|
|
||||||
val reg = codeGen.registers.nextFree()
|
|
||||||
code += IRInstruction(Opcode.POP, IRDataType.WORD, reg1=reg)
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>(code)
|
|
||||||
result += assignRegisterTo(call.args.single(), reg)
|
|
||||||
return ExpressionCodeResult(result, IRDataType.WORD, reg, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun funcPush(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
|
||||||
val tr = exprGen.translateExpression(call.args.single())
|
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
|
||||||
result += IRCodeChunk(null, null).also {
|
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=tr.resultReg)
|
|
||||||
}
|
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun funcPushw(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
|
||||||
val tr = exprGen.translateExpression(call.args.single())
|
|
||||||
addToResult(result, tr, tr.resultReg, -1)
|
|
||||||
result += IRCodeChunk(null, null).also {
|
|
||||||
it += IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1 = tr.resultReg)
|
|
||||||
}
|
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun funcReverse(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
private fun funcReverse(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||||
val arrayName = call.args[0] as PtIdentifier
|
val arrayName = call.args[0] as PtIdentifier
|
||||||
val arrayLength = codeGen.symbolTable.getLength(arrayName.name)
|
val arrayLength = codeGen.symbolTable.getLength(arrayName.name)
|
||||||
|
@ -269,6 +269,34 @@ save_SCRATCH_ZPWORD2 .word 0
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub push(ubyte value @A) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pushw(uword value @AY) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pop() -> ubyte @A {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub popw() -> uword @AY {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx16 {
|
cx16 {
|
||||||
|
@ -774,6 +774,34 @@ _longcopy
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub push(ubyte value @A) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pushw(uword value @AY) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pop() -> ubyte @A {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub popw() -> uword @AY {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx16 {
|
cx16 {
|
||||||
|
@ -772,6 +772,33 @@ _longcopy
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub push(ubyte value @A) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pushw(uword value @AY) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pop() -> ubyte @A {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub popw() -> uword @AY {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx16 {
|
cx16 {
|
||||||
|
@ -114,10 +114,10 @@ psg {
|
|||||||
; cx16.r0 = the volume word (volume scaled by 256)
|
; cx16.r0 = the volume word (volume scaled by 256)
|
||||||
; cx16.r1L = the voice number
|
; cx16.r1L = the voice number
|
||||||
; cx16.r2L = attack value
|
; cx16.r2L = attack value
|
||||||
pushw(cx16.r0)
|
sys.pushw(cx16.r0)
|
||||||
push(cx16.r1L)
|
sys.push(cx16.r1L)
|
||||||
push(cx16.r2L)
|
sys.push(cx16.r2L)
|
||||||
pushw(cx16.r9)
|
sys.pushw(cx16.r9)
|
||||||
; calculate new volumes
|
; calculate new volumes
|
||||||
for cx16.r1L in 0 to 15 {
|
for cx16.r1L in 0 to 15 {
|
||||||
when envelope_states[cx16.r1L] {
|
when envelope_states[cx16.r1L] {
|
||||||
@ -166,10 +166,10 @@ psg {
|
|||||||
cx16.VERA_DATA0 = cx16.VERA_DATA1 & %11000000 | msb(envelope_volumes[cx16.r1L])
|
cx16.VERA_DATA0 = cx16.VERA_DATA1 & %11000000 | msb(envelope_volumes[cx16.r1L])
|
||||||
}
|
}
|
||||||
cx16.restore_vera_context()
|
cx16.restore_vera_context()
|
||||||
popw(cx16.r9)
|
cx16.r9 = sys.popw()
|
||||||
pop(cx16.r2L)
|
cx16.r2L = sys.pop()
|
||||||
pop(cx16.r1L)
|
cx16.r1L = sys.pop()
|
||||||
popw(cx16.r0)
|
cx16.r0 = sys.popw()
|
||||||
return true ; run the system IRQ handler afterwards
|
return true ; run the system IRQ handler afterwards
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1615,4 +1615,31 @@ save_SCRATCH_ZPWORD2 .word 0
|
|||||||
ldy #>prog8_program_end
|
ldy #>prog8_program_end
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub push(ubyte value @A) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pushw(uword value @AY) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
phy
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pop() -> ubyte @A {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub popw() -> uword @AY {
|
||||||
|
%asm {{
|
||||||
|
ply
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -361,6 +361,34 @@ save_SCRATCH_ZPWORD2 .word 0
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline asmsub push(ubyte value @A) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pushw(uword value @AY) {
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub pop() -> ubyte @A {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline asmsub popw() -> uword @AY {
|
||||||
|
%asm {{
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx16 {
|
cx16 {
|
||||||
|
@ -126,6 +126,38 @@ sys {
|
|||||||
returnr.b r0
|
returnr.b r0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub push(ubyte b) {
|
||||||
|
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||||
|
%ir {{
|
||||||
|
loadm.b r65535,sys.push.b
|
||||||
|
push.b r65535
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pushw(uword w) {
|
||||||
|
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||||
|
%ir {{
|
||||||
|
loadm.w r65535,sys.pushw.w
|
||||||
|
push.w r65535
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pop() -> ubyte {
|
||||||
|
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||||
|
%ir {{
|
||||||
|
pop.b r65535
|
||||||
|
returnr.b r65535
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub popw() -> uword {
|
||||||
|
; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works
|
||||||
|
%ir {{
|
||||||
|
pop.w r65535
|
||||||
|
returnr.w r65535
|
||||||
|
}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx16 {
|
cx16 {
|
||||||
|
@ -1216,19 +1216,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
errors.err("sorting a floating point array is not supported", functionCallStatement.args.first().position)
|
errors.err("sorting a floating point array is not supported", functionCallStatement.args.first().position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(funcName[0] in arrayOf("pop", "popw")) {
|
|
||||||
// can only pop into a variable, that has to have the correct type
|
|
||||||
val idref = functionCallStatement.args[0]
|
|
||||||
if(idref !is IdentifierReference) {
|
|
||||||
if(idref is TypecastExpression) {
|
|
||||||
val passByRef = idref.expression.inferType(program).isPassByReference
|
|
||||||
if(idref.type!=DataType.UWORD || !passByRef)
|
|
||||||
errors.err("invalid argument to pop, must be a variable with the correct type: ${functionCallStatement.args.first()}", functionCallStatement.args.first().position)
|
|
||||||
} else {
|
|
||||||
errors.err("invalid argument to pop, must be a variable with the correct type: ${functionCallStatement.args.first()}", functionCallStatement.args.first().position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(funcName[0].startsWith("divmod")) {
|
else if(funcName[0].startsWith("divmod")) {
|
||||||
if(functionCallStatement.args[2] is TypecastExpression || functionCallStatement.args[3] is TypecastExpression) {
|
if(functionCallStatement.args[2] is TypecastExpression || functionCallStatement.args[3] is TypecastExpression) {
|
||||||
errors.err("arguments must be all ubyte or all uword", functionCallStatement.position)
|
errors.err("arguments must be all ubyte or all uword", functionCallStatement.position)
|
||||||
|
@ -2,7 +2,6 @@ package prog8tests
|
|||||||
|
|
||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
|
||||||
import prog8.ast.expressions.NumericLiteral
|
import prog8.ast.expressions.NumericLiteral
|
||||||
import prog8.ast.statements.Assignment
|
import prog8.ast.statements.Assignment
|
||||||
import prog8.ast.statements.FunctionCallStatement
|
import prog8.ast.statements.FunctionCallStatement
|
||||||
@ -69,19 +68,6 @@ class TestBuiltinFunctions: FunSpec({
|
|||||||
conv.returns.reg shouldBe null
|
conv.returns.reg shouldBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("push pop") {
|
|
||||||
val src="""
|
|
||||||
main {
|
|
||||||
sub start () {
|
|
||||||
pushw(cx16.r0)
|
|
||||||
push(cx16.r1L)
|
|
||||||
pop(cx16.r1L)
|
|
||||||
popw(cx16.r0)
|
|
||||||
}
|
|
||||||
}"""
|
|
||||||
compileText(Cx16Target(), false, src, writeAssembly = true) shouldNotBe null
|
|
||||||
}
|
|
||||||
|
|
||||||
test("certain builtin functions should be compile time evaluated") {
|
test("certain builtin functions should be compile time evaluated") {
|
||||||
val src="""
|
val src="""
|
||||||
main {
|
main {
|
||||||
|
@ -693,9 +693,9 @@ main {
|
|||||||
sub start() {
|
sub start() {
|
||||||
uword variable
|
uword variable
|
||||||
|
|
||||||
pushw(variable)
|
sys.pushw(variable)
|
||||||
pushw(handler)
|
sys.pushw(handler)
|
||||||
pushw(&handler)
|
sys.pushw(&handler)
|
||||||
handler(variable)
|
handler(variable)
|
||||||
handler(handler)
|
handler(handler)
|
||||||
handler(&handler)
|
handler(&handler)
|
||||||
|
@ -16,6 +16,7 @@ import prog8.code.target.Cx16Target
|
|||||||
import prog8.code.target.VMTarget
|
import prog8.code.target.VMTarget
|
||||||
import prog8tests.helpers.ErrorReporterForTests
|
import prog8tests.helpers.ErrorReporterForTests
|
||||||
import prog8tests.helpers.compileText
|
import prog8tests.helpers.compileText
|
||||||
|
import kotlin.io.path.readText
|
||||||
|
|
||||||
class TestVariousCodeGen: FunSpec({
|
class TestVariousCodeGen: FunSpec({
|
||||||
test("bool to byte cast in expression is correct") {
|
test("bool to byte cast in expression is correct") {
|
||||||
@ -358,4 +359,24 @@ main {
|
|||||||
compileText(VMTarget(), true, src, writeAssembly = false) shouldNotBe null
|
compileText(VMTarget(), true, src, writeAssembly = false) shouldNotBe null
|
||||||
compileText(Cx16Target(), true, src, writeAssembly = false) shouldNotBe null
|
compileText(Cx16Target(), true, src, writeAssembly = false) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("push pop are inlined also with noopt") {
|
||||||
|
val text = """
|
||||||
|
main {
|
||||||
|
sub start() {
|
||||||
|
sys.push(11)
|
||||||
|
sys.pushw(2222)
|
||||||
|
cx16.r2++
|
||||||
|
cx16.r1 = sys.popw()
|
||||||
|
cx16.r0L = sys.pop()
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||||
|
val assemblyFile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".asm")
|
||||||
|
val assembly = assemblyFile.readText()
|
||||||
|
assembly shouldContain "inlined routine follows: push"
|
||||||
|
assembly shouldContain "inlined routine follows: pushw"
|
||||||
|
assembly shouldContain "inlined routine follows: pop"
|
||||||
|
assembly shouldContain "inlined routine follows: popw"
|
||||||
|
}
|
||||||
})
|
})
|
@ -140,6 +140,20 @@ sys (part of syslib)
|
|||||||
It stores and restores the values of the internal prog8 variables.
|
It stores and restores the values of the internal prog8 variables.
|
||||||
This allows other code to run that might clobber these values temporarily.
|
This allows other code to run that might clobber these values temporarily.
|
||||||
|
|
||||||
|
``push (value)``
|
||||||
|
pushes a byte value on the CPU hardware stack. Low-level function that should normally not be used.
|
||||||
|
|
||||||
|
``pushw (value)``
|
||||||
|
pushes a 16-bit word value on the CPU hardware stack. Low-level function that should normally not be used.
|
||||||
|
|
||||||
|
``pop ()``
|
||||||
|
pops a byte value off the CPU hardware stack and returns it.
|
||||||
|
Low-level function that should normally not be used.
|
||||||
|
|
||||||
|
``popw ()``
|
||||||
|
pops a 16-bit word value off the CPU hardware stack and returns it.
|
||||||
|
Low-level function that should normally not be used.
|
||||||
|
|
||||||
|
|
||||||
conv
|
conv
|
||||||
----
|
----
|
||||||
|
@ -898,20 +898,6 @@ pokemon (address, value)
|
|||||||
Like poke(), but also returns the previous value in the given address.
|
Like poke(), but also returns the previous value in the given address.
|
||||||
Also doesn't have anything to do with a certain video game.
|
Also doesn't have anything to do with a certain video game.
|
||||||
|
|
||||||
push (value)
|
|
||||||
pushes a byte value on the CPU hardware stack. Low-level function that should normally not be used.
|
|
||||||
|
|
||||||
pushw (value)
|
|
||||||
pushes a 16-bit word value on the CPU hardware stack. Low-level function that should normally not be used.
|
|
||||||
|
|
||||||
pop (variable)
|
|
||||||
pops a byte value off the CPU hardware stack into the given variable. Only variables can be used.
|
|
||||||
Low-level function that should normally not be used.
|
|
||||||
|
|
||||||
popw (value)
|
|
||||||
pops a 16-bit word value off the CPU hardware stack into the given variable. Only variables can be used.
|
|
||||||
Low-level function that should normally not be used.
|
|
||||||
|
|
||||||
rol (x)
|
rol (x)
|
||||||
Rotate the bits in x (byte or word) one position to the left.
|
Rotate the bits in x (byte or word) one position to the left.
|
||||||
This uses the CPU's rotate semantics: bit 0 will be set to the current value of the Carry flag,
|
This uses the CPU's rotate semantics: bit 0 will be set to the current value of the Carry flag,
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
%import textio
|
%import textio
|
||||||
%zeropage dontuse
|
;;%import floats
|
||||||
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
uword empty
|
sys.push(11)
|
||||||
uword block = memory("block", 500, 0)
|
sys.pushw(2222)
|
||||||
|
;;floats.pushf(floats.π)
|
||||||
|
cx16.r2++
|
||||||
|
|
||||||
txt.print_uwhex(&empty, true)
|
;;float pi = floats.popf()
|
||||||
|
;;floats.print_f(pi)
|
||||||
|
;;txt.nl()
|
||||||
|
|
||||||
|
cx16.r1 = sys.popw()
|
||||||
|
cx16.r0L = sys.pop()
|
||||||
|
|
||||||
|
txt.print_ub(cx16.r0L)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print_uwhex(block, true)
|
txt.print_uw(cx16.r1)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<filetype binary="false" default_extension="prog8" description="Prog8 source file" name="Prog8">
|
<filetype binary="false" default_extension="p8" description="Prog8 source file" name="Prog8">
|
||||||
<highlighting>
|
<highlighting>
|
||||||
<options>
|
<options>
|
||||||
<option name="LINE_COMMENT" value=";" />
|
<option name="LINE_COMMENT" value=";" />
|
||||||
@ -14,10 +14,10 @@
|
|||||||
<keywords keywords="&;->;@;and;as;asmsub;break;clobbers;continue;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" />
|
<keywords keywords="&;->;@;and;as;asmsub;break;clobbers;continue;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;%encoding;%import;%ir;%launcher;%option;%output;%zeropage;%zpallowed;%zpreserved;atascii:;default:;iso:;petscii:;sc:" />
|
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%encoding;%import;%ir;%launcher;%option;%output;%zeropage;%zpallowed;%zpreserved;atascii:;default:;iso:;petscii:;sc:" />
|
||||||
<keywords3 keywords="@requirezp;@shared;@split;@zp;bool;byte;const;float;str;ubyte;uword;void;word" />
|
<keywords3 keywords="@requirezp;@shared;@split;@zp;bool;byte;const;float;str;ubyte;uword;void;word" />
|
||||||
<keywords4 keywords="abs;all;any;call;callfar;clamp;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekf;peekw;poke;pokef;pokew;pop;popw;push;pushw;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sort;sqrt;swap;|>" />
|
<keywords4 keywords="abs;all;any;call;callfar;clamp;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekf;peekw;poke;pokef;pokew;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sort;sqrt;swap;|>" />
|
||||||
</highlighting>
|
</highlighting>
|
||||||
<extensionMap>
|
<extensionMap>
|
||||||
<mapping ext="prog8" />
|
|
||||||
<mapping ext="p8" />
|
<mapping ext="p8" />
|
||||||
|
<mapping ext="prog8" />
|
||||||
</extensionMap>
|
</extensionMap>
|
||||||
</filetype>
|
</filetype>
|
@ -27,7 +27,7 @@
|
|||||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
word uword
float
zp shared split requirezp</Keywords>
|
<Keywords name="Keywords1">void const
str
byte ubyte bool
word uword
float
zp shared split requirezp</Keywords>
|
||||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%breakpoint
%encoding
%import
%launcher
%option
%output
%zeropage
%zpreserved
%zpallowed</Keywords>
|
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%breakpoint
%encoding
%import
%launcher
%option
%output
%zeropage
%zpreserved
%zpallowed</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 continue return goto</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 continue return goto</Keywords>
|
||||||
<Keywords name="Keywords4">abs all any call callfar clamp cmp divmod len lsb lsl lsr memory mkword min max msb peek peekw peekf poke pokew pokef push pushw pop popw rsave rsavex rrestore rrestorex reverse rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof sort sqrtw swap</Keywords>
|
<Keywords name="Keywords4">abs all any call callfar clamp cmp divmod len lsb lsl lsr memory mkword min max msb peek peekw peekf poke pokew pokef rsave rsavex rrestore rrestorex reverse rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof sort sqrtw swap</Keywords>
|
||||||
<Keywords name="Keywords5">true false
not and or xor
as to downto |></Keywords>
|
<Keywords name="Keywords5">true false
not and or xor
as to downto |></Keywords>
|
||||||
<Keywords name="Keywords6"></Keywords>
|
<Keywords name="Keywords6"></Keywords>
|
||||||
<Keywords name="Keywords7"></Keywords>
|
<Keywords name="Keywords7"></Keywords>
|
||||||
|
@ -13,7 +13,7 @@ syn keyword prog8BuiltInFunc sgn sqrtw
|
|||||||
syn keyword prog8BuiltInFunc any all len reverse sort
|
syn keyword prog8BuiltInFunc any all len reverse sort
|
||||||
|
|
||||||
" Miscellaneous functions
|
" Miscellaneous functions
|
||||||
syn keyword prog8BuiltInFunc cmp divmod lsb msb mkword min max peek peekw peekf poke pokew pokef push pushw pop popw rsave rsavex rrestore rrestorex
|
syn keyword prog8BuiltInFunc cmp divmod lsb msb mkword min max peek peekw peekf poke pokew pokef rsave rsavex rrestore rrestorex
|
||||||
syn keyword prog8BuiltInFunc rol rol2 ror ror2 sizeof setlsb setmsb
|
syn keyword prog8BuiltInFunc rol rol2 ror ror2 sizeof setlsb setmsb
|
||||||
syn keyword prog8BuiltInFunc swap memory call callfar clamp
|
syn keyword prog8BuiltInFunc swap memory call callfar clamp
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class VmProgramLoader {
|
|||||||
|
|
||||||
block.children.forEach { child ->
|
block.children.forEach { child ->
|
||||||
when(child) {
|
when(child) {
|
||||||
is IRAsmSubroutine -> throw IRParseException("vm does not support asmsubs (use normal sub): ${child.label}")
|
is IRAsmSubroutine -> throw IRParseException("vm does not support non-inlined asmsubs (use normal sub): ${child.label}")
|
||||||
is IRCodeChunk -> programChunks += child
|
is IRCodeChunk -> programChunks += child
|
||||||
is IRInlineAsmChunk -> throw IRParseException("encountered unconverted inline assembly chunk")
|
is IRInlineAsmChunk -> throw IRParseException("encountered unconverted inline assembly chunk")
|
||||||
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM")
|
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM")
|
||||||
|
@ -85,7 +85,7 @@ class TestVm: FunSpec( {
|
|||||||
)
|
)
|
||||||
block += startSub
|
block += startSub
|
||||||
program.addBlock(block)
|
program.addBlock(block)
|
||||||
shouldThrowWithMessage<IRParseException>("vm does not support asmsubs (use normal sub): main.asmstart") {
|
shouldThrowWithMessage<IRParseException>("vm does not support non-inlined asmsubs (use normal sub): main.asmstart") {
|
||||||
VirtualMachine(program)
|
VirtualMachine(program)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user