jvkelley@watcgl.waterloo.edu (Jeff Kelley) (10/30/87)
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by watcgl!jvkelley on Sat Oct 17 20:18:34 EDT 1987
# Contents: README load.doc load.device.uue makefile asmsupp.i load.i macros.i
# device.a load.h
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
This is an Amiga device, called "load.device", which measures CPU, blitter,
and memory usage.
Instructions:
Casual User:
Copy load.device to your "devs:" directory.
Dedicated Programmer:
Copy "load.h" and "load.i" to your "include:devices/" directory.
Read "load.doc".
Comments, suggestions, and bug reports welcome.
Jeff Kelley
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
UUCP: {ihnp4,watmath}!watcgl!jvkelley | Postal Address:
BITNET: jvkelley@cgl.waterloo.bitnet | Jeff Kelley
INTERNET: jvkelley@cgl.waterloo.edu | Dept. of Computer Science
EAN: jvkelley@cgl.waterloo.cdn | University of Waterloo
| Waterloo, Ont., Canada
| N2L 3G1
| tel: (519) 578-4514
@//E*O*F README//
chmod u=rw,g=r,o=r README
echo x - load.doc
sed 's/^@//' > "load.doc" <<'@//E*O*F load.doc//'
TABLE OF CONTENTS
load.device/structure/LoadBase
load.device/command/Flush
load.device/command/Read
load.device/command/Reset
load.device/command/Set
load.device/command/Start
load.device/command/Stop
load.device/function/AbortIO
load.device/function/BeginIO
load.device/function/CloseDevice
load.device/function/OpenDevice
load.device/structure/LoadBase load.device/command/LoadBase
NAME
LoadBase - the load device data structure
DESCRIPTION
The io_Device field of the loadrequest structure points to the
LoadBase structure. This structure should not be modified except
indirectly as a result of executing a device command. It is
permissible to read the data structure (using Forbid/Permit as
appropriate), but the only values of any interest are probably
ld_max_chip - the maximum amount of chip memory available at
the time the load device was first loaded.
ld_max_fast - as above, but for fast memory.
SEE ALSO
devices/load.h
devices/load.i
load.device/command/Flush load.device/command/Flush
NAME
Flush -- clear all queued I/O requests for the load task
FUNCTION
This command purges the read request queue for the load
task.
IO REQUEST
io_Message mn_ReplyPort initialized
io_Device set by OpenDevice
io_Command CMD_FLUSH
RESULTS
io_Error -- if the Flush succeded, then io_Error will be 0.
If the Flush failed, then the io_Error will be non-zero.
(No known reason for it to fail.)
SEE ALSO
load.device/command/Read
load.device/command/Read load.device/command/Read
NAME
Read -- read load values collected by load task
FUNCTION
This command reads the load values of the CPU, blitter, chip
memory, and fast memory.
IO REQUEST
io_Message mn_ReplyPort initialized
io_Device set by OpenDevice
io_Command CMD_READ
io_Flags IOF_QUICK if quick I/O desired
RESULTS
If the read succeeded, the following load values will be set:
lr_load.lv_cpu -- The sum of the length of the ready queue as
measured at each tick during the interval.
This value may be greater than the number of
ticks in an interval, theoretically having no
upper bound (but try to tell that to your
poor little 68000!).
lr_load.lv_blitter -- The number of ticks at which the blitter was
detected to be busy during the interval.
lr_load.lv_chip -- The number of bytes of chip memory currently
in use. To find the maximum chip memory
available, see the description of the
LoadBase structure.
lr_load.lv_fast -- The number of bytes of fast memory currently
in use. To find the maximum fast memory
available, see the description of the
LoadBase structure.
io_Error -- If the Read succeeded, then io_Error will be 0.
If the Read failed, then the io_Error will be non-zero.
It may fail if IOF_QUICK is not set and a Flush or AbortIO
request is executed before the end of the current interval,
in which case the error will be IOERR_ABORTED.
BUGS
The length of the ready queue is measured, which may not be an
accurate measurement of CPU usage.
Time arithmetic is not currently used to ensure that an interval is
really an interval. That is, that due to delays between the time
that the load.device task is signalled by the timer and when the
task places its next timer request, the actual interval will end up
being greater than the specified interval.
SEE ALSO
load.device/structure/LoadBase
load.device/command/Flush
load.device/function/AbortIO
load.device/command/Reset load.device/command/Reset
NAME
Reset -- reinitializes the load device parameters
FUNCTION
This command sets the interval time, the number of ticks per interval,
and the priority of the load task to their default values.
IO REQUEST
io_Message mn_ReplyPort initialized
io_Device set by OpenDevice
io_Command CMD_RESET
RESULTS
io_Error -- If the Reset succeeded, then io_Error will be 0.
If the Reset failed, then the io_Error will be non-zero.
(No known reason for it to fail.)
If the Reset succeeded, then the lr_interval, lr_ticks, and lr_pri
fields of the loadrequest will contain the default settings of
those parameters.
SEE ALSO
load.device/command/Set
load.device/function/OpenDevice
load.device/command/Set load.device/command/Set
NAME
Set -- change load device parameters
FUNCTION
This command sets the interval time, number of ticks per interval,
and priority of the load task to values specified in the load IO
request.
IO REQUEST
io_Message mn_ReplyPort initialized
io_Command LD_SET
lr_interval A word indicating the sampling period time (in seconds),
during which a number of samples may be taken.
lr_ticks A word indicating the number of samples to be taken
during each interval.
lr_pri A byte indicating the priority of the load task.
NOTE: The last three fields are initialized when OpenDevice
is called to indicate the devices current configuration.
RESULTS
io_Error -- 0 if the command succeeded, otherwise an error number.
(No known reason for it to fail.)
SEE ALSO
load.device/command/Reset
load.device/function/OpenDevice
load.device/command/Start load.device/command/Start
NAME
Start -- restart the paused load task.
FUNCTION
Restarts the paused load task, but not if other Stop commands
have been performed without corresponding Start commands.
IO REQUEST
io_Message mn_ReplyPort initialized
io_Device set by OpenDevice
io_Command CMD_START
RESULTS
io_Error -- 0 if the start succeeded, an error number otherwise.
The only possible error is LDERR_NOT_STOPPED, if the
device was not currently in the stopped state.
SEE ALSO
load.device/command/Stop
load.device/command/Stop load.device/command/Stop
NAME
Stop -- stop the load task from executing
FUNCTION
Stops the load task at the end of the current interval if it is not
already stopped, otherwise increments the number of Stop commands
that must be cancelled by Start commands before the load task will
begin executing again.
IO REQUEST
io_Message mn_ReplyPort initialized
io_Device set by OpenDevice
io_Command CMD_STOP
RESULTS
io_Error -- 0 if the Stop succeeded, an error number otherwise.
(No known reason for it to fail.)
SEE ALSO
load.device/command/Start
BUGS
If 255 Stop commands are already outstanding, executing
another Stop command will cause a counter to wrap around, and
undesirable behaviour may result.
load.device/function/AbortIO load.device/function/AbortIO
NAME
AbortIO -- abort an I/O request
SYNOPSIS
AbortIO(ioRequest)
FUNCTION
This function aborts a specified read request
If the request is queued, it is painlessly removed.
INPUTS
iORequest -- pointer to the IORequest Block that is to be aborted.
RESULTS
io_Error -- IOERR_ABORTED if the AbortIO succeeded.
0 if the AbortIO failed (the request was not in the queue).
SEE ALSO
load.device/function/BeginIO
load.device/function/BeginIO load.device/function/BeginIO
NAME
BeginIO -- start up an I/O process
FUNCTION
This function initiates a I/O request made to the load
device. Other than read, the functions are performed
synchronously, and do not depend on any interrupt handling
logic (or it's associated discontinuities), and hence, if so
selected, can be performed as IO_QUICK.
Read requests that are not flagged as IO_QUICK are queued and
replied to by the load task at the end of the next interval.
Completion is signalled via the standard ReplyMsg routine.
INPUTS
iORequest -- pointer to an I/O Request Block of size
sizeof(struct loadrequest) (see devices/load.h for
definition), containing a valid command in io_Command
to process, as well as the command's other required parameters.
The io_Device field must have been initialized during the
OpenDevice call to point to the load.device.
RESULTS
Error -- if the BeginIO succeded, then Error will be 0.
If the BeginIO failed, then the Error will be non-zero.
Possible errors:
IOERR_NOCMD - Invalid command attempted.
IOERR_ABORTED - The request was aborted before completion.
SEE ALSO
devices/load.h
devices/load.i
load.device/function/CloseDevice load.device/function/CloseDevice
NAME
CloseDevice -- close the load device
SYNOPSIS
CloseDevice(ioRequest)
FUNCTION
Close the device previously opened by calling OpenDevice.
INPUTS
ioRequest - pointer to a load request initialized by a call to
OpenDevice.
SEE ALSO
load.device/function/OpenDevice
load.device/function/OpenDevice load.device/function/OpenDevice
NAME
OpenDevice -- Request an opening of the load device.
SYNOPSIS
error = OpenDevice(loadname, unit, ioRequest, flags)
FUNCTION
Open the load device and initialize the ioRequest.
INPUTS
loadname - pointer to literal string "load.device"
unit - ignored (should be 0).
ioRequest - pointer to an ioRequest block of size
sizeof(loadrequest) (see devices/load.i,h
for size/definition) to be
initialized by the OpenDevice routine.
flags - LDF_OPEN_EXCL if exclusive access to the load
device is desired, othewise 0.
RESULTS
error - 0 if the OpenDevice succeeded, an error number otherwise.
Possible errors:
IOERR_OPENFAIL - generic
LDERR_ACCESS_DENIED - the device is currently opened
by a task with exclusive access.
LDERR_IN_USE - an attempt was made to obtain exclusive
access to the device but it has already been
opened by another task.
If the OpenDevice succeeded, the io_Device field of the ioRequest
structure will be initialized to point to the load.device. The
three load device parameters will contain their current settings:
lr_interval - The number of seconds in each interval.
lr_ticks - The number of ticks in each interval. Measurements
of CPU usage (ready queue length) and blitter usage
are taken at each tick during an interval, and at
the end of the interval queued read requests are
replied to.
lr_pri - The priority of the load.device task. Note that
CPU usage of tasks running at a priority greater
than this cannot be measured, and those at an
equal priority are not accurately measured.
SEE ALSO
load.device/function/CloseDevice
devices/load.h
devices/load.i
@//E*O*F load.doc//
chmod u=rw,g=r,o=r load.doc
echo x - load.device.uue
sed 's/^@//' > "load.device.uue" <<'@//E*O*F load.device.uue//'
begin 644 load.device
M #\P ! %G #Z0 6=P $YU2OP $ %
MG( ! P K -P %IT:6UE<BYD979I8V4 ;&]A9"YD979I8V4 ;&]A
M9"YD979I8V4@,2XP("@Q-B!/8W1O8F5R(#$Y.#<I#0 (. :@ (8
M "R !A >0 (2 EX )^_____^ @# , H K
MX #@8 T % !T %@ P & #< +PTJ0"M( > K3@'D0>T
MFB%\ *P *$7P ! ($7P @ .0>@ %""(6)!"J $(4@ "#M\ 4!Z#M\
M #T!ZB\.+$UA -,+%]![0 B3J[]TD'M ").KOW,(&X!0B(09QX@* 8D*@
M% @H $ #V<&T:T!]& $T:T!^"!!8-Y#[0"\$WP 0 ($WP &0 )(WP K
M I![0$8(T@ .M'\ R"-( #XC2 V0>D 2B"(6)!"J $(4@ "$7Z Q@F
M? !.KO[F( TJ7TYU""X (-9E ( 0 9Q9*;@ @9PH3>?____L 'TYU
M".X (-4FX ( QN $ (&800>X (B\.+&X!Y$ZN_<8L7S-N >@ ,#-N >H
M,A-N ,4 -$(I !]@!A-\ /H 'TYU0JD %%-N "!F($'N "(O#BQN >1.KOW,
M+%\(K@ @T(+@ # YG F $< !.=2\-*DXL;0'D2FT (&<*".T P .< !@
M+B\M > B34ZN_P1#[0"\3J[^X$/M %!.KOX^< B33 M !"2P-!M !).KO\N
M(!\L32I?3G5"*0 ?,"D '.5 0?H 9M# L?P +X901!^@!8(%!.T"\.+&X!
MY$ZN_WPL7R(N *X@02(09RJSR&<"8/0B"2!1(FD !"*((4D !"\.+&X!Y$ZN
M_W8L7R)!$WP _@ ?3G4O#BQN >1.KO]V+%]"*0 ?3G4 +X #Z@ P
M +X "^ O@ ,T #: Z8 /\$WP _0 ?3G4(*0 !YG&B-N
M ?P ("-N @ ("-N @0 *"-N @@ +& 00>X FB\.+&X!Y$ZN_I(L7TYU+PXL
M;@'D3J[_?"Q?2BX"#&800>X (B\.+&X!Y$ZN_<PL7U(N @PO#BQN >1.KO]V
M+%].=4HN @QF"!-\ /D 'V N+PXL;@'D3J[_?"Q?4RX"#&800>X (B\.+&X!
MY$ZN_<8L7R\.+&X!Y$ZN_W8L7TYU+PXL;@'D3J[_?"Q?0>X FB\.+&X!Y$ZN
M_HPL7TJ 9Q8B0!-\ /X 'R\.+&X!Y$ZN_H8L7V#6+PXL;@'D3J[_=BQ?3G4S
M? % # S? ] #(3? 9 #0O"4'N "(O#BQN >1.KOW,+%\B7SUI # !Z#UI
M #(!ZF$F$"D -$/N +PO#BQN >1.KO[4+%]![@ B+PXL;@'D3J[]QBQ?3G4O
M G( ,BX!Z#0N >K"_ 4POS#4#!!0D%(08+"( %(03 (@,(R $*N >P,@0 /
M0D!M# 2! ]"0%*N >Q@["U! ? D'TYU+'D $2^_^)$7M ")'[0!X%WP
M! (%WP .</].KOZV%T #T'M +PG2 00>L %""(6)!"J $(4@ "$GM
M % 9? % @I2P ..7P * 20?K[/B),< %R $ZN_D0@2DZN_<PT+0'J=@!X
M #E\ D '"EM >P ("EM ? )"),3J[^.$ZN_X@B;@&6(!%G!E*#(D!@]DZN
M_X(P.0#?\ (( .9P)2A%-"9P)@OB(\ DZN_R@J+0'TFH B/ 1.
MKO\H+"T!^)R *T,!_"M$ @ K10($*T8""$'M )I.KOZ,2H!G&") (T, ("-$
M "0C10 H(T8 +$ZN_H9@W$'M ").KOW&8 #_4@ ^P = 8
M * $@ !8 : 7@ &( !F :@ &X !R =@
M 'H !^ D *H #$ !1 G +0 "U M@ +< "
=X N0 +H "[ O +T _+0
end
@//E*O*F load.device.uue//
chmod u=rw,g=r,o=r load.device.uue
echo x - makefile
sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
load.device: device.o
blink FROM device.o TO load.device LIB lib:amiga.lib
device.o: device.a include:devices/load.i
asm -NL -Iinclude: device.a
include:devices/load.i: assem:include/devices/load.i
cp assem:include/devices/load.i include:devices/load.i
cp assem:include/devices/load.h include:devices/load.h
@//E*O*F makefile//
chmod u=rw,g=r,o=r makefile
echo x - asmsupp.i
sed 's/^@//' > "asmsupp.i" <<'@//E*O*F asmsupp.i//'
CLEAR MACRO
moveq.l #0,\1
ENDM
CALLSYS MACRO
jsr _LVO\1(a6)
ENDM
LINKSYS MACRO
move.l a6,-(sp)
movea.l LD_sysbase(a6),a6
jsr _LVO\1(a6)
movea.l (sp)+,a6
ENDM
XLIB MACRO
XREF _LVO\1
ENDM
@//E*O*F asmsupp.i//
chmod u=rw,g=r,o=r asmsupp.i
echo x - load.i
sed 's/^@//' > "load.i" <<'@//E*O*F load.i//'
*----------------------------------------------------------------
*
* Load Device Structure
*
*----------------------------------------------------------------
LOAD_STACK_SIZE EQU 200
STRUCTURE LD,DD_SIZE
STRUCT LD_Semaphore,SS_SIZE
STRUCT LD_TimerRequest,IOTV_SIZE
STRUCT LD_TimerPort,MP_SIZE
STRUCT LD_Port,MP_SIZE
STRUCT LD_TaskCB,TC_SIZE
STRUCT LD_Stack,LOAD_STACK_SIZE
ULONG LD_seglist
ULONG LD_sysbase
UWORD LD_Interval ; Interval in seconds
UWORD LD_Ticks ; Number of measurements / time interval
ULONG LD_secs ; seconds between ticks
ULONG LD_micro ; microseconds between ticks
ULONG LD_Max_Chip ; absolute maximum chip memory available
ULONG LD_Max_Fast ; absolute maximum fast memory available
ULONG LD_CPU
ULONG LD_BLITTER
ULONG LD_CHIP
ULONG LD_FAST
UBYTE LD_stop_count
UBYTE LD_flags
LABEL LD_SIZE
*----------------------------------------------------------------
*
* Load Request Structure
*
*----------------------------------------------------------------
STRUCTURE LR,IO_SIZE
ULONG LV_CPU
ULONG LV_BLITTER
ULONG LV_CHIP
ULONG LV_FAST
UWORD LV_INTERVAL
UWORD LV_TICKS
BYTE LV_PRI
LABEL LR_SIZE
LOADNAME MACRO
DC.B 'load.device',0
ENDM
BITDEF LD,OPEN_EXCL,0
LDERR_IN_USE EQU -5
LDERR_ACCESS_DENIED EQU -6
LDERR_NOT_STOPPED EQU -7
DEVINIT
DEVCMD LD_SET
@//E*O*F load.i//
chmod u=rw,g=r,o=r load.i
echo x - macros.i
sed 's/^@//' > "macros.i" <<'@//E*O*F macros.i//'
IF MACRO
ifok SET 0
IFC \1,eq
bne.s else\2
ifok SET 1
ENDC
IFC \1,ne
beq.s else\2
ifok SET 1
ENDC
IFC \1,ge
blt.s else\2
ifok SET 1
ENDC
IFC \1,gt
ble.s else\2
ifok SET 1
ENDC
IFC \1,le
bgt.s else\2
ifok SET 1
ENDC
IFC \1,lt
bge.s else\2
ifok SET 1
ENDC
IFEQ ifok
FAIL 'Bad IF'
ENDC
ENDM
ELSE MACRO
bra.s fi\1
else\1:
ENDM
FI MACRO
IFND else\1
else\1:
ENDC
fi\1:
ENDM
DO MACRO
do\1:
ENDM
OD MACRO
bra.s do\1
od\1:
ENDM
ODL MACRO
bra do\1
od\1:
ENDM
WHILE MACRO
whilok SET 0
IFC \1,eq
bne.s od\2
whilok SET 1
ENDC
IFC \1,ne
beq.s od\2
whilok SET 1
ENDC
IFC \1,ge
blt.s od\2
whilok SET 1
ENDC
IFC \1,gt
ble.s od\2
whilok SET 1
ENDC
IFC \1,le
bgt.s od\2
whilok SET 1
ENDC
IFC \1,lt
bge.s od\2
whilok SET 1
ENDC
IFEQ whilok
FAIL 'Bad WHILE'
ENDC
ENDM
UNTIL MACRO
b\1.s od\2
ENDM
QUIF MACRO
b\1.s od\2
ENDM
@//E*O*F macros.i//
chmod u=rw,g=r,o=r macros.i
echo x - device.a
sed 's/^@//' > "device.a" <<'@//E*O*F device.a//'
*
* 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
@//E*O*F device.a//
chmod u=rw,g=r,o=r device.a
echo x - load.h
sed 's/^@//' > "load.h" <<'@//E*O*F load.h//'
#ifndef DEVICES_LOAD_H
#define DEVICES_LOAD_H
#ifndef DEVICES_TIMER_H
#include <devices/timer.h>
#endif DEVICES_TIMER_H
#ifndef EXEC_DEVICES_H
#include <exec/devices.h>
#endif
#ifndef EXEC_SEMAPHORES_H
#include <exec/semaphores.h>
#endif
#define LOAD_STACK_SIZE 200
struct LoadBase {
struct Device ld_device;
struct SignalSemaphore ld_semaphore;
struct timerequest ld_timerequest;
struct MsgPort ld_timerport;
struct MsgPort ld_port;
struct Task ld_taskcb;
char ld_stack[LOAD_STACK_SIZE];
ULONG ld_seglist;
ULONG ld_sysbase;
UWORD ld_interval;
UWORD ld_ticks;
ULONG ld_secs;
ULONG ld_micro;
ULONG ld_max_chip;
ULONG ld_max_fast;
ULONG ld_cpu;
ULONG ld_blitter;
ULONG ld_chip;
ULONG ld_fast;
UBYTE ld_stop_count;
UBYTE ld_flags;
};
typedef struct _loadval {
ULONG lv_cpu;
ULONG lv_blitter;
ULONG lv_chip;
ULONG lv_fast;
} loadval;
typedef struct _loadrequest {
struct IORequest lr_node;
struct _loadval lr_load;
UWORD lr_interval;
UWORD lr_ticks;
BYTE lr_pri;
} loadrequest;
#define LDB_OPEN_EXCL 0
#define LDF_OPEN_EXCL (1<<LDB_OPEN_EXCL)
#define LDERR_IN_USE -5
#define LDERR_ACCESS_DENIED -6
#define LDERR_NOT_STOPPED -7
#define LD_SET CMD_NONSTD
@//E*O*F load.h//
chmod u=rw,g=r,o=r load.h
exit 0