koreth@ssyx.ucsc.edu (Steven Grimm) (09/27/88)
Submitted-by: achowe@watmsg.waterloo.edu (Anthony C. Howe)
Posting-number: Volume 1, Issue 75
Archive-name: achlib/part02
tst.b (a0)
beq.s .X
move.b (a0)+,(a1)+
subq.w #1,d0
bne .1
.X:
clr.b (a1)
rts
;void strcat( char* s1, char* s2 )
.text
_strcat::
.cargs .str1.l, .str2.l
move.l .str1(sp), a0
.1:
tst.b (a0)+
bne .1
subq.l #1,a0
movea.l .str2(sp),a1
.2:
move.b (a1)+,(a0)+
bne .2
rts
;long strlen( char* s )
.text
_strlen::
moveq.l #-1,d0
movea.l 4(sp),a0
.1:
addq.l #1,d0
tst.b (a0)+
bne .1
rts
;*** Find next token in string.
;
; e long pointer to string / NULL to continue with last string
; long pointer to delimeter string / NULL use default delimeters
;
; x long pointer to start of token / NULL if no tokens left
;
; Note: a) original string will be modified.
; b) leading spaces are skipped.
.data
DEFDELIM: .dc.b SPACE, ',', 0
.bss
_NEXTTOK::
.ds.l 1
.text
_STRTOK::
move.l 4(sp), d0 ;get string
bne.s .1 ;if NULL then
move.l _NEXTTOK, d0 ; continue with previous
beq.s .X ; string, return NULL if EOS
.1:
movea.l d0, a0
.2:
cmpi.b #SPACE, (a0)+ ;skip leading spaces
beq .2
subq.l #1, a0
move.l a0, d0 ;start of token to return
move.l 8(sp), d1 ;get delimeter string
bne.s .3 ;if NULL then use default
move.l #DEFDELIM, d1
.3:
movea.l d1, a1 ;reset delimeter string
move.b (a0)+, d2 ;get char in token
.4:
cmp.b (a1), d2 ;check against delims
beq.s .5
tst.b (a1)+
bne .4 ;end of delim string?
bra .3
.5:
clr.b -1(a0) ;terminate token at delim
tst.b d2 ;was it end of search string
bne.s .6
suba.l a0, a0 ;save NULL for next search
.6:
move.l a0, _NEXTTOK ;remember current position
.X:
rts
;*** Find index of character in string
;
; e long pointer to string
; word character value
;
; x D0.L = index into string if character is found else -1
.text
_FINDI::
move.l 4(sp),a0 ;pointer to string
moveq.l #-1, d0
move.w 8(sp),d1 ;character
.1:
tst.b (a0) ;EOS?
beq.s .X
cmp.b (a0)+, d1 ;check character
bne .1
move.l a0, d0
sub.l 4(sp), d0 ;current - original
subq.l #1, d0 ;adjust overrun -1
.X:
rts
;*** Find index of last occurence of character in string
;
; e long pointer to string
; word character value
;
; x D0.L = index into string if character is found else -1
.text
_LFINDI::
movea.l 4(sp), a0
moveq.l #-1, d0
move.w 8(sp), d1
bra.s .2
.1:
cmp.b (a0)+, d1
bne.s .2
move.l a0, d0
sub.l 4(sp), d0
subq.l #1, d0
.2:
tst.b (a0)
bne .1
rts
;*** Deque Rouitines
;*** Make Deque
;
; e long # of long words for deque
;
; x D0.L = ptr to deque structure / NULL unsuccessful
.text
_MKDEQ::
link a6, #0
movem.l a3-a4, -(sp)
move.l 8(a6), d1
lsl.l #2, d1
addi.l #16, d1
move.l d1, -(sp)
move.w #$48, -(sp)
trap #1
addq.l #6, sp
tst.l d0
beq.s .X
movea.l d0, a0
movea.l d0, a1
adda.l #16, a1 ;base of deque
movea.l a1, a2 ;left pointer
movea.l a1, a3 ;right pointer
movea.l a1, a4
adda.l d1, a4 ;end of deque +1
movem.l a1-a4, (a0) ;save deque structure
.X:
movem.l (sp), a3-a4
unlk a6
rts
;*** Remove Deque
;
; e long ptr to deque structure
;
; x D0.W = NULL for success / error code
.text
_RMDEQ::
move.l 4(sp), -(sp)
move.w #$49, -(sp)
trap #1
addq.l #6, sp
rts
;*** Add an element to deque
;
; e long ptr to deque structure
; word 0 left / 1 right
; long value to store
.text
_DEQADD::
link a6, #0
movem.l a3-a4, -(sp)
movea.l 8(a6), a0 ;ptr to deque structure
movem.l (a0), a1-a4 ;fetch deque structure
move.l 14(a6), d0 ;value
move.w 12(a6), d1 ;if adding to the right
bne.s .2
cmpa.l a1, a2
bhi.s .1 ;if begin < left then
movea.l a4, a2 ;wrap deque to end
.1:
move.l d0, -(a2) ;save value
bra.s .X
.2:
move.l d0, (a3)+ ;save value
cmpa.l a3, a4 ;if right < end then
bhi.s .X
movea.l a1, a3 ;wrap deque to beginning
.X:
movem.l a1-a4, (a0) ;update deque structure
movem.l (sp), a3-a4
unlk a6
rts
;*** Delete value from deque
;
; e long ptr to deque structure
; word 0 left / 1 right
;
; x D0.L value
.text
_DEQDEL::
link a6, #0
movem.l a3-a4, -(sp)
movea.l 8(a6), a0
movem.l (a0), a1-a4
move.w 12(a6), d1
bne.s .1
move.l (a2)+, d0 ;get value
cmpa.l a2, a4 ;if left < end then
bhi.s .X
movea.l a1, a2 ;wrap deque to beginning
bra.s .X
.1:
cmpa.l a1, a3 ;if begin < right then
bhi.s .2
movea.l a4, a3 ;wrap deque to end
.2:
move.l -(a3), d0 ;get value
.X:
movem.l a1-a4, (a0) ;update deque structure
movem.l (sp), a3-a4
unlk a6
rts
.globl _PUTDEC
.globl PUTDEC
;*** Print Unsigned Decimal (0-65535)
;
; _PUTDEC e word value
; PUTDEC e D0.W value
; x none
.text
_PUTDEC:
move.w 4(sp),d0
PUTDEC:
ext.l d0
divu #10,d0
beq.s PUTDEC1
move.l d0,-(sp)
bsr PUTDEC
move.l (sp)+,d0
PUTDEC1:
swap d0
addi.w #$30,d0
move.w d0,-(sp)
move.w #CCONOUT,-(sp)
trap #1
addq.l #4,sp
rts
;*** Print Unsigned Decimal
;
; _PUTLONG e long value
; PUTLONG e D0.L value
; x none
.text
_PUTLONG::
move.l 4(sp),d0
PUTLONG::
move.l #10, -(sp)
move.l d0, -(sp)
bsr.s _ULD
addq.l #8, sp
tst.l d0
beq.s .1
movem.l d0-d1,-(sp)
bsr PUTLONG
movem.l (sp)+, d0-d1
.1:
addi.w #$30, d1
move.w d1,-(sp)
move.w #CCONOUT,-(sp)
trap #1
addq.l #4,sp
rts
;*** Unsigned Long to ASCII
;
; e long value
; long pointer to string buffer
;
; x ASCIIZ string in buffer
.text
_ULTOA::
move.l 4(sp),d0
movea.l 8(sp), a0
ULTOA::
move.l #10, -(sp)
move.l d0, -(sp)
bsr.s _ULD
addq.l #8, sp
tst.l d0
beq.s .1
movem.l d0-d1,-(sp)
bsr ULTOA
movem.l (sp)+, d0-d1
.1:
addi.w #$30, d1
move.b d1, (a0)+
clr.b (a0)
rts
;*** Unsigned long division
;
; e long dividend
; long divisor
;
; x D0.L = quoitent
; D1.L = remainder
.text
_ULD::
move.l 4(sp), d0 ;dividend
move.l 8(sp), d2 ;divisor
move.w d3, -(sp)
move.w #31, d3 ;bit count
clr.l d1 ;remainder
.1:
add.l d0, d0
addx.l d1, d1
sub.l d2, d1
bcc.s .2
add.l d2, d1
bra.s .3
.2:
addq.l #1, d0
.3:
dbf d3, .1
move.w (sp)+, d3
rts
;*** DOS Function Call (CP/M-68k)
;
; e word function number
; long parameter
;
; x D0.L = returned value
.text
___BDOS::
move.w 4(sp),d0 ; get function number
move.l 8(sp),d1 ; get parameter
trap #2 ; call DOS
rts
.globl _gemdos
;*** GEM Dos Function Call
;
; e word function number
; word / long parameters
;
; x D0 = return value if any
;
; See GEM Dos notes
.text
_gemdos:
move.l (sp)+, GEMRET
trap #1
move.l GEMRET, -(sp)
rts
.bss
GEMRET: .ds.l 1
.globl _xbios
;*** XBIOS Function Call
;
; e word function number
; word / long parameters
;
; x D0 = return value if any
;
; See XBIOS notes
.text
_xbios:
move.l (sp)+, XBRET
trap #14
move.l XBRET, -(sp)
rts
.bss
XBRET: .ds.l 1
@\Rogue\Monster\
else
echo "shar: Will not over write ACHSLIB.S"
fi
if `test ! -s LIST.C`
then
echo "x - LIST.C"
cat > LIST.C << '@\Rogue\Monster\'
/*
line.c
880821 ACH
*/
#include "runtime.h"
void InsBefore( list, curr, new )
cell* list;
cell* curr;
cell* new;
{
cell* prev;
if( !new ) return;
++list->x;
if( curr ){
prev = curr->prev;
curr->prev = new;
} else {
prev = list->prev;
list->prev = new;
}
new->prev = prev;
new->next = curr;
if( prev )
prev->next = new;
else
list->next = new;
}
void InsAfter( list, curr, new )
cell* list;
cell* curr;
cell* new;
{
cell* next;
if( !new ) return;
++list->x;
if( curr ){
next = curr->next;
curr->next = new;
} else {
next = list->next;
list->next = new;
}
new->prev = curr;
new->next = next;
if( next )
next->prev = new;
else
list->prev = new;
}
void DelCurr( list, curr )
cell* list;
cell* curr;
{
cell* next;
cell* prev;
if( !curr ) return;
--list->x;
prev = curr->prev;
next = curr->next;
if( prev )
prev->next = next;
else
list->next = next;
if( next )
next->prev = prev;
else
list->prev = prev;
}
@\Rogue\Monster\
else
echo "shar: Will not over write LIST.C"
fi
if `test ! -s MAKEFILE`
then
echo "x - MAKEFILE"
cat > MAKEFILE << '@\Rogue\Monster\'
mtest.prg: achapp.o mtest.o list.o memory.o achslib.o
aln -c d:mtest.lnk
achapp.o: achapp.s
mac -u -s -v -oachapp.o achapp.s
achslib.o: achslib.s
mac -u -s -v -oachslib.o achslib.s
list.o: list.c
cc -c list.c
mtest.o: mtest.c
cc -c mtest.c
memory.o: memory.c
cc -c memory.c
@\Rogue\Monster\
else
echo "shar: Will not over write MAKEFILE"
fi
if `test ! -s MEMORY.C`
then
echo "x - MEMORY.C"
cat > MEMORY.C << '@\Rogue\Monster\'
/*
memory.c Anthony's Memory Management Routines
880824 ACH
*/
#include "runtime.h"
/* BLOCK_SIZE is the size of heaps to be requested from the system. This value
should be even and in the range 2 <= BLOCK_SIZE <= 2^n-1 -2. */
#define BLOCK_SIZE 65534
#define BLOCK_SIZE_L 65534L
cell Avail = { 0, NIL, NIL };
unsigned CellsUsed = 0;
unsigned TotalHeaps = 0;
static bool Mavail( curr )
/*
Return TRUE if cell is available.
*/
cell* curr;
{
if( !curr ) return( FALSE );
return( !(curr->x & 1) );
}
static cell* Madjcent( curr )
/*
Return address of right adjcent cell.
*/
cell* curr;
{
if( curr ) return( (cell*) ((char*) curr + (curr->x & ~1)) );
return( NIL );
}
static cell* Mcore()
/*
Allocate another heap block from the system and add to free list.
Return pointer to new block or NIL if out of system memory.
*/
{
cell* p;
p = (cell*) SysAlloc( BLOCK_SIZE_L );
if( p ){
p->x = BLOCK_SIZE | 1;
++CellsUsed;
Mdispose( (cell*) ((char*) p + sizeof( unsigned )) );
++TotalHeaps;
}
return( p );
}
static bool Mrelease( curr )
/*
Return TRUE is a heap block was released.
*/
cell* curr;
{
if( TotalHeaps && curr && curr->x == BLOCK_SIZE ){
DelCurr( &Avail, curr );
SysFree( curr );
--TotalHeaps;
return( TRUE );
}
return( FALSE );
}
bool Mfini()
/*
We free up all that is left of the heaps. We assume that the programmer
did all the necessary clean-up so that all the cells merged into heaps.
Return TRUE if all heaps and cells where released.
*/
{
cell* p;
for( p = Avail.next; p; p = p->next )
Mrelease( p );
return( !(CellsUsed && TotalHeaps) );
}
void* Mnew( request )
/*
Return pointer to requested memory. If NIL returned then unsuccessful
memory request. The range for requests is 1 to BLOCK_SIZE.
*/
unsigned request;
{
cell* p;
unsigned amount;
unsigned left;
/* You don't get anything for nothing. */
if( !request ) return( NIL );
/* Word align our request, so we always ask for even sizes. */
amount = (request + sizeof( unsigned ) +1) & ~1;
/* Check for overflow. */
if( amount <= request || amount > BLOCK_SIZE ) return( NIL );
/* Min request possible since we have to be able to store pointers
back into the block when it is later freed. */
if( amount < sizeof( cell ) ) amount = sizeof( cell );
/* assert: sizeof( cell ) <= amount <= BLOCK_SIZE */
/* Traverse free list for first fit. */
for( p = Avail.next; p; p = p->next ){
if( Mrelease( p ) ) continue;
/* assert: sizeof( cell ) <= p->x <= BLOCK_SIZE */
if( p->x >= amount ){
allocate:
left = p->x - amount;
if( left < sizeof( cell ) )
DelCurr( &Avail, p );
else {
/* Split block and return upper half. */
p->x = left;
p = Madjcent( p );
p->x = amount;
}
/* Mark block as used. */
p->x |= 1;
++CellsUsed;
return( (void*) ((char*) p + sizeof( unsigned )) );
}
}
p = Mcore();
if( p ){
/* assert: p->x = BLOCK_SIZE >= amount */
goto allocate;
}
return( NIL );
}
void Mdispose( curr )
/*
Free cell, return to free list and try and merge with neighbors.
*/
cell* curr;
{
cell* p;
cell* q;
if( !curr ) return;
curr = (cell*) ((char*) curr - sizeof( unsigned ));
/* Mark block as available. */
curr->x &= ~1;
--CellsUsed;
for( p = Avail.next; p < curr && p; p = p->next );
InsBefore( &Avail, p, curr );
if( Madjcent( curr ) == p && curr->x != BLOCK_SIZE ){
/* Merge right neighbor. */
curr->x += p->x;
DelCurr( &Avail, p );
}
q = curr->prev;
if( Madjcent( q ) == curr && q->x != BLOCK_SIZE ){
/* Merge left neighbor. */
q->x += curr->x;
DelCurr( &Avail, curr );
}
}
@\Rogue\Monster\
else
echo "shar: Will not over write MEMORY.C"
fi
if `test ! -s MTEST.C`
then
echo "x - MTEST.C"
cat > MTEST.C << '@\Rogue\Monster\'
#include <stdio.h>
#include "runtime.h"
void main( argc, argv )
int argc;
char** argv;
{
char** p;
char* a;
char* b;
char* c;
char* d;
int i;
printf( "Check upper limit (max should be 65532)\n" );
a = Mnew( (unsigned) 65531 );
b = Mnew( (unsigned) 65532 );
c = Mnew( (unsigned) 65533 );
d = Mnew( (unsigned) 65534 );
printf( "a= %lx, b= %lx, c= %lx, d= %lx. C and D should be zero.\n",
a,b,c,d );
Mdispose( a );
Mdispose( b );
printf( "Copy Argv Test\n\nAllocating p-array\n" );
p = (char*) Mnew( sizeof( char* ) * argc );
printf( "p = %lx\n", p );
for( i = 0; i < argc; ++i ){
printf( "Allocating space for '%s'\n", argv[ i ] );
p[ i ] = (char*) Mnew( strlen( argv[i] ) +1 );
strcpy( p[ i ], argv[ i ] );
printf( "Our copy p[%d] = %lx '%s'\n", i, p[ i ], p[ i ] );
}
for( i = 0; i < argc; ++i ){
printf( "Releasing p[%d]\n", i );
Mdispose( p[i] );
}
printf( "Releasing p-array\n" );
Mdispose( p );
Mfini();
}
@\Rogue\Monster\
else
echo "shar: Will not over write MTEST.C"
fi
if `test ! -s MTEST.LNK`
then
echo "x - MTEST.LNK"
cat > MTEST.LNK << '@\Rogue\Monster\'
-s -v -u
-o mtest.prg
achapp.o
mtest.o
list.o
memory.o
achslib.o
gemlib
@\Rogue\Monster\
else
echo "shar: Will not over write MTEST.LNK"
fi
if `test ! -s README`
then
echo "x - README"
cat > README << '@\Rogue\Monster\'
readme 88.09.20
files in archive:
achacc.s Anthony's MADMAC Assembler Library for Acylon C
achapp.s
achslib.h
achslib.s
list.c Doubly Link List Routines - InsBefore, InsAfter, DelCurr
memory.c Memory Management Routines - Mnew, Mdispose, Mfini
runtime.h Data types and funtion prototypes.
makefile Make file for mtest.prg
mtest.c Memory management test program.
mtest.lnk Aln link file
readme This file.
I've provided my assembler library for those who still use Acylon C (like me).
It has been modified since the last release. Basically adopting standard C
library names and parameter conventions.
List.c provides generic doubly link list routines that are used by Memory.c
to mantain the free list. Runtime.h contains all the data types used and
function prototypes.
Reference for that helped in the development of Memory.c:
1) Knuth vol 1, pg 435-451
2) Kernighan & Ritchie "The C Progamming Language" pg 173-177
Memory.c uses unsigned int which limits memory requests to Mnew in the range
1-65534. This is because Acylon C doesn't support unsigned long. Also the
application for which this was written did not require large memory blocks.
The source could be modified to fix this limitation if compiled under MWC
or GNU CC.
Notes:
1) All source used tabstops = 4
2) Development site was Colour Mega ST 2
3) Development software: BDT Micro C-Shell, BDT Make, LV, Acylon C,
MadMac Assembler, Aln Linker
Any inquires send mail to:
achowe@watmsg.waterloo.edu
Disclaimer: The software provided has been written out of need and a desire
to learn. Everything has been tested, yet things can go wrong (ie. typos).
I refuse to take any responsablity for damage that could have resulted from the
use of this code. I have enough trouble finding a decent pizza at 1 am.
PLEASE PLEASE test code independantly till you get that warm feeling like
when you p__s in a pool :)
Anthony C. Howe
@\Rogue\Monster\
else
echo "shar: Will not over write README"
fi
if `test ! -s RUNTIME.H`
then
echo "x - RUNTIME.H"
cat > RUNTIME.H << '@\Rogue\Monster\'
/*
runtime.h
880821 ACH
*/
#undef ANSI
#define ATARI
#define ACYLON
#define SCREEN_WIDTH 80
#define TAB_WIDTH 4
#ifndef ANSI
typedef int void;
#endif
#ifdef ATARI
#include <gembind.h>
#include <gemdefs.h>
#include <osbind.h>
#include <tosdefs.h>
#include <vdibind.h>
#include "achslib.h"
#define putch(c) (Cconout(c))
#define Key() (Cconin())
#define SysAlloc(x) (Malloc(x))
#define SysFree(x) (Mfree(x))
#define READ 0
#define WRITE 1
#define READ_WRITE 2
typedef struct dta
{
char reserved[21];
char attr;
short time;
short date;
long size;
char name[14];
}
dta;
#else
#define READ "r"
#define WRITE "w"
#define READ_WRITE "rw"
#endif
#undef FALSE
#define FALSE 0
#undef TRUE
#define TRUE (!FALSE)
#undef NULL
#define NULL 0
#undef NIL
#define NIL 0L
typedef int bool;
typedef struct cell
{
unsigned x;
struct cell* prev;
struct cell* next;
}
cell;
#ifdef ANSI
/* list.c */
extern void InsBefore( cell* list, cell* curr, cell* new );
extern void InsAfter( cell* list, cell* curr, cell*, new );
extern void DelCurr( cell* list, cell* curr );
/* memory.c */
extern bool Mfini();
extern void* Mnew( unsigned request );
extern void Mdispose( cell* curr );
#else
/* list.c */
extern void InsBefore();
extern void InsAfter();
extern void DelCurr();
extern cell* Lalloc();
extern void Lfree();
extern void Lfini();
/* memory.c */
extern bool Mfini();
extern void* Mnew();
extern void Mdispose();
#endif
@\Rogue\Monster\
else
echo "shar: Will not over write RUNTIME.H"
fi
# to concatenate archives, remove anything after this line
exit 0