Getting random number from assembler 6502

Trying to create a series of random numbers on my C64 using JSR $ E09A and get a number from 63 to 64 dollars. (which, according to all the documentation I saw, is the same procedure when you use RND (0) from BASIC but cannot get it for repetition. The following will work and put a different number at 63 and 64 dollars when executed by myself by oneself.

. C000 A5 00 LDA $00 . C002 20 9A E0 JSR $E09A . C005 00 BRK 

Now when I try to repeat the repetition 10 times with the following code, it never returns.

 . C000 A0 0A LDY #$0A . C002 A9 00 LDA #$00 . C004 20 9A E0 JSR $E09A . C007 88 DEY . C008 D0 F8 BNE $C002 . C00A 00 BRK 

I missed something so obvious that I can’t see it. I am not worried about how this is "accidental." At this point, I just want a series of random numbers.

+5
source share
5 answers

Thanks to Ross Ridge for calling the function to change the value in register Y. I knew that this must be something obvious!

By saving Y before the JSR and restoring after, it will now iterate correctly. Here is a quick solution:

Edit: Updated 7/10/17 - to show the full code and include the JeremyP offer . This is essentially a coin flip iterator (50,000 reps) for random experiments

 .C 033c A9 00 LDA #$00 .C 033e 85 FB STA $FB ; set up register for counter .C 0340 85 FC STA $FC .C 0342 A2 C8 LDX #$C8 ; outer loop= 200 .C 0344 86 FD STX $FD .C 0346 A0 FA LDY #$FA ; inner loop=250 .C 0348 84 FE STY $FE .C 034a 20 94 E0 JSR $E094 ; Get random# Vic20 Address (E09B for C64) .C 034d A5 63 LDA $64 .C 034f C9 80 CMP #$80 ; >128 = HEADS .C 0351 90 0D BCC $0360 ; else continue loop .C 0353 18 CLC ; increment 2 byte number .C 0354 A5 FB LDA $FB .C 0356 69 01 ADC #$01 ; LSB .C 0358 85 FB STA $FB .C 035a A5 FC LDA $FC .C 035c 69 00 ADC #$00 ; MSB .C 035e 85 FC STA $FC .C 0360 C6 FE DEC $FE .C 0362 D0 E6 BNE $034A ; end inner loop .C 0364 C6 FD DEC $FD .C 0366 D0 DE BNE $0346 ; end outer loop .C 0368 60 RTS ; return to basic 

I can get a random number LDA $63 or LDA $64 inside the loop and use it for my purposes.

This turned out to be much slower than expected, taking only half the time he would have done at BASIC. The RND function takes many cycles, however I found this Compute! article that uses a SID chip as a random number generator.

 LDA #$FF ; maximum frequency value STA $D40E ; voice 3 frequency low byte STA $D40F ; voice 3 frequency high byte LDA #$80 ; noise waveform, gate bit off STA $D412 ; voice 3 control register 

Once enabled, it generates numbers independently and should not be executed again. A loop that repeats the calls of LDA $D41B will give you a new random number at each iteration. In my test, 50,000 iterations took 1.25 seconds, and a million took just over 24 seconds. Pretty impressive for a 1 megahertz computer!

+4
source

A SID chip can actually generate numbers that are more random than BASIC pseudo random numbers. Start the generator using:

 LDA #$FF ; maximum frequency value STA $D40E ; voice 3 frequency low byte STA $D40F ; voice 3 frequency high byte LDA #$80 ; noise waveform, gate bit off STA $D412 ; voice 3 control register RTS 

Then you can get random numbers whenever you want:

 LDA $D41B ; get random value from 0-255 
+4
source

You essentially call RND(0) , which uses a timer to generate seed. However, this cannot be used directly in the assembly. First, try switching to a positive number (any number) and see if it starts to create values.

+1
source

If you don’t have a program with a temporary raster IRQ or something similar, you can simply get a β€œrandom” number with lda $d012 .

0
source

It's very late, but depending on your requirements, you can also flip your own PRNG. Some algorithms are simple enough to implement, as an example I will show a 32-bit xorshift using the parameters [3,25,24] (because it makes two shifts of very little code). The returned random number has 16 bits:

 rnd_seed: sta $22 ; store pointer to PRNG state stx $23 lda #$00 ; initialize with 0 ldy #$03 rs_clrloop: sta ($22),y dey bne rs_clrloop lda $d012 ; except for LSB, use current raster bne seed_ok lda #$7f ; or a fixed value if 0 seed_ok: sta ($22),y rts rnd: sta $22 ; store pointer to PRNG state stx $23 ldy #$03 r_cpyloop: lda ($22),y ; copy to ZP $fb - $fe sta $fb,y dey bpl r_cpyloop ldy #$03 ; and shift left 3 bits r_shiftloop: asl $fb rol $fc rol $fd rol $fe dey bpl r_shiftloop ldy #$03 r_xorloop: lda ($22),y ; xor with original state eor $fb,y sta ($22),y dey bpl r_xorloop ldy #$03 lda ($22),y lsr a ; MSB >> 1 gives ">> 25" ldy #$00 eor ($22),y ; xor with original state sta ($22),y ldy #$03 ; this is also value for "<< 24" eor ($22),y ; so xor with MSB sta ($22),y tax ; use the two "higher" bytes as result ... dey lda ($22),y ; ... in A/X rts 

Usage example:

 main: lda init bne noinit lda #<prng ldx #>prng inc init jsr rnd_seed noinit: lda #<prng ldx #>prng jsr rnd jmp $bdcd ; C64 BASIC routine output 16bit int in A/X init: .byte $00 prng: .res 4 ; 32bit PRNG state 
0
source

Source: https://habr.com/ru/post/1269538/


All Articles