Initial commit.
[amiga/xmodule.git] / Startup.asm
1 ;**
2 ;** Startup.asm
3 ;**
4 ;** Copyright (C) 1994,95,96,97 Bernardo Innocenti
5 ;**
6 ;** Amiga/m68k startup code for XModule
7 ;**
8
9         INCLUDE "exec/types.i"
10         INCLUDE "exec/alerts.i"
11         INCLUDE "exec/nodes.i"
12         INCLUDE "exec/lists.i"
13         INCLUDE "exec/ports.i"
14         INCLUDE "exec/libraries.i"
15         INCLUDE "exec/tasks.i"
16         INCLUDE "exec/memory.i"
17         INCLUDE "exec/macros.i"
18         INCLUDE "exec/execbase.i"
19         INCLUDE "libraries/dos.i"
20         INCLUDE "libraries/dosextens.i"
21         INCLUDE "workbench/startup.i"
22
23
24 AbsExecBase     EQU     4
25
26 ;**************************************************************************
27 ; External symbol definitions and references
28 ;**************************************************************************
29
30         xdef    _Start
31         xdef    @_XCEXIT
32         xdef    _SysBase,_DOSBase
33         xdef    _ThisTask
34         xdef    _StdOut
35         xdef    _WBenchMsg
36
37         xdef    _SPrintf
38         xdef    _VSPrintf
39         xdef    _AsmAllocVecPooled
40         xdef    _AsmFreeVecPooled
41         xdef    _AsmCAllocPooled
42
43         xref    _LinkerDB               ; linker defined base value
44         xref    __BSSBAS                ; linker defined base of BSS
45         xref    __BSSLEN                ; linker defined length of BSS
46         xref    ___main                 ; Name of C entry point
47
48         xref    _AsmAllocPooled
49         xref    _AsmFreePooled
50
51         IFD     DEBUG
52         xref    _kprintf
53         ENDC
54
55         IFND    STKSIZE
56 STKSIZE EQU     8192
57         ENDC
58
59 ;**************************************************************************
60 ; Macro definitions
61 ;**************************************************************************
62
63
64 PUSH    MACRO                           ; push to stack
65         move.\0 \1,-(sp)                ; push.(w|l) <ea>
66         ENDM
67
68 POP     MACRO                           ; pop from stack
69         move.\0 (sp)+,\1              ; pop.(w|l) <ea>
70         ENDM
71
72
73
74 ;**************************************************************************
75 ; Code entry point
76 ;**************************************************************************
77
78         SECTION __MERGED,code
79
80 _Start:
81
82         NEAR
83         lea     _LinkerDB,a4            ; load base register
84         move.l  AbsExecBase.w,a6
85
86 ; The BSS segment is being cleared by LoadSeg() starting from V37
87 ;
88 ;       lea     __BSSBAS,a3             ; get base of BSS
89 ;       moveq   #0,d1
90 ;       move.l  #__BSSLEN,d0            ; get length of BSS in longwords
91 ;       bra.s   .clr_lp                 ; and clear for length given
92 ;.clr_bss:
93 ;       move.l  d1,(a3)+
94 ;.clr_lp:
95 ;       dbf     d0,.clr_bss
96
97         move.l  a7,_StackPtr(a4)        ; Save StackPtr
98         move.l  a6,_SysBase(a4)         ; Save SysBase
99
100
101 ; Find our Task (Process) structure
102         suba.l  a1,a1
103         JSRLIB  FindTask                ; FindTask (NULL)
104         move.l  d0,a3
105         move.l  d0,_ThisTask(a4)
106
107
108 ;**************************************************************************
109 ; CPU checking
110 ;**************************************************************************
111
112         IFD     _MC68020_
113         btst.b  #AFB_68020,AttnFlags+1(a6)
114         beq.s   returnfail
115         ENDC
116
117
118 ;**************************************************************************
119 ; Open dos.library
120 ;**************************************************************************
121
122         lea     DOSName(PC),a1
123         moveq.l #37,d0
124         JSRLIB  OpenLibrary
125         move.l  d0,_DOSBase(a4)
126         beq.s   returnfail
127
128 ; Find output
129         move.l  d0,a6                   ; Load DOSBase in A6
130         JSRLIB  Output                  ; Call Output()
131         move.l  d0,_StdOut(a4)          ; Save result
132         move.l  _SysBase(a4),a6         ; Restore SysBase in A6
133
134 ; are we running as a son of Workbench?
135         move.l  pr_CurrentDir(a3),__curdir(a4)
136         move.l  pr_CLI(a3),d0
137         bne.s   cli_stack
138
139
140 ;**************************************************************************
141 ;* Workbench Startup Code: get for startup message
142 ;**************************************************************************
143
144         lea     pr_MsgPort(a3),a0       ; our process message port
145         JSRLIB  WaitPort
146         lea     pr_MsgPort(a3),a0       ; our process message port
147         JSRLIB  GetMsg
148         move.l  d0,_WBenchMsg(a4)
149
150         move.l  d0,a2                   ; get first argument
151         move.l  sm_ArgList(a2),d0
152         beq.s   .wb_stack
153
154         move.l  _DOSBase(a4),a6         ; CurrentDir()
155         move.l  d0,a0
156         move.l  wa_Lock(a0),d1
157         JSRLIB  DupLock
158         move.l  d0,__curdir(a4)
159         move.l  d0,d1
160         JSRLIB  CurrentDir
161         move.l  _SysBase(a4),a6 ; Restore SysBase in A6
162
163 ; Now calculate the remaining stack size (SP - TC_SPLOWER)
164
165 .wb_stack:
166         move.l  sp,d0
167         sub.l   TC_SPLOWER(a3),d0
168         bra.s   swapstack
169
170
171 cli_stack:
172
173 ; get the size of the stack cli_DefaultStack
174 ; D0 still holds process->pr_CLI
175
176         lsl.l   #2,d0                   ; Shift BPTR
177         move.l  d0,a0
178         move.l  cli_DefaultStack(a0),d0
179         lsl.l   #2,d0                   ; # longwords -> # bytes
180
181
182
183 ;**************************************************************************
184 ;* Stack swapping code
185 ;**************************************************************************
186
187 swapstack:
188         cmpi.l  #STKSIZE,d0             ; D0 = current stack size
189         bcc.s   do_main
190
191
192 ; current stack is not as big as STKSIZE says it needs
193 ; to be.  Allocate a new one.
194
195         IFD     DEBUG
196
197         lea     .msg(pc),a0
198         PUSH.l  a0                      ; push format string
199         jsr     _kprintf                ; call kprintf()
200         addq    #4,sp                   ; fix stack
201         bra.s   .end_debug
202
203 .msg:   dc.b    'Startup.asm: Allocating new stack...',$0A, 0
204         even
205 .end_debug:
206
207         ENDC
208
209         move.l  #STKSIZE,d0
210
211         moveq.l #MEMF_PUBLIC,d1
212         JSRLIB  AllocMem
213         tst.l   d0
214         bne.s   .do_swap
215
216         moveq   #RETURN_FAIL,d7         ; Fail
217         bra.s   exitdos
218
219 .do_swap:
220
221 ; Call StackSwap to set up the new stack
222
223         lea     stackswapstruct(a4),a0
224         move.l  d0,(a0)                 ; stk_Lower
225         add.l   #STKSIZE,d0             ; SP to top of new stack (base + size)
226         move.l  d0,stk_Pointer(a0)      ; stk_Pointer
227         move.l  d0,stk_Upper(a0)        ; stk_Upper
228         JSRLIB  StackSwap
229
230
231
232 ;**************************************************************************
233 ; Call main()
234 ;**************************************************************************
235
236 do_main:
237
238         IFD     DEBUG
239 ; Fill all free stack space with a magic number to check
240 ; maximum program stack usage later.
241
242         move.l  #$DEADF00D,d0
243         move.l  TC_SPLOWER(a3),a0
244
245 .fillstack:
246         move.l  d0,(a0)+
247         cmp.l   a0,sp
248         bgt.s   .fillstack
249
250         ENDC
251
252
253         jsr     ___main(pc)             ; call C entrypoint
254
255
256 @XCEXIT:                                ; XCEXIT() routine
257 @_XCEXIT:
258
259 ; Save Return Code
260         move.l  d0,d7
261
262         IFD     DEBUG
263
264 ; Check maximum stack used during execution.
265 ; Search the first longword not containing our magic number.
266 ;
267 ;           <- TC_SPUPPER     <- top of stack
268 ; |xxxxxxxx|               \
269 ; |xxxxxxxx|               |- stack used by startup code
270 ; |xxxxxxxx|               /
271 ; |yyyyyyyy|<- sp          \  <- current stack position
272 ; |yyyyyyyy|               |
273 ; |yyyyyyyy|               |
274 ; |yyyyyyyy|               |- stack used by C program
275 ; |yyyyyyyy|               |
276 ; |yyyyyyyy|               |
277 ; |yyyyyyyy|<- Pivot (d0)  /  <- last used longword
278 ; |DEADF00D|               \
279 ; |DEADF00D|               |
280 ; |DEADF00D|               |- unused stack
281 ; |DEADF00D|               |
282 ; |DEADF00D|<- TC_SPLOWER  /  <- bottom of stack
283 ;
284
285         move.l  TC_SPLOWER(a3),a0
286         move.l  #$DEADF00D,d0
287
288 .cmpstack:
289         move.l  (a0)+,d1                ; read one longword and go on next
290         cmp.l   d0,d1                   ; is the magic number still there?
291         beq.s   .cmpstack               ; yes: loop again
292
293         move.l  a0,d0                   ; make a copy of the Pivot
294
295         move.l  TC_SPLOWER(a3),d1
296         sub.l   d1,d0                   ; Pivot - TC_SPLOWER
297         PUSH.l  d0                      ; push unused stack size (argument 4)
298
299         move.l  TC_SPUPPER(a3),d0
300         sub.l   a0,d0                   ; TC_SPUPPER - Pivot
301         PUSH.l  d0                      ; push used stack size (argument 3)
302
303         move.l  TC_SPUPPER(a3),d0
304         sub.l   d1,d0                   ; TC_SPUPPER - TC_SPLOWER
305         PUSH.l  d0                      ; push total stack size (argument 2)
306
307         pea     .msg(pc)                ; push format string (argument 1)
308         jsr     _kprintf                ; output debug string with kprintf()
309
310         lea     16(sp),sp               ; fix stack (4 arguments)
311         bra.s   .end_debug
312
313 .msg:   dc.b    'Startup.asm: Total stack size: %ld,  Used: %ld,  Unused: %ld.',$0A, 0
314         even
315 .end_debug:
316
317         move.l  d7,d0                   ; restore return code
318         ENDC
319
320
321
322 ; Swap back to original stack
323         move.l  _SysBase(a4),a6
324         lea     stackswapstruct(a4),a0
325         tst.l   (a0)
326         beq.s   .noswap
327
328         JSRLIB  StackSwap
329
330 ; free the stack
331         move.l  stackswapstruct(a4),a1  ; FreeMem (stk_Lower,STKSIZE)
332         move.l  #STKSIZE,d0
333         JSRLIB  FreeMem
334
335 .noswap:
336         move.l  _StackPtr(a4),a2        ; restore original StackPtr
337
338 ; if we ran from CLI, skip workbench cleanup:
339         tst.l   _WBenchMsg(a4)
340         beq.s   exitdos
341         move.l  _DOSBase(a4),a6
342         move.l  __curdir(a4),d1
343         beq.s   .nounlock
344         JSRLIB  UnLock
345
346 .nounlock:
347
348 ; return the startup message to our parent.
349 ; We Forbid() so Workbench can't UnLoadSeg() us
350 ; before we are done.
351
352         move.l  _SysBase(a4),a6
353         JSRLIB  Forbid
354         move.l  _WBenchMsg(a4),a1
355         JSRLIB  ReplyMsg
356
357 exitdos:
358         move.l  _DOSBase(a4),a1         ; Close dos.library
359         JSRLIB  CloseLibrary
360         move.l  d7,d0                   ; Put return code in D0
361         rts                             ; This RTS sends us back to our caller
362
363 returnfail:
364         moveq.l #RETURN_FAIL,d0
365         rts
366
367
368
369 ;**************************************************************************
370 ;* Simple (V)SPrintf routines
371 ;**************************************************************************
372
373 _SPrintf:
374         movem.l a2-a3/a6,-(sp)          ; Save registers
375
376         move.l   4+12(sp),a3            ; Get destination buffer
377         move.l   8+12(sp),a0            ; Get format string
378         lea.l   12+12(sp),a1            ; Get arguments
379         lea.l   StuffChar(pc),a2        ; Get formatting routine
380
381         move.l  _SysBase(a4),a6         ; Get ExecBase
382         JSRLIB  RawDoFmt                ; Format the string
383
384         movem.l (sp)+,a2-a3/a6          ; Restore registers
385
386         rts
387
388
389
390 _VSPrintf:
391         movem.l a2/a3/a6,-(sp)
392
393         move.l   4+12(sp),a3
394         move.l   8+12(sp),a0
395         move.l  12+12(sp),a1
396         lea     StuffChar(pc),a2
397
398         move.l  _SysBase(a4),a6
399         JSRLIB  RawDoFmt
400
401         movem.l (sp)+,a2/a3/a6
402
403         rts
404
405 StuffChar:
406         move.b  d0,(a3)+
407         rts
408
409
410
411 ;**************************************************************************
412 ;* Memory pools support
413 ;**************************************************************************
414
415 ;
416 ; AsmAllocVecPooled (Pool, memSize, SysBase)
417 ;                    a0    d0       a6
418 ;
419 _AsmAllocVecPooled:
420         addq.l  #4,d0           ; Get space for tracking
421         move.l  d0,-(sp)        ; Save the size
422
423  IFD    OS30_ONLY
424         JSRLIB  AllocPooled
425  ELSE
426         jsr     _AsmAllocPooled ; Call pool...
427  ENDC
428
429         move.l  (sp)+,d1        ; Get size back...
430         tst.l   d0              ; Check for error
431         beq.s   .fail           ; If NULL, failed!
432         move.l  d0,a0           ; Get pointer...
433         move.l  d1,(a0)+        ; Store size
434         move.l  a0,d0           ; Get result
435 .fail   rts                     ; Return
436
437
438
439 ;
440 ; AsmFreeVecPooled (Pool, Memory, SysBase)
441 ;                   a0    a1      a6
442
443 _AsmFreeVecPooled:
444         move.l  a1,d0           ; Test for NULL
445         beq.s   .noblock
446         move.l  -(a1),d0        ; Get size / ajust pointer
447
448  IFD OS30_ONLY
449         JMPLIB  FreePooled
450  ELSE
451         jmp     _AsmFreePooled
452  ENDC
453
454 .noblock
455         rts
456
457 ;
458 ; CAllocPooled (Pool, memSize, SysBase)
459 ;               a0    d0       a6
460
461 _AsmCAllocPooled:
462         move.l  d0,-(sp)        ; Save the size
463  IFD OS30_ONLY
464         JSRLIB  AllocPooled     ; Allocate memory from pool...
465  ELSE
466         jsr     _AsmAllocPooled ; Allocate memory from pool...
467  ENDC
468         move.l  (sp)+,d1        ; Get size back...
469         move.l  d0,a0
470         tst.l   d0              ; Check for error
471         beq.s   .fail           ; If NULL, failed!
472
473         move.l  d0,-(sp)        ; Save result
474
475
476         moveq   #$F,d0          ; Check for odd length (not multiple of 16)
477         and.w   d1,d0
478         beq.s   .noneed
479
480         move.l  a0,a1
481         add.l   d1,a1
482         subq.w  #1,d0           ; DBRA loops once too much for us
483
484 .clear2 move.b  #0,-(a1)        ; Clear up to 15 bytes
485         dbra    d0,.clear2
486
487 .noneed
488         lsr.l   #4,d1           ; Divide by 16
489         tst.l   d1              ; Check for 0
490         beq.s   .endclear
491
492         moveq   #0,d0           ; D0 will be used to clear our memory buffer
493         subq.l  #1,d1           ; DBRA does one cycle more!
494
495 .clear  move.l  d0,(a0)+        ; Clear memory block
496         move.l  d0,(a0)+
497         move.l  d0,(a0)+
498         move.l  d0,(a0)+
499         dbra    d1,.clear
500         swap    d1              ; dbra only works on words
501         subq.w  #1,d1
502         bmi.s   .endclear
503         swap    d1
504         bra.s   .clear
505 .endclear
506
507         move.l  (sp)+,d0        ; Get result back...
508 .fail   rts                     ; Return
509
510
511
512 DOSName dc.b    'dos.library',0
513
514
515
516 ;**************************************************************************
517 ;* Data section
518 ;**************************************************************************
519
520         SECTION __MERGED,BSS
521
522 _SysBase        ds.l    1
523 _DOSBase        ds.l    1
524 _ThisTask       ds.l    1
525 _StdOut         ds.l    1
526 _StackPtr       ds.l    1
527 _WBenchMsg      ds.l    1
528 __curdir        ds.l    1
529
530 stackswapstruct ds.b    StackSwapStruct_SIZEOF
531
532         END