
**********************************************************************
files: Bitwise.TXT, Bitwise.TAP
       Bitwise1.BAS, Bitwise1.ASM
       BitBASIC1.BAS, BitBASIC2.BAS, BitBASIC3.BAS
**********************************************************************


** AND,XOR,OR,BIT,RES,SET,CPL,NEG,RLC,RRC,SLA,SRL,RL,RR,SRA for BASIC
   ==================================================================

Bitwise1
Here's a routine to provide all of the above operations from BASIC.

;operation # on parameter a:    PRINT USR address,"#",C,a;
;# values: CPL=C, NEG=N, RLC=(, RRC=), SLA=<, SRL=>, RL={, RR=}, SRA=]
;operation # on parameters a,b: PRINT USR address,"#",C,a,b;
;# values: AND=A, XOR=X, OR=O, BIT=B, RES=R, SET=S

Separate the parameters with ',' and terminate with ';'. The result is stored in 'bc' and the Carry flag is returned in C (these may be any numeric variable names, terminated with a ':'; see Bitwise1.ASM:VARNAME). Input 'a','b','C' may be any numeric expressions. The accumulator always takes 'a', so for BIT,RES,SET the bit number is the second parameter 'b'. The variables used for the returned values must already exist.

The ASSIGN segment at the end also demonstrates how to assign values to BASIC variables from machine code. Just put the value on the calculator stack and point CH_ADD to the name and "call CLASS_01: call LET". Remember to restore the initial value of CH_ADD before returning to BASIC.

Bitwise1.BAS [code]
   5 CLEAR 39999: LET C=0: DIM b$(5)
  10 INPUT "RlcRrc,SlaSrl,RlRr,SRA,CplNeg"'a'"AndXorOr,BitResSet"'b
  19 RESTORE 100: PRINT "OpCd A       C","=     C"
  20 FOR d=0 TO 8: READ a$,b$: GO SUB 200: NEXT d
  35 PRINT '"OpCd A   B   C","=     C"
  36 FOR d=9 TO 11: READ a$,b$: GO SUB 201: NEXT d
  47 LET b=b-INT(b/8)*8
  48 PRINT '"OpCd A   bit C","=     C"
  50 FOR d=12 TO 14: READ a$,b$: GO SUB 201: NEXT d
  99 PAUSE 0: CLS : GO TO 10
 100 DATA "(","RLC", ")","RRC", "<","SLA", ">","SRL",
          "{","RL",  "}","RR",  "]","SRA",
          "C","CPL", "N","NEG"
 101 DATA "A","AND", "X","XOR", "O","OR"
 102 DATA "B","BIT", "R","RES", "S","SET"
 200 PRINT b$;a;TAB 13;C,"= ";: PRINT USR 40021,"bc:",a$,C,a;:
     PRINT bc;TAB 22;C: RETURN
 201 PRINT b$;a;TAB 9;b;TAB 13;C,"= ";: PRINT USR 40021,"bc:",a$,C,a,b;:
     PRINT bc;TAB 22;C: RETURN
[/code]

Bitwise1.ASM [code]
STAKA:  equ  $2d28           ;STACK-A   to calculator stack: A
STAKBC: equ  $2d2b           ;STACK-BC  to calculator stack: BC
FPTOBC: equ  $2da2           ;FP-TO-BC  from calculator stack: BC
FPTOA:  equ  $2dd5           ;FP-TO-A   from calculator stack: A
FETCHS: equ  $2bf1           ;STK-FETCH from calculator stack: AEDCB
ERRORA: equ  $34e7           ;"A Invalid argument"
CH_ADD: equ  23645
STKBOT: equ  23651
STKEND: equ  23653
STORE:  equ  23660           ;S_TOP

LOCATE: equ  40021           ;anywhere
        org  LOCATE

BITWISE:push bc
        pop  hl              ;HL=runtime   location
        ld   de,LOCATE       ;DE=assembled location
        and  a
        sbc  hl,de
        ld   (STORE),hl      ;=runtime displacement from LOCATE

ssss:   ld   hl,14
        add  hl,sp
        ld   sp,hl           ;undo USR
GETARG: rst  $20
        call $24fb           ;SCANNING
        rst  $18
        cp   ","
        jr   z,GETARG
        ld   ix,(STKBOT)

        ld   hl,OPTIONS+14   ;***
        ld   de,(STORE)      ;DE=runtime displacement
        add  hl,de
        ld   d,(ix+7)
        ld   e,(ix+6)
        ld   a,(de)          ;A =operation code
        ld   bc,15
        cpdr                 ;check code
        jp   nz,ERRORA       ;exit on error

        ld   de,(STKEND)
        push de
        ld   a,c             ;A =operator offset in OPTIONS
        ld   hl,OPCODES      ;***
        ld   de,(STORE)      ;DE=runtime displacement
        add  hl,de
        add  hl,bc
        add  hl,bc           ;HL=opcodes position in OPCODES
        ex   de,hl
        ld   hl,OPERATE      ;***
        ld   bc,(STORE)      ;DE=runtime displacement
        add  hl,bc
        ex   de,hl
        ldi                  ;enter command opcodes
        ldi
        cp   $09
        jr   c,EXECOP        ;1st 9 ops just take 1 arg

        push af
        call FPTOBC          ;C =2nd parameter
        pop  af              ;A =$00->$0E
        ld   hl,OPERATE+1    ;***
        ld   de,(STORE)      ;DE=runtime displacement
        add  hl,de
        cp   $0C
        ld   a,(hl)
        jr   c,EXECOP        ;1st 12 ops need no mod
        sla  c               ;calc 2nd opcode for BIT,RES,SET
        sla  c
        sla  c               ;C =bit pos * 8
        add  a,c
LDOPC2: ld   (hl),a

EXECOP: push bc
        call FPTOA           ;A =1st parameter
        push af
        call FPTOA           ;A =Carry flag
        sub  1
        ccf                  ;set Carry=A
        pop  bc
        ld   a,b             ;A =1st parameter
        pop  bc              ;C =2nd parameter for AND,XOR,OR
OPERATE:defw $0000           ;opcodes go here
        push af
        ld   d,(ix+7)
        ld   e,(ix+6)
        ld   a,(de)          ;A =operation code
        cp   "B"
        jr   nz,ASSIGN
        pop  bc              ;B =result; C =Flags
        ld   a,c
        and  %01000000       ;preserve Zero flag for BIT operation
        rlca
        rlca                 ;move to bit 0
        xor  %00000001
        push af

ASSIGN: pop  bc              ;B =result; C =Flags
        ld   a,c
        and  %00000001       ;preserve Carry flag
        push bc
        call STAKA
        ld   hl,CARRY        ;***
        ld   de,(STORE)      ;DE=runtime displacement
        add  hl,de
        ld   de,(CH_ADD)
        ld   (STORE),de
        ex   de,hl           ;DE=pointer for variable 'C' name
        ld   (CH_ADD),de
        call $1c1f           ;CLASS_01
        call $2aff           ;LET C=Carry
        pop  bc
        ld   a,b
        call STAKA
        ld   d,(ix+2)
        ld   e,(ix+1)        ;DE=pointer for variable 'bc' name
        ld   (CH_ADD),de
        call $1c1f           ;CLASS_01
        call $2aff           ;LET bc=result
        ld   de,(STORE)
        ld   (CH_ADD),de     ;restore (CH_ADD) to entry value
        pop  de
        ld   (STKEND),de     ;restore (STKEND) to entry value
        ret

CARRY:  defm "C:"

        ;RLC, RRC, SLA, SRL, RL, RR, SRA
        ;CPL, NEG, AND, XOR, OR, BIT, RES, SET

OPTIONS:defb "(",")","<",">","{","}","]"
        defb "C","N","A","X","O","B","R","S"

OPCODES:defb $CB,$07, $CB,$0F, $CB,$27, $CB,$3F, $CB,$17, $CB,$1F, $CB,$2F
        defb $2F,$00, $ED,$44, $A1,$00, $A9,$00, $B1,$00
        defb $CB,$47, $CB,$87, $CB,$C7
[/code]


*********************************************************************


** Bit Operations in BASIC: AND,XOR,OR,BIT,RES,SET,CPL
   ===================================================

BitBASIC
I was prompted to revisit the "AND,XOR,OR,...for BASIC" topic and came up with this function to do bitwise AND,XOR,OR - not as m/code routines called from BASIC, but entirely in BASIC. It's inevitably slow, as it does 16 divisions and 8 exponentiations for each evaluation, but it provides the facility, for those not inclined to use m/code. An advantage of this version over that posted last October is that it's not limited to 8 bits.

BitBASIC1.BAS [code]
     REM a = val1   = 1st number
         b = val2   = 2nd number
         c = opcode = 0(OR), 1(AND), 2(XOR)
         d = bits   = number of bits to check
         g = nnnn   = GO SUB line
         v = 0      = result on RETURN

llll DEF FN b(a,b,c,d,g,v)=g:
     RESTORE llll: LET da=PEEK 23639+256*PEEK 23640+8:
     POKE 23563,da-INT (da/256)*256: POKE 23564,INT (da/256)
....
     GO SUB FN b(val1,val2,opcode,bits,nnnn,0)
....
nnnn FOR p=0 TO d-1:
       LET ba2=INT (a/2): LET bb2=INT (b/2):
       LET ba=a-ba2*2: LET bb=b-bb2*2:
       LET a=ba2: LET b=bb2:
       IF ba+bb AND ba+bb<>c THEN LET v=v+2^p
oooo NEXT p: RETURN
[/code]

   ===================================================

Here's a similar routine for BIT,RES,SET (although see next section for a much simpler method).

BitBASIC2.BAS [code]
     REM a = val0   = number to address
         b = bita   = bit to address
         c = opcode = 0(RES), 1(SET), 2(BIT)
         d = bits   = number of bits to check
         g = nnnn   = GO SUB line
         v = 0      = result on RETURN

llll DEF FN c(a,b,c,d,g,v)=g:
     RESTORE llll: LET da=PEEK 23639+256*PEEK 23640+8:
     POKE 23563,da-INT (da/256)*256: POKE 23564,INT (da/256)
....
     GO SUB FN c(val0,bita,opcode,bits,nnnn,0)
....
nnnn FOR p=0 TO d-1:
       LET ba2=INT (a/2): LET ba=a-ba2*2: LET a=ba2:
       IF p=b THEN LET ba=c AND c<2 OR ba AND c=2:
         IF c=2 THEN LET v=ba: RETURN
oooo   IF ba THEN LET v=v+2^p
pppp NEXT p: RETURN
[/code]

   ===================================================

... and CPL ... (NEG is just LET val0=-val0).

BitBASIC3.BAS [code]
     REM a = val0   = number to complement
         d = bits   = number of bits to check
         g = nnnn   = GO SUB line
         v = 0      = result on RETURN

llll DEF FN d(a,d,g,v)=g:
     RESTORE llll: LET da=PEEK 23639+256*PEEK 23640+8:
     POKE 23563,da-INT (da/256)*256: POKE 23564,INT (da/256)
....
     GO SUB FN d(val0,bits,nnnn,0)
....
nnnn FOR p=0 TO d-1:
       LET ba2=INT (a/2): LET ba=a-ba2*2: LET a=ba2:
       IF NOT ba THEN LET v=v+2^p
pppp NEXT p: RETURN
[/code]


*********************************************************************


** Simple BIT,RES,SET in BASIC
   ===========================

To reference a particular bit 'n' in BASIC:
[code]
[b]REM bit n,(address)[/b]
LET byte=PEEK address: LET bit=INT (byte/2^n)-INT (byte/2^(n+1))*2
[b]REM res n,(address)[/b]
IF bit THEN POKE address,byte-2^n
[b]REM set n,(address)[/b]
IF NOT bit THEN POKE address,byte+2^n
[/code]

The TAP file versions of BitBASIC1,2,3 include comparative timings.

*********************************************************************

