mirror of
https://github.com/irmen/prog8.git
synced 2025-08-09 19:25:22 +00:00
float.rndseedf() now takes float seed value and is consistent for all CBM compilation targets
This commit is contained in:
@@ -57,6 +57,7 @@ romsub $af4e = ABS() clobbers(A,X,Y) ; fac1 = ABS(fac1)
|
|||||||
romsub $af51 = SIGN() clobbers(X,Y) -> ubyte @ A ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
|
romsub $af51 = SIGN() clobbers(X,Y) -> ubyte @ A ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
|
||||||
romsub $af54 = FCOMP(uword mflpt @ AY) clobbers(X,Y) -> ubyte @ A ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
|
romsub $af54 = FCOMP(uword mflpt @ AY) clobbers(X,Y) -> ubyte @ A ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
|
||||||
romsub $af57 = RND_0() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator
|
romsub $af57 = RND_0() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator
|
||||||
|
romsub $af57 = RND() clobbers(A,X,Y) ; alias for RND_0
|
||||||
romsub $af5a = CONUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac2
|
romsub $af5a = CONUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac2
|
||||||
romsub $af5d = ROMUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in current bank in A/Y into fac2
|
romsub $af5d = ROMUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in current bank in A/Y into fac2
|
||||||
romsub $af60 = MOVFRM(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac1 (use MOVFM instead)
|
romsub $af60 = MOVFRM(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac1 (use MOVFM instead)
|
||||||
@@ -161,21 +162,6 @@ sub rndf() -> float {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub rndseedf(ubyte s1 @A, ubyte s2 @X, ubyte s3 @Y) clobbers(X) {
|
|
||||||
%asm {{
|
|
||||||
sta _tmpseed
|
|
||||||
stx _tmpseed+1
|
|
||||||
sty _tmpseed+2
|
|
||||||
stx _tmpseed+3
|
|
||||||
sty _tmpseed+4
|
|
||||||
lda #<_tmpseed
|
|
||||||
ldy #>_tmpseed
|
|
||||||
jsr MOVFM
|
|
||||||
lda #-1
|
|
||||||
jmp RND_0
|
|
||||||
_tmpseed .byte 0,0,0,0,0
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
%asminclude "library:c128/floats.asm"
|
%asminclude "library:c128/floats.asm"
|
||||||
%asminclude "library:c64/floats_funcs.asm"
|
%asminclude "library:c64/floats_funcs.asm"
|
||||||
|
@@ -182,17 +182,6 @@ sub rndf() -> float {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub rndseedf(ubyte s1 @A, ubyte s2 @X, ubyte s3 @Y) clobbers(X) {
|
|
||||||
%asm {{
|
|
||||||
pha
|
|
||||||
tya
|
|
||||||
ora #128 ; make sure the seed is negative
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
jsr FREADS24AXY
|
|
||||||
jmp RND
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
%asminclude "library:c64/floats.asm"
|
%asminclude "library:c64/floats.asm"
|
||||||
%asminclude "library:c64/floats_funcs.asm"
|
%asminclude "library:c64/floats_funcs.asm"
|
||||||
|
@@ -58,6 +58,7 @@ romsub $fe4e = ABS() clobbers(A,X,Y) ; fac1 = ABS(fac1)
|
|||||||
romsub $fe51 = SIGN() clobbers(X,Y) -> ubyte @ A ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
|
romsub $fe51 = SIGN() clobbers(X,Y) -> ubyte @ A ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
|
||||||
romsub $fe54 = FCOMP(uword mflpt @ AY) clobbers(X,Y) -> ubyte @ A ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
|
romsub $fe54 = FCOMP(uword mflpt @ AY) clobbers(X,Y) -> ubyte @ A ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
|
||||||
romsub $fe57 = RND_0() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator NOTE: incompatible with C64's RND routine
|
romsub $fe57 = RND_0() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator NOTE: incompatible with C64's RND routine
|
||||||
|
romsub $fe57 = RND() clobbers(A,X,Y) ; alias for RND_0
|
||||||
romsub $fe5a = CONUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac2
|
romsub $fe5a = CONUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac2
|
||||||
romsub $fe5d = ROMUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in current bank in A/Y into fac2
|
romsub $fe5d = ROMUPK(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in current bank in A/Y into fac2
|
||||||
romsub $fe60 = MOVFRM(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac1 (use MOVFM instead)
|
romsub $fe60 = MOVFRM(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac1 (use MOVFM instead)
|
||||||
@@ -160,20 +161,8 @@ sub rndf() -> float {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub rndseedf(ubyte s1 @A, ubyte s2 @X, ubyte s3 @Y) clobbers(X) {
|
|
||||||
%asm {{
|
|
||||||
sta P8ZP_SCRATCH_REG
|
|
||||||
lda #0
|
|
||||||
php
|
|
||||||
lda P8ZP_SCRATCH_REG
|
|
||||||
ora #32 ; not sure why this is needed but without it the seed is not consistent
|
|
||||||
plp ; Z=N=0
|
|
||||||
jmp floats.RND_0
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%asminclude "library:c64/floats.asm"
|
%asminclude "library:c64/floats.asm"
|
||||||
%asminclude "library:c64/floats_funcs.asm"
|
%asminclude "library:c64/floats_funcs.asm"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -221,4 +221,20 @@ sub ceil(float value) -> float {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub rndseedf(float seed) {
|
||||||
|
if seed>0
|
||||||
|
seed = -seed ; make sure fp seed is always negative
|
||||||
|
|
||||||
|
%asm {{
|
||||||
|
stx floats_store_reg
|
||||||
|
lda #<seed
|
||||||
|
ldy #>seed
|
||||||
|
jsr MOVFM ; load float into fac1
|
||||||
|
lda #-1
|
||||||
|
jsr floats.RND
|
||||||
|
ldx floats_store_reg
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -131,11 +131,9 @@ sub rndf() -> float {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rndseedf(ubyte s1, ubyte s2, ubyte s3) {
|
sub rndseedf(float seed) {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.b r65500,floats.rndseedf.s1
|
loadm.f fr65500,floats.rndseedf.seed
|
||||||
loadm.b r65501,floats.rndseedf.s2
|
|
||||||
loadm.b r65502,floats.rndseedf.s3
|
|
||||||
syscall 32
|
syscall 32
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@@ -310,7 +310,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
||||||
if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD
|
if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD
|
||||||
&& param.first.type != DataType.STR && param.first.type !in ArrayDatatypes && param.first.type != DataType.FLOAT)
|
&& param.first.type != DataType.STR && param.first.type !in ArrayDatatypes)
|
||||||
err("parameter '${param.first.name}' should be (u)word (an address) or str")
|
err("parameter '${param.first.name}' should be (u)word (an address) or str")
|
||||||
}
|
}
|
||||||
else if(param.second.statusflag!=null) {
|
else if(param.second.statusflag!=null) {
|
||||||
@@ -325,7 +325,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
else if(pair.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
else if(pair.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
||||||
if (pair.first != DataType.UWORD && pair.first != DataType.WORD
|
if (pair.first != DataType.UWORD && pair.first != DataType.WORD
|
||||||
&& pair.first != DataType.STR && pair.first !in ArrayDatatypes && pair.first != DataType.FLOAT)
|
&& pair.first != DataType.STR && pair.first !in ArrayDatatypes)
|
||||||
err("return type #${index + 1} should be (u)word/address")
|
err("return type #${index + 1} should be (u)word/address")
|
||||||
}
|
}
|
||||||
else if(pair.second.statusflag!=null) {
|
else if(pair.second.statusflag!=null) {
|
||||||
|
@@ -259,12 +259,8 @@ tan(x)
|
|||||||
rndf()
|
rndf()
|
||||||
returns the next random float between 0.0 and 1.0 from the Pseudo RNG sequence.
|
returns the next random float between 0.0 and 1.0 from the Pseudo RNG sequence.
|
||||||
|
|
||||||
rndseedf(ubyte s1, ubyte s2, ubyte s3)
|
rndseedf(seed)
|
||||||
Sets a new seed for the float pseudo-RNG sequence. The seed consists of a three byte value.
|
Sets a new seed for the float pseudo-RNG sequence. Use a negative non-zero number as seed value.
|
||||||
Do not use zeros for the seed!
|
|
||||||
|
|
||||||
.. attention::
|
|
||||||
The rndseedf and maybe the rndf routines may change a bit in the future.
|
|
||||||
|
|
||||||
|
|
||||||
graphics
|
graphics
|
||||||
|
@@ -648,16 +648,17 @@ the statement body of such a subroutine should consist of just an inline assembl
|
|||||||
|
|
||||||
The ``@ <register>`` part is required for rom and assembly-subroutines, as it specifies for the compiler
|
The ``@ <register>`` part is required for rom and assembly-subroutines, as it specifies for the compiler
|
||||||
what cpu registers should take the routine's arguments. You can use the regular set of registers
|
what cpu registers should take the routine's arguments. You can use the regular set of registers
|
||||||
(A, X, Y), the special 16-bit register pairs to take word values (AX, AY and XY) and even a processor status
|
(A, X, Y), special 16-bit register pairs to take word values (AX, AY and XY) and even a processor status
|
||||||
flag such as Carry (Pc).
|
flag such as Carry (Pc).
|
||||||
|
|
||||||
|
It is not possible to use floating point arguments or return values in an asmsub.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Asmsubs can also be tagged as ``inline asmsub`` to make trivial pieces of assembly inserted
|
Asmsubs can also be tagged as ``inline asmsub`` to make trivial pieces of assembly inserted
|
||||||
directly instead of a call to them. Note that it is literal copy-paste of code that is done,
|
directly instead of a call to them. Note that it is literal copy-paste of code that is done,
|
||||||
so make sure the assembly is actually written to behave like such - which probably means you
|
so make sure the assembly is actually written to behave like such - which probably means you
|
||||||
don't want a ``rts`` or ``jmp`` or ``bra`` in it!
|
don't want a ``rts`` or ``jmp`` or ``bra`` in it!
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The 'virtual' 16-bit registers from the Commander X16 can also be specified as ``R0`` .. ``R15`` .
|
The 'virtual' 16-bit registers from the Commander X16 can also be specified as ``R0`` .. ``R15`` .
|
||||||
This means you don't have to set them up manually before calling a subroutine that takes
|
This means you don't have to set them up manually before calling a subroutine that takes
|
||||||
|
@@ -3,6 +3,7 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
- ir: register allocation per data type a specific allocation, so we are certain when a reg is used it's just for one specific datatype
|
||||||
- ir: write addresses as hex into p8ir file
|
- ir: write addresses as hex into p8ir file
|
||||||
|
|
||||||
...
|
...
|
||||||
@@ -19,7 +20,6 @@ Future Things and Ideas
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Compiler:
|
Compiler:
|
||||||
|
|
||||||
- ir: register allocation per data type a specific allocation, so we are certain when a reg is used it's just for one specific datatype
|
|
||||||
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
|
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
|
||||||
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
- ir: mechanism to determine for chunks which registers are getting input values from "outside"
|
||||||
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
|
||||||
|
@@ -1,28 +1,27 @@
|
|||||||
%import gfx2
|
|
||||||
%import textio
|
%import textio
|
||||||
|
%import floats
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
gfx2.screen_mode(6)
|
float f1
|
||||||
ubyte pix1 = gfx2.pget(162,120)
|
|
||||||
gfx2.plot(162,120,7)
|
floats.rndseedf(-1.2345)
|
||||||
ubyte pix2 = gfx2.pget(162,120)
|
|
||||||
gfx2.plot(162,120,231)
|
|
||||||
ubyte pix3 = gfx2.pget(162,120)
|
|
||||||
ubyte pix4 = gfx2.pget(163,120)
|
|
||||||
ubyte pix5 = gfx2.pget(162,121)
|
|
||||||
sys.wait(20)
|
|
||||||
gfx2.screen_mode(0)
|
|
||||||
txt.print_ub(pix1)
|
|
||||||
txt.spc()
|
txt.spc()
|
||||||
txt.print_ub(pix2)
|
floats.print_f(floats.rndf())
|
||||||
txt.spc()
|
txt.spc()
|
||||||
txt.print_ub(pix3)
|
floats.print_f(floats.rndf())
|
||||||
txt.spc()
|
txt.spc()
|
||||||
txt.print_ub(pix4)
|
floats.print_f(floats.rndf())
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
|
floats.rndseedf(1.2345)
|
||||||
txt.spc()
|
txt.spc()
|
||||||
txt.print_ub(pix5)
|
floats.print_f(floats.rndf())
|
||||||
|
txt.spc()
|
||||||
|
floats.print_f(floats.rndf())
|
||||||
|
txt.spc()
|
||||||
|
floats.print_f(floats.rndf())
|
||||||
txt.nl()
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -297,10 +297,11 @@ object SysCalls {
|
|||||||
vm.registers.setSB(0, 1)
|
vm.registers.setSB(0, 1)
|
||||||
}
|
}
|
||||||
Syscall.RNDFSEED -> {
|
Syscall.RNDFSEED -> {
|
||||||
val seed1 = vm.registers.getUB(SyscallRegisterBase)
|
val seed = vm.registers.getFloat(SyscallRegisterBase)
|
||||||
val seed2 = vm.registers.getUB(SyscallRegisterBase+1)
|
if(seed>0) // always use negative seed, this mimics the behavior on CBM machines
|
||||||
val seed3 = vm.registers.getUB(SyscallRegisterBase+2)
|
vm.randomSeedFloat(-seed)
|
||||||
vm.randomSeedFloat(seed1, seed2, seed3)
|
else
|
||||||
|
vm.randomSeedFloat(seed)
|
||||||
}
|
}
|
||||||
Syscall.RNDSEED -> {
|
Syscall.RNDSEED -> {
|
||||||
val seed1 = vm.registers.getUW(SyscallRegisterBase)
|
val seed1 = vm.registers.getUW(SyscallRegisterBase)
|
||||||
|
@@ -2148,9 +2148,8 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
randomGenerator = Random(((seed1.toUInt() shl 16) or seed2.toUInt()).toInt())
|
randomGenerator = Random(((seed1.toUInt() shl 16) or seed2.toUInt()).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun randomSeedFloat(seed1: UByte, seed2: UByte, seed3: UByte) {
|
fun randomSeedFloat(seed: Float) {
|
||||||
val seed = (seed1.toUInt() shl 24) or (seed2.toUInt() shl 16) or (seed3.toUInt())
|
randomGeneratorFloats = Random(seed.toBits())
|
||||||
randomGeneratorFloats = Random(seed.toInt())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user