rnd()/rndf() routines can now be seeded with new rndseed()/rndseedf() routines. fixes #80

This commit is contained in:
Irmen de Jong 2022-10-22 13:33:35 +02:00
parent 733c17ad3a
commit ec5adffdc2
12 changed files with 177 additions and 60 deletions

View File

@ -56,7 +56,7 @@ romsub $af4b = ROUND() clobbers(A,X,Y) ; round fac1
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 $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 NOTE: special cx16 setup required, use RND() stub instead!!
romsub $af57 = RND_0() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator
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 $af60 = MOVFRM(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac1 (use MOVFM instead)
@ -151,6 +151,32 @@ asmsub FREADUY (ubyte value @Y) {
&uword AYINT_facmo = $66 ; $66/$67 contain result of AYINT
sub rndf() -> float {
%asm {{
stx P8ZP_SCRATCH_REG
lda #1
jsr RND_0
ldx P8ZP_SCRATCH_REG
rts
}}
}
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:c64/floats_funcs.asm"

View File

@ -171,6 +171,29 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
&uword AYINT_facmo = $64 ; $64/$65 contain result of AYINT
sub rndf() -> float {
%asm {{
stx P8ZP_SCRATCH_REG
lda #1
jsr FREADSA
jsr RND ; rng into fac1
ldx P8ZP_SCRATCH_REG
rts
}}
}
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_funcs.asm"

View File

@ -57,7 +57,7 @@ romsub $fe4b = ROUND() clobbers(A,X,Y) ; round fac1
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 $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: special cx16 setup required, use RND() stub instead!!
romsub $fe57 = RND_0() clobbers(A,X,Y) ; fac1 = RND(fac1) float random number generator NOTE: incompatible with C64's RND routine
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 $fe60 = MOVFRM(uword mflpt @ AY) clobbers(A,X,Y) ; load mflpt value from memory in A/Y into fac1 (use MOVFM instead)
@ -147,17 +147,31 @@ asmsub FREADUY (ubyte value @Y) {
}}
}
asmsub RND() clobbers(A,X,Y) {
&uword AYINT_facmo = $c6 ; $c6/$c7 contain result of AYINT
sub rndf() -> float {
%asm {{
lda #0
php
jsr cx16.entropy_get
plp
jmp RND_0
phx
lda #1
jsr RND_0
plx
rts
}}
}
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
}}
}
&uword AYINT_facmo = $c6 ; $c6/$c7 contain result of AYINT
%asminclude "library:c64/floats.asm"
%asminclude "library:c64/floats_funcs.asm"

View File

@ -221,15 +221,4 @@ sub ceil(float value) -> float {
}}
}
sub rndf() -> float {
%asm {{
stx P8ZP_SCRATCH_REG
lda #1
jsr FREADSA
jsr RND ; rng into fac1
ldx P8ZP_SCRATCH_REG
rts
}}
}
}

View File

@ -229,23 +229,7 @@ _divisor .word 0
.pend
randseed .proc
; -- reset the random seeds for the byte and word random generators
; arguments: uword seed in A/Y clobbers A
; (default starting values are: A=$2c Y=$9e)
sta randword._seed
sty randword._seed+1
clc
adc #14
sta randbyte._seed
rts
.pend
randbyte .proc
; -- 8 bit pseudo random number generator into A (by just reusing randword)
jmp randword
.pend
randbyte = randword ; -- 8 bit pseudo random number generator into A (by just reusing randword)
randword .proc
; -- 16 bit pseudo random number generator into AY

View File

@ -71,4 +71,16 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
}}
}
asmsub rndseed(uword seed1 @AY, uword seed2 @R0) clobbers(A,Y) {
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
%asm {{
sta math.randword.sr1
sty math.randword.sr1+1
lda cx16.r0L
ldy cx16.r0H
sta math.randword.sr2
sty math.randword.sr2+1
rts
}}
}
}

View File

@ -130,4 +130,14 @@ sub rndf() -> float {
return
}}
}
sub rndseedf(ubyte s1, ubyte s2, ubyte s3) {
%ir {{
loadm.b r0,floats.rndseedf.s1
loadm.b r1,floats.rndseedf.s2
loadm.b r2,floats.rndseedf.s3
syscall 32
}}
}
}

View File

@ -159,4 +159,13 @@ math {
return costab[radians] as byte
}
sub rndseed(uword seed1, uword seed2) {
; -- reset the pseudo RNG's seed values. Defaults are: $a55a, $7653.
%ir {{
loadm.w r0,math.rndseed.seed1
loadm.w r1,math.rndseed.seed2
syscall 31
}}
}
}

View File

@ -3,8 +3,10 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- ir: get rid of IRCodeLabel, make every label start a new code chunk, give those a 'label' property.
- ir: fix joinChunks() in the IR optimizer ?
- replace rnd() builtin functions by regular functions in math and in floats
- update docs for rnd() and rndseed() functions
- ir: replace RND opcodes by syscalls
- ir: asmsub contents remains blank in IR file
...

View File

@ -1,23 +1,45 @@
%import textio
%import math
%import floats
%zeropage basicsafe
main {
asmsub multi() -> ubyte @A, ubyte @Pc {
%asm {{
lda #42
sec
rts
}}
sub printnumbers() {
txt.print_ub(rnd())
txt.spc()
txt.print_ub(rnd())
txt.spc()
txt.print_ub(rnd())
txt.nl()
txt.print_uw(rndw())
txt.spc()
txt.print_uw(rndw())
txt.spc()
txt.print_uw(rndw())
txt.nl()
floats.print_f(floats.rndf())
txt.spc()
floats.print_f(floats.rndf())
txt.spc()
floats.print_f(floats.rndf())
txt.nl()
}
sub start() {
ubyte value
value = multi()
while 0==multi() {
value++
}
if multi() {
value++
}
txt.print("initial:\n")
math.rndseed($a55a, $7653)
floats.rndseedf(11,22,33)
printnumbers()
txt.print("\nsame seeds:\n")
math.rndseed($a55a, $7653)
floats.rndseedf(11,22,33)
printnumbers()
txt.print("\ndifferent seeds:\n")
math.rndseed($1234, $5678)
floats.rndseedf(44,55,66)
printnumbers()
txt.nl()
}
}

View File

@ -37,6 +37,8 @@ SYSCALLS:
28 = reverse_floats array
29 = compare strings
30 = gfx_getpixel ; get byte pixel value at coordinates r0.w/r1.w
31 = rndseed
32 = rndfseed
*/
enum class Syscall {
@ -70,7 +72,9 @@ enum class Syscall {
REVERSE_WORDS,
REVERSE_FLOATS,
COMPARE_STRINGS,
GFX_GETPIXEL
GFX_GETPIXEL,
RNDSEED,
RNDFSEED
}
object SysCalls {
@ -279,6 +283,17 @@ object SysCalls {
val comparison = first.compareTo(second)
vm.registers.setSB(0, comparison.toByte())
}
Syscall.RNDFSEED -> {
val seed1 = vm.registers.getUB(0)
val seed2 = vm.registers.getUB(1)
val seed3 = vm.registers.getUB(2)
vm.randomSeedFloat(seed1, seed2, seed3)
}
Syscall.RNDSEED -> {
val seed1 = vm.registers.getUW(0)
val seed2 = vm.registers.getUW(1)
vm.randomSeed(seed1, seed2)
}
else -> throw AssemblyError("missing syscall ${call.name}")
}
}

View File

@ -41,6 +41,8 @@ class VirtualMachine(irProgram: IRProgram) {
var statusCarry = false
var statusZero = false
var statusNegative = false
private var randomGenerator = Random(0xa55a7653)
private var randomGeneratorFloats = Random(0xc0d3dbad)
private val cx16virtualregsBaseAddress: Int
init {
@ -1061,9 +1063,9 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsRND(i: IRInstruction) {
when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, Random.nextInt().toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, Random.nextInt().toUShort())
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, Random.nextFloat())
IRDataType.BYTE -> registers.setUB(i.reg1!!, randomGenerator.nextInt().toUByte())
IRDataType.WORD -> registers.setUW(i.reg1!!, randomGenerator.nextInt().toUShort())
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, randomGeneratorFloats.nextFloat())
}
pc++
}
@ -2105,6 +2107,15 @@ class VirtualMachine(irProgram: IRProgram) {
fun waitvsync() {
Toolkit.getDefaultToolkit().sync() // not really the same as wait on vsync, but there's noting else
}
fun randomSeed(seed1: UShort, seed2: UShort) {
randomGenerator = Random(((seed1.toUInt() shl 16) or seed2.toUInt()).toInt())
}
fun randomSeedFloat(seed1: UByte, seed2: UByte, seed3: UByte) {
val seed = (seed1.toUInt() shl 24) or (seed2.toUInt() shl 16) or (seed3.toUInt())
randomGeneratorFloats = Random(seed.toInt())
}
}
// probably called via reflection