Initial revision
[ssr] / StraySrc / Dynamite / dynamite / s / dynamite
1 ;
2 ; dynamite.s
3 ;
4 ; Memory management in a dynamic area
5 ;
6 ; © 1994-1998 Straylight
7
8 ;----- Licensing note -------------------------------------------------------
9 ;
10 ; This file is part of Straylight's Dynamite
11 ;
12 ; Dynamite is free software; you can redistribute it and/or modify
13 ; it under the terms of the GNU General Public License as published by
14 ; the Free Software Foundation; either version 2, or (at your option)
15 ; any later version.
16 ;
17 ; Dynamite is distributed in the hope that it will be useful,
18 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ; GNU General Public License for more details.
21 ;
22 ; You should have received a copy of the GNU General Public License
23 ; along with Dynamite. If not, write to the Free Software Foundation,
24 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 ;----- Standard header ------------------------------------------------------
27
28 GET libs:header
29 GET libs:swis
30
31 GET libs:stream
32
33 ;----- External dependencies ------------------------------------------------
34
35 GET sh.dynAnchor
36 GET sh.dynArea
37 GET sh.dynHeap
38 GET sh.dynTask
39 GET sh.wSpace
40
41 GET sh.messages
42
43 IMPORT version
44 IMPORT |Dynamite$$Commands$$Base|
45
46 ;----- Module header --------------------------------------------------------
47
48 AREA |!!!Module$$Header|,CODE,READONLY
49
50 dyn__base DCD dt_run ;Application code
51 DCD dyn__init ;Initialisation
52 DCD dyn__quit ;Finalisation
53 DCD dt_service ;Service call handling
54 DCD dyn__name ;Module title string
55 DCD version ;Module help string
56 DCD |Dynamite$$Commands$$Base| ;Command table
57 DCD &4A3C0 ;SWI chunk number
58 DCD dyn__swis ;SWI handler code
59 DCD dyn__swiNames ;SWI name table
60 DCD 0 ;SWI name-number code
61
62 dyn__name DCB "Dynamite",0
63
64 ;----- Main module code -----------------------------------------------------
65
66 AREA |Dynamite$$Code|,CODE,READONLY
67
68 ; --- dyn_base ---
69 ;
70 ; On entry: --
71 ;
72 ; On exit: R14 == base address of module
73 ;
74 ; Use: Finds the base address of the module.
75
76 EXPORT dyn_base
77 dyn_base ROUT
78
79 STMFD R13!,{R14}
80 ADR R14,dyn__base
81 LDMFD R13!,{PC}^
82
83 LTORG
84
85 ; --- dyn__init ---
86 ;
87 ; On entry: --
88 ;
89 ; On exit: --
90 ;
91 ; Use: Claims some memory, and intercepts OS_ChangeDynamicArea.
92
93 dyn__init ROUT
94
95 STMFD R13!,{R7,R8,R14} ;Save some registers
96
97 ; --- Allocate module workspace ---
98
99 MOV R0,#6 ;Claim RMA workspace
100 LDR R3,=dyn_wSize ;Get my workspace size
101 SWI XOS_Module ;Allocate the workspace
102 LDMVSFD R13!,{R7,R8,PC} ;If it failed, return error
103 STR R2,[R12,#0] ;Save workspace address
104 MOV R12,R2 ;Point to workspace nicely
105 STR R12,dyn__wsAddr ;Store for my patch code
106
107 MOV R0,#0 ;Initialise some workspace
108 STR R0,dyn_areaSize ;Dynamic area not created yet
109 STR R0,dyn_heapSize ;No data in the heap
110 STR R0,dyn_lockCount ;And clear the lock counter
111 STR R0,dyn_launch ;Make RMRun do clever stuff
112 STR R0,dyn_taskHandle ;And make the task handle 0
113 STR R0,dyn_ancTable ;Clear the free anchor table
114 STR R0,dyn_ancList ;And the anchor block list
115 MOV R0,#hpFlag_tidy ;We are compacted now
116 STR R0,dyn_hpFlags ;So make a note of this
117
118 ADR R14,dyn_stack ;Point to reloc stack base
119 STR R14,dyn_stackPtr ;Save as the stack pointer
120
121 ; --- Claim OS_ChangeDynamicArea ---
122 ;
123 ; We trap this in the kernel branch table, rather than at
124 ; the SWI vector, because it's so much easier.
125
126 SWI XOS_ReadMemMapInfo ;Read nice things
127 STR R0,dyn_pageSize ;Save the page size
128 SUB R1,R1,#1 ;Chop one off for da_findPage
129 STR R1,dyn_pageCount ;And the number of them
130 MOV R14,#0 ;Log 2 of page size
131 00dyn__init TST R0,#1 ;Is bottom bit set yet?
132 MOVEQ R0,R0,LSR#1 ;No -- shift along a bit
133 ADDEQ R14,R14,#1 ;Add to the log
134 BEQ %00dyn__init ;And keep on going
135 STR R14,dyn_log2PageSize ;And store this away
136
137 MOV R0,#129 ;The OS_Byte number
138 MOV R1,#0 ;Lovely...
139 MOV R2,#255 ;...jubbly!
140 SWI XOS_Byte ;Get OS Version number
141 STR R1,dyn_machine ;Store this away
142 CMP R1,#&A5 ;Is this a RISC PC?
143 BGE %50dyn__init ;Yes -- jump ahead then
144 CMP R1,#&A3 ;Is it RISC OS 2?
145 LDRLT R0,=&ABC ;Yes --- this is sprarea size
146 LDRGE R0,=&ACC ;No -- this is then
147 STR R0,dyn_sprSize ;Save in the workspace
148
149 MOV R6,PC ;Get the current status
150 TST R6,#IRQ_disable ;Are IRQs enabled?
151 TEQEQP R6,#IRQ_disable ;Yes -- disable them then
152
153 LDR R0,=&01F033FC ;Find the kernel dispatcher
154 LDR R14,[R0,#OS_ChangeDynamicArea*4]
155 STR R14,dyn_oldChnArea ;Save this in my workspace
156 ADR R14,dyn__patch ;Point to my patch routine
157 STR R14,[R0,#OS_ChangeDynamicArea*4]
158
159 LDR R14,[R0,#OS_ReadDynamicArea*4]
160 STR R14,dyn_oldReadArea ;Save this in my workspace
161 ADR R14,dyn__readPatch ;Point to my patch routine
162 STR R14,[R0,#OS_ReadDynamicArea*4]
163
164 LDR R14,[R0,#OS_ValidateAddress*4]
165 STR R14,dyn_oldValidate ;Save this in my workspace
166 ADR R14,dyn__valPatch ;Point to my patch routine
167 STR R14,[R0,#OS_ValidateAddress*4]
168 TEQP R6,#0 ;Restore interrupt status
169 MOV R0,R0 ;Shut the assembler up
170
171 ; --- Find the TaskManager and WindowManager addresses ---
172
173 ADR R6,dyn_switchBase ;Point to bit of workspace
174 MOV R0,#18 ;Look up modules by name
175 ADR R1,dyn__switcher ;Point to the Switcher's name
176 SWI XOS_Module ;Try and find its address
177 MOVVS R3,#0 ;If not there, dummy address
178 MOVVS R4,#0 ;For that and the end
179 LDRVC R4,[R3,#-4] ;Otherwise load module length
180 STMIA R6!,{R3,R4} ;Save them in workspace
181
182 ADR R1,dyn__wimp ;Point to the Wimp's name
183 SWI XOS_Module ;Try and find its address
184 MOVVS R3,#0 ;If not there, dummy address
185 MOVVS R4,#0 ;For that and the end
186 LDRVC R4,[R3,#-4] ;Otherwise load module length
187 STMIA R6!,{R3,R4} ;Save them in workspace
188 LDMFD R13!,{R7,R8,PC}^ ;Return to caller
189
190 ; --- The machine is a RISC PC -- lucky sod! ---
191
192 50dyn__init MOV R0,#0 ;Create dynamic area
193 MOV R1,#-1 ;No particular number
194 MOV R2,#0 ;Initial size of area
195 MOV R3,#-1 ;No particular base address
196 MOV R4,#&80 ;The area flags
197 MOV R5,#-1 ;No maximum size please
198 MOV R6,#0 ;No handler needed
199 MOV R7,#0 ;Workspace to pass to handler
200 ADR R8,dyn__areaName ;Dynamic area name
201 SWI XOS_DynamicArea ;Create the area
202 STRVC R1,dyn_areaHandle ;Store the handle
203 STRVC R3,dyn_areaBase ;And the base address
204
205 LDMFD R13!,{R7,R8,PC} ;Return to caller
206
207 dyn__switcher DCB "TaskManager",0
208 dyn__wimp DCB "WindowManager",0
209 dyn__areaName DCB "Dynamite",0
210
211 LTORG
212
213 dyn__wsAddr DCD 0 ;Yuk -- address of workspace
214
215 ; --- dyn__quit ---
216 ;
217 ; On entry: --
218 ;
219 ; On exit: --
220 ;
221 ; Use: Tries to close Dynamite down.
222
223 dyn__quit ROUT
224
225 STMFD R13!,{R12,R14} ;Save a register
226 LDR R12,[R12] ;Find my workspace address
227
228 ; --- Make sure we're not needed ---
229
230 BL dh_compact ;Compact the heap first
231 LDR R14,dyn_areaSize ;How much space are we using?
232 CMP R14,#0 ;Is it 0?
233 BNE %45dyn__quit ;No -- people might want them
234 LDR R14,dyn_stackPtr ;Load the stack pointer
235 ADR R0,dyn_stack ;Point to the stack base
236 CMP R14,R0 ;Are these equal?
237 BNE %45dyn__quit ;No -- we're still used then
238
239 ; --- Close down the compactor ---
240
241 LDR R14,dyn_taskHandle ;Get the task handle
242 CMP R14,#0 ;Is it a sensible one?
243 BLGT dt_quit ;Yes -- kill the task then
244 BL danc_quit ;Free all anchor blocks
245
246 ; --- Get rid of all used pages ---
247
248 LDR R0,dyn_areaSize ;Get the area size
249 LDR R1,dyn_log2PageSize ;And log 2 of page size
250 MOV R0,R0,LSR R1 ;Number of pages in area
251 BL da_removePages ;Remove pages
252
253 LDR R0,dyn_machine ;Get the machine type
254 CMP R0,#&A5 ;Is it a RISC PC?
255 BGE %60dyn__quit ;Yes -- jump ahead
256
257 ; --- First, try to release OS_ChangeDynamicArea ---
258
259 LDR R0,=&01F033FC ;Find the kernel dispatcher
260 LDR R1,[R0,#OS_ChangeDynamicArea*4]
261 ADR R14,dyn__patch ;Point to my patch routine
262 CMP R1,R14 ;Can I release it safely?
263 BNE %50dyn__quit ;No -- report an error
264
265 LDR R1,[R0,#OS_ReadDynamicArea*4]
266 ADR R14,dyn__readPatch ;Point to my patch routine
267 CMP R1,R14 ;Can I release it safely?
268 BNE %50dyn__quit ;No -- report an error
269
270 LDR R1,[R0,#OS_ValidateAddress*4]
271 ADR R14,dyn__valPatch ;Point to my patch routine
272 CMP R1,R14 ;Can I release it safely?
273 BNE %50dyn__quit ;No -- report an error
274
275 LDR R14,dyn_oldChnArea ;Load the previous value
276 STR R14,[R0,#OS_ChangeDynamicArea*4]
277 LDR R14,dyn_oldReadArea ;Load the previous value
278 STR R14,[R0,#OS_ReadDynamicArea*4]
279 LDR R14,dyn_oldValidate ;Load the previous value
280 STR R14,[R0,#OS_ValidateAddress*4]
281
282 ; --- Free the workspace I claimed ---
283
284 40dyn__quit MOV R0,#7 ;Free RMA workspace
285 MOV R2,R12 ;Point to my workspace
286 SWI XOS_Module ;Try to free it nicely
287 LDR R0,[R13],#4 ;Load private word address
288 MOV R14,#0 ;Clear private word value
289 STR R14,[R0,#0] ;To stop OS doing this too...
290 LDMFD R13!,{PC}^ ;Return to caller
291
292 ; --- We have handles or relocation entries ---
293
294 45dyn__quit ADRL R0,msg_errInUse ;Point to error message
295 LDMFD R13!,{R12,R14} ;Unstack some registers
296 ORRS PC,R14,#V_flag ;Return to caller with error
297
298 ; --- We couldn't release OS_ChangeDynamicArea ---
299
300 50dyn__quit ADRL R0,msg_errRelease ;Point to error message
301 LDMFD R13!,{R12,R14} ;Unstack some registers
302 ORRS PC,R14,#V_flag ;Return to caller with error
303
304 ; --- We're on a RISC PC ---
305
306 60dyn__quit MOV R0,#1 ;Remove dynamic area
307 LDR R1,dyn_areaHandle ;Get the area handle
308 SWI XOS_DynamicArea ;Remove it then
309 B %40dyn__quit ;Now free workspace etc.
310
311 LTORG
312
313 ; --- dyn__patch ---
314 ;
315 ; On entry: As for ChangeDynamicArea
316 ;
317 ; On exit: Ditto
318 ;
319 ; Use: Mangles ChangeDynamicArea when being used on the system
320 ; sprite area.
321
322 dyn__patch ROUT
323
324 LDR R12,dyn__wsAddr ;Find my workspace address
325 CMP R0,#3 ;Is it the sprite area?
326 LDRNE PC,dyn_oldChnArea ;No -- continue as normal
327
328 ; --- Mangle the `remembered' size of the sprite area ---
329
330 STMFD R13!,{R14} ;Save another register
331 LDR R11,dyn_sprSize ;Find the size word
332 LDR R14,[R11,#0] ;Load total sprite area size
333 ADD R10,R14,R1 ;How much does he want?
334 CMP R10,#4*1024*1024 ;More than 4 megs?
335 BGT %90dyn__patch ;Yes -- that's an error
336 LDR R10,dyn_areaSize ;Load my area's size
337 SUB R14,R14,R10 ;Get the size of the sprites
338 STR R14,[R11,#0] ;Save that for the duration
339
340 ; --- This is nasty and complicated ---
341 ;
342 ; Post processing on kernel SWIs is not something normally
343 ; to be enjoyed. The way things will have to be done is as
344 ; follows:
345 ;
346 ; * We save R14 and the value &2002A (XOS_ChangeDynamicArea)
347 ; on the stack. The SWI value is so that we regain control
348 ; if something went sadly amiss.
349 ;
350 ; * We call the previous OS_ChangeDynamicArea routine, having
351 ; set a suitably bogus return address.
352 ;
353 ; * We mangle the system sprite area in a manner in keeping
354 ; with the aim of the program.
355 ;
356 ; * Then we examine the status returned to us, and if V was
357 ; set AND the X bit of the R11 saved on the stack before
358 ; we were entered at the top was clear we call
359 ; OS_GenerateError.
360
361 MOV R11,#OS_ChangeDynamicArea ;Get the SWI number
362 ORR R11,R11,#&20000 ;Set the X bit nicely
363 STMFD R13!,{R10-R12} ;Save other registers here
364 STMFD R13!,{R11} ;And the obviously bogus R11
365 MOV R14,PC ;Set up a return address
366 LDR PC,dyn_oldChnArea ;And let it rip...
367
368 ; --- We have now done a ChangeDynamicArea ---
369 ;
370 ; R14 saved above is on the stack, along with the caller's
371 ; R10-R12 from the OS SWI dispatcher.
372
373 LDR R11,dyn_sprSize ;Find the size word
374 LDR R14,[R11,#0] ;Load the new area size
375 ADD R14,R14,R10 ;Add the old difference
376 STR R14,[R11,#0] ;And save it back again
377
378 50dyn__patch LDMFD R13!,{R14} ;Get his return address
379 LDMFD R13!,{R11} ;Get the SWI number too
380 LDMVCFD R13!,{R10-R12} ;Restore his registers
381 BICVCS PC,R14,#V_flag ;And return control to him
382
383 TST R11,#&20000 ;Was the X bit set?
384 SWIEQ OS_GenerateError ;No -- do error like things
385
386 LDMFD R13!,{R10-R12} ;Restore his registers
387 ORRS PC,R14,#V_flag ;And return the error
388
389 ; --- He wanted too much memory ---
390
391 90dyn__patch ADRL R0,msg_errTooBig ;Point to the error
392 CMP R0,#&80000000 ;Create an overflow
393 B %50dyn__patch ;Make it look like it came
394 ;from ChangeDynamicArea
395 LTORG
396
397 ; --- dyn__readPatch ---
398 ;
399 ; On entry: R0 == dynamic area to read, and flags etc.
400 ;
401 ; On exit: R1 == size of dynamic area, R2 == optional maximum size
402 ;
403 ; Use: Reads the size of a dynamic area. If the caller is
404 ; interested in the sprite area AND they're not either the
405 ; TaskManager or the WindowManager, we mangle the result so
406 ; they think that the sprite area doesn't contain our clever
407 ; heap.
408
409 dyn__readPatch ROUT
410
411 LDR R12,dyn__wsAddr ;Find my workspace address
412 BIC R10,R0,#&80 ;Clear the clever flag bit
413 CMP R10,#3 ;Is it the sprite area?
414 LDRNE PC,dyn_oldReadArea ;No -- continue as normal
415
416 ; --- Do all the work then ---
417 ;
418 ; Seeing as we know all there is to know about the sprite
419 ; area, we can do all this here without the yukkiness of
420 ; postprocessing.
421
422 STMFD R13!,{R2,R14} ;Save the link register
423 ADR R11,dyn_switchBase ;Find module addresses
424 BIC R10,R14,#&FC000003 ;Find caller's address
425 LDMIA R11!,{R1,R2} ;Load switcher base/size
426 SUB R14,R10,R1 ;Subtract switcher base
427 CMP R14,R2 ;Is it within switcher?
428 LDMHSIA R11!,{R1,R2} ;No -- load wimp base/size
429 SUBHS R14,R10,R1 ;Subtract wimp base
430 CMPHS R14,R2 ;Is it within wimp?
431 LDMFD R13!,{R2,R14} ;Unstack registers again
432
433 LDR R1,dyn_sprSize ;Find sprite area size word
434 LDR R1,[R1,#0] ;Load current sprite size
435 LDRHS R10,dyn_areaSize ;If caller is pleb, mangle it
436 SUBHS R1,R1,R10 ;By subtracting our heap size
437 TST R0,#&80 ;Does he want max size?
438 MOVNE R2,#4*1024*1024 ;Yes -- that's 4MB
439 MOV R0,#&01400000 ;Point to sprite area start
440
441 ADD R13,R13,#4 ;Skip past stacked R11
442 LDMFD R13!,{R10-R12} ;Unstack caller's registers
443 BICS PC,R14,#V_flag ;And return to caller
444
445 LTORG
446
447 ; --- dyn__valPatch ---
448 ;
449 ; On entry: As for OS_ValidateAddress
450 ;
451 ; On exit: As for OS_ValidateAddress
452 ;
453 ; Use: Mangles OS_ValidateAddress so that it gets our somewhat
454 ; rearranged sprite area correct. This is necessary due to
455 ; braindead implementation of OS_ValidateAddress. I'd like to
456 ; be able to do the job properly by hacking the CAM map, but
457 ; the Mysterious Background Address Validator assumes that the
458 ; SWI works in the way Acorn wrote it, so that's put the
459 ; kybosh on that plan.
460
461 dyn__valPatch ROUT
462
463 LDR R12,dyn__wsAddr ;Find my workspace address
464
465 STMFD R13!,{R14} ;Save the link register
466 MOV R10,#&01400000 ;Get base of the sprite area
467 MOV R11,#&01800000 ;Get limit too
468 CMP R0,R10 ;Is it in there?
469 CMPCS R11,R0
470 CMPCS R1,R10
471 CMPCS R11,R1
472 LDMCCFD R13!,{R14} ;No -- restore link
473 LDRCC PC,dyn_oldValidate ;And let OS_VA do it then
474
475 ; --- Check for weird sprite area thing and Dynamite area ---
476
477 LDR R11,dyn_sprSize ;Get address of sprite size
478 LDR R11,[R11,#0] ;Load size of sprite area
479 LDR R14,dyn_areaSize ;Load our area size
480 ADD R11,R10,R11 ;Find end of sprite area
481 SUB R10,R11,R14 ;Taking our area into account
482 MOV R11,#&01800000 ;Find top of sprite slot
483 SUB R11,R11,R14 ;Find bottom of our area
484 CMP R11,R0 ;This is deep -- think about
485 CMPHI R1,R10 ;it for a while.
486 LDMFD R13!,{R14} ;If it isn't invalid...
487 ADD R13,R13,#4
488 LDMFD R13!,{R10-R12}
489 ORRHIS PC,R14,#C_flag
490 BICLSS PC,R14,#C_flag
491
492 LTORG
493
494 ; --- dyn__swis ---
495 ;
496 ; On entry: R11 == SWI index
497 ;
498 ; On exit: Depends on the SWI
499 ;
500 ; Use: Dispatches SWIs to other routines
501
502 dyn__swis ROUT
503
504 LDR R12,[R12] ;Find my module workspace
505
506 CMP R11,#&3F
507 BEQ dh_dump
508
509 CMP R11,#(%10-%00)/4 ;Is the SWI in range?
510 ADDLO PC,PC,R11,LSL #2 ;Yes -- dispatch it then
511 B %10dyn__swis ;Otherwise report the error
512
513 00dyn__swis B dh_alloc ;Dynamite_Claim
514 B dh_free ;Dynamite_Free
515 B dh_freeWithID ;Dynamite_FreeWithID
516 B dh_blockInfo ;Dynamite_BlockInfo
517 B dh_changeID ;Dynamite_ChangeID
518 B dh_extend ;Dynamite_Resize
519 B dh_midExtend ;Dynamite_MidExtend
520 B dh_save ;Dynamite_Save
521 B dh_load ;Dynamite_Load
522 B dh_reduce ;Dynamite_Reduce
523 B dh_compact ;Dynamite_Compact
524 B dh_lock ;Dynamite_Lock
525 B dh_unlock ;Dynamite_Unlock
526 B danc_alloc ;Dynamite_ClaimAnchor
527 B danc_free ;Dynamite_ReleaseAnchor
528 B da_readSize ;Dynamite_ReadSpriteSize
529 B da_describe ;Dynamite_Describe
530 B dh_checkHeap ;Dynamite_IntegrityCheck
531 B dh_changeAnchor ;Dynamite_ChangeAnchor
532
533 10dyn__swis ADRL R0,msg_errBadSWI ;Point at the error
534 ORRS PC,R14,#V_flag ;And return it back
535
536 dyn__swiNames DCB "Dynamite",0
537 DCB "Alloc",0
538 DCB "Free",0
539 DCB "FreeWithID",0
540 DCB "BlockInfo",0
541 DCB "ChangeID",0
542 DCB "Resize",0
543 DCB "MidExtend",0
544 DCB "Save",0
545 DCB "Load",0
546 DCB "Reduce",0
547 DCB "Compact",0
548 DCB "Lock",0
549 DCB "Unlock",0
550 DCB "ClaimAnchor",0
551 DCB "ReleaseAnchor",0
552 DCB "ReadSpriteSize",0
553 DCB "Describe",0
554 DCB "IntegrityCheck",0
555 DCB "ChangeAnchor",0
556 DCB 0
557
558 LTORG
559
560 ; --- *Dynamite_Clear ---
561
562 dyn__clear ROUT
563
564 STMFD R13!,{R14} ;Save a register
565 LDR R12,[R12] ;Load the workspace address
566
567 ; --- Empty the heap ---
568
569 LDR R0,dyn_areaSize ;Get the area size
570 LDR R1,dyn_log2PageSize ;And log 2 of page size
571 MOV R0,R0,LSR R1 ;Number of pages in area
572 BL da_removePages ;Remove pages
573
574 ; --- Free all the anchors ---
575
576 BL danc_quit ;Free all allocated anchors
577
578 ; --- Reset the heap variables ---
579
580 MOV R0,#0 ;Initialise some workspace
581 STR R0,dyn_areaSize ;Dynamic area not created yet
582 STR R0,dyn_heapSize ;No data in the heap
583 STR R0,dyn_lockCount ;And clear the lock counter
584 STR R0,dyn_ancTable ;Clear the free anchor table
585 STR R0,dyn_ancList ;And the anchor block list
586 MOV R0,#hpFlag_tidy ;We are compacted now
587 STR R0,dyn_hpFlags ;So make a note of this
588
589 LDMFD R13!,{PC}^ ;And return to caller
590
591 LTORG
592
593 ; --- *Commands ---
594
595 AREA |Dynamite$$Commands|,CODE,READONLY
596
597 DCB "Dynamite_Clear",0
598 DCD dyn__clear
599 DCD 0
600 DCD synt_clear
601 DCD help_clear
602
603 AREA |Dynamite$$Commands_End|,CODE,READONLY
604 DCD 0
605
606 ;----- That's all, folks ----------------------------------------------------
607
608 END