home *** CD-ROM | disk | FTP | other *** search
- *
- * Load Device by Jeff Kelley
- *
- * You may give this software to anyone you please. If you sell it for
- * a profit, you'll just have to live with your conscience.
- *
- * (in W.W. Howe V1.0.2 Assembler)
- *
- LOAD_TASK_PRIORITY EQU 25
- LOAD_PRIORITY EQU 0
- MICROSPERSEC EQU 1000000
- INTERVAL EQU 5 ; Default time interval length in seconds (sample period)
- TICKS EQU 61 ; Default number of ticks (when samples are taken) per interval
-
- INCLUDE "exec/types.i"
- INCLUDE "exec/nodes.i"
- INCLUDE "exec/lists.i"
- INCLUDE "exec/ports.i"
- INCLUDE "exec/libraries.i"
- INCLUDE "exec/devices.i"
- INCLUDE "exec/memory.i"
- INCLUDE "exec/io.i"
- INCLUDE "exec/resident.i"
- INCLUDE "exec/tasks.i"
- INCLUDE "exec/errors.i"
- INCLUDE "exec/initializers.i"
- INCLUDE "exec/semaphores.i"
- INCLUDE "exec/execbase.i"
- INCLUDE "hardware/dmabits.i"
- INCLUDE "hardware/custom.i"
- INCLUDE "devices/timer.i"
- INCLUDE "devices/load.i"
- INCLUDE "asmsupp.i"
- INCLUDE "macros.i"
-
- XLIB OpenDevice
- XLIB OpenLibrary
- XLIB AddDevice
- XLIB AddTask
- XLIB CloseDevice
- XLIB Signal
- XLIB Remove
- XLIB RemTask
- XLIB PutMsg
- XLIB GetMsg
- XLIB ReplyMsg
- XLIB Wait
- XLIB DoIO
- XLIB AvailMem
- XLIB FreeMem
- XLIB Disable
- XLIB Enable
- XLIB Forbid
- XLIB Permit
- XLIB AllocSignal
- XLIB InitSemaphore
- XLIB ObtainSemaphore
- XLIB ReleaseSemaphore
- XLIB SetTaskPri
- XREF _AbsExecBase
- XREF _custom
-
- SECTION load.device,CODE
-
- FirstAddress:
- CLEAR d0
- rts
-
- initDDescrip:
- DC.W RTC_MATCHWORD
- DC.L initDDescrip
- DC.L EndCode
- DC.B RTF_AUTOINIT
- DC.B VERSION
- DC.B NT_DEVICE
- DC.B LOAD_PRIORITY
- DC.L LoadName
- DC.L idString
- DC.L Init
-
- VERSION EQU 1
- REVISION EQU 0
-
- TimerName TIMERNAME
- LoadName LOADNAME
-
- idString:
- DC.B 'load.device 1.0 (16 October 1987)',13,0
-
- Init:
- DC.L LD_SIZE
- DC.L funcTable
- DC.L dataTable
- DC.L initRoutine
-
- funcTable:
- DC.L Open
- DC.L Close
- DC.L Expunge
- DC.L FirstAddress ; Null Command (reserved for expansion)
-
- DC.L BeginIO
- DC.L AbortIO
-
- DC.L -1
-
- dataTable:
- INITBYTE LN_TYPE,NT_DEVICE
- INITLONG LN_NAME,LoadName
- INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
- INITWORD LIB_VERSION,VERSION
- INITWORD LIB_REVISION,REVISION
- INITLONG LIB_IDSTRING,idString
- DC.L 0
-
- *********************************************************************
- *
- * InitRoutine - initialize the load device structure
- *
- * D0 = Device Pointer
- * A0 = Segment List
- * A6 = SysBase
- * If this routine returns non-zero, it will be linked into system
- * device list.
-
-
- initRoutine:
- move.l a5,-(sp)
- movea.l d0,a5 ; get device pointer into safe register
-
- move.l a0,LD_seglist(a5)
- move.l a6,LD_sysbase(a5)
-
- * Initialize the Message Port.
- lea LD_Port(a5),a0
- move.l #LoadName,LN_NAME(a0)
- move.b #NT_MSGPORT,LN_TYPE(a0)
- move.b #PA_IGNORE,MP_FLAGS(a0)
- lea MP_MSGLIST(a0),a0
- NEWLIST a0
-
- move.w #INTERVAL,LD_Interval(a5)
- move.w #TICKS,LD_Ticks(a5)
- move.l a6,-(sp)
- movea.l a5,a6
- bsr ComputeDelay
- move.l (sp)+,a6
-
- * Initialize the semaphore.
- lea LD_Semaphore(a5),a0
- CALLSYS InitSemaphore ; InitSemaphore(signalSemaphore)
- ; A0
- lea LD_Semaphore(a5),a0
- CALLSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
- ; A0
-
- * Compute the maximum MEMF_CHIP and MEMF_FAST
- move.l MemList+LH_HEAD(a6),a0 ; get pointer to first MemHeader node
- DO addmemory
- move.l (a0),d1 ; check LN_SUCC
- UNTIL eq,addmemory
- move.l MH_UPPER(a0),d0
- sub.l MH_LOWER(a0),d0
- btst #MEMB_CHIP,MH_ATTRIBUTES+1(a0)
- IF ne,chipmemory
- add.l d0,LD_Max_Chip(a5)
- ELSE chipmemory
- add.l d0,LD_Max_Fast(a5)
- FI chipmemory
- move.l d1,a0
- OD addmemory
-
- * Create the Load Device task.
- lea LD_TaskCB(a5),a1
- move.b #NT_TASK,LN_TYPE(a1)
- move.b #LOAD_TASK_PRIORITY,LN_PRI(a1)
- move.l #LoadName,LN_NAME(a1)
- lea LD_Stack(a5),a0
- move.l a0,TC_SPLOWER(a1)
- add.l #LOAD_STACK_SIZE,a0
- move.l a0,TC_SPUPPER(a1)
- move.l a0,TC_SPREG(a1)
- lea TC_MEMENTRY(a1),a0
- NEWLIST a0
- lea Task_Start,a2
- movea.l #0,a3
- CALLSYS AddTask ; AddTask(taskCB, initialPC, finalPC)
- ; A1 A2 A3
- move.l a5,d0 ; Return device pointer
-
- move.l (sp)+,a5 ; restore a5
- rts
-
- ***************************************************************************
- *
- * Open
- *
- * A6 = Device
- * A1 = IOB
- * D0 = Unit Number
- * D1 = Flags
- * Return: Set IO_ERROR Field to indicate success/errno
-
- Open:
- btst #LDB_OPEN_EXCL,LD_flags(a6)
- IF eq,shared_access_ok
- btst #LDB_OPEN_EXCL,d1
- IF ne,want_exclusive
- tst.w LIB_OPENCNT(a6)
- IF ne,device_in_use
- move.b LDERR_IN_USE,IO_ERROR(a1)
- rts
- FI device_in_use
- bset #LDB_OPEN_EXCL,LD_flags(a6)
- FI want_exclusive
- addq.w #1,LIB_OPENCNT(a6)
- cmpi.w #1,LIB_OPENCNT(a6)
- IF eq,startup
- lea LD_Semaphore(a6),a0
- LINKSYS ReleaseSemaphore ; ReleaseSemaphore(signalSemaphore)
- ; A0
- FI startup
- move.w LD_Interval(a6),LV_INTERVAL(a1)
- move.w LD_Ticks(a6),LV_TICKS(a1)
- move.b LD_TaskCB+LN_PRI(a6),LV_PRI(a1)
- clr.b IO_ERROR(a1)
- ELSE shared_access_ok
- move.b #LDERR_ACCESS_DENIED, IO_ERROR(a1)
- FI shared_access_ok
- rts
-
- ***************************************************************************
- *
- * Close
- *
- * A6 = Device
- * A1 = IOB
- * Return: If the device is no longer open and a delayed expunge is pending,
- * do the expunge and return the segment list. Else return NULL.
-
- Close:
- clr.l IO_DEVICE(a1)
- subq.w #1,LIB_OPENCNT(a6)
- IF eq,do_close
- lea LD_Semaphore(a6),a0
- LINKSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
- ; A0
- bclr #LDB_OPEN_EXCL,LD_flags(a6)
- btst #LIBB_DELEXP,LIB_FLAGS(a6)
- IF ne,go_expunge
- bra.s Expunge
- FI go_expunge
- FI do_close
- CLEAR d0
- rts
-
- ****************************************************************************
- *
- * Expunge
- *
- * A6 = Device
- * Return: If the device is no longer open return seg list. Else set
- * delayed Expunge flag and return NULL.
- Expunge:
-
- move.l a5,-(sp)
- move.l a6,a5
- move.l LD_sysbase(a5),a6
- * Check to see if anyone has us open
-
- tst.w LIB_OPENCNT(a5)
- IF ne,still_open
-
- * It is still open, set delayed Expunge flag
-
- bset #LIBB_DELEXP,LIB_FLAGS(a5)
- CLEAR d0
-
- ELSE still_open
-
- * Go ahead and get rid of us.
-
- move.l LD_seglist(a5),-(a7) ; We need to return this value
-
- * Unlink from device list.
- movea.l a5,a1
- CALLSYS Remove ; Remove(node)
- ; A1
- * Remove the load.device task
- lea LD_TaskCB(a5),a1
- CALLSYS RemTask ; RemTask(taskCB)
- ; A1
- * Close the timer device.
- lea LD_TimerRequest(a5),a1
- CALLSYS CloseDevice ; CloseDevice(ioRequest)
- ; A1
- * Free the memory allocated to the library.
- CLEAR d0
- movea.l a5,a1
- move.w LIB_NEGSIZE(a5),d0
- sub.w d0,a1
- add.w LIB_POSSIZE(a5),d0
- CALLSYS FreeMem ; FreeMem(memBlock, byteSize)
- ; A1 D0
- move.l (a7)+,d0
- FI still_open
- move.l a5,a6
- move.l (sp)+,a5
- rts
-
- *************************************************************************
- *
- * BeginIO
- *
- * A6 = Device
- * A1 = IOB
-
- BeginIO:
- clr.b IO_ERROR(a1)
- move.w IO_COMMAND(a1),d0
- asl.w #2,d0 ; Compute displacement
- lea cmdtable(pc),a0
- add.w d0,a0
- * cmpa.l #cmdtable_end,a0 ; Check to make sure it's in range.
- * (Assembler doesn't handle it right, so...)
- dc.w $B1FC
- dc.l cmdtable_end
- bcs.s cmd_ok ; branch if a0 < #cmdtable_end
- lea cmdtable(pc),a0 ; Get the address of CMD_INVALID
- cmd_ok:
- movea.l (a0),a0
- jmp (a0)
-
- ****************************************************************************
- *
- * AbortIO
- *
- * A6 = Device
- * A1 = IOB
- AbortIO:
- * Scan list for the IOB node
- LINKSYS Forbid
- move.l LD_Port+MP_MSGLIST+LH_HEAD(a6),d1
- DO scanlist
- movea.l d1,a0
- move.l (a0),d1 ; get LN_SUCC
- beq.s not_found
- cmpa.l a0,a1
- WHILE ne,scanlist
- OD scanlist
-
- move.l a1,d1
- REMOVE a1 ; Remove the IOB node from the list.
- LINKSYS Permit
- movea.l d1,a1
- move.b #IOERR_ABORTED,IO_ERROR(a1)
- rts
- not_found:
- LINKSYS Permit
- clr.b IO_ERROR(a1) ; Indicate an error occurred.
- rts
-
- cmdtable:
- DC.L Invalid
- DC.L Reset
- DC.L Read
- DC.L Write
- DC.L Update
- DC.L Clear
- DC.L Stop
- DC.L Start
- DC.L Flush
- DC.L Set
- cmdtable_end:
-
- *******************************************************************
- *
- * A6 = device
- * A1 = IOB
-
- Write:
- Update:
- Clear:
- Invalid:
- move.b #IOERR_NOCMD,IO_ERROR(a1)
- rts
-
- Read:
- * If IO_QUICK is set, get the most recent values and return, do not reply.
- * Otherwise, queue the IO request. Return. Reply will come later.
-
- btst #IOB_QUICK,IO_FLAGS(a1)
- IF ne,do_quickio
- move.l LD_CPU(a6),LV_CPU(a1)
- move.l LD_BLITTER(a6),LV_CPU(a1)
- move.l LD_CHIP(a6),LV_CHIP(a1)
- move.l LD_FAST(a6),LV_FAST(a1)
- ELSE do_quickio
- lea LD_Port(a6),a0
- LINKSYS PutMsg ; PutMsg(msgPort, message)
- FI do_quickio ; A0 A1
- rts
- Stop:
- LINKSYS Forbid
- tst.b LD_stop_count(a6)
- IF eq,stop_load_task
- lea LD_Semaphore(a6),a0
- LINKSYS ObtainSemaphore
- FI stop_load_task
- addq.b #1,LD_stop_count(a6)
- LINKSYS Permit
- rts
- Start:
- tst.b LD_stop_count(a6)
- IF eq,not_stopped
- move.b #LDERR_NOT_STOPPED,IO_ERROR(a1)
- ELSE not_stopped
- LINKSYS Forbid
- subq.b #1,LD_stop_count(a6)
- IF eq,start_load_task
- lea LD_Semaphore(a6),a0
- LINKSYS ReleaseSemaphore
- FI start_load_task
- LINKSYS Permit
- FI not_stopped
- rts
-
- * Reply to all pending requests, setting IOERR_ABORTED.
- Flush:
- LINKSYS Forbid
- DO flushrequests
- lea LD_Port(a6),a0
- LINKSYS GetMsg ; message = GetMsg(msgPort)
- tst.l d0 ; D0 A0
- UNTIL eq,flushrequests
- movea.l d0,a1
- move.b #IOERR_ABORTED,IO_ERROR(a1)
- LINKSYS ReplyMsg ; ReplyMsg(message)
- ; A1
- OD flushrequests
- LINKSYS Permit
- rts
-
- Reset:
- ; Set default values.
- move.w #INTERVAL,LV_INTERVAL(a1)
- move.w #TICKS,LV_TICKS(a1)
- move.b #LOAD_TASK_PRIORITY,LV_PRI(a1)
- ; FALLTHROUGH into the Set command
-
- Set:
- move.l a1,-(sp)
- lea LD_Semaphore(a6),a0
- LINKSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
- ; A0
- move.l (sp)+,a1
- move.w LV_INTERVAL(a1),LD_Interval(a6)
- move.w LV_TICKS(a1),LD_Ticks(a6)
- bsr.s ComputeDelay
- move.b LV_PRI(a1),d0
- lea LD_TaskCB(a6),a1
- LINKSYS SetTaskPri ; oldPriority = SetTaskPri(taskCB, newpriority)
- ; D0.b A1 D0.b
- lea LD_Semaphore(a6),a0
- LINKSYS ReleaseSemaphore ; ReleaseSemaphore(signalSemaphore)
- ; A0
- rts
-
- ***************************************************************************
- *
- * ComputeDelay subroutine - From the LD_Interval and LD_Ticks, compute the
- * delay in seconds and microseconds between ticks.
- *
- * Input: A6 - Load Device
- * LD_Interval(a6) - Interval in seconds
- * LD_Ticks(a6) - Number of Ticks per Interval
- *
- * Output: LD_secs(a6) - delay in seconds
- * LD_micro(a6) - delay in microseconds
- *
- * Destroys: a0,d0,d1
- *
-
- ComputeDelay:
- move.l d2,-(a7)
- CLEAR d1
- move.w LD_Interval(a6),d1 ; INTERVAL in seconds
- move.w LD_Ticks(a6),d2 ; number of TICKS per INTERVAL
- mulu #20,d1 ; multiply d0 by a MICROSPERSEC
- mulu #50000,d1 ; (in 2 steps, since can't mult by >65536)
-
- * d1.l = d1.l / d2.w
-
- movea.w d1,a0
- clr.w d1
- swap d1
- divu d2,d1
- move.l d1,d0
- swap d1
- move.w a0,d0
- divu d2,d0
- move.w d0,d1
-
- * LD_secs = d1.l / MICROSPERSEC
- * LD_micro = d1.l % MICROSPERSEC
-
- clr.l LD_secs(a6)
- DO incrsecs
- cmp.l #MICROSPERSEC,d1
- WHILE ge,incrsecs
- sub.l #MICROSPERSEC,d1
- addi.l #1,LD_secs(a6)
- OD incrsecs
- move.l d1,LD_micro(a6)
-
- move.l (a7)+,d2
- rts
-
- ********************************************************************
- *
- * Load Task
- *
- * Register Usage: a6 : SysBase
- * a2 : Semaphore
- * a3 : TimerPort
- * a4 : TimerMessage
- * a5 : LoadDevice
- *
- * d2 : Current Tick count
- * d3 : Ready Queue counter
- * d4 : Blitter Use counter
- * d5 : Chip Mem available
- * d6 : Fast Mem available
- * d7 : <Free Safety>
-
- * To get a pointer to the Load Device structure, use a7 as a base.
- * It points to the last longword of the stack (which contains the
- * address of a cleanup routine).
- * a7
- * | <---------- LD_Stack -----------> | <- LOAD_STACK_SIZE - 4 -> |
- * |----------------------------------------------------------------------|
- * | Load Device | TimerRequest | etc. | Stack |
- * |----------------------------------------------------------------------|
-
- Task_Start:
- move.l _AbsExecBase,a6
- lea -LD_Stack-LOAD_STACK_SIZE+4(a7),a5 ; Get Load Device ptr
-
- lea LD_Semaphore(a5),a2
-
- * Initialize the Timer Port.
- lea LD_TimerPort(a5),a3
- move.b #NT_MSGPORT,LN_TYPE(a3)
- move.b #PA_SIGNAL,MP_FLAGS(a3)
- moveq.l #-1,d0
- CALLSYS AllocSignal ; signalNum = AllocSignal(signalNum)
- move.b d0,MP_SIGBIT(a3) ; D0 D0
- lea LD_TaskCB(a5),a0
- move.l a0,MP_SIGTASK(a3)
- lea MP_MSGLIST(a3),a0
- NEWLIST a0
-
- * Initialize the timer IO request
- lea LD_TimerRequest(a5),a4
- move.b #NT_MESSAGE,LN_TYPE(a4)
- move.l a3,MN_REPLYPORT(a4)
- move.w #IOTV_SIZE,MN_LENGTH(a4)
-
- * Open the timer.device
- lea TimerName,a0
- movea.l a4,a1
- moveq.l #UNIT_VBLANK,d0
- CLEAR d1
- CALLSYS OpenDevice ; error = OpenDevice(Name,Unit,ioRequest,flags)
- ; D0 A0 D0 A1 D1
- DO mainloop
- move.l a2,a0
- CALLSYS ObtainSemaphore ; ObtainSemaphore(signalSemaphore)
- move.w LD_Ticks(a5),d2 ; A0
- moveq.l #0,d3
- moveq.l #0,d4
-
- * 'tickloop' is done once for each 'tick'.
- DO tickloop
- move.w #TR_ADDREQUEST,IO_COMMAND(a4)
- move.l LD_secs(a5),IOTV_TIME+TV_SECS(a4)
- move.l LD_micro(a5),IOTV_TIME+TV_MICRO(a4)
- movea.l a4,a1
- CALLSYS DoIO ; error = DoIO(ioRequest)
- ; D0 A1
- * Compute System Statistics:
-
- * Measure length of ready queue
- * Note: LoadTask is not in this queue, since we are running.
-
- CALLSYS Disable
- movea.l TaskReady+LH_HEAD(a6),a1 ; Get Pointer to first
- DO readycount ; node into a1.
- move.l (a1),d0 ; Look ahead.
- UNTIL eq,readycount
- addq.l #1,d3
- movea.l d0,a1
- OD readycount
- CALLSYS Enable
-
- * Check if blitter busy
-
- * move.w _custom+dmaconr,d0 ; Assembler can't handle this...
- move.w $DFF002,d0
- btst #DMAB_BLTDONE,d0
- IF ne,busy
- addq.l #1,d4
- FI busy
-
- subq.w #1,d2 ; Decrement tick count
- UNTIL eq,tickloop
- OD tickloop
-
- * Compute available memory
-
- move.l #MEMF_CHIP,d1
- CALLSYS AvailMem ; size = AvailMem(requirements)
- move.l LD_Max_Chip(a5),d5 ; D0 D1
- sub.l d0,d5
-
- move.l #MEMF_FAST,d1
- CALLSYS AvailMem ; size = AvailMem(requirements)
- move.l LD_Max_Fast(a5),d6 ; D0 D1
- sub.l d0,d6
- move.l d3,LD_CPU(a5)
- move.l d4,LD_BLITTER(a5)
- move.l d5,LD_CHIP(a5)
- move.l d6,LD_FAST(a5)
-
- DO reply
- lea LD_Port(a5),a0
- CALLSYS GetMsg ; message = GetMsg(msgPort)
- tst.l d0 ; D0 A0
- UNTIL eq,reply
- movea.l d0,a1
- move.l d3,LV_CPU(a1)
- move.l d4,LV_BLITTER(a1)
- move.l d5,LV_CHIP(a1)
- move.l d6,LV_FAST(a1)
- CALLSYS ReplyMsg ; ReplyMsg(message)
- OD reply ; A1
-
- lea LD_Semaphore(a5),a0
- CALLSYS ReleaseSemaphore ; ReleaseSemaphore(signalSemaphore)
- ODL mainloop ; A0
-
- EndCode:
- END
-