chiark / gitweb /
Initial revision
[ssr] / StraySrc / Libraries / Sapphire / Modules / s / constrain
1 ;
2 ; constrain.s
3 ;
4 ; Mouse movement constraining
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; Constrain is free software; you can redistribute it and/or modify
12 ; it under the terms of the GNU General Public License as published by
13 ; the Free Software Foundation; either version 2, or (at your option)
14 ; any later version.
15 ;
16 ; Constrain is distributed in the hope that it will be useful,
17 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ; GNU General Public License for more details.
20 ;
21 ; You should have received a copy of the GNU General Public License
22 ; along with Constrain.  If not, write to the Free Software Foundation,
23 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 ;----- Standard header ------------------------------------------------------
26
27                 GET     libs:header
28                 GET     libs:swis
29
30                 IMPORT  version
31
32 ;----- Module header --------------------------------------------------------
33
34                 AREA    |!!!Module$$Header|,CODE,READONLY
35
36                 DCD     0                       ;Start code
37                 DCD     initialise              ;Initialisation routine
38                 DCD     finalise                ;Finalisation code
39                 DCD     0                       ;Service call handler
40                 DCD     title                   ;Title pointer
41                 DCD     version                 ;The help string
42                 DCD     0                       ;No keyword table
43                 DCD     &4A340                  ;SWI chunk number
44                 DCD     swi_handler             ;SWI handler code
45                 DCD     swi_decode              ;SWI decode table
46                 DCD     0                       ;No decoding code needed
47
48 title           DCB     "Constrain",0
49
50 ;----- Initialisation and finalisation --------------------------------------
51
52 initialise      ROUT
53
54                 STMFD   R13!,{R14}              ;Stack link register nicely
55
56                 ; --- Get some workspace ---
57
58                 MOV     R0,#6                   ;Allocate workspace
59                 MOV     R3,#ws__wSize           ;Make it *this* big
60                 SWI     XOS_Module              ;Get me memory
61                 LDMVSFD R13!,{PC}               ;Return if it barfed
62                 STR     R2,[R12]                ;Stash the workspace pointer
63                 MOV     R12,R2                  ;Move the pointer across
64
65                 ; --- Do some initialising ---
66
67                 MOV     R14,#0                  ;No current constraint
68                 STR     R14,ws__routine         ;Store that away
69
70                 ; --- Done ---
71
72                 LDMFD   R13!,{PC}^              ;Return to caller happy
73
74                 LTORG
75
76 finalise        ROUT
77
78                 STMFD   R13!,{R11,R14}
79                 MOV     R11,R12                 ;Keep the private word ptr
80                 LDR     R12,[R12]               ;Find my workspace
81
82                 BL      constrain_finish        ;Close any constraint
83
84                 ; --- Free my workspace ---
85
86                 MOV     R0,#7                   ;Free RMA space
87                 MOV     R2,R12                  ;Point to workspace
88                 SWI     XOS_Module              ;Try to free the memory
89                 MOV     R0,#0                   ;Gonna zero the private word
90                 STR     R0,[R11]                ;Then zero it
91                 LDMFD   R13!,{R11,PC}^          ;A happy bunny
92
93                 LTORG
94
95 ;----- SWI dispatching ------------------------------------------------------
96
97 swi_decode      DCB     "Constrain",0
98                 DCB     "Finish",0
99                 DCB     "MousePos",0
100                 DCB     "Circle",0
101                 DCB     "Disc",0
102                 DCB     0
103
104 swi_handler     LDR     R12,[R12]               ;Get my workspace
105                 CMP     R11,#(%01-%00)/4        ;Within range?
106                 ADDLO   PC,PC,R11,LSL#2         ;Yes -- dispatch
107                 B       %01                     ;No -- complain
108
109 00              B       constrain_finish
110                 B       constrain_mousePos
111                 B       constrain_circ
112                 B       constrain_disc
113
114 01              ADR     R0,noSuchSWI            ;Point to the error
115                 ORRS    PC,R14,#V_flag          ;And return with error
116
117 noSuchSWI       DCD     &1E6
118                 DCB     "Unknown Constrain operation",0
119
120 ;----- Main code ------------------------------------------------------------
121
122 ; --- divide ---
123 ;
124 ; On entry:     R0 == dividend
125 ;               R1 == divisor
126 ;
127 ; On exit:      R0 == quotient
128 ;               R1 == remainder
129 ;
130 ; Use:          A standard divide routine.  Fairly speedy, hopefully.
131 ;               The results are always such that
132 ;
133 ;                       |quotient| <= |(divisor/dividend)|,
134 ;
135 ;                       |remainder| < |divisor|
136 ;
137 ;               and
138 ;
139 ;                       quotient * divisor + remainder == dividend
140
141 divide          ROUT
142
143                 STMFD   R13!,{R2,R3,R14}        ;Save some registers
144
145                 ; --- A note about the method ---
146                 ;
147                 ; We use traditional long division, but unroll the loop a
148                 ; lot to keep the thing ticking over at a good rate.
149
150                 ; --- First, mess about with the signs ---
151
152                 ANDS    R14,R0,#&80000000       ;Get the dividend's sign bit
153                 ORR     R14,R14,R14,LSR #1      ;Copy -- this is sign of mod
154                 RSBNE   R0,R0,#0                ;Take absolute value of R0
155                 ANDS    R3,R1,#&80000000        ;Get the divisor's sign too
156                 RSBNE   R1,R1,#0                ;Take absolute value of R1
157                 EOR     R14,R14,R3              ;Calculate sign of quotient
158                 MOV     R3,R1                   ;Look after the divisor
159
160                 ; --- Shift divisor up for long division ---
161                 ;
162                 ; We keep shifting the divisor up until it's greater than
163                 ; the dividend, and then we skip ahead to the divide section
164
165                 MOV     R2,#0                   ;Quotient starts off at 0
166 00divide        CMP     R0,R3,LSL #0
167                 BLS     %10divide
168                 CMP     R0,R3,LSL #1
169                 BLS     %11divide
170                 CMP     R0,R3,LSL #2
171                 BLS     %12divide
172                 CMP     R0,R3,LSL #3
173                 BLS     %13divide
174                 CMP     R0,R3,LSL #4
175                 BLS     %14divide
176                 CMP     R0,R3,LSL #5
177                 BLS     %15divide
178                 CMP     R0,R3,LSL #6
179                 BLS     %16divide
180                 CMP     R0,R3,LSL #7
181                 MOVHI   R3,R3,LSL #8
182                 BHI     %00divide
183
184                 ; --- Now we have the shift-down loop ---
185                 ;
186                 ; This is where the actual job of dividing is performed.
187                 ; We shift the divisor back down until it's back where we
188                 ; started again.
189
190 17divide        CMP     R0,R3,LSL #7
191                 ADC     R2,R2,R2
192                 SUBCS   R0,R0,R3,LSL #7
193 16divide        CMP     R0,R3,LSL #6
194                 ADC     R2,R2,R2
195                 SUBCS   R0,R0,R3,LSL #6
196 15divide        CMP     R0,R3,LSL #5
197                 ADC     R2,R2,R2
198                 SUBCS   R0,R0,R3,LSL #5
199 14divide        CMP     R0,R3,LSL #4
200                 ADC     R2,R2,R2
201                 SUBCS   R0,R0,R3,LSL #4
202 13divide        CMP     R0,R3,LSL #3
203                 ADC     R2,R2,R2
204                 SUBCS   R0,R0,R3,LSL #3
205 12divide        CMP     R0,R3,LSL #2
206                 ADC     R2,R2,R2
207                 SUBCS   R0,R0,R3,LSL #2
208 11divide        CMP     R0,R3,LSL #1
209                 ADC     R2,R2,R2
210                 SUBCS   R0,R0,R3,LSL #1
211 10divide        CMP     R0,R3,LSL #0
212                 ADC     R2,R2,R2
213                 SUBCS   R0,R0,R3,LSL #0
214
215                 CMP     R3,R1                   ;Have we finished dividing?
216                 MOVHI   R3,R3,LSR #8            ;No -- shift down a byte
217                 BHI     %17divide               ;And loop round again
218
219                 ; --- Now tidy everything up ---
220
221                 TST     R14,#&40000000          ;Is remainder to be negative?
222                 RSBNE   R1,R0,#0                ;Yes -- negate it
223                 MOVEQ   R1,R0                   ;No -- just copy it nicely
224                 TST     R14,#&80000000          ;Is quotient to be negative?
225                 RSBNE   R0,R2,#0                ;Yes -- negate it
226                 MOVEQ   R0,R2                   ;No -- just copy it nicely
227
228                 LDMFD   R13!,{R2,R3,PC}^        ;Return to caller
229
230                 LTORG
231
232 ; --- divRound ---
233 ;
234 ; On entry:     R0 == dividend
235 ;               R1 == divisor
236 ;
237 ; On exit:      R0 == quotient, rounded to nearest integer
238 ;               R1 == remainder
239 ;
240 ; Use:          Calculates a rounded-to-nearest quotient, rather than one
241 ;               rounded towards zero, which is what divide returns you.
242 ;
243 ;               The remainder is fiddled during this process, so that the
244 ;               properties
245 ;
246 ;                       quotient * divisor + remainder == dividend
247 ;
248 ;               and
249 ;
250 ;                       |remainder| < |divisor|
251 ;
252 ;               still hold (so the remainder's sign may well change).
253
254 divRound        ROUT
255
256                 STMFD   R13!,{R2,R14}           ;Save some registers
257                 MOV     R2,R0                   ;Keep a copy of the dividend
258                 CMP     R1,#0                   ;Is the divisor positive?
259                 MOVGE   R14,R1                  ;Yes -- just copy it
260                 RSBLT   R14,R1,#0               ;No -- negate it on the way
261                 CMP     R0,#0                   ;Is the dividend positive?
262                 ADDGE   R0,R0,R14,ASR #1        ;Yes -- add half the divisor
263                 SUBLT   R0,R0,R14,ASR #1        ;No -- subtract it
264                 SUB     R2,R2,R0                ;Remember this difference
265                 BL      divide                  ;Do the division
266                 ADD     R1,R1,R2                ;Modify remainder suitably
267                 LDMFD   R13!,{R2,PC}^           ;Return to caller
268
269                 LTORG
270
271 ; --- sqrt ---
272 ;
273 ; On entry:     R0 == value to square-root
274 ;
275 ; On exit:      R0 == the result
276 ;
277 ; Use:          Evaluates the square root of the number given.  This routine
278 ;               is constructed from the information supplied by David Seal,
279 ;               and is *extremely* fast.
280
281                 EXPORT  sqrt
282 sqrt            ROUT
283
284                 STMFD   R13!,{R1-R4,R14}        ;Stack registers
285                 MOV     R1,#0                   ;Result so far
286                 MOV     R2,#0                   ;Current remainder
287                 MOV     R3,#1                   ;A '01' pair
288                 MOV     R4,#3                   ;A nice mask
289
290                 GBLA    count
291 count           SETA    0                       ;Start the count at 30
292
293                 WHILE   count<=28               ;Set up the loop condition
294
295                 AND     R14,R4,R0,LSR #30-count
296                 ORR     R2,R14,R2,LSL #2
297                 ORR     R14,R3,R1,LSL #2
298                 CMP     R2,R14
299                 ADC     R1,R1,R1
300                 SUBCS   R2,R2,R14
301
302 count           SETA    count+2
303
304                 WEND
305
306                 AND     R14,R4,R0
307                 ORR     R2,R14,R2,LSL #2
308                 ORR     R14,R3,R1,LSL #2
309                 CMP     R2,R14
310                 ADC     R1,R1,R1
311                 SUBCS   R2,R2,R14
312
313 c               MOV     R0,R1                   ;Put the result in R0
314                 LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
315
316                 LTORG
317
318 ; --- constrain_circ ---
319 ;
320 ; On entry:     R0 == x position of circle centre
321 ;               R1 == y position of circle centre
322 ;               R2 == radius of circle
323 ;               R3 == maximum distance below centre allowed
324 ;
325 ; On exit:      --
326 ;
327 ; Use:          Constrains the mouse to the given circle outline
328
329 constrain_circ  ROUT
330
331                 STMFD   R13!,{R0-R2,R14}        ;Stack some registers
332                 BL      constrain_finish        ;Clear a current constraint
333                 MUL     R14,R2,R2               ;Get the radius squared
334                 MOV     R2,R14                  ;Put in back in R2
335                 STMIA   R12,{R0-R3}             ;Store parameter in RMA ws
336                 MOV     R0,#1                   ;Call this often
337                 ADR     R1,constrain__circ      ;Routine to call
338                 STR     R1,ws__routine          ;Remember this pointer
339                 MOV     R2,R12                  ;Pass this R12 value
340                 SWI     XOS_CallEvery           ;Call every 50cs
341                 MOV     R0,#106                 ;Define mouse parameters
342                 MOV     R1,#&81                 ;Pointer 1 -- de-linked
343                 SWI     XOS_Byte                ;Do the OS_Byte call
344                 LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
345
346 ; --- constrain_disc ---
347 ;
348 ; On entry:     R0 == x position of circle centre
349 ;               R1 == y position of circle centre
350 ;               R2 == radius of circle
351 ;
352 ; On exit:      --
353 ;
354 ; Use:          Constrains the mouse to the given circle outline
355
356 constrain_disc  ROUT
357
358                 STMFD   R13!,{R0-R2,R14}        ;Stack some registers
359                 BL      constrain_finish        ;Clear a current constraint
360                 MUL     R14,R2,R2               ;Get the radius squared
361                 MOV     R2,R14                  ;Put in back in R2
362                 STMIA   R12,{R0-R2}             ;Store parameter in RMA ws
363                 MOV     R0,#1                   ;Call this often
364                 ADR     R1,constrain__disc      ;Routine to call
365                 STR     R1,ws__routine          ;Remember this pointer
366                 MOV     R2,R12                  ;Pass this R12 value
367                 SWI     XOS_CallEvery           ;Call every 50cs
368                 MOV     R0,#106                 ;Define mouse parameters
369                 MOV     R1,#&81                 ;Pointer 1 -- de-linked
370                 SWI     XOS_Byte                ;Do the OS_Byte call
371                 LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
372
373 ; --- constrain__circ ---
374 ;
375 ; On entry:     --
376 ;
377 ; On exit:      --
378 ;
379 ; Use:          Called on interrupts to constrin the mouse
380
381 constrain__circ ROUT
382                 STMFD   R13!,{R0-R11,R14}       ;Stack some registers
383
384                 SWI     XOS_Mouse               ;Get the current mouse pos
385 10              LDMIA   R12,{R4-R6,R9}          ;Load interesting values
386                 MOV     R10,#0                  ;Temporary flags word
387
388                 ; --- Set R7 == horizontal distance from centre squared ---
389
390                 SUB     R14,R0,R4               ;Get distance in R14
391                 MUL     R7,R14,R14              ;Square it and copy
392                 CMP     R7,#&10000              ;Is it too big?
393                 MOVGT   R7,#&10000              ;Yes -- reduce (stop oflow)
394                 LDR     R8,ws__oldX             ;Get the old x position
395                 SUB     R8,R8,R4                ;Get the relative position
396                 EOR     R8,R8,R14               ;See if top bit is changed
397                 TST     R8,#(1<<31)             ;Test the top bit
398                 ORRNE   R10,R10,#(1<<0)         ;Set the 'side changed' bit
399
400                 ; --- Set R8 == vertical distance from centre squared ---
401
402                 SUB     R11,R5,R9               ;Get actual maximum height
403                 MUL     R8,R9,R9                ;Get the y distance squared
404                 CMP     R1,R11                  ;Is it high enough?
405                 MOVLE   R1,R11                  ;No -- then raise it
406                 SUBLE   R7,R6,R8                ;Calculate the corner x pos
407                 ORRLE   R10,R10,#2              ;Remember we made this bodge
408                 SUBS    R14,R1,R5               ;Get distance in R14
409                 BGE     %00constrain__circ      ;If in upper quadrants, skip
410                 CMP     R8,R6                   ;Is there a sensible distance
411                 BGT     %00constrain__circ      ;No -- skip this magic bit
412                 TST     R10,#1                  ;Have we changed sides?
413                 BEQ     %00constrain__circ      ;Nope -- skip ahead
414                 LDR     R0,ws__oldX             ;Make sure were on correct sd
415                 SUB     R7,R6,R8                ;Calculate the corner x pos
416                 ORR     R10,R10,#2              ;Remember we made this bodge
417                 B       %01constrain__circ      ;Skip next instruction
418
419 00              MUL     R8,R14,R14              ;Square it and copy
420                 CMP     R8,#&10000              ;Is it too big?
421                 MOVGT   R8,#&10000              ;Yes -- reduce (stop oflow)
422
423 01              ADDS    R9,R7,R8                ;Dist from centre squared
424                 BEQ     %90constrain__circ      ;If 0, return
425
426                 ; --- Don't allow a diagonal skip ---
427
428                 TST     R10,#1                  ;Has x changed sides?
429                 BEQ     %02constrain__circ      ;No -- forget this check
430                 LDR     R14,ws__oldY            ;Get the old Y value
431                 SUB     R3,R14,R5               ;Get distance from centre
432                 MOV     R2,R1                   ;Get the new Y value
433                 SUB     R2,R2,R5                ;Get the new distance
434                 EOR     R3,R3,R2                ;Has sign bit changed?
435                 TST     R3,#(1<<31)             ;Test it
436                 BEQ     %02constrain__circ      ;No -- skip ahead
437                 MOV     R1,R14                  ;Use this Y value
438                 LDR     R0,ws__oldX             ;And this X value
439                 SUB     R14,R0,R4               ;Get the hz distance
440                 MUL     R7,R14,R14              ;And put the square in R7
441                 SUB     R14,R1,R5               ;Get the vt distance
442                 MUL     R8,R14,R14              ;And put the square in R8
443                 ORR     R10,R10,#2              ;Force a *mouse* update
444                 ADDS    R9,R7,R8                ;Dist from centre squared
445                 BEQ     %90constrain__circ      ;If 0, return
446
447                 ; --- Calculate corrected relative positions ---
448
449 02              MOV     R2,R0                   ;Look after the original...
450                 MOV     R3,R1                   ;... mouse position
451
452                 MOV     R1,R9                   ;We'll need to divide by this
453                 MUL     R0,R7,R6                ;Multiply up to give thing
454                 BL      divRound                ;Do the main division
455                 BL      sqrt                    ;And take the square root
456                 CMP     R2,R4                   ;Which side of the centre?
457                 ADDGE   R2,R4,R0                ;This is the x position
458                 SUBLT   R2,R4,R0                ;This is the x position
459
460                 MOV     R1,R9                   ;We'll need to divide by this
461                 MUL     R0,R8,R6                ;Multiply up to give thing
462                 BL      divRound                ;Do the main division
463                 BL      sqrt                    ;And take the square root
464                 CMP     R3,R5                   ;Which side of the centre?
465                 ADDGE   R3,R5,R0                ;This is the y position
466                 SUBLT   R3,R5,R0                ;This is the y position
467
468                 ; --- Make sure y isn't too low now ---
469
470                 CMP     R3,R11                  ;Is the y value too low?
471                 MOVLT   R0,R2                   ;Yes -- get the new x and...
472                 MOVLT   R1,R3                   ;... y coordinates
473                 BLT     %10constrain__circ      ;And skip back round (yeuch)
474
475                 ; --- Store the newly modified mouse positions ---
476
477                 STR     R2,ws__oldX             ;Store the new pointer...
478                 STR     R3,ws__oldY             ;...positions away
479
480                 ; --- Now move the mouse pointer position ---
481
482                 MOV     R0,#5                   ;OS_Word subreason code
483                 ORR     R0,R0,R2,LSL #8         ;Move in the x position
484                 ORR     R0,R0,R3,LSL #24        ;And the bottom of the y
485                 MOV     R1,R3,LSR #8            ;Get the top of the y
486                 STMFD   R13!,{R0,R1}            ;Save the block on the stack
487                 MOV     R0,#21                  ;OS_Word main reason code
488                 MOV     R1,R13                  ;Point to the new block thing
489                 SWI     XOS_Word                ;Position the mouse pointer
490
491                 ; --- Constrain the *mouse* to the circular band ---
492
493                 SUBS    R14,R9,R6               ;f(distance from circumf.)
494                 RSBLT   R14,R14,#0              ;Make sure it's positive
495                 CMP     R14,#256                ;Is this within the band?
496                 CMPLE   R10,#1                  ;Make sure we didn't bodge
497                 MOVGT   R14,#3                  ;No -- move mouse position
498                 STRGTB  R14,[R13,#0]            ;Store new subreason code
499                 SWIGT   XOS_Word                ;And move the position
500
501                 ADD     R13,R13,#8              ;Reclaim the OS_Word block
502 90              LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
503
504                 LTORG
505
506 ; --- constrain__disc ---
507 ;
508 ; On entry:     --
509 ;
510 ; On exit:      --
511 ;
512 ; Use:          Called on interrupts to constrin the mouse
513
514 constrain__disc ROUT
515                 STMFD   R13!,{R0-R11,R14}       ;Stack some registers
516                 SWI     XOS_Mouse               ;Get the current mouse pos
517 10              LDMIA   R12,{R4-R6}             ;Load interesting values
518                 MOV     R10,#0                  ;Temporary flags word
519
520                 ; --- Set R7 == horizontal distance from centre squared ---
521
522                 SUB     R14,R0,R4               ;Get distance in R14
523                 MUL     R7,R14,R14              ;Square it and copy
524                 CMP     R7,#&10000              ;Is it too big?
525                 MOVGT   R7,#&10000              ;Yes -- reduce (stop oflow)
526
527                 ; --- Set R8 == vertical distance from centre squared ---
528
529                 SUBS    R14,R1,R5               ;Get distance in R14
530 00              MUL     R8,R14,R14              ;Square it and copy
531                 CMP     R8,#&10000              ;Is it too big?
532                 MOVGT   R8,#&10000              ;Yes -- reduce (stop oflow)
533
534 01              ADDS    R9,R7,R8                ;Dist from centre squared
535                 BEQ     %90constrain__disc      ;If 0, return
536
537                 ; --- Calculate corrected relative positions ---
538
539
540 02              MOV     R2,R0                   ;Look after the original...
541                 MOV     R3,R1                   ;... mouse position
542
543                 CMP     R6,R9                   ;Are we in the circle?
544                 BGE     %03constrain__disc      ;Yes -- just move it then
545
546                 MOV     R1,R9                   ;We'll need to divide by this
547                 MUL     R0,R7,R6                ;Multiply up to give thing
548                 BL      divRound                ;Do the main division
549                 BL      sqrt                    ;And take the square root
550                 CMP     R2,R4                   ;Which side of the centre?
551                 ADDGE   R2,R4,R0                ;This is the x position
552                 SUBLT   R2,R4,R0                ;This is the x position
553
554                 MOV     R1,R9                   ;We'll need to divide by this
555                 MUL     R0,R8,R6                ;Multiply up to give thing
556                 BL      divRound                ;Do the main division
557                 BL      sqrt                    ;And take the square root
558                 CMP     R3,R5                   ;Which side of the centre?
559                 ADDGE   R3,R5,R0                ;This is the y position
560                 SUBLT   R3,R5,R0                ;This is the y position
561
562                 ; --- Store the newly modified mouse positions ---
563
564 03              STR     R2,ws__oldX             ;Store the new pointer...
565                 STR     R3,ws__oldY             ;...positions away
566
567                 ; --- Now move the mouse pointer position ---
568
569                 MOV     R0,#5                   ;OS_Word subreason code
570                 ORR     R0,R0,R2,LSL #8         ;Move in the x position
571                 ORR     R0,R0,R3,LSL #24        ;And the bottom of the y
572                 MOV     R1,R3,LSR #8            ;Get the top of the y
573                 STMFD   R13!,{R0,R1}            ;Save the block on the stack
574                 MOV     R0,#21                  ;OS_Word main reason code
575                 MOV     R1,R13                  ;Point to the new block thing
576                 SWI     XOS_Word                ;Position the mouse pointer
577
578                 ; --- Constrain the *mouse* to the circular band ---
579
580                 CMP     R6,R9
581                 MOVLT   R14,#3                  ;No -- move mouse position
582                 STRLTB  R14,[R13,#0]            ;Store new subreason code
583                 SWILT   XOS_Word                ;And move the position
584
585                 ADD     R13,R13,#8              ;Reclaim the OS_Word block
586 90              LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
587
588                 LTORG
589
590 ; --- constrain_finish ---
591 ;
592 ; On entry:     --
593 ;
594 ; On exit:      --
595 ;
596 ; Use:          Finishes a constraining operation
597
598 constrain_finish ROUT
599
600                 STMFD   R13!,{R0-R2,R14}        ;Stack some registers
601
602                 ; --- Check whether there's a constrain on ---
603
604                 LDR     R0,ws__routine          ;Check the routine
605                 CMP     R0,#0                   ;Is there one going?
606                 LDMEQFD R13!,{R0-R2,PC}^        ;No -- do nothing then
607
608                 ; --- Remove the routine ---
609
610                 MOV     R1,R12                  ;Pass this R12 value
611                 SWI     XOS_RemoveTickerEvent   ;Call every 50cs
612                 MOV     R0,#106                 ;Change mouse parameters
613                 MOV     R1,#&1                  ;Pointer 1, linked
614                 SWI     XOS_Byte                ;Do the thing
615
616                 ; --- Clear the routine ---
617
618                 MOV     R14,#0                  ;Clear the pointer
619                 STR     R14,ws__routine         ;Store that away
620                 LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
621
622 ; --- constrain_mousePos ---
623 ;
624 ; On entry:     --
625 ;
626 ; On exit:      R0 == x coordinate of pointer
627 ;               R1 == y coordinate of pointer
628 ;
629 ; Use:          Returns the current mouse position during a constrain
630 ;               operation.
631
632 constrain_mousePos ROUT
633
634                 ADR     R0,ws__oldX             ;Point to the coordinates
635                 LDMIA   R0,{R0,R1}              ;And read them out
636                 MOVS    PC,R14                  ;Return to caller
637
638                 LTORG
639
640 ;----- Workspace layout -----------------------------------------------------
641
642                 ^       0,R12
643
644 ws__wStart      #       0                       ;The start of the workspace
645 ws__parameters  #       16                      ;Parameters for the constrain
646 ws__routine     #       4                       ;The routine to call
647 ws__oldX        #       4                       ;The old X coordinate
648 ws__oldY        #       4                       ;The old Y coordinate
649
650 ws__wSize       EQU     {VAR}-ws__wStart        ;The workspace size
651
652 ;----- That's all, folks ----------------------------------------------------
653
654                 END