vm: printing of numbers now via conv module.

assigning strings now converted to strcopy function call in the compiler ast.
This commit is contained in:
Irmen de Jong 2022-04-23 02:15:51 +02:00
parent 7eea97d741
commit cf50e4f6ec
14 changed files with 488 additions and 142 deletions

View File

@ -185,15 +185,7 @@ internal class AssignmentAsmGen(private val program: Program,
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
}
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> {
// copy the actual string result into the target string variable
asmgen.out("""
pha
lda #<${assign.target.asmVarname}
sta P8ZP_SCRATCH_W1
lda #>${assign.target.asmVarname}
sta P8ZP_SCRATCH_W1+1
pla
jsr prog8_lib.strcpy""")
throw AssemblyError("stringvalue assignment should have been replaced by a call to strcpy")
}
else -> throw AssemblyError("weird target dt")
}

View File

@ -568,6 +568,7 @@ class CodeGen(internal val program: PtProgram,
private fun translate(assignment: PtAssignment): VmCodeChunk {
// TODO can in-place assignments be optimized more?
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
if(assignment.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val code = VmCodeChunk()
@ -607,7 +608,7 @@ class CodeGen(internal val program: PtProgram,
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else {
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, addressReg)
code += expressionEval.translateExpression(memory.address, addressReg)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
}
}

View File

@ -67,6 +67,17 @@ sys {
}}
}
asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) {
; Called when the compiler wants to assign a string value to another string.
%asm {{
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r0
ldy cx16.r0+1
jmp prog8_lib.strcpy
}}
}
asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) {
; note: only works for NON-OVERLAPPING memory regions!
; note: can't be inlined because is called from asm as well

View File

@ -554,6 +554,17 @@ sys {
}}
}
asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) {
; Called when the compiler wants to assign a string value to another string.
%asm {{
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r0
ldy cx16.r0+1
jmp prog8_lib.strcpy
}}
}
asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) {
; note: only works for NON-OVERLAPPING memory regions!
; note: can't be inlined because is called from asm as well

View File

@ -519,6 +519,17 @@ sys {
}}
}
asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) {
; Called when the compiler wants to assign a string value to another string.
%asm {{
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r0
ldy cx16.r0+1
jmp prog8_lib.strcpy
}}
}
asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) {
; note: only works for NON-OVERLAPPING memory regions!
; note: can't be inlined because is called from asm as well

View File

@ -267,7 +267,7 @@ inline asmsub str2ubyte(str string @AY) clobbers(Y) -> ubyte @A {
}}
}
inline asmsub str2byte(str string @AY) clobbers(Y) -> ubyte @A {
inline asmsub str2byte(str string @AY) clobbers(Y) -> byte @A {
; -- returns in A the signed byte value of the string number argument in AY
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)

View File

@ -840,6 +840,17 @@ sys {
}}
}
asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) {
; Called when the compiler wants to assign a string value to another string.
%asm {{
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r0
ldy cx16.r0+1
jmp prog8_lib.strcpy
}}
}
asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) {
; note: only works for NON-OVERLAPPING memory regions!
; If you have to copy overlapping memory regions, consider using

View File

@ -0,0 +1,230 @@
; Number conversions routines.
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
conv {
; ----- number conversions to decimal strings ----
str string_out = "????????????????" ; result buffer for the string conversion routines
sub str_ub0(ubyte value) {
; ---- convert the ubyte in A in decimal string form, with left padding 0s (3 positions total)
ubyte hundreds = value / 100
value -= hundreds*100
ubyte tens = value / 10
value -= tens*10
string_out[0] = hundreds+'0'
string_out[1] = tens+'0'
string_out[2] = value+'0'
string_out[3] = 0
}
sub str_ub(ubyte value) {
; ---- convert the ubyte in A in decimal string form, without left padding 0s
internal_str_ub(value, string_out)
}
sub str_b(byte value) {
; ---- convert the byte in A in decimal string form, without left padding 0s
uword out_ptr = &string_out
if value<0 {
@(out_ptr) = '-'
out_ptr++
value = -value
}
internal_str_ub(value as ubyte, out_ptr)
}
sub internal_str_ub(ubyte value, uword out_ptr) {
ubyte hundreds = value / 100
value -= hundreds*100
ubyte tens = value / 10
value -= tens*10
if hundreds
goto output_hundreds
if tens
goto output_tens
goto output_ones
output_hundreds:
@(out_ptr) = hundreds+'0'
out_ptr++
output_tens:
@(out_ptr) = tens+'0'
out_ptr++
output_ones:
@(out_ptr) = value+'0'
out_ptr++
@(out_ptr) = 0
}
str hex_digits = "0123456789abcdef"
sub str_ubhex (ubyte value) {
; ---- convert the ubyte in A in hex string form
string_out[0] = hex_digits[value>>4]
string_out[1] = hex_digits[value&15]
string_out[2] = 0
}
sub str_ubbin (ubyte value) {
; ---- convert the ubyte in A in binary string form
uword out_ptr = &string_out
repeat 8 {
rol(value)
if_cc
@(out_ptr) = '0'
else
@(out_ptr) = '1'
out_ptr++
}
@(out_ptr) = 0
}
sub str_uwbin (uword value) {
; ---- convert the uword in A/Y in binary string form
uword out_ptr = &string_out
repeat 16 {
rol(value)
if_cc
@(out_ptr) = '0'
else
@(out_ptr) = '1'
out_ptr++
}
@(out_ptr) = 0
}
sub str_uwhex (uword value) {
; ---- convert the uword in A/Y in hexadecimal string form (4 digits)
ubyte bits = msb(value)
string_out[0] = hex_digits[bits>>4]
string_out[1] = hex_digits[bits&15]
bits = lsb(value)
string_out[2] = hex_digits[bits>>4]
string_out[3] = hex_digits[bits&15]
string_out[4] = 0
}
sub str_uw0 (uword value) {
; ---- convert the uword in A/Y in decimal string form, with left padding 0s (5 positions total)
ubyte tenthousands = (value / 10000) as ubyte
value -= 10000*tenthousands
ubyte thousands = (value / 1000) as ubyte
value -= 1000*thousands
ubyte hundreds = (value / 100) as ubyte
value -= 100 as uword * hundreds
ubyte tens = (value / 10) as ubyte
value -= 10*tens
string_out[0] = tenthousands+'0'
string_out[1] = thousands+'0'
string_out[2] = hundreds+'0'
string_out[3] = tens+'0'
string_out[4] = value as ubyte + '0'
string_out[5] = 0
}
sub str_uw (uword value) {
; ---- convert the uword in A/Y in decimal string form, without left padding 0s
internal_str_uw(value, string_out)
}
sub str_w (word value) {
; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's
uword out_ptr = &string_out
if value<0 {
@(out_ptr) = '-'
out_ptr++
value = -value
}
internal_str_uw(value as uword, out_ptr)
}
sub internal_str_uw(uword value, uword out_ptr) {
ubyte tenthousands = (value / 10000) as ubyte
value -= 10000*tenthousands
ubyte thousands = (value / 1000) as ubyte
value -= 1000*thousands
ubyte hundreds = (value / 100) as ubyte
value -= 100 as uword * hundreds
ubyte tens = (value / 10) as ubyte
value -= 10*tens
if tenthousands
goto output_tenthousands
if thousands
goto output_thousands
if hundreds
goto output_hundreds
if tens
goto output_tens
goto output_ones
output_tenthousands:
@(out_ptr) = tenthousands+'0'
out_ptr++
output_thousands:
@(out_ptr) = thousands+'0'
out_ptr++
output_hundreds:
@(out_ptr) = hundreds+'0'
out_ptr++
output_tens:
@(out_ptr) = tens+'0'
out_ptr++
output_ones:
@(out_ptr) = value as ubyte + '0'
out_ptr++
@(out_ptr) = 0
}
; ---- string conversion to numbers -----
sub str2ubyte(str string) -> ubyte {
; -- returns in A the unsigned byte value of the string number argument in AY
; the number may NOT be preceded by a + sign and may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
}
sub str2byte(str string) -> byte {
; -- returns in A the signed byte value of the string number argument in AY
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
}
sub str2uword(str string) -> uword {
; -- returns the unsigned word value of the string number argument in AY
; the number may NOT be preceded by a + sign and may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
}
sub str2word(str string) -> word {
; -- returns the signed word value of the string number argument in AY
; the number may be preceded by a + or - sign but may NOT contain spaces
; (any non-digit character will terminate the number string that is parsed)
; TODO
return 0
}
sub hex2uword(str string) -> uword {
; -- hexadecimal string (with or without '$') to uword.
; string may be in petscii or c64-screencode encoding.
; stops parsing at the first character that's not a hex digit (except leading $)
; TODO
return 0
}
sub bin2uword(str string) -> uword {
; -- binary string (with or without '%') to uword.
; stops parsing at the first character that's not a 0 or 1. (except leading %)
; TODO
return 0
}
}

View File

@ -0,0 +1,94 @@
; Prog8 definitions for floating point handling on the VirtualMachine
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
%option enable_floats
floats {
const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586
sub print_f(float value) {
; ---- prints the floating point value (without a newline).
; TODO
}
sub pow(float value, float power) -> float {
; TODO
return 0.0
}
sub fabs(float value) -> float {
; TODO
return 0.0
}
sub sin(float angle) -> float {
; TODO
return 0.0
}
sub cos(float angle) -> float {
; TODO
return 0.0
}
sub tan(float value) -> float {
; TODO
return 0.0
}
sub atan(float value) -> float {
; TODO
return 0.0
}
sub ln(float value) -> float {
; TODO
return 0.0
}
sub log2(float value) -> float {
; TODO
return 0.0
}
sub sqrt(float value) -> float {
; TODO
return 0.0
}
sub rad(float angle) -> float {
; -- convert degrees to radians (d * pi / 180)
; TODO
return 0.0
}
sub deg(float angle) -> float {
; -- convert radians to degrees (d * (1/ pi * 180))
; TODO
return 0.0
}
sub round(float value) -> float {
; TODO
return 0.0
}
sub floor(float value) -> float {
; TODO
return 0.0
}
sub ceil(float value) -> float {
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
; TODO
return 0.0
}
sub rndf() -> float {
; TODO
return 0.0
}
}

View File

@ -81,6 +81,16 @@ sys {
void syscall(SC_WAITVSYNC)
}
sub internal_stringcopy(uword source, uword target) {
; Called when the compiler wants to assign a string value to another string.
while @(source) {
@(target) = @(source)
source++
target++
}
@(target)=0
}
sub memcopy(uword source, uword target, uword count) {
repeat count {
@(target) = @(source)

View File

@ -2,8 +2,7 @@
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
%import syslib
%import conv
txt {
@ -37,146 +36,70 @@ sub print (str text) {
sub print_ub0 (ubyte value) {
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
; TODO use conv module?
ubyte hundreds = value / 100
value -= hundreds*100
ubyte tens = value / 10
value -= tens*10
chrout(hundreds+'0')
chrout(tens+'0')
chrout(value+'0')
conv.str_ub0(value)
print(conv.string_out)
}
sub print_ub (ubyte value) {
; ---- print the ubyte in decimal form, without left padding 0s
; TODO use conv module?
ubyte hundreds = value / 100
value -= hundreds*100
ubyte tens = value / 10
value -= tens*10
if hundreds
goto print_hundreds
if tens
goto print_tens
goto print_ones
print_hundreds:
chrout(hundreds+'0')
print_tens:
chrout(tens+'0')
print_ones:
chrout(value+'0')
conv.str_ub(value)
print(conv.string_out)
}
sub print_b (byte value) {
; ---- print the byte in decimal form, without left padding 0s
if value<0 {
chrout('-')
value = -value
}
print_ub(value as ubyte)
conv.str_b(value)
print(conv.string_out)
}
str hex_digits = "0123456789abcdef"
sub print_ubhex (ubyte value, ubyte prefix) {
; ---- print the ubyte in hex form
if prefix
chrout('$')
chrout(hex_digits[value>>4])
chrout(hex_digits[value&15])
conv.str_ubhex(value)
print(conv.string_out)
}
sub print_ubbin (ubyte value, ubyte prefix) {
; ---- print the ubyte in binary form
; TODO use conv module?
if prefix
chrout('%')
repeat 8 {
rol(value)
if_cc
txt.chrout('0')
else
txt.chrout('1')
}
conv.str_ubbin(value)
print(conv.string_out)
}
sub print_uwbin (uword value, ubyte prefix) {
; ---- print the uword in binary form
; TODO use conv module?
if prefix
chrout('%')
repeat 16 {
rol(value)
if_cc
txt.chrout('0')
else
txt.chrout('1')
}
conv.str_uwbin(value)
print(conv.string_out)
}
sub print_uwhex (uword value, ubyte prefix) {
; ---- print the uword in hexadecimal form (4 digits)
print_ubhex(msb(value), true)
print_ubhex(lsb(value), false)
if prefix
chrout('$')
conv.str_uwhex(value)
print(conv.string_out)
}
sub print_uw0 (uword value) {
; ---- print the uword value in decimal form, with left padding 0s (5 positions total)
; TODO use conv module?
ubyte tenthousands = (value / 10000) as ubyte
value -= 10000*tenthousands
ubyte thousands = (value / 1000) as ubyte
value -= 1000*thousands
ubyte hundreds = (value / 100) as ubyte
value -= 100 as uword * hundreds
ubyte tens = (value / 10) as ubyte
value -= 10*tens
chrout(tenthousands+'0')
chrout(thousands+'0')
chrout(hundreds+'0')
chrout(tens+'0')
chrout(value as ubyte + '0')
conv.str_uw0(value)
print(conv.string_out)
}
sub print_uw (uword value) {
; ---- print the uword in decimal form, without left padding 0s
ubyte tenthousands = (value / 10000) as ubyte
value -= 10000*tenthousands
ubyte thousands = (value / 1000) as ubyte
value -= 1000*thousands
ubyte hundreds = (value / 100) as ubyte
value -= 100 as uword * hundreds
ubyte tens = (value / 10) as ubyte
value -= 10*tens
if tenthousands
goto print_tenthousands
if thousands
goto print_thousands
if hundreds
goto print_hundreds
if tens
goto print_tens
goto print_ones
print_tenthousands:
chrout(tenthousands+'0')
print_thousands:
chrout(thousands+'0')
print_hundreds:
chrout(hundreds+'0')
print_tens:
chrout(tens+'0')
print_ones:
chrout(value as ubyte + '0')
conv.str_uw(value)
print(conv.string_out)
}
sub print_w (word value) {
; ---- print the (signed) word in decimal form, without left padding 0's
if value<0 {
chrout('-')
value = -value
}
print_uw(value as uword)
conv.str_w(value)
print(conv.string_out)
}
sub input_chars (uword buffer) -> ubyte {

View File

@ -316,6 +316,9 @@ internal class StatementReorderer(val program: Program,
}
}
if(valueType.isString && (targetType istype DataType.STR || targetType istype DataType.ARRAY_B || targetType istype DataType.ARRAY_UB))
return copyStringValue(assignment)
return noModifications
}
@ -409,8 +412,26 @@ internal class StatementReorderer(val program: Program,
return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
}
private fun copyStringValue(assign: Assignment): List<IAstModification> {
val identifier = assign.target.identifier!!
val sourceIdent = assign.value as? IdentifierReference
val strcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "internal_stringcopy"), assign.position),
mutableListOf(
if(sourceIdent!=null)
AddressOf(sourceIdent, assign.position)
else
assign.value,
AddressOf(identifier, assign.position)
),
true,
assign.position
)
return listOf(IAstModification.ReplaceNode(assign, strcopy, assign.parent))
}
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
val function = functionCallStatement.target.targetStatement(program)!!
val function = functionCallStatement.target.targetStatement(program)
?: throw FatalAstException("no target for $functionCallStatement")
checkUnusedReturnValues(functionCallStatement, function, program, errors)
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
}

View File

@ -3,7 +3,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- %import inside a block/subroutine should give compilation error
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type

View File

@ -1,40 +1,72 @@
%import textio
%import floats
; %import floats
%import conv
%zeropage dontuse
; NOTE: meant to test to virtual machine output target (use -target vitual)
main {
sub start() {
sub newstring() -> str {
return "new"
}
float f1 = 1.555
floats.print_f(floats.sin(f1))
sub start() {
str name = "irmen\n"
txt.print(name)
name = "pipo\n"
txt.print(name)
ubyte cc
ubyte[] array = [11,22,33,44]
for cc in array {
txt.print_ub(cc)
txt.spc()
}
txt.nl()
floats.print_f(floats.cos(f1))
array = [99,88,77,66]
for cc in array {
txt.print_ub(cc)
txt.spc()
}
txt.nl()
floats.print_f(floats.tan(f1))
txt.print_ub0(99)
txt.spc()
txt.print_ub(99)
txt.nl()
floats.print_f(floats.atan(f1))
txt.nl()
floats.print_f(floats.ln(f1))
txt.nl()
floats.print_f(floats.log2(f1))
txt.nl()
floats.print_f(floats.sqrt(f1))
txt.nl()
floats.print_f(floats.rad(f1))
txt.nl()
floats.print_f(floats.deg(f1))
txt.nl()
floats.print_f(floats.round(f1))
txt.nl()
floats.print_f(floats.floor(f1))
txt.nl()
floats.print_f(floats.ceil(f1))
txt.nl()
floats.print_f(floats.rndf())
txt.print_uw0(9988)
txt.spc()
txt.print_uw(9988)
txt.nl()
; float f1 = 1.555
; floats.print_f(floats.sin(f1))
; txt.nl()
; floats.print_f(floats.cos(f1))
; txt.nl()
; floats.print_f(floats.tan(f1))
; txt.nl()
; floats.print_f(floats.atan(f1))
; txt.nl()
; floats.print_f(floats.ln(f1))
; txt.nl()
; floats.print_f(floats.log2(f1))
; txt.nl()
; floats.print_f(floats.sqrt(f1))
; txt.nl()
; floats.print_f(floats.rad(f1))
; txt.nl()
; floats.print_f(floats.deg(f1))
; txt.nl()
; floats.print_f(floats.round(f1))
; txt.nl()
; floats.print_f(floats.floor(f1))
; txt.nl()
; floats.print_f(floats.ceil(f1))
; txt.nl()
; floats.print_f(floats.rndf())
; txt.nl()
; "sin", "cos", "tan", "atan",
; "ln", "log2", "sqrt", "rad",
; "deg", "round", "floor", "ceil", "rndf"