Example 4
|
For this part of our assembler programming series, we shall turn our attention to Relocatable
Modules.
Modules are special programs which link themselves into the operating system to provide extra
functionality, such as SWIs or *commands, or simply background tasks. They are loaded into the
RMA (Relocatable Module Area) and are available all the time.
Examples of modules are new filing systems, or the nested WindowManager (which replaces the
WindowManager in the OS ROMs).
We are not going to aim quite so high as rewriting the WIMP. Instead you will discuss a small
module which resets the computer upon a *command, or all mouse keys pressed.
This module might seen a bit pointless. I was originally written for my network server, which is slung under the desk and has no monitor. Resetting via Econet DoImmediate was precarious. So plug in a mouse, press all three buttons, and Bob is your father's brother...
This example shows several things:
REM >SourceCode REM REM Resetter module REM Version 1.02 REM REM by Richard Murray REM REM Downloaded from: http://www.heyrick.co.uk/assembler/ : ON ERROR PRINT REPORT$+" at "+STR$(ERL/10) : END : DIM code% 1024 FOR x%=0 TO 1023 : code%?x%=0 : NEXT : FOR pass% = 4 TO 7 STEP 3 P%=0 O%=code% [ OPT pass% EQUD 0 ; Start-up code EQUD initialise ; Initialisation EQUD finalise ; Finalisation EQUD 0 ; Service call handler EQUD module_title ; Module title EQUD module_help ; Module help EQUD help_table ; Help and command decoding table EQUD 0 ; SWI chunk base number EQUD 0 ; SWI handling code EQUD 0 ; SWI decoding code EQUD 0 ; SWI decoding codeTwo things should be immediately visible. Firstly, offset assembly is being used. This is because relocatable modules can be loaded anywhere. In fact, relocatable modules should be truly relocatable, and support being moved whilst active. Unfortunately many modules (including several of the OS ones!) misbehave if moved after initialisation.
.module_title EQUS "Resetter" EQUB 0 ALIGN .module_help EQUS "Resetter"+CHR$(9)+"1.02 (03 Jan 1997)" EQUB 0 ALIGNTitle and details for module...
.help_table EQUS "ResetNow" ; Keyword string EQUB 0 ALIGN EQUD reset_code ; Pointer to code EQUD 0 ; Parameter information ; (no parameters) EQUD reset_syntax ; Pointer to syntax string EQUD reset_help ; Pointer to help string EQUD 0 ; End of command table .reset_help EQUS "*ResetNow will reset your computer." EQUB 13 EQUB 13 EQUS " ********************************************" EQUB 13 EQUS " * WARNING : All unsaved work WILL be lost! *" EQUB 13 EQUS " ********************************************" EQUB 13 EQUB 0 EQUB 0 EQUB 0 .reset_syntax EQUS "Syntax: *ResetNow" EQUB 0 ALIGNThe *command comprises of the command name, followed by data words for the command.
.initialise STMFD R13!, {R14} MOV R0, #14 ; Set up event on mouse ; button change MOV R1, #10 SWI "OS_Byte" MOV R0, #&10 ; Claim event vector ADR R1, check_mouse MOV R2, #&100 SWI "OS_Claim" LDMFD R13!, {PC}This is our initialisation code. It enables mouse button events, and then sets up a claim on the mouse button event.
.finalise STMFD R13!, {R14} MOV R0, #13 ; Remove mouse event MOV R1, #10 SWI "OS_Byte" MOV R0, #&10 ; Release event vector ADR R1, check_mouse MOV R2, #&100 SWI "OS_Release" LDMFD R13!, {PC}This routine deals with unlinking the event and claim if the module is shut down (ie, by
*RMKill
).
.reset_code MOV R0, #200 MOV R1, #2 ; Set to clear memory MOV R2, #0 SWI "OS_Byte" SWI 131178 ; SWI XOS_Reset SWI "OS_EnterOS" ; If not, fall back to MOV R0, #&03800000 ; conventional reset code. LDR R1, [R0, #0] STR R1, [R0, -R0] MOV PC, #0This is the code which performs the reset.
.check_mouse STMFD R13!, {R0 - R12, R14} CMP R0, #10 ; The right vector? BNE exit CMP R3, #7 ; All keys pressed? BNE exit LDMFD R13!, {R0 - R12, R14} B reset_codeWe handle mouse clicks with redundant checking. The first thing we do is ensure that we have been passed the correct vector. With something that, say, filters ^A keypresses this is not necessary as we can expect to get what we ask for and not something else. However with resetting things are slightly more dangerous so we test this redundantly.
.exit LDMFD R13!, {R0 - R12, PC}...restores the saved registers, only it places the setting of R14 into PC to save having to do it manually.
.stuff_at_the_end EQUB 10 EQUB 10 EQUS "Resetter module © 1997 Richard Murray" EQUB 10 ] NEXT pass% : OSCLI("Save <Obey$Dir>.ResetMod "+STR$~code%+" +"+STR$~P%) OSCLI("SetType <Obey$Dir>.ResetMod FFA") : ENDFinally, write out an ID string (it's a habit, there's no actual reason for the ID string), loop, then save the module.