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 ENTRYDefines 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 0Storage. 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, lrThis 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_GenerateErrorOur 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, lrAnd, guess what? That's it!
ENDTo make a program: