Example 2
|
Previously, we created a program to save 16 colour screens in a compressed form. What we shall do this time is present code to reload the image.
REM >Sloader BudgieSoft screen loader REM V1.01 © 1997 Richard Murray REM REM Assembler programming example 2 REM Downloaded from: http://www.heyrick.co.uk/assembler/ : ON ERROR PRINT REPORT$+" at "+STR$(ERL/10) : END : DIM code% &1000 FOR pass% = 4 TO 6 STEP 2 P%=0 O%=code% [ OPT pass%Again, a standard beginning...
MOV R10, R14 MOV R0, #&4C SWI "XOS_Find" BVS exit MOV R5, R0Our program is designed to be called as "SLoader <filename>". We preserve the return address and try to open the filename in our entry parameters. If the V (oVerflow) flag is set, something went wrong so we exit. Otherwise we move the file handle into R5 for safe keeping.
MOV R8, #0 .skip_header MOV R1, R5 BL read_byte ADD R8, R8, #1 CMP R8, #26 BLT skip_headerSkip the header text.
MOV R0, #&87 SWI "XOS_Byte"Get the current screen mode. If you are wondering about the "get character at cursor position", read the previous example again...
MOV R1, R5 BL read_byte CMP R0, R2 SWINE &100 + 22 SWINE "OS_WriteC"Here we read the screen mode defined and compare it with the current screen mode. If different, we change to the required mode.
ADR R0, vdu_block ADD R1, R0, #12 SWI "OS_ReadVduVariables" LDR R2, [R1] LDR R3, [R1, #4] ADD R3, R3, R2 SUB R2, R2, #1As the screen addresses can change, they are not written to the file. We have to find them out for ourselves. We do assume that MODE 12 is the same across the entire range of RISC OS computers (multisync users can fudge it with the megamodes module). This calls "OS_ReadVduVariables" asking for the screen base address and the size of the screen. Adding the two gives us our result, with the data held in the memory area defined later as ".vdu_block".
MOV R4, #0 ADR R7, os_block .col_loop MOV R1, R5 STRB R4, [R7, #0] MOV R0, #17 STRB R0, [R7, #1] BL read_byte STRB R0, [R7, #2] BL read_byte STRB R0, [R7, #3] BL read_byte STRB R0, [R7, #4] MOV R0, #&0C MOV R1, R7 SWI "OS_Word" MOV R1, R5 MOV R0, #18 STRB R0, [R7, #1] BL read_byte STRB R0, [R7, #2] BL read_byte STRB R0, [R7, #3] BL read_byte STRB R0, [R7, #4] MOV R0, #&0C MOV R1, R7 SWI "OS_Word" ADD R4, R4, #1 CMP R4, #16 BLT col_loopThis lengthy section takes an area known as "os_block" (defined later) and reads colour data into it, building up each colour in turn.
MOV R0, #0 MOV R1, R5 .main_loop BL read_byte MOV R4, R0 BL read_byte .loop2 SUB R0, R0, #1 STRB R4, [R2, #1]! CMP R0, #0 BGT loop2 CMP R2, R3 BLT main_loopHere is the main loop. What it does is it reads the value of the current byte (ie: the colour) and then it reads how long it continues for. As a byte can only hold 256 different values, it loops up to a maximum of 255 times, writing this byte into memory thus reconstructing the image.
MOV R0, #0 MOV R1, R5 SWI "XOS_Find"This wraps up, closing our file. It falls through to "exit" which follows...
.exit MOV PC, R10Leave the program - places stored return address (in register 10) into the Program Counter (register 15).
.read_byte SWI "XOS_BGet" MOVVC PC, R14Simple routine to read a byte of data. Not terribly efficient, however you could change it to move the file handle here instead of beforehand (using MOV R1, R5). It returns by way of function returning (move return address into Program Counter); but only if the V flag is clear. If something went wrong, however, then we fall through to "error" which follows.
.error MOV R2, R0 MOV R1, R5 MOV R0, #0 SWI "XOS_Find" MOV R0, R2 ORR PC, R7, #1<<28This closes the file, restores the cursor and exits with the V flag set (error condition). It is the 'standard' error handler for this program.
.vdu_block EQUD 149 EQUD 7 EQUD -1 EQUD 0 EQUD 0This is the block for the OS_ReadVduVariables command. The 149 and 7 are the codes for the values we wish to read. The -1 terminates the list. The two 0's are where the information is placed by the OS.
.os_block EQUD 0 EQUB 0 ALIGNThis reserves a little memory for the OS_Word call which sets up the palette.
] NEXT OSCLI("Save <Obey$Dir>.Sloader "+STR$~(code%)+" "+STR$~(O%)) OSCLI("SetType <Obey$Dir>.Sloader &FFC")And finally the end. Close the loop, save the file and exit.
There you have it!
To use it, try an Obey file similar to:
| Obey file to run SLoader | <Obey$Dir>.SLoader <Obey$Dir>.comp_piccy
Now, you should remember that I showed you how this format can be inefficient (in example 1).
So we shall, in the next part, propose a new format that will make the compression even more efficient. And, later, we shall consider a "smart" loader that can automatically identify the type of image being loaded and decode it properly.
Now you have the ability to load and save compressed 16 colour screens. You have done something useful with your ARM code. Wasn't that better than poking "Hello World!" into random memory locations to see how quickly you could crash the computer? :-)