REM Stars_src : REM Kludge to report errors in nice WIMP boxes with line numbers included ON ERROR E$=REPORT$+" at line "+STR$(ERL):ON ERROR OFF:ERROR 0,E$ : length=2048 : REM Numbers come from the !Paint 256-colour palette star1_col=2 star2_col=3 star3_col=47 star4_col=255 REM Reduce / increase depending on your processor stars=500 : DIM code length REM Note we are selecting offset assembly, so O% now points to code and P% REM is the pretend address we're assembling at FOR pass=12 TO 14 STEP 2 P%=&8000:O%=code:L%=code+length [OPT pass : MOV R12,R14 ; Keep return address : SWI "OS_GetEnv" ; Read RAM limit SUB R1,R1,#&8000 ; R1 = memory free CMP R1,#32*1024 ; 32k wanted (rough guess) ADRLT R0,memory_error SWILT "OS_GenerateError" ; Error if there isn't enough memory : SWI &100 + 22 ; VDU 22 changes mode SWI &100 + 13 + 128 ; Change to mode 13 with shadowing SWI "OS_RemoveCursors" MOV R0,#112 MOV R1,#2 SWI "OS_Byte" ; Select 'write to shadow bank' MOV R0,#113 MOV R1,#1 SWI "OS_Byte" ; Select 'display current bank' ADR R0,vdu_variables ADR R1,screen_1 SWI "OS_ReadVduVariables" ; Read screen base address / length : SWI "OS_ReadMonotonicTime" STR R0,rand_seed1 ; Initialise random number generator : LDR R2,number_of_stars ; Initialise registers for loop ADR R3,end_code LDR R4,screen_length ADR R5,star_colours .create_stars_loop BL random ; Get random 32-bit word into R0 MOV R1,R0,LSR#30 ; LSR#30 leaves upper-most two bits BIC R0,R0,#&FF000000 ; Clear top 12 bits (note operand 2 BIC R0,R0,#&00F00000 ; restrictions, so we need to use ; two instructions). R1 now holds a ; number between 0-3 denoting our ; star colour. .in_range_loop CMP R0,R4 SUBGE R0,R0,R4 BGE in_range_loop ; Subtract total screen size from ; our random number until: ; random number <= screen memory length ; Now R0 holds a random offset in the ; screen memory. ORR R0,R0,R1,LSL#30 ; Squish star colour and star offset ; into a 32-bit word. STR R0,[R3],#4 ; Store star in table, and increment R3 SUBS R2,R2,#1 BNE create_stars_loop ; Stop if we've created the specified ; number of stars. : .display_stars_loop MOV R0,#112 LDR R1,shadow_number SWI "OS_Byte" ; Select shadow bank to plot on SWI &100 + 12 ; Clear screen (with VDU12! yuck!) CMP R1,#1 LDREQ R1,screen_1 ; Fetch address of the correct screen LDRNE R1,screen_2 ; bank into R1 ADR R0,end_code ; end_code = start of the stars table LDR R2,number_of_stars ; R2 will be our loop counter again LDR R5,screen_length ADR R6,star_colours ; Pointer to table of star colours .draw_stars LDR R3,[R0] ; Get next star into R3 MOV R4,R3,LSR#30 ; R4 = star colour (as above) LDRB R7,[R6,R4] ; Get byte to plot into R7 from the ; colour table pointed to by R6 BIC R3,R3,#&FF000000 ; Scrub colour info from the offset STRB R7,[R1,R3] ; Plot star at screen_base+star_offset SUB R3,R3,#1 SUBS R3,R3,R4 ; Move star on according to colour MOVLE R3,R5 ; If it goes past zero, loop offset ; round to the maximum screen size ORR R3,R3,R4,LSL#30 ; Put colour info back onto offset STR R3,[R0],#4 ; Store star data back again SUBS R2,R2,#1 BNE draw_stars ; Loop round, draw next star MOV R0,#19 SWI "OS_Byte" ; Wait for monitor refresh (*FX19) MOV R0,#113 LDR R1,shadow_number SWI "OS_Byte" ; Display starfield STR R1,shadow_number ; Store altered screen number back SWI "OS_ReadEscapeState" ; Sets (C)arry flag if escape presed BCC display_stars_loop ; ...carry on if it isn't : MOV PC,R12 : .random STR R1,temp_r1 ; Random number generator, lifted from STR R2,temp_r2 ; the Acorn Assembler manual. Its LDR R0,rand_seed1 ; workings venture into the realm of LDR R1,rand_seed2 ; maths, so I'm not going to try to TST R1,R1,LSR#1 ; explain it! Call it, and you'll get MOVS R2,R0,RRX ; a random number back in R0. ADC R1,R1,R1 EOR R2,R2,R0,LSL#12 EOR R0,R2,R2,LSR#20 STR R0,rand_seed1 STR R1,rand_seed2 LDR R1,temp_r1 LDR R2,temp_r2 MOVS PC,R14 : .number_of_stars EQUD stars ; Constants used by the program .star_colours EQUB star1_col EQUB star2_col EQUB star3_col EQUB star4_col : .vdu_variables EQUD 148:EQUD 149:EQUD 7:EQUD -1 .shadow_number EQUD 2 ; Buffer for OS_ReadVduVariables .screen_1 EQUD 0 .screen_2 EQUD 0 .screen_length EQUD 0 : .rand_seed1 EQUD 0 ; Space for random number generator .rand_seed2 EQUD 0 ; to store seed + temporary variables .temp_r1 EQUD 0 .temp_r2 EQUD 0 : .memory_error EQUD 0:EQUS "Stars needs a 32k wimpslot to work":EQUB 0:ALIGN .end_code ]:NEXT REM Save code out to an absolute file, so we can run it independently SYS "OS_File",10,"Stars",&FF8,,code,O%