Documentation for VBI, a vertical blank handler package
Copyright (C) 1987 by Amgem, Inc.
Permission is hereby granted for anyone to make or distribute copies of this program provided the copyright notice and this permission notice are retained.
This software, or software containing all or part of it, may not be sold except with express permission of the authors.
Authors: Bill Dorsey & John Iarocci
If you have any questions or comments, the authors may be reached at The Tanj BBS, (301)-251-0675. Updates and bug fixes may also be obtained through the above service.
OVERVIEW
VBI is a vertical blank handler package designed to allow easy access to the Atari STs vertical blank interrupt system. It allows programmers to incorporate many features which would otherwise require a multi-tasking operating system into their programs with a minimum of difficulty. Examples of its use include alarms, blinking characters, and any other functions that need to be active all the time without getting in the way of normal program execution.
The authors have successfuly used this package in a system which tells users calling in to a BBS that the BBS is down. It runs in the background, and thus allows use of editors, compilers, games, etc. while it runs. When the program detects a carrier detect, it sends a message to the modem, and toggles the DTR line, hanging up the modem.
Although this program has been tested and is believed to be bug-free, no guarantees are made of its functionality or suitability to any application.
USE
In order to use this package, you will need to compile the file vbi.c using your C compiler and generate an object file. This object file will then be linked with any code you later generate to use the facilities in this package.
Before compiling, you may wish to change some definitions in vbi.h. If you are using an RGB system, you will want to change the constant TICKSPERSEC to the value indicated in vbi.h. Additionally, you may wish to change other values, such as QUANTUM, which specifies how often programs are called from the vertical blank handler.
Be very careful when using BIOS, XBIOS, and GEMDOS functions from within interrupt routines. There is a fixed amount of register save space for calls to these functions, and when they are re-entered several times, crashes can occur without warning. Admittedly, there are times when no alternative exists but to use calls to the operating system. If crashes occur under these circumstances, you should first suspect a register space overflow before blaming your code, or the interrupt handler.
If there is a simple way to tell if the operating system can be called at a given time, say by checking some system variable, it would be the perfect solution to the above dilemma. The interrupt routine could look to see if it was save to call the operating system before doing so. If it was safe, it could go ahead, otherwise, it should wait until it is safe.
On final note. These interrupt routines must be FAST! They should preferably complete execution in a few milliseconds. If they take much longer, the computer will be slowed down substantially. The constant QUANTUM can be increased to relieve this problem somewhat, but the user should be aware that any routines that take longer than one vertical blank cycle with result in vertical blank interrupts being masked until their completion.
If you are using a C compiler other than the Mark Williams C compiler, you may need to make some minor modifications to the code. The only thing that requires any explanation is the constant BP which comes from the include file basepage.h. It is a pointer to the basepage of the program. In Alcyon C, the external variable _base points to the basepage and would thus be used instead of BP.
FUNCTIONS
- init() - This function initializes the vertical blank handler. It must be called before any vertical blank processes are created.
- vbiexit() - This function does a terminate and stay resident call. It should be used only if the vertical blank handler is to be left active after program termination. Failure to use it under these circumstances WILL lead to your computer crashing!
- remove() - This function removes the vertical blank handler. Calling it will also disable any existing vertical blank processes.
- schedule() - This function is the vertical blank scheduler. It should not be referenced by the user under normal circumstances.
- create(a) - This function creates vertical blank processes. Its single argument should be a pointer to the function to be added to the vert- ical blank proces queue. Create will return the process id (an integer) of the process it adds to the queue.
- delete(a) - This function removes vertical blank processes. Its single argument should be the process id of the process to be deleted.
- sleep(a) - This function causes a process not to be called for a fixed amount of time. Its argument is the number of seconds before it is to resume execution. The call will return IMMEDIATELY. It does not take effect until the current process exits.
FILES
- vbi.doc - you're looking at it
- vbi.c - source code for vbi handler functions
- vbi.h - include file for vbi.c
- example.c - an example program using vbi
VBI.C
/* vbi.c -- vertical blank interrupt handler [Version 1.0 01/01/87]
*
* Copyright (C) 1987 by Amgem, Inc.
*
* Permission is hereby granted for anyone to make or distribute copies of
* this program provided the copyright notice and this permission notice are
* retained.
*
* This software, or software containing all or part of it, may not be sold
* except with express permission of the authors.
*
* Authors: Bill Dorsey & John Iarocci
*
* If you have any questions or comments, the authors may be reached at
* The Tanj BBS, (301)-251-0675. Updates and bug fixes may also be obtained
* through the above service.
*
* The code which follows was compiled using the Mark Williams C compiler,
* but should be portable with little work to other C compilers. See the
* associated documentation for notes on how to convert it for use with other
* C compilers
*/
#include <osbind.h>
#include <basepage.h>
#include "vbi.h"
int count; /* count remaining until next scheduling */
int curpid; /* current process id */
PROC proctab[NPROC]; /* process table */
init() /* initialization */
{
int i;
long ssp;
int schedule();
count=QUANTUM; /* # of vblanks per scheduling */
for (i=0; i<NPROC; i++)
proctab[i].state=FREE; /* initialize process table */
ssp=Super(0L); /* enter supervisor state */
for (i=0; i<8; i++) {
if ((*VBLQUEUE)[i] == (int (*)()) 0) {
(*VBLQUEUE)[i]=schedule; /* install scheduler in vblank queue */
Super(ssp);
return OK; /* installation successful */
}
}
Super(ssp);
return SYSERR; /* installation failed */
}
vbiexit() /* exit code (leave VBI handler) */
{
long prglen;
prglen=0x100L+BP->p_tlen+BP->p_dlen+BP->p_blen;
Ptermres(prglen,0); /* terminate and stay resident */
}
remove() /* removes VBI handler */
{
int i;
long ssp;
int schedule();
ssp=Super(0L); /* enter supervisor mode */
for (i=0; i<8; i++)
if ((*VBLQUEUE)[i] == schedule) {
(*VBLQUEUE)[i]=(int (*)()) 0; /* remove scheduler from vblqueue */
Super(ssp); /* resume user mode */
return OK; /* return success */
}
Super(ssp); /* resume user mode */
return SYSERR; /* return failure */
}
schedule() /* process scheduler */
{
register int i;
register PROC *pptr;
DISABLE; /* disable further vb interrupts */
if (--count == 0) { /* schedule when count reaches zero */
count=QUANTUM; /* re-initialize count */
pptr=proctab; /* get pointer to process table */
for (i=0; i<NPROC; i++,pptr++)
switch (pptr->state) {
case READY: /* if process ready, set curpid to its */
curpid=i; /* process id, and then execute it */
(*pptr->func)();
break;
case SLEEP: /* if process sleeping, decrement its */
if (--pptr->count == 0) /* count. If count reaches zero, set */
pptr->state=READY; /* process state back to READY */
break;
}
}
ENABLE; /* enable vb interrupts */
}
create(func) /* process creation */
int (*func)();
{
register int i;
register PROC *pptr;
pptr=proctab; /* initialize pointer to process table */
for (i=0; i<NPROC; i++,pptr++)
if (pptr->state == FREE) { /* find free entry in process table */
pptr->func=func; /* store pointer to code in table */
pptr->state=READY; /* set process state to READY */
return i; /* return process id */
}
return SYSERR; /* process table full --> failure */
}
delete(pid) /* process deletion */
int pid;
{
if (proctab[pid].state == FREE)
return SYSERR; /* if process already free, return failure */
proctab[pid].state=FREE; /* set process state to FREE */
return OK; /* return success */
}
sleep(tsec) /* process sleep */
int tsec;
{
proctab[curpid].state=SLEEP; /* set process state to SLEEP */
proctab[curpid].count=tsec*INTERVAL; /* set count to proper amount */
}
VBI.H
/* vbi.h -- vertical blank interrupt handler [Version 1.0 01/01/87]
*
* Copyright (C) 1987 by Amgem, Inc.
*
* Permission is hereby granted for anyone to make or distribute copies of
* this program provided the copyright notice and this permission notice are
* retained.
*
* This software, or software containing all or part of it, may not be sold
* except with express permission of the authors.
*
* Authors: Bill Dorsey & John Iarocci
*
* If you have any questions or comments, the authors may be reached at
* The Tanj BBS, (301)-251-0675. Updates and bug fixes may also be obtained
* through the above service.
*
* The code which follows was compiled using the Mark Williams C compiler,
* but should be portable with little work to other C compilers. See the
* associated documentation for notes on how to convert it for use with other
* C compilers
*/
/* operating system variables */
#define VBLSEM ((int *) 0x452L)
#define VBLQUEUE ((int (***)()) 0x456L)
#define PSG ((char *) 0xff8800L)
#define PSG2 ((char *) 0xff8802L)
#define GPIP ((char *) 0xfffa01L)
/* process states */
#define FREE 0
#define READY 1
#define SLEEP 2
/* return values */
#define OK (-1)
#define SYSERR (-2)
/* system values */
#define TICKSPERSEC 70 /* 70 for MONO, 50 for RGB */
#define QUANTUM 5 /* should be a factor of tickspersec */
#define INTERVAL (TICKSPERSEC/QUANTUM)
#define NPROC 8 /* maximum number of processes */
/* misc macros */
#define DISABLE *VBLSEM=0
#define ENABLE *VBLSEM=1
typedef struct {
int state;
int (*func)();
int count;
} PROC;
EXAMPLE.C
/* vbishell.c -- vertical blank interrupt handler shell
*
* Copyright (C) 1987 by Amgem, Inc.
*
* Permission is hereby granted for anyone to make or distribute copies of
* this program provided the copyright notice and this permission notice are
* retained.
*
* This software, or software containing all or part of it, may not be sold
* except with express permission of the authors.
*
* Authors: Bill Dorsey & John Iarocci
*
* If you have any questions or comments, the authors may be reached at
* The Tanj BBS, (301)-251-0675. Updates and bug fixes may also be obtained
* through the above service.
*
* The code which follows was compiled using the Mark Williams C compiler,
* but should be portable with little work to other C compilers. See the
* associated documentation for notes on how to convert it for use with other
* C compilers
*/
#include <osbind.h>
#include "vbi.h"
extern PROC proctab[NPROC];
main()
{
int pid1,pid2;
long i;
int process1(),process2();
if (init() == SYSERR) {
printf("Installation failure\n");
exit(1);
}
if ((pid1=create(process1)) == SYSERR) /* create process 1 */
printf("Could not create process 1\n");
if ((pid2=create(process2)) == SYSERR) /* create process 2 */
printf("Could not create process 2\n");
printf("Now entering loop...\n");
for (i=0; i<2000000L; i++) /* delay for a while */
;
if (delete(pid1) == SYSERR) /* delete process 1 */
printf("Could not delete process 1\n");
if (delete(pid2) == SYSERR) /* delete process 2 */
printf("Could not delete process 2\n");
if (remove() == SYSERR) /* remove VBI handler */
printf("Could not remove VBI handler\n");
exit(0); /* return to OS */
}
int process1()
{
Bconout(2,'A'); /* output 'A' to console */
sleep(4); /* 4 seconds until next call */
}
int process2()
{
Bconout(2,'B'); /* output 'B' to console */
sleep(5); /* 5 seconds until next call */
}