I have been plundering around and trying to get random numbers. After thinking about it and not finding anything useful on the net I came up with this method:
- Get 3 random seed numbers, 1 from rasterline position, 2 from VIA counters (they are fetched at program start)
- Make 3 virtual "oscillators" and are 3 words that increase by each random seed from a simple add.
- Execute the "oscillators" for some time interval
To get the random number each 16-bit oscillator produces a 8-bit byte by adding MSB+LSB.
Calculate the random number as:
((MSB1+LSB1)*(MSB2+LSB2))+(MSB3*256+LSB3)
The result is a 16-bit random number. You can reduce it to 8-bit by adding MSB+LSB.
The code:
Code: Select all
tab44=$1D00 ; use a page of mem (multiplication)
start
lda $9119
sta randomseed
lda $9004
sta randomseed+1
cmp $9004
beq *-3
lda $9118
sta randomseed+2
jsr initmult
ldx #$ff
rndlp1 ldy #$ff
rndlp2
jsr randomize
dey
bne rndlp2
dex
bne rndlp1
jsr get16rand
rts
randomize
; "oscillates" 3 different 16-bit numbers based on 3 seeds
lda randomosc
clc
adc randomseed
sta randomosc
lda randomosc+1
adc #0
sta randomosc+1
lda randomosc+2
clc
adc randomseed+1
sta randomosc+2
lda randomosc+3
adc #0
sta randomosc+3
lda randomosc+4
clc
adc randomseed+2
sta randomosc+4
lda randomosc+5
adc #0
sta randomosc+5
rts
get16rand
lda randomosc
clc
adc randomosc+1
tax
lda randomosc+2
adc randomosc+3
tay
jsr mult88f ;Result in $92-$93
lda randomosc+4
clc
adc $92
tax
lda randomosc+5
adc $93
tay
rts ;random number in x & y register
; lower4bits=l4b
; higher4bits=h4b
; utilize x=l4bx+16*h4bx and y=l4by+16*h4by
; x*y=14bx*14by+l4bx*16*h4by+16*h4bx*l4by+16*16*h4bx*h4by
; Multiplication routine for faster multiplication
initmult ; set up 15x15 multiplication table
ldx #$f
im1 ldy #$f
im2 jsr mult44
sta $96
iny
txa
asl
asl
asl
asl
sta im3+1
lda $96
im3 sta tab44,y
dey
bne im2
dex
bne im1
rts
mult44 ; Mike's 4x4 multiplication code
DEY ; 2 To counteract carry add: %1111->%1110 + C
STY $96 ; 3
TXA ; 2
ASL ; 2
ASL ; 2
ASL ; 2
ASL ; 2 %XXXX0000
ASL ; 2 %XXX00000
BCC rm0 ; 3
ADC $96 ; 3 %XXX01111
rm0 ASL ; 2 %XX011110
BCC rm1 ; 3
ADC $96 ; 3 %XX011110+1110+c=%11101101
rm1 ASL ; 2 %X1011010
BCC rm2 ; 3
ADC $96 ; 3 %X1011010+1110+c=%X1101001
rm2 ASL ; 2 %11010010
BCC rm3 ; 3
ADC $96 ; 3 %11010010+1110+c=%11100001=225=15*15
rm3 RTS ; 2
mult88f
txa ;2
and #$f ;2
sta m4s1+1 ;4
asl ;2
asl ;2
asl ;2
asl ;2
sta m4u1+1 ;4
; 20c
txa ;2
and #$f0 ;2
sta m4s2+1 ;4
lsr ;2
lsr ;2
lsr ;2
lsr ;2 (c=0)
sta m4s3+1 ;4
; 20c
tya ;2
and #$f0 ;2 h4by
tax ;2
tya ;2
and #$f ;2 l4by
tay ;2
m4s1 lda tab44,x ;5 l4bx*h4by
m4s2 adc tab44,y ;5 h4bx*l4by - c=0, overflow in carry
; 22c
sta $92 ;3
; and #$f0 ;4 highest bits unnecessary -> lowest bits cleared
ror ;2 shift right and put carry in bit7
lsr ;2
lsr ;2
lsr ;2 all bits in bit4-bit0
sta $93 ;3 high byte result (e.g. *16)
lda $92 ;3
and #$f ;2
asl ;2
asl ;2
asl ;2
asl ;2 *16
; sta $92 ;3 low byte result
m4u1 adc tab44,y ;5 l4bx*l4by
; adc $92 ;3 add low byte, overflow->carry (kept until adc)
sta $92 ;3
lda $93 ;3
m4s3 adc tab44,x ;5 h4bx*h4by*16*16, add overflow carry
;adc $93 ;3 result high byte, add overflow carry
sta $93 ;3
; 108cycles for 8-bit*8-bit multiplication
rts
randomseed
byte 0,0,0
randomosc
word 0,0,0
I am not using the VIA's, but they would practically do the same thing. As the code is in assembly, the timing will always be the same (the code runs at the same speed), so only some artificial "oscillator" will work.
For the C64 someone used the noise generator to get random numbers, but I can't see how this could be done on the Vic-20.
For simplicity I put the "randomizer" in a nested loop to run it >65000 times before it gets the random number. In a program (game or whatever) you would simply use "randomizer" as part of the interrupt/game loop.
Any suggestions would be appreciated.