|
Post by Leif Bloomquist on Jun 26, 2006 15:10:52 GMT -5
How do you create random numbers in machine language on the 64? I've heard of one technique using the SID noise generator. How about reading the current raster line?
Furthermore, how would you get a random number in a certain range? My first guess would be to use a lookup table, but is there a way you could do it programmatically?
|
|
|
Post by Golan Klinger on Jun 26, 2006 15:44:13 GMT -5
How do you create random numbers in machine language on the 64? Try this: LDA #$FF STA $D40F LDA $80 STA $D412 LDA $D41B You'll end up with a random number between 1 and 255 in the accumulator but you won't be able to use voice 3 for sound unless your program calls for high-pitched squealing.
|
|
TMR
Newbie
Posts: 38
|
Post by TMR on Jun 26, 2006 16:12:25 GMT -5
Best way to use the SID number generation seems to be what Andrew Braybrook wrote about in the Paradroid diary if memory serves, simply set the sound up, dump a load of random values to a table and just read from that as need be.
The "simplest" method i've found is the one SEUCK uses, an 8 bit timer that constantly has some value added to it under interrupt and, when a number is needed at runtme, just go...
ldx counter lda part_of_the_code,x
...and there y'go. =-)
|
|
|
Post by Robin Harbron on Jun 26, 2006 17:21:37 GMT -5
Furthermore, how would you get a random number in a certain range? My first guess would be to use a lookup table, but is there a way you could do it programmatically? TMR and Golan gave good examples for your first question, so I'll just handle the second: If you just want a power of 2 type range... like 2,4,8,16 etc. different values, then AND will do the trick very nicely: LDA rand AND #%00011111 ;value in range 0-31 Less tidy ranges can be arranged by adding two or more ANDed values together, *however* this will cause some values to be more likely than others. Another possibility, if you're not worried about efficiency, is to simply loop, throwing away random numbers until you get one in the range you want. And yes, a table is another choice... use the 8-bit random number as an index into a table full of legitimate values, as evenly distributed as possible.
|
|
TMR
Newbie
Posts: 38
|
Post by TMR on Jun 26, 2006 18:31:25 GMT -5
This works for a range, get a random number using one of the previous examples into X and #lowest_val and #highest_val are, predictably, the lowest and highest number y'want to pick from.
ldy seed loop iny cpy #highest_val bcc *+$04 ldy #lowest_val dex bne loop
Takes a little while to run through, but it works within fixed ranges. If the range is small (under 128 bytes) have the code go...
txa and #$7f tay
...first and it'll give a similar result without as much CPU overhead. But if speed is a serious consideration, use pre-clipped tables. =-)
|
|
|
Post by Leif Bloomquist on Jun 26, 2006 19:31:47 GMT -5
You'll end up with a random number between 1 and 255 in the accumulator but you won't be able to use voice 3 for sound unless your program calls for high-pitched squealing. Thanks! Exactly what I need for now. That should read as follows....right? LDA #$FF STA $D40F LDA #$80STA $D412 LDA $D41B
|
|
|
Post by drdatassette on Oct 15, 2006 8:23:17 GMT -5
speaking of random numbers, i want to create a set of random numbers but i dont want the same numbers to come up twice, is it possible to do in basic (whitout slowing down the d**n thing more than it already is lol)
|
|
TMR
Newbie
Posts: 38
|
Post by TMR on Oct 15, 2006 15:01:17 GMT -5
It's pretty easy to do in BASIC but, depending on what you want out of it, there might be speed concessions. Say you want to pick numbers between 1 and 200;
dim nm(200) fort=1to200:nm(t)=t:next fort=1to1000 n1=int(rnd(1)*200)+1 n2=int(rnd(1)*200)+1 x=nm(n1):nm(n1)=nm(n2):nm(n2)=x next
Now just wander through the array and it should contain seemingly random numbers but they're all within the range you want and never repeat. The initial "scrambling" will take time, obviously, and if you get past the 200 number point you'll either need to run the scramble again (from the fort=1to1000 part) or cycle through the same number you've just had.
|
|
|
Post by Jim Lawless on Oct 15, 2006 22:34:05 GMT -5
speaking of random numbers, i want to create a set of random numbers but i dont want the same numbers to come up twice, is it possible to do in basic (whitout slowing down the d**n thing more than it already is lol) You could keep a bitmap of values you've used. When you encounter a used value, bump up the value of your random number by 1 and re-test against the bitmap ( or write code to probe the bitmap for the first 0-bit and set your random number to that number). Wrap around to the beginning when you break the end boundary.
|
|
|
Post by Nomen Nescio on Oct 21, 2006 11:10:54 GMT -5
How do you create random numbers in machine language on the 64? I've heard of one technique using the SID noise generator. How about reading the current raster line? Furthermore, how would you get a random number in a certain range? My first guess would be to use a lookup table, but is there a way you could do it programmatically? Hello. This is my first post to these forums. I haven't had a Commodore computer since the late '80s (a Vic-20 was my first, followed by a C64 then a C128) but I've recently become interested in them again due to the C64 D2TV. Anyway, here is an example of a simple pseudorandom number generator in assembly. It's not the best, but it is ok for games and such. Also, by 65XX assembly is a little rusty since it has been a number of years since I last programmed in it. Anyway, hope this helps. ; ; 6502 Assembly 16-bit Pseudorandom Number Generator Example ; Written by Nomen Nescio ; October 20, 2006 ; This program is public domain. ; ; Written for xa65 cross assembler. ; www.floodgap.com/retrotech/xa/ ; ; This pseudorandom number generator is a simple linear congruential generator ; which takes the form of ; ; V = ( A * V + B ) MOD M ; ; See: ; en.wikipedia.org/wiki/Linear_congruential_generator ; for more information. ; ; Usage: ; SYS 49152 calculate pseudorandom number ; SYS 49155,VALUE seed pseudorandom generator with 16-bit integer value ; SYS 49158 print current pseudorandom number ; ; Example BASIC test program: ; 10 input "enter rnd seed";seed ; 20 sys 49155,seed : rem seed rnd gen ; 30 for i = 1 to 15 ; 40 sys 49152 : rem calc rnd number ; 50 sys 49158 : rem print rnd number ; 60 next i ;
; BASIC check for comma #define CHKCMA $aefd
; BASIC evaluate formula/number #define FRMNUM $ad8a
; BASIC convert float into unsigned 16-bit int #define FAC2IN $b7f7
; KERNAL output a character #define CHROUT $ffd2
; value for PETSCII return #define RETCHR $0d
#define ORG $c000 loadadr .word ORG ; first 2 bytes of the program image contain the load address *=ORG
;=[ Jump table ]=============================================================== jmp dornd ; calculate next pseudorandom number jmp seed ; seed pseudorandom number generator from BASIC jmp printv ; print current pseudorandom number
;=[ Global variables ]=========================================================
V .word 0 A .word 3671 ; not an optimal constant for this B .word 1 ; In this example, M is 65535 ($FFFF) so we can optimize it out to save several ; clock cycles.
;-- for 16-bit multiplication subroutine ---- mcand .word 0 ; 16-bit multiplicand mult .word 0 ; 16-bit multiplier product .word 0,0 ; 32-bit product
;=[ Seed random number generator ]============================================= seed .( jsr CHKCMA jsr FRMNUM jsr FAC2IN lda $14 sta V lda $15 sta V+1 jsr dornd rts .) ;=[ Generate next pseudorandom number ]======================================== dornd .( ;-- do A * V ---- lda A sta mult lda A+1 sta mult+1
lda V sta mcand lda V+1 sta mcand+1
jsr domult
;-- do V = product + B (we've optimized away MOD M where M=$FFFF). ---- ;-- If you're going to have B=1 always, this could be optimized ---- ;-- even more. ---- clc lda B adc product sta V lda B+1 adc product+1 sta V+1 rts .) ;=[ Multiply two 16-bit integers to get 32-bit product ]======================= ; Uses global variables "mcand" and "mult"; returns result in "product" ; May swap values in "mcand" and "mult". domult .( ;- clear product ---- lda #$0 sta product sta product+1 sta product+2 sta product+3
.( ;- check if mult is larger than mcand. If so, swap them. ----
lda mcand+1 ; compare MSBs cmp mult+1 bpl done ; if MSB(mcand) > MSB(mult) then we're done bmi swap ; if MSB(mcand) < MSB(mult) then swap them lda mcand ; if here then MSBs must be equal so compare LSBs cmp mult bpl done ; if LSB(mcand) > LSB(mult) then we're done beq done ; if LSB(mcand) = LSB(mult) then we're done swap ldx mcand ; if here, mcand < mult so do swap lda mult sta mcand stx mult ldx mcand+1 lda mult+1 sta mcand+1 stx mult+1 done .)
.( ;- calculate how many iterations of loop are needed ----
lda mult+1 sta shftmnd+1 lda mult sta shftmnd ldx #16 ; 16-bit numbers therefore worse case = 16 iterations
caloop ; loop until X counts down to zero, or we find the leftmost asl shftmnd ; "1" bit of multiplicand. rol shftmnd+1 bcs ctdne dex bne caloop
jmp done ; if here, then multiplying by zero so exit domult function ; since answer will obviously be zero.
ctdne stx count ; X contains number of iterations needed, store as count. .)
;- copy multiplicand to temp variable area ---- lda #$0 sta shftmnd+3 ; zero high word sta shftmnd+2 ; " " " lda mcand+1 sta shftmnd+1 lda mcand sta shftmnd
;- copy multiplier to temp variable area ---- lda mult sta tmpmult lda mult+1 sta tmpmult+1 ;- start of multiplication loop ---- .( loop lsr tmpmult+1 ; shift 16-bit multiplier (temp copy) ror tmpmult ; into carry flag bcc skip ; if c=0 then skip add
;- add shifted multiplicand to product ---- clc lda shftmnd adc product sta product lda shftmnd+1 adc product+1 sta product+1 lda shftmnd+2 adc product+2 sta product+2 lda shftmnd+3 adc product+3 sta product+3
;- stick in fork to check for doneness ---- skip dec count beq done
;- shift multiplicand left (temp storage) ---- asl shftmnd rol shftmnd+1 rol shftmnd+2 rol shftmnd+3 jmp loop .) done rts
;-- domult work variables ---- ; would be better to put these in page 0 if you can spare it.
shftmnd .word 0,0 ; 32-bit temp storage for left shifted multiplicand tmpmult .word 0 count .byt 0 ; number of iterations for loop
.) ; end domult
;=[ Output routines for example ]============================================== ;-- print hex byte in Accumulator ---- prax .( pha lsr lsr lsr lsr tax lda tbl,x jsr CHROUT pla and #$0f tax lda tbl,x jsr CHROUT done rts tbl .byt "0123456789ABCDEF" .)
;-- print hex word stored in V ---- printv .( lda #"$" jsr CHROUT lda V+1 jsr prax lda V jsr prax lda #RETCHR jsr CHROUT rts .)
|
|
|
Post by Nomen Nescio on Oct 21, 2006 11:17:31 GMT -5
speaking of random numbers, i want to create a set of random numbers but i dont want the same numbers to come up twice, is it possible to do in basic (whitout slowing down the d**n thing more than it already is lol) This should be doable using a Linear Feedback Shift Register. I've never used one, but from what I understand they can be thought of as a counter whose values are pseudo-randomized. See the Wikipedia entry.
|
|