Completed, tested, debugged, and documented module bitlib

This commit is contained in:
Curtis F Kaylor 2020-10-04 22:17:09 -04:00
parent 0fbbc6dce2
commit d816bd1273
6 changed files with 423 additions and 25 deletions

70
doc/bitlib.txt Normal file
View File

@ -0,0 +1,70 @@
Bit Manipulation Functions for C02 Programs
This module contains functions to shift and rotate the bits in a byte,
and to extract, combine, swap and duplicate nybbles in a byte.
At the beginning of the program use the directives
#include <stddef.h02>
#include <bitlib.h02>
The following functions are defined:
r = shiftl(b,n) Shifts byte b by n bits to the left and returns
the result in r. If n is 0, the byte is not
shifted, and if n greater than 8, the returned
value will be 0.
r = shiftr(b,n) Shifts byte b by n bits to the right and returns
the result in r. If n is 0, the byte is not
shifted, and if n greater than 8, the returned
value will be 0.
r = rotl(b,n) Rotate byte b by n bits to the left and returns
the result in r, with the high bit rotated into
the low bit on each rotation. If n is 0, the
byte is not rotated, and any value of n greater
than 8, will return the same result as n modulo 8.
r = rotr(b,n) Rotate byte b by n bits to the right and returns
the result in r, with the high bit rotated into
the low bit on each rotation. If n is 0, the
byte is not rotated, and any value of n greater
than 8, will return the same result as n modulo 8.
b = pack(l,r); Packs the low nybbles of bytes l and r into a
single byte, with l becoming the left (or high)
nybble and r becoming the right (or low) nybble.
and returns the packed byte in b.
l,r = unpack(b); Unpacks byte b, returning the left (or high)
nybble in l, and the right (or low) nybble in r.
d = dupl(b); Duplicates the low nybble of byte b into the
high nybble and returns the new byte in d.
Note: Executes function pack() with b as both
arguments.
d = swap(b); Swaps the left (or high) and right (or low)
nybbles of byte b and returns the new byte in d.
Note: Executes function rotl() with the arguments
b and 4.
c,d,e = func(a,&d); Stores the input value a and the address of d
in memory.
Returns three bytes read from memory.
Note: Writes argument a to variable arg0,
the address of d to variables adr0 and adr1,
and returns the values of variables var0,
var1, and var2.
Note: This library expects the following external variables to be defined:
temp0: Temporary Variable

103
include/bitlib.a02 Normal file
View File

@ -0,0 +1,103 @@
; C02 Module bitlib.h02 Assembly Language Subroutines
; Requires external location TEMP0 (system header)
SUBROUTINE BITLIB
;dupl(nybble) - Duplicate Low Order Nybble
;Args: A = Left Nybble
;Destroys: TEMP0
;Affects: Y
;Returns: A = Byte Containing Byte
DUPL: TAY ;Copy Left Nybble to Right
BEQ PACK ;If Zero, Return
;pack(nybble,nybble) - Pack Two Low Order Nybbles into Single Byte
;Args: A = Left Nybble
; Y = Right Nybble
;Destroys: TEMP0
;Returns: A = Packed Byte
PACK: ASL ;Shift Right Nybble to High Order
ASL
ASL
ASL
STA TEMP0 ;and Save It
TYA ;Get Right Nybble
AND #$0F ;Isolate Right Nybble
ORA TEMP0 ;Copy in Left Nybble
RTS
;unpack(byte) - Unpack Byte into Two Low Order Nybbles
;Args: A = Byte to Unpack
;Returns: A = Left Nybble
; Y = Right Nybble
UNPACK: PHA ;Save Byte
AND #$0F ;Isolate Right Nybble
TAY ;and Copy to Y Register
PLA ;Retrieve Byte
LSR ;and Shift Left Nybble to Low Order
LSR
LSR
LSR
RTS
;swap(byte) - Swap Low and High Nybbles in Byte
;Args: A = Byte to Swap
;Affects Y,N,Z,C
;Returns: A = Swapped Byte
SWAP: LDY #4 ;Set Count to 4 and Rotate Left
;rotl(byte,count) - Rotate byte by count Bits to the Left
;Args = Byte to Rotate
;Y = Number of Bits to Rotate
;Affects Y,N,Z,C
;Returns: A = Rotated Byte
ROTL: CPY #0 ;If Number of Bits is 0
BEQ .RETURN ; Return
.LOOPRL CLC ;Bit 0 will be 0
ROL ;Rotate Left
ADC #0 ; Copy Carry to Bit 0
DEY ;Decrement Counter
BNE .LOOPRL ; and Loop if Not 0
.RETURN RTS
;rotr(byte,count) - Shift byte by count Bits to the Right
;Args = Byte to Rotate
;Y = Number of Bits to Rotate
;Affects Y,N,Z,C
;Returns: A = Rotated Byte
ROTR: CPY #0 ;If Number of Bits is 0
BEQ .RETURN ; Return
.LOOPRR CLC ;Bit 7 will be 0
ROR ;Rotate Right
BCC .SKIPRR ;If Bit 0 was Set
ORA #$80 ; Set Bit 8
.SKIPRR DEY ;Decrement Counter
BNE .LOOPRR ; and Loop if Not 0
RTS
;shiftl(byte,count) - Shift byte by Count bits to the Left
;Args = Byte to Shift
;Y = Number of Bits to Rotate
;Affects Y,N,Z,C
;Returns: A = Shifted Byte
SHIFTL: CPY #0 ;If Number of Bits is 0
BEQ .RETURN ; Return
.LOOPSL ASL ;Shift Byte to Left
DEY ;Decrement Counter
BNE .LOOPSL ; and Loop if Not 0
RTS
;shiftr(byte,count) - Shift byte by Count bits to the Right
;Args = Byte to Shift
;Y = Number of Bits to Rotate
;Affects Y,N,Z,C
;Returns: A = Shifted Byte
SHIFTR: CPY #0 ;If Number of Bits is 0
BEQ .RETURN ; Return
.LOOPSR LSR ;Shift Byte to Right
DEY ;Decrement Counter
BNE .LOOPSR ; and Loop if Not 0
RTS
ENDSUBROUTINE

50
include/bitlib.h02 Normal file
View File

@ -0,0 +1,50 @@
/**********************************************
* bitlib - Bit Manipulation Routines for C02 *
**********************************************/
/* Duplicate Low Order Nybble in Byte *
* Args: char b - Byte to Duplicate *
* Returns: char d - Duplicated Byte */
char dupl();
/* Pack Nybbles into Single Byte *
* Args: char l - Left Nybble *
* char r - Right Nybble *
* Returns: char b - Packed Byte */
char pack();
/* Rotate Byte Left *
* Args: char b - Byte to Rotate *
* char n - Number of Bits *
* Returns: char r - Rotated Byte */
char rotl();
/* Rotate Byte Right *
* Args: char b - Byte to Rotate *
* char n - Number of Bits *
* Returns: char r - Rotated Byte */
char rotr();
/* Shift Byte Left *
* Args: char b - Byte to Shift *
* char n - Number of Bits *
* Returns: char r - Shifted Byte */
char shiftl();
/* Shift Byte Right *
* Args: char b - Byte to Shift *
* char n - Number of Bits *
* Returns: char r - Shifted Byte */
char shiftr();
/* Swap Nybbles in Byte *
* Args: char b - Byte to Swap *
* Returns: char d - Swapped Byte */
char swap();
/* Unpack Byte into Separate Nybbles *
* Args: char b - Byte to Unpack *
* Returns: char l - Left Nybble *
* char r - Right Nybble */
char unpack();

128
test/bittest.c02 Normal file
View File

@ -0,0 +1,128 @@
/*********************************
* BITTEST - Test Module bitlib *
*********************************/
//Specify System Header using -H option
#include <stddef.h02>
#include <bitlib.h02>
const char detail = #FALSE;
char argone,argtwo,expone,exptwo,resone,restwo;
char high,low,left,right;
void pr1arg() {putchr(' ');prbyte(argone);putchr('=');prbyte(resone);}
void pr2arg() {putchr(' ');prbyte(argone);putchr(',');prbyte(argtwo);
putchr('=');prbyte(resone);}
void pr2res() {putchr(' ');prbyte(argone);putchr('=');
prbyte(resone);putchr(',');prbyte(restwo);}
void prtok() {putstr(" OK"); newlin();}
main:
putstr("DUPL():");
high = 0; low = 0;
for (argone = 0; argone < $10; argone++) {
expone = high | low; high = high + 16; low++;
resone = dupl(argone); if (detail) pr1arg();
if (resone <> expone) goto er1arg;
}
prtok();
putstr("PACK():");
high = 0;
for (argone = 0; argone < $10; argone++) {
low = 0;
for (argtwo = 0; argtwo < $10; argtwo++) {
expone = high | low; low++;
resone = pack(argone,argtwo); if (detail) pr2arg();
if (resone <> expone) goto er2arg;
}
high = high + 16;
}
prtok();
putstr("UNPACK():");
high = 0;
for (expone = 0; expone < $10; expone++) {
low = 0;
for (exptwo = 0; exptwo < $10; exptwo++) {
argone = high | low; low++;
resone, restwo = unpack(argone); if (detail) pr2res();
if (resone <> expone or restwo <> exptwo) goto er2arg;
}
high = high + 16;
}
prtok();
putstr("SWAP():");
high = 0;
for (right = 0; right < $10; right++) {
low = 0; left = 0;
do {
argone = high | low; low++;
expone = left | right; left = left + 16;
resone = swap(argone); if (detail) pr1arg();
if (resone <> expone) goto er1arg;
} while (left);
high = high + 16;
}
prtok();
putstr("ROTL():");
argone = %10101010; expone = argone;
for (argtwo = 0; argtwo < 9; argtwo++) {
resone = rotl(argone, argtwo); if (detail) pr2arg();
if (resone <> expone) goto er2arg;
high = expone & $80; expone<<; if (high) expone++;
}
prtok();
putstr("ROTR():");
argone = %10101010; expone = argone;
for (argtwo = 0; argtwo < 9; argtwo++) {
resone = rotr(argone, argtwo); if (detail) pr2arg();
if (resone <> expone) goto er2arg;
low = expone & $01; expone>>; if (low) expone = expone | $80;
}
prtok();
putstr("SHIFTL():");
argone = %10101010; expone = argone;
for (argtwo = 0; argtwo < 9; argtwo++) {
resone = shiftl(argone, argtwo); if (detail) pr2arg();
if (resone <> expone) goto er2arg;
expone<<;
}
prtok();
putstr("SHIFTR():");
argone = %10101010; expone = argone;
for (argtwo = 0; argtwo < 9; argtwo++) {
resone = shiftr(argone, argtwo); if (detail) pr2arg();
if (resone <> expone) goto er2arg;
expone>>;
}
prtok();
goto exit;
er1arg:
if (detail) newlin();
putstr(" ARG $"); prbyte(argone); putstr(" RESULT $"); prbyte(resone);
putstr(" EXPECTED $"); prbyte(expone); newlin();
goto exit;
er2arg:
if (detail) newlin();
putstr(" ARGS $"); prbyte(argone); putstr(",$"); prbyte(argtwo);
putstr(" RESULT $"); prbyte(resone);
putstr(" EXPECTED $"); prbyte(expone); newlin();
goto exit;
er2res:
if (detail) newlin();
putstr(" ARG $"); prbyte(argone); putstr(" RESULT $"); prbyte(resone);
putstr(" EXPECTED $"); prbyte(expone); putstr(",$"); prbyte(exptwo);
newlin();
goto exit;

16
test/bittest.err Normal file
View File

@ -0,0 +1,16 @@
cleared iocb for channel 0
cleared iocb for channel 1
cleared iocb for channel 2
cleared iocb for channel 3
cleared iocb for channel 4
cleared iocb for channel 5
cleared iocb for channel 6
cleared iocb for channel 7
cleared iocb for channel 8
cleared iocb for channel 9
cleared iocb for channel 10
cleared iocb for channel 11
cleared iocb for channel 12
cleared iocb for channel 13
cleared iocb for channel 14
cleared iocb for channel 15

View File

@ -8,11 +8,19 @@
char aa,xx,yy; //Function Arguments
char i; //Loop Index
char r,h,l; //Register#, MSB, LSB
int v; //Register Contents
const char rvals = {$0F,$F0, $1E,$E1, $2D,$D2, $3C,$C3, $4B,$B4, $5A,$A5, $69,$96, $78,$87,
$80,$08, $91,$19, $A2,$2A, $B3,$B3, $C4,$4C, $D5,$5D, $E6,$6E, $F7,$7F};
char rcomp[32];
void clrabi() {for (i=0; i<=@rvals; i++) abi[i] = 0;}
void prword() {putchr('$'); prbyte(y); prbyte(x); putchr(' ');}
void putlin() {putstr(); newlin();}
void error() {putlin(); goto exit;}
void passed() {putlin("PASSED");}
void prtadr(aa,yy,xx) {
putchr('$');
if (yy) prbyte(yy);
@ -22,32 +30,55 @@ void prtadr(aa,yy,xx) {
main:
//Print Register Addresses
putstr("R0 "); prtadr(&R0); putstr(" R0L "); prtadr(&R0L); putstr(" R0H "); prtadr(&R0H); newlin();
putstr("R1 "); prtadr(&R1); putstr(" R1L "); prtadr(&R1L); putstr(" R1H "); prtadr(&R1H); newlin();
putstr("R2 "); prtadr(&R2); putstr(" R2L "); prtadr(&R2L); putstr(" R2H "); prtadr(&R2H); newlin();
putstr("R3 "); prtadr(&R3); putstr(" R3L "); prtadr(&R3L); putstr(" R3H "); prtadr(&R3H); newlin();
putstr("R4 "); prtadr(&R4); putstr(" R4L "); prtadr(&R4L); putstr(" R4H "); prtadr(&R4H); newlin();
putstr("R5 "); prtadr(&R5); putstr(" R5L "); prtadr(&R5L); putstr(" R5H "); prtadr(&R5H); newlin();
putstr("R6 "); prtadr(&R6); putstr(" R6L "); prtadr(&R6L); putstr(" R6H "); prtadr(&R6H); newlin();
putstr("R7 "); prtadr(&R7); putstr(" R7L "); prtadr(&R7L); putstr(" R7H "); prtadr(&R7H); newlin();
putstr("R8 "); prtadr(&R8); putstr(" R8L "); prtadr(&R8L); putstr(" R8H "); prtadr(&R8H); newlin();
putstr("R9 "); prtadr(&R9); putstr(" R9L "); prtadr(&R9L); putstr(" R9H "); prtadr(&R9H); newlin();
putstr("R10 "); prtadr(&R10); putstr(" R10L "); prtadr(&R10L); putstr(" R10H "); prtadr(&R10H); newlin();
putstr("R11 "); prtadr(&R11); putstr(" R11L "); prtadr(&R11L); putstr(" R11H "); prtadr(&R11H); newlin();
putstr("R12 "); prtadr(&R12); putstr(" R12L "); prtadr(&R12L); putstr(" R12H "); prtadr(&R12H); newlin();
putstr("R13 "); prtadr(&R13); putstr(" R13L "); prtadr(&R13L); putstr(" R13H "); prtadr(&R13H); newlin();
putstr("R14 "); prtadr(&R14); putstr(" R14L "); prtadr(&R14L); putstr(" R14H "); prtadr(&R14H); newlin();
putstr("R15 "); prtadr(&R15); putstr(" R15L "); prtadr(&R15L); putstr(" R15H "); prtadr(&R15H); newlin();
putstr("R0 "); prtadr(&abi.r0); putstr(" R0L "); prtadr(&abi.r0.lo); putstr(" R0H "); prtadr(&abi.r0.hi); newlin();
putstr("R1 "); prtadr(&abi.r1); putstr(" R1L "); prtadr(&abi.r1.lo); putstr(" R1H "); prtadr(&abi.r1.hi); newlin();
putstr("R2 "); prtadr(&abi.r2); putstr(" R2L "); prtadr(&abi.r2.lo); putstr(" R2H "); prtadr(&abi.r2.hi); newlin();
putstr("R3 "); prtadr(&abi.r3); putstr(" R3L "); prtadr(&abi.r3.lo); putstr(" R3H "); prtadr(&abi.r3.hi); newlin();
putstr("R4 "); prtadr(&abi.r4); putstr(" R4L "); prtadr(&abi.r4.lo); putstr(" R4H "); prtadr(&abi.r4.hi); newlin();
putstr("R5 "); prtadr(&abi.r5); putstr(" R5L "); prtadr(&abi.r5.lo); putstr(" R5H "); prtadr(&abi.r5.hi); newlin();
putstr("R6 "); prtadr(&abi.r6); putstr(" R6L "); prtadr(&abi.r6.lo); putstr(" R6H "); prtadr(&abi.r6.hi); newlin();
putstr("R7 "); prtadr(&abi.r7); putstr(" R7L "); prtadr(&abi.r7.lo); putstr(" R7H "); prtadr(&abi.r7.hi); newlin();
putstr("R8 "); prtadr(&abi.r8); putstr(" R8L "); prtadr(&abi.r8.lo); putstr(" R8H "); prtadr(&abi.r8.hi); newlin();
putstr("R9 "); prtadr(&abi.r9); putstr(" R9L "); prtadr(&abi.r9.lo); putstr(" R9H "); prtadr(&abi.r9.hi); newlin();
putstr("R10 "); prtadr(&abi.r10); putstr(" R10L "); prtadr(&abi.r10.lo); putstr(" R10H "); prtadr(&abi.r10.hi); newlin();
putstr("R11 "); prtadr(&abi.r11); putstr(" R11L "); prtadr(&abi.r11.lo); putstr(" R11H "); prtadr(&abi.r11.hi); newlin();
putstr("R12 "); prtadr(&abi.r12); putstr(" R12L "); prtadr(&abi.r12.lo); putstr(" R12H "); prtadr(&abi.r12.hi); newlin();
putstr("R13 "); prtadr(&abi.r13); putstr(" R13L "); prtadr(&abi.r13.lo); putstr(" R13H "); prtadr(&abi.r13.hi); newlin();
putstr("R14 "); prtadr(&abi.r14); putstr(" R14L "); prtadr(&abi.r14.lo); putstr(" R14H "); prtadr(&abi.r14.hi); newlin();
putstr("R15 "); prtadr(&abi.r15); putstr(" R15L "); prtadr(&abi.r15.lo); putstr(" R15H "); prtadr(&abi.r15.hi); newlin();
//Test setabi() and getabi()
for (i=0; i<=@rvals; i++) r0l[i] = 0; //Clear ABI Registers
//inline $ff;
setabi(@rvals, rvals); //Write to ABI Registers
for (i=0; i<@rvals; i++) {
if (!i&7) newlin();
if (!i&1) putstr(" $");
prbyte(R0l[i]);
if (R0l[i] <> rvals[i]) {putstr("ERROR!"); goto exit;}
putstr("SETABI(), GETABI() ");
clrabi(); //Clear Registers
i = 0;
for (r=0; r<16; r++) {
l = r | 16; h = r | 32;
setabi(r, h, l);
xx = abi[i]; i++;
yy = abi[i]; i++;
v = getabi(r);
//newlin(); prhex(r); putchr(':'); prword(.,h,l); prword(.,yy,xx); prword(v);
if (xx<>l or yy<>h) error("SETABI: WRITE ERROR");
if (<v<>l or >v<>h) error("GETABI: READ ERROR");
}
passed();
goto exit;
//Test setabi() and getabi()
putstr("SETABR(), GETABR() ");
for (i=0; i<=@rvals; i++) {
abi[i] = 0; //Clear ABI Registers
rcomp[i] = 0; //Clear Compare Array
}
//inline $ff;
setabr(@rvals, rvals); //Write to ABI Registers
getabr(@rcomp, rcomp); //Read from ABI Registers
for (i=0; i<@rvals; i++) {
//if (!i&7) newlin(); if (!i&1) putstr(" $"); prbyte(abi[i]);
if (abi[i] <> rvals[i]) error("SETABR() WRITE ERROR");
if (rcomp[i] <> rvals[i]) error("GETABR() READ ERROR");
}
if (abi[@rvals] <> 0) error("SETABR() OVERFLOW");
if (rcomp[@rvals] <> 0) error("GETABR() OVERFLOW");
passed();
goto exit;