      TITLE FCOL4
      MODULE FCOL4
      AREADEF PROG,[CODE,PIC,READ],DOUBLE
      AREADEF DATA,[DATA,PIC],DOUBLE
      DEFSB   DATA
      EXPORTC STOPCODE4,STARTCODE4,FCOL4
      IMPORTC OSWord='BBC'.'OSWord',OSFile='BBC'.'XOSFile'
mc    EQU     16  ; maximum # of colours
      AREA    PROG
STOPCODE4 ; stops the fchost program in the BBC
      MOVQW  2,bbc
      ADDR   bbc,TOS
      ADDR   @255,TOS
      CXP    OSWord
      RXP    4
host  DCS    "$.graphics.utils.hostfcol"
STARTCODE4  ; initializes for FCOL4 & starts the BBC host code
;     SUBROUTINE STARTCODE(nx,mscale,mode,nc,kols,nds)
;     nx is # columns
;     mscale is the scale of points to graphics coords (0 - 1023)
;     mode is MODE of plot
;     nc is # of colours & iteration bounds
;     kols are colours
;     nds  are iteration bounds
      SPRD   FP,TOS
      LPRD   FP,12(SP)
; load the BBC code first time through
      CMPQB  0,host
      BEQ    fc0
      MOVQD  -1,bbc+4
      ADDR   bbc,TOS
      MOVZBD host,TOS
      ADDR   host+1,TOS
      ADDR   @255,TOS
      CXP    OSFile
      MOVQB  0,host
fc0   MOVD   0(12(FP)),R0    ;nc
      MOVD   16(FP),R1       ;addr. kols
      MOVD   20(FP),R2       ;addr. nds
      MOVQW  -1,bnd[R0:W]    ;guard band
fc1   MOVW   -4(R2)[R0:D],bnd-2[R0:W]    ;store bands
      MOVW   -4(R1)[R0:D],col-2[R0:W]    ;store colour
      ACBD   -1,R0,fc1
      MOVQD  0,buf
      ADDR   buf,R1
      ADDR   4(R1),R2
      ADDR   @15,R0
      MOVSD                  ;clear buf
      MOVD   0(8(FP)),R7     ;mode
      MOVB   R7,mode
      MOVD   0(0(FP)),R0     ;nx
      MOVD   R0,R1           ;copy of nx
      ADDD   R0,R0
      ADDR   @0[R0:W],nx4    ;keep nx*4
      MULW   R7,R0
      ADDW   =22,R0
      ASHW   =-3,R0
      MOVW   R0,bbc          ;# bytes to send per row
      ADDQD  -1,R1           ;nx-1
      MOVD   R1,R2           ;ditto
      CMPQB  1,R7
      BNE    fc2
      ANDB   =15,R1
      ASHD   =-4,R2
      BR     fc3
fc2   ANDB   =7,R1
      ASHD   =-3,R2
fc3   MOVB   R1,byte         ;#colour bit pairs in last word
      ADDR   buf[R2:D],disp  ;address of last word
      MOVD   0(4(FP)),R1     ;mscale
      ASHD   =-2,R1          ;convert to pixels (0 - 255)
      MOVB   R1,stc+5        ;# rows for each Y
      DIVW   R7,R1
      MOVB   R1,stc+4        ;# columns for each X
      MOVB   R7,stc+6        ;mode
      MOVW   =#X0200,R0
      BSR    rdbyt           ;get byte @ &200 in BBC
      MOVB   R1,stc+2
      MOVW   =#X0201,R0
      BSR    rdbyt           ;get byte @ &201 in BBC
      MOVB   R1,stc+3
      MOVQW  7,stc           ;7 bytes in initialization of BBC code
      MOVW   =#X0200,R0
      MOVQB  0,R1
      BSR    sndbyt          ;put 0 in &200 in BBC
      MOVW   =#X0201,R0
      MOVB   =#X2D,R1
      BSR    sndbyt          ;put &2D in &201 in BBC
      ADDR   stc,TOS
      ADDR   @255,TOS
      CXP    OSWord          ;start BBC code
      LPRD   FP,TOS
      RXP    4
rdbyt  ; get byte from BBC
      MOVQD  -1,temp
      MOVW   R0,temp
      ADDR   temp,TOS
      MOVQD  5,TOS
      CXP    OSWord
      MOVB   temp+4,R1
      RET    0
sndbyt ; send byt to BBC
      MOVQD  -1,temp
      MOVW   R0,temp
      MOVB   R1,temp+4
      ADDR   temp,TOS
      MOVQD  6,TOS
      CXP    OSWord
      RET    0
FCOL4   ;  SUBROUTINE FCOL4(ib)
        ;  ib is the array of iteration counts (integer *2)
      MOVD   8(SP),R0
      MOVD   0(R0),R0        ;addr of ib
      MOVD   nx4,R1
      ADDD   R0,R1           ;end of ib
      MOVD   disp,R6
      ADDR   bnd,R2          ;initial boundary address
      MOVB   byte,R5         ;count of colour bits
      CMPQB  1,mode
      BNE    n0              ;mode 2
m0    MOVQD  0,R4            ;clear accumulator
m1    ADDQD  -4,R1
      MOVW   0(R1),R3        ;# iterations for point
m2    ADDQD  2,R2
      CMPW   0(R2),R3
      BLS    m2              ;bound is too big
m3    ADDQD  -2,R2
      CMPW   0(R2),R3
      BHI    m3              ;bound is too low
      ADDD   R4,R4
      ADDD   R4,R4           ;shift accumulator
      ORB    col-bnd(R2),R4  ;insert new colour
      ADDQB  -1,R5
      BCS    m1              ;accumulator not full
      MOVD   R4,0(R6)        ;store accumulator in O/P buffer
      ADDQD  -4,R6
      MOVB   =15,R5
      CMPD   R1,R0
      BHI    m0              ;loop over points
snd   ADDR   bbc,TOS
      ADDR   @255,TOS
      CXP    OSWord
      RXP    4
n0    MOVQD  0,R4            ;clear accumulator
n1    ADDQD  -4,R1
      MOVW   0(R1),R3        ;# iterations for point
n2    ADDQD  2,R2
      CMPW   0(R2),R3
      BLS    n2              ;bound is too big
n3    ADDQD  -2,R2
      CMPW   0(R2),R3
      BHI    n3              ;bound is too low
      ADDD   R4,R4
      ADDD   R4,R4
      ADDD   R4,R4
      ADDD   R4,R4           ;shift accumulator
      ORB    col-bnd(R2),R4  ;insert new colour
      ADDQB  -1,R5
      BCS    n1              ;accumulator not full
      MOVD   R4,0(R6)        ;store accumulator in O/P buffer
      ADDQD  -4,R6
      MOVQB  7,R5
      CMPD   R1,R0
      BHI    n0              ;loop over points
      BR     snd             ;send data to BBC
      AREA   DATA
nx4   ALLOCD 1
mode  ALLOCB 1
byte  ALLOCB 1
disp  ALLOCD 1
bnd   ALLOCW mc+1
col   ALLOCW mc
bbc   ALLOCW 41
buf   EQU    bbc+2
temp  ALLOCW 3
stc   ALLOCW 4
      END
