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