|
Example 5
|
|
For this example, we are going to implement a simple program...
10 MODE 12 20 OFF 30 MOUSE ON 40 50 REPEAT 60 MOUSE X%, Y%, Z% 70 PRINT TAB(0,0);X%, y%, Z% 80 UNTIL Z% = 7 90 MOUSE OFF 100 ENDBut why stop there? Let's have a little fun. Include the following...
75 IF Z% = 4 OR Z% = 1 THEN PROCplot 110 : 120 DEFPROCplot 130 IF Z% = 4 THEN colour = 3 ELSE colour = 0 140 GCOL colour 150 POINT X%, Y% 160 ENDPROCNow, holding down SELECT will draw yellow dots, and ADJUST will draw black dots (a sort of primitive 'erase').
This is a DDE example. This code is for objasm, but can be easily altered for those assemblers that don't accept compatible input...
Okay, no BASIC, so you can forget about the DIMs and the OPT and the FOR NEXT loop.
Ready?
; mousetest ; ; Version 0.01 8th July 2000 ; by Richard Murray ; ; Downloaded from http://www.heyrick.co.uk/assembler/ ;Always write a header to tell you what is going on. Some people include version changes in the header but I prefer a separate file. Personal choice really, if I had 2Mb of comments, the final program wouldn't be affected - but I might need a pretty beefy computer to assemble it all!
a1 RN 0 a2 RN 1 a3 RN 2 a4 RN 3 v6 RN 9 sp RN 13 lr RN 14 pc RN 15Definitions for the registers that we shall be using.
AREA |asmcode|, CODE, READONLY
ENTRY
Defines the area, and sets this as the program entry point.
; Store registers that must be preserved
MOV sp, a2
STMFD sp!, {v6, lr}
The initial value of the stack pointer is passed to the application in R1. Actually, this is the
RAM limit for the application (refer to OS_GetEnv), but it works for a fully descending stack
such as that which is used by convention on RISC OS.By now, you should be able to follow assembler without so many descriptions, so here goes...
; Set v6 to point to variable storage
ADR v6, storage
; Select MODE 12 (VDU 22, 12)
SWI 256 + 22
SWI 256 + 12
; OFF
SWI &36 ; OS_RemoveCursors
; MOUSE ON
MOV a1, #106 ; Set mouse state
MOV a2, #1 ; 1 = on
SWI &06 ; OS_Byte
; REPEAT
repeat
; MOUSE x%, y%, z%
SWI &1C ; OS_Mouse
STMIA v6, {a1-a3} ; Store X%, Y%, Z%
; PRINT TAB(0,0);
SWI 256 + 31 ; VDU 31, 0, 0
SWI 256
SWI 256
; PRINT x%, y%, z%
LDR a1, [v6, #0] ; Retrieve X%
BL print_integer
LDR a1, [v6, #4] ; Retrieve Y%
BL print_integer
LDR a1, [v6, #8] ; Retrieve Z%
BL print_integer
; Something extra...
LDR a1, [v6, #8] ; Retrieve Z%
CMP a1, #4 ; Is it 4? [SELECT]
CMPNE a1, #1 ; If not, is it 1? [ADJUST]
BLEQ plot ; If either, then go to plot
; UNTIL z% = 7 (all buttons pressed)
LDR a1, [v6, #8] ; Retrieve Z%
CMP a1, #7 ; Is it 7? [SELECT, MENU, ADJUST]
BLNE check_escape ; If not, check for Esc press
BNE repeat ; If not, repeat
; MOUSE OFF
MOV a1, #106 ; Set mouse state
MOV a2, #0 ; 0 = off
SWI &06 ; OS_Byte
; END
SWI &37 ; OS_RestoreCursors
LDMFD sp!, {v6, pc}
SWI &11 ; OS_Exit (only, we shouldn't come to here...)
Of note, in this lot, are:
IF Z% = 4 OR Z% = 1 THEN PROCplot in only four
instructions.
storage
DCD 0
DCD 0
DCD 0
string
DCD 0
DCD 0
Storage. Roughly in the middle, so it doesn't get too far for an ADR instruction to cope with.
I'm not sure if objasm automatically does long ADRs, but it is something to be aware of as
other assemblers may require an ADRL instruction instead, if they do it at all.
This next routine prints an integer in much the same way that BASIC does when you tell it to
PRINT X%.
print_integer
ADR a2, string ; Get address of buffer
MOV a3, #8 ; Length of buffer
SWI &28 ; OS_BinaryToDecimal
; Integer has been converted to a string, a3 gives size.
RSBS a4, a3, #10 ; How many spaces left?
BEQ no_spaces
; print leading spaces
MOV a1, #32 ; ASCII 32 = space
spaces_loop
SWI &00 ; OS_WriteC
SUBS a4, a4, #1 ; Print until none left
BNE spaces_loop
no_spaces
ADR a2, string
;
print_loop
LDRB a1, [a2], #1
SWI &00 ; OS_WriteC
SUBS a3, a3, #1
BNE print_loop
MOV pc, lr
This code might seem odd, why not simply OS_Write0?Because we aren't in BASIC any more, we can't rely on an Escape press having any effect. While it is inefficient to check the escape state in every loop, it isn't that much faster to maintain a loop count and do it every X times round. So, in the spirit of keeping things simple...
check_escape
SWI &2C ; OS_ReadEscapeState
BCS escape_code ; If Carry (Esc pressed), abort.
MOV pc, lr
errblock
DCD 17
= "Escape", 0
ALIGN
escape_code
MOV a1, #126 ; Ack. Escape condition
SWI &06 ; OS_Byte
SWI &37 ; OS_RestoreCursors
ADR a1, errblock
SWI &2B ; OS_GenerateError
Our way out is through OS_GenerateError. That causes the stored entry point to be restored (this
is done by RISC OS, and used for things like when OS_Exit is called).
Next comes the plot routine.
plot
MOVEQ a2, #256 ; Set colour to be black
CMP a1, #4 ; If SELECT pressed,
ADDEQ a2, a2, #3 ; Set colour to be yellow.
SWI 256 + 18 ; Set graphics colour
SWI 256
MOV a1, a2
SWI &00 ; OS_WriteC
MOV a1, #69 ; Point, absolute, foreground
LDMIA v6, {a2-a3} ; Load X% and Y% for plot
SWI &45 ; OS_Plot
MOV pc, lr
And, guess what? That's it!
ENDTo make a program: