
; Exec-Support-Routinen.

      NOLIST
      INCLUDE  "exec/types.i"
      INCLUDE  "exec/nodes.i"
      INCLUDE  "exec/lists.i"
      INCLUDE  "exec/memory.i"
      INCLUDE  "exec/interrupts.i"
      INCLUDE  "exec/ports.i"
      INCLUDE  "exec/io.i"
      INCLUDE  "exec/libraries.i"
      INCLUDE  "exec/tasks.i"
      INCLUDE  "exec/execbase.i"
      INCLUDE  "lvo/exec.i"
      LIST



_SysBase EQU   4

CALL  MACRO
   IFEQ NARG-2
      move.l   \2,a6
   ENDC
   IFLE NARG-2
      jsr      _LVO\1(a6)
      MEXIT
   ENDC
      FAIL     CALL MACRO: PARAMETERFEHLER
      ENDM










;****************************************************************************
; NewList.

      IFD   NewList

      XDEF  _NewList

_NewList
      move.l   4(SP),a0
      NEWLIST  a0
      rts

      ENDC










;****************************************************************************
; BeginIO.

      IFD   BeginIO

      XDEF  _BeginIO

_BeginIO
      move.l   4(SP),a1
      BEGINIO
      rts

      ENDC










;****************************************************************************
; CreatePort und DeletePort.

      IFD   CreatePort

      XDEF  _CreatePort,_DeletePort





; Portzeiger = CreatePort (Namenzeiger, Priorität)
; Rückgabewert in D0; gibt Null zurück, wenn Port nicht erzeugbar ist.

_CreatePort_REG   REG   d1/d7/a0-a2/a6    ; 6 Register
REGISTER SET   6

_CreatePort
      ; Hole ein Signalbit.
      movem.l  _CreatePort_REG,-(SP)
      moveq    #-1,d0               ; beliebiges Bit
      CALL     AllocSignal,_SysBase
      move.l   d0,d7                ; belegt ?
      bmi.s    1$                   ; nein, gib Null zurück

      ; Belege die Port-Struktur.
      moveq    #MP_SIZE,d0
      move.l   #MEMF_CLEAR!MEMF_PUBLIC,d1
      CALL     AllocMem
      tst.l    d0                   ; belegt ?
      bne.s    2$
      move.l   d7,d0                ; nein, Signal freigeben
      CALL     FreeSignal
1$    moveq    #0,d0                ; gib Null zurück
      bra.s    0$

      ; Initialisiere den Port.
2$    move.l   d0,a2
      move.l   REGISTER*4+4(SP),LN_NAME(a2)  ; Name
      move.b   REGISTER*4+8+3(SP),LN_PRI(a2) ; Priorität, nimm nur 8 Bits !
      move.b   #NT_MSGPORT,LN_TYPE(a2) ; Typ
      move.b   #PA_SIGNAL,MP_FLAGS(a2)
      move.b   d7,MP_SIGBIT(a2)     ; Signalbit
      suba.l   a1,a1
      CALL     FindTask             ; finde uns selber
      move.l   d0,MP_SIGTASK(a2)

      ; Melde den Port an das System.
      tst.l    REGISTER*4+4(SP)     ; ist Namenzeiger Null ?
      beq.s    3$
      move.l   a2,a1
      CALL     AddPort              ; nein
      bra.s    4$

3$    lea      MP_MSGLIST(a2),a0    ; wenn Nullzeiger
      NEWLIST  a0
4$    move.l   a2,d0                ; Portzeiger

      ; Fertig.
0$    movem.l  (SP)+,_CreatePort_REG
      rts





; DeletePort (Portzeiger)

_DeletePort_REG   REG   d0-d1/a0-a2/a6    ; 6 Register
REGISTER SET   6

_DeletePort
      ; Entferne den Port aus dem System.
      movem.l  _DeletePort_REG,-(SP)
      move.l   _SysBase,a6
      move.l   REGISTER*4+4(SP),a2
      move.l   LN_NAME(a2),d0
      beq.s    1$
      move.l   d0,a1
      CALL     RemPort

      ; Lösche Portwerte.
1$    moveq    #-1,d0
      move.b   d0,LN_TYPE(a2)
      move.l   d0,MP_MSGLIST+LH_HEAD(a2)

      ; Gib das Signalbit und den Speicher frei.
      moveq    #0,d0                ; FreeSignal braucht 32-Bit-Wert !
      move.b   MP_SIGBIT(a2),d0
      CALL     FreeSignal
      move.l   a2,a1
      moveq    #MP_SIZE,d0
      CALL     FreeMem

      ; Fertig.
      movem.l  (SP)+,_DeletePort_REG
      rts





      ENDC










;****************************************************************************
; CreateStdIO, DeleteStdIO, CreateExtIO und DeleteExtIO.

      IFD   CreateIO

      XDEF  _CreateStdIO,_DeleteStdIO,_CreateExtIO,_DeleteExtIO





; IOStdReq-Zeiger = CreateStdIO (ioReplyPort)
; Rückgabe in D0; gibt Null zurück, wenn etwas schiefging.

_CreateStdIO
      pea      IOSTD_SIZE
      move.l   4+4(SP),-(SP)
      bsr.s    _CreateExtIO
      addq     #2*4,SP              ; korrigiere Stack
      rts





; IORequest-Zeiger = CreateExtIO (ioReplyPort, Requestgröße)
; Rückgabe in D0; gibt Null zurück, wenn etwas schiefging.

_CreateExtIO_REG  REG   d1/a0-a1/a6    ; 4 Register
REGISTER SET   4

_CreateExtIO
      ; Ist der Portzeiger Null ?
      movem.l  _CreateExtIO_REG,-(SP)
      move.l   REGISTER*4+4(SP),d0
      beq.s    0$                   ; ja, Ende mit Null

      ; Belege die Request-Struktur.
      move.l   REGISTER*4+8(SP),d0  ; Requestgröße
      move.l   #MEMF_CLEAR!MEMF_PUBLIC,d1
      CALL     AllocMem,_SysBase
      tst.l    d0                   ; belegt ?
      beq.s    0$                   ; nein, Ende mit Null

      ; Initialisiere die Struktur.
      move.l   d0,a0
      move.b   #NT_MESSAGE,LN_TYPE(a0)
      move.w   REGISTER*4+8+2(SP),MN_LENGTH(a0)    ; nimm nur 16 Bit !
      move.l   REGISTER*4+4(SP),MN_REPLYPORT(a0)

      ; Fertig.
0$    movem.l  (SP)+,_CreateExtIO_REG
      rts





; DeleteExtIO (ioExt)
; DeleteStdIO ist funktionell identisch !

_DeleteExtIO_REG  REG   d0-d1/a0-a1/a6    ; 5 Register
REGISTER SET   5

_DeleteStdIO
_DeleteExtIO
      ; Wurde ein Nullzeiger übergeben ?
      movem.l  _DeleteExtIO_REG,-(SP)
      move.l   REGISTER*4+4(SP),d0
      beq.s    0$                   ; ja, Ende

      ; Mache den Request kaputt und gib ihn frei.
      move.l   d0,a1
      moveq    #-1,d0
      move.b   d0,LN_TYPE(a1)
      move.l   d0,IO_DEVICE(a1)
      move.l   d0,IO_UNIT(a1)
      moveq    #0,d0                ; FreeMem braucht 32 Bit !
      move.w   MN_LENGTH(a1),d0
      CALL     FreeMem,_SysBase

      ; Fertig.
0$    movem.l  (SP)+,_DeleteExtIO_REG
      rts





      ENDC










;****************************************************************************
; CreateTask.

      IFD   CreateTask

      XDEF  _CreateTask,_DeleteTask





; Taskzeiger = CreateTask (Namenzeiger, Priorität, AnfangsPC, Stackgröße)
; Rückgabe in D0; gibt im Fehlerfall Null zurück.

ML_GROESSE  EQU   ML_SIZE+2*ME_SIZE

_CreateTask_REG   REG   d1/d7/a0-a4/a6
REGISTER SET   8

_CreateTask
      ; Runde die Stackgröße auf Langwortgrenze.
      movem.l  _CreateTask_REG,-(SP)
      link     a4,#-ML_GROESSE      ; Platz für zweite MemList
      move.l   REGISTER*4+8+4*3(a4),d7 ; Stackgröße
      addq.l   #3,d7
      and      #~3,d7

      ; Benutze die zweite MemList, damit CreateTask reentrant ist.
      lea      _TaskMemTemplate(PC),a2 ; Quelle
      move.l   SP,a1                ; Ziel
      move.l   a1,a0                ; für AllocEntry
      moveq    #(ML_GROESSE/2)-1,d0
1$    move.w   (a2)+,(a1)+
      dbra     d0,1$
      move.l   d7,-ML_GROESSE+ML_SIZE+ME_SIZE+ME_LENGTH(a4) ; Stackgröße

      ; Belege den Speicher.
      CALL     AllocEntry,_SysBase
      bclr     #31,d0               ; alles Ok ?
      beq.s    2$
      moveq    #0,d0                ; nein
      bra.s    0$

      ; Hole die Speicherzeiger.
2$    move.l   d0,a1
      move.l   ML_SIZE+ME_ADDR(a1),a2   ; Task-Struktur
      move.l   ML_SIZE+ME_SIZE+ME_ADDR(a1),a0   ; Stack

      ; Setze die Stackwerte.
      move.l   a0,TC_SPLOWER(a2)
      add.l    d7,a0                ; addiere Stackgröße
      move.l   a0,TC_SPUPPER(a2)
      move.l   a0,TC_SPREG(a2)

      ; Setze Taskwerte.
      move.b   #NT_TASK,LN_TYPE(a2)
      move.b   REGISTER*4+8+4*1+3(a4),LN_PRI(a2)   ; Priorität, nimm 8 Bits
      move.l   REGISTER*4+8+4*0(a4),LN_NAME(a2)    ; Name

      ; Klebe die MemList an die Task.
      lea      TC_MEMENTRY(a2),a0
      NEWLIST  a0
      CALL     AddHead              ; statt des Makro, damit's kurz ist

      ; Melde dem System die Task.
      move.l   a2,a1                ; Task
      move.l   a2,d7                ;   merken
      move.l   REGISTER*4+8+4*2(a4),a2 ; Anfangs-PC
      suba.l   a3,a3                ; finalPC
      CALL     AddTask
      move.l   d7,d0                ; Rückgabewert: Taskzeiger

      ; Fertig.
0$    unlk     a4
      movem.l  (SP)+,_CreateTask_REG
      rts





; DeleteTask (Taskzeiger)

_DeleteTask_REG   REG   d0-d1/a0-a1/a6
REGISTER SET   5

_DeleteTask
      movem.l  _DeleteTask_REG,-(SP)
      move.l   REGISTER*4+4(SP),a1  ; das Freigeben der Taskstruktur und des
      CALL     RemTask,_SysBase     ; Stacks wird von RemTask erledigt
      movem.l  (SP)+,_DeleteTask_REG
      rts





_TaskMemTemplate
   ; Die Memory-Liste
   dcb.b LN_SIZE,0         ; kein Node
   dc.w  2                 ; 2 Einträge:
      dc.l  MEMF_PUBLIC!MEMF_CLEAR,TC_SIZE   ; für die Task-Struktur
      dc.l  MEMF_CLEAR,0      ; für den Stack, Größe wird später eingetragen





      ENDC










      END

