From d816bd12738e5008f4dc0b72c92b04cd05e73f4b Mon Sep 17 00:00:00 2001 From: Curtis F Kaylor Date: Sun, 4 Oct 2020 22:17:09 -0400 Subject: [PATCH] Completed, tested, debugged, and documented module bitlib --- doc/bitlib.txt | 70 +++++++++++++++++++++++++ include/bitlib.a02 | 103 ++++++++++++++++++++++++++++++++++++ include/bitlib.h02 | 50 ++++++++++++++++++ test/bittest.c02 | 128 +++++++++++++++++++++++++++++++++++++++++++++ test/bittest.err | 16 ++++++ x16/abitest.c02 | 81 +++++++++++++++++++--------- 6 files changed, 423 insertions(+), 25 deletions(-) create mode 100644 doc/bitlib.txt create mode 100644 include/bitlib.a02 create mode 100644 include/bitlib.h02 create mode 100644 test/bittest.c02 create mode 100644 test/bittest.err diff --git a/doc/bitlib.txt b/doc/bitlib.txt new file mode 100644 index 0000000..6498437 --- /dev/null +++ b/doc/bitlib.txt @@ -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 + #include + +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 diff --git a/include/bitlib.a02 b/include/bitlib.a02 new file mode 100644 index 0000000..9d610d7 --- /dev/null +++ b/include/bitlib.a02 @@ -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 diff --git a/include/bitlib.h02 b/include/bitlib.h02 new file mode 100644 index 0000000..704fef2 --- /dev/null +++ b/include/bitlib.h02 @@ -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(); + diff --git a/test/bittest.c02 b/test/bittest.c02 new file mode 100644 index 0000000..985ad4a --- /dev/null +++ b/test/bittest.c02 @@ -0,0 +1,128 @@ +/********************************* + * BITTEST - Test Module bitlib * + *********************************/ + +//Specify System Header using -H option +#include +#include + +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; diff --git a/test/bittest.err b/test/bittest.err new file mode 100644 index 0000000..cf3fc2c --- /dev/null +++ b/test/bittest.err @@ -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 diff --git a/x16/abitest.c02 b/x16/abitest.c02 index d948e2a..8946b16 100644 --- a/x16/abitest.c02 +++ b/x16/abitest.c02 @@ -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 (l or >v<>h) error("GETABI: READ ERROR"); } + passed(); -goto exit; \ No newline at end of file + //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;