/*  VDCLIB 1.3  */
/*  Routines to bitmap the C128 8563 Video Display Controller  */
/*  17 Jul 87 update - L. Howie  */

/*  bitmap()    :  Puts VDC in 80 col bitmap mode              */

/*  colorm()    :  Sets proper monochrome values in reg 26     */

/*  wrtvdc(i,j) :  i = reg nr, j=value to be written to reg    */

/*  k=rdvdc(i)  :  i = reg nr, k= register value               */

/*  zeroram()   :  Points to first byte of VDC memory          */

/*  clrmap()    :  Clears the bitmap                           */

/*  textmode()  :  Return register 25 to text                  */

/*  vdcram(i)   :  i=1 saves ram to disk, i=0 returns ram      */
/*                 i=3 saves, i=2 returns under filename given */
/*                 in scrnam[]                                 */

/*  saveram()   :  Save entire VDC ram to disk file VDCRAM.DAT */

/*  ramback()   :  Return VDCRAM.DAT data to VDC ram           */

/*  plot(x,y,n) :  plots a dot on 639x199 map if n=1.  Erase if n=0 */

/*  hires80     :  Sets, clears, and colors the bitmap         */

/*  chrpat(chr) :  Returns address of 8 byte char pattern       */

/*  rotpat(chr) :  Returns address of 8 byte character pattern */
/*                 character is rotated 90 deg counter clockwise  */

/*  plotby(byte,x,y) : Plot a byte - upper left hand corner     */
/*      (bit 7) located at x=0-631, y=0-199                     */

/*  plotch(chraddr,x,y) : Plot a character - upper left hand corner */
/*  (bit 7, byte 0) located at x,y : address of byte at chraddr */
/*  x <= 631, y>=7                                              */  

/*  twotal(chraddr,x,y) : Plot a  character using 16 bits */
/*  in the horizontal direction - upper left corner as above      */
/*  compensates for squat look due to screen aspect ratio         */

/*  hstrg1(strg addr,x,y) : write a horizontal string of 8 bit  wide */
/*    characters with upper left corner of first char at x,y    */

/*  hstrg2(strg addr,x,y) : write a horizontal string of 16 bit wide */
/*    chars with upper left corner of first char at x,y         */

/*  vstrg1(strg addr,x,y) : write a vertical string  of 8 bit wide */
/*    ROTATED chars starting at x,y for upper left corner, char #1. */
/*    string is drawn from bottom of screen to top of screen    */

/*  vstrg2(strg addr,x,y) : same as above but chars are 16 bit wide */
/*    in the screen's horizontal direction                      */

/*  vstrg3(strg addr,x,y):  write a vertical string with ordinary */
/*    unrotated chars with x,y being the upper left corner of the */
/*    first char.  String is drawn DOWN from TOP OF SCREEN.       */

/*  doline(x1,y1,x2,y2,color): draw/erase line between 2 points */

/*  doscrn(k,l) : Does the work for savescrn() & getscrn()      */

/*  savescrn(k)  : saves 16k screen- k is address of filename   */
/*      filename must be UPPERCASE.SCR                          */

/*  getscrn(k)   : returns 16k screen - k is filename address   */
/*      filename must be UPPERCASE.SCR                          */

 
int stakm1,stakm2,stakm3,stakm4;
int chrrot[8];
char scrnam[16];

wrtvdc()
 {        /* General register write */
#asm
        maclib  z80

        pop     h               ;get args off stack
        shld    stakm1          ;save args in mem
        pop     h
        shld    stakm2          ;data byte
        pop     h
        shld    stakm3          ;register nr
        lhld    stakm3          ;restore stack
        push    h
        lhld    stakm2
        push    h
        lhld    stakm1
        push    h
        mvi     d,0             ;zero the hi byte
        lda     stakm2          ;get the data byte
        mov     e,a             ;to the de pair
        lda     stakm3          ;get the register nr
        call    waitwr          ;wait for chip ready
        outp    e               ;output data to port
        ret

waitwr:                         ;routine writes to d600h
        push    psw             ;waits for bit 7 d600h
        lxi     b,0d600h        ;to turn to 1
portwt:                         ;then sets chip write
        inp     a               ;address to d601h
        ral
        jrnc    portwt
        pop     psw
        outp    a
        inr     c
        ret
#endasm
 }


rdvdc()
 {
#asm
        maclib  z80
                                ;get args off stack
        pop     h               ;1st arg is return addr
        shld    stakm1          ;save args in mem
        pop     h               ;2nd arg is register nr
        shld    stakm2          ;to be read
        push    h               ;restore stack
        lhld    stakm1
        push    h

        lda     stakm2          ;get the register nr
        call    waitrd          ;wait for chip ready
        inp     a               ;input data from port
        sta     stakm3          ;store it away
        lhld    stakm3          ;return in hl register
        ret

waitrd:
        push    psw
        lxi     b,0d600h
portrd:
        inp     a
        ral
        jrnc    portrd
        pop     psw
        outp    a
        inr     c
        ret
#endasm
 }


bitmap()
 {
  int i,j,k;

  i=25; j=135;
  wrtvdc(i,j);
 }


colorm()
 {
  int i,j,k;

  i=26; j=144;
  wrtvdc(i,j);
 } 


zeroram()
 {                  /* Set chip ram pointer to start of ram  */
  int i,j,k;
 
  i=18; j=19; k=0;
  wrtvdc(i,k);
  wrtvdc(j,k);
 }


clrmap()
 {
#asm
        maclib  z80

        mvi     h,0             ;set display address
        mvi     l,0             ;to col 0,row 0
        mvi     a,18
        call    waitcl
        outp    h
        mvi     a,19
        call    waitcl
        outp    l

clearm:
        mvi     h,160           ;16000 bytes
lcloo1      
        mvi     l,100           ;to clear
dtloo1
        mvi     a,31            ;the chip data reg nr
        mvi     d,0             ;blank for chip data 
        call    waitcl          
        outp    d               ;output blank to port
        dcr     l               ;repeat
        jnz     dtloo1          ;until 16000 bytes
        dcr     h
        jnz     lcloo1          ;are done
        ret


waitcl:
        push    psw
        lxi     b,0d600h
looper:
        inp     a
        ral
        jrnc    looper
        pop     psw
        outp    a
        inr     c
        ret
#endasm
 }


rvsmap()
 {
  int i,j,k;
  i=26; j=9;
  wrtvdc(i,j);
 }


textmode()
 {
  int i,j;
  i=25;  j=71;  /* j=64 if vdc chip 7a */
  wrtvdc(i,j);
  i=26;  j=0;
  wrtvdc(i,j);
 }


vdcram()
 {
#asm
                      ;read/write vdc ram from/to disk
        maclib  z80
;
bdos    equ     0005h
dbuff   equ     0080h
openf   equ     15
closef  equ     16
deletef equ     19
readf   equ     20
writef  equ     21
makef   equ     22

        
        pop     h
        shld    stakm1
        pop     h
        shld    stakm2
        push    h
        lhld    stakm1
        push    h
        lda     stakm2
        cpi     3               ;3 means write input filename
        jz      dorite
        cpi     2               ;2 means read input filename
        jz      doread
        cpi     1               ;1 means write VDCRAM.DAT
        jz      dorite
doread: jmp     ramret          ;0 means read VDCRAM.DAT
dorite: jmp     wrtram
;
setfcb:
        mvi     c,16            ;setup the file contrl
        lxi     d,fcbnam        ;assume VDCRAM.DAT
        lxi     h,myfcb         ;target bytes for filename
        lda     stakm2          ;check to see if current screen
        cpi     2               ;less than 2 means VDCRAM.DAT
        jc      mfcb            ;less than 2, dump/read charset
        lxi     d,scrnam        ;otherwise dump/read input filename
mfcb:   ldax    d
        inx     d
        mov     m,a
        inx     h
        dcr     c
        jnz     mfcb
        ret
;
opnfcb: xra     a               ;open the file
        sta     myfcr
        lxi     d,myfcb
        call    open
        ret
;
rdrec   lxi     d,myfcb         ;read a 128 byte rec
        call    read            ;into buffer at 80h
        ora     a
        jz      rdbuff
        jmp     eofile
;
rdbuff: lxi     b,0080h         ;read the chars from
getbyt: ldax    b               ;the buffer and send
        mov     e,a             ;to the VDC
        mvi     d,0
        mvi     a,31
        push    b
        call    waitsv
        outp    e
        pop     b
        inr     c
        jnz     getbyt
;
        ret          

;
;
waitsv: push    psw
        lxi     b,0d600h
portsv: inp     a
        ral
        jrnc    portsv
        pop     psw
        outp    a
        inr     c
        ret

setzro:        ;set vdc ram pointer to start of ram
        mvi     d,0
        mvi     e,0
        mvi     a,18
        call    waitsv
        outp    e
        mvi     a,19
        call    waitsv
        outp    e
        ret

ramret:        ;return 16k vdc ram to chip from disk file
        call    setfcb          ;set filename
        call    opnfcb          ;open file 'VDCRAM.DAT'
        call    setzro          ;set vdc ram pointer to zero
        mvi     a,0             ;set record counter to zero
        sta     ctrecs       
morecs: 
        call    rdrec
        lda     ctrecs
        inr     a
        sta     ctrecs
        cpi     7fh
        jnz     morecs
        call    eofile
        ret
                        

wrtram:        ;write 16k VDC chip ram to default disk file
        call    setfcb          ;setup file 'VDCRAM.DAT'
        lxi     d,myfcb
        call    delete          ;delete if present
        lxi     d,myfcb         ;now create file
        call    make
        call    setzro          ;beginning of vdc ram
        xra     a               ;start write at zero
        sta     myfcr
        sta     ctrecs          ;set record count to zero        
filbuf: lxi     d,007fh         ;write ram into buffer
morchr: inr     e               ;start at 80h
        mvi     a,31            ;read a vdc byte
        call    waitsv
        inp     a
        stax    d               ;place in buffer
        mov     a,e
        cpi     255             ;got 128 chars yet?
        jnz     morchr          ;no-get another  
        lxi     d,myfcb         ;yes-write the record
        call    write
        lda     ctrecs          ;check record count
        inr     a               ;inrement record counter
        sta     ctrecs
        cpi     7fh             ;got 128 records yet?
        jnz     filbuf          ;no, get another record
        call    eofile          ;yes-close out file
        ret         

eofile:
        lxi     d,myfcb
        call    close
        ret        
             
                        

open:   mvi     c,openf
        call    bdos
        ret
close:  mvi     c,closef
        call    bdos
        ret
read:   mvi     c,readf
        call     bdos
        ret
write:  mvi     c,writef
        call    bdos
        ret
delete: mvi     c,deletef
        call    bdos
        ret
make:   mvi     c,makef
        call    bdos
        ret
finis:  ret


myfcb:  ds      33
fcbnam  db      0,'VDCRAM  DAT',0,0,0,0
myfcr   equ     myfcb+32
ctrecs  ds      1

#endasm
 }


saveram()
 {
  vdcram(1);
 }

ramback()
 {
  vdcram(0);
 }


plot(i,j,k)
 int i,j,k;
 {              /*  plot or erase a dot in vdc memory  */

 /*  i=x coordinate, 0 to 639  j=y coord ( 0 to 199 )  */ 
 /*  0,0 located in lower left hand corner of screen   */

int xp,yp,xm,by,bt,bv,r,hi,lo,m;

  yp= 199-j;
  if (yp > 199) yp=199;   if(yp<0) yp=0;  /* trap out-of-bounders */
  if (i>639) i=639;  if(i<0) i=0; 
                                          /* get vdc byte nr */
  xp=i/8; xm= i % 8; 
  by=80*yp + xp;
                                          /* set display address */
  hi= by/256;     lo=by % 256;
                                          /* find correct bit in byte */
  bt=7-xm;
  bv=1;            r=31;
  if(bt==0) bv=1;
  if(bt==1) bv=2;
  if(bt==2) bv=4;
  if(bt==3) bv=8;
  if(bt==4) bv=16;
  if(bt==5) bv=32;
  if(bt==6) bv=64;
  if(bt==7) bv=128;

  wrtvdc(18,hi);    wrtvdc(19,lo);       /* set vdc memory pointer  */

  if(k != 0)                                /* plot dot if k  */
   {
    m = rdvdc(r);                         /* current value of byte    */
    bv= m | bv;                           /* turn on designated bit   */
    wrtvdc(18,hi);                        /* have to re-address byte  */
    wrtvdc(19,lo);                        /* because vdc byte pointer */
    wrtvdc(r,bv);                         /* advanced during read     */
   }
  if(k==0)                                /* erase if k=0 */
   {
    m=rdvdc(r);                                                    
    bv=m & (255-bv);                      /* turn off designated bit */
    wrtvdc(18,hi);                                                      
    wrtvdc(19,lo);                       
    wrtvdc(r,bv);                                                      
   }
 }    

hires80()
 {
  bitmap();
  colorm();
  clrmap();
 }


chrpat()
 {
#asm
        maclib  z80

bdos    equ     0005h
dbuff   equ     0080h
openf   equ     15
closef  equ     16
readf   equ     20


        pop     h
        shld    stakm1
        pop     h
        shld    stakm2          ;the ascii code
        push    h
        lhld    stakm1
        push    h
                                ;zero out the 16 pattern bytes
        mvi     e,0
        lxi     b,pattrn
zerpat: mvi     a,0
        stax    b     
        inx     b
        inr     e
        mov     a,e
        cpi     16      
        jnz     zerpat
                                ;get index number of input code
        lxi     h,chrasc-1
        mvi     e,255
nexchr: 
        inx     h
        inr     e
        mov     a,e
        cpi     64
        jz      badchr
        lda     stakm2
        cmp     m
        jnz     nexchr
        mov     a,e
        sta     stakm1          ;got the index into chrasc

        
        mvi     h,0             ;now x16 - each vdc pattern
        mov     l,a             ;is 16 bytes long
        dad     h        
        dad     h
        dad     h
        dad     h               ;the number of offset bytes from
                                ;$2000 where the pattern starts
        shld    stakm3
                                ;start is 64 128 byte records
        mov     a,h
        ral      
        mov     c,a   
lorecs:
        mov     a,l
        sui     128
        jc      upnone
        inr     c
        mov     l,a
upnone: 
        mov     a,l
        sta     stakm1          ;byte offset in the record
        mov     a,c             ;get record count
        adi     64              ;add base count
        sta     chrfcr
        mvi     c,16            ;setup the file control
        lxi     d,chrnam
        lxi     h,chrfcb
charcb: ldax    d               ;move the name
        inx     d
        mov     m,a
        inx     h
        dcr     c
        jnz     charcb
        lxi     d,chrfcb        ;open the file
        mvi     c,openf
        call    bdos
        lxi     d,chrfcb        ;read the record
        mvi     c,readf
        call    bdos
        lda     stakm1          ;retrieve byte offset
        adi     128
        mov     c,a
        mvi     b,0
        lxi     d,pattrn        ;put 16 byte pattern in storage
getach:       
        ldax    b
        stax    d
        inx     b
        inx     d
        inx     d
        inr     l
        mov     a,l
        cpi     8
        jnz     getach
        
        mvi     c,closef        ;close file and go home
        lxi     d,chrfcb
        call    bdos
 badchr:   
        lxi     h,pattrn        ;leave pointer to pattern
        ret        
        
                 

pattrn  ds      16
chrfcb: ds      33
chrnam  db      0,'VDCRAM  DAT',0,0,0,0
chrfcr  equ     chrfcb + 32
chrasc:
 db      '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ !"#$%&\()*+,-./0123456789:;<=>?'

#endasm
 }

shfchr()         /*  move byte to the right by one bit  */
{
#asm
        pop     h
        shld    stakm1 
        pop     h
        shld    stakm2
        push    h
        lhld    stakm1
        push    h
        lda     stakm2
        ani     254
        rrc             
        mov     l,a
        mvi     h,0
        ret
#endasm
}        

rotpat(i)
int i;
 {
  int j,*k,l;
  int workbyte,dumbyte,nbit,nbyte,ander,shifter;
  int savebase;

  savebase = chrpat(i);                   
  for(j=0;  j<=7; j++)
   {
      switch(j)                      
        {
      case 0: ander=1;     break;
      case 1: ander=2;     break;
      case 2: ander=4;     break;
      case 3: ander=8;     break;
      case 4: ander=16;    break;
      case 5: ander=32;    break;
      case 6: ander=64;    break;
      case 7: ander=128;   break;            
        }
    dumbyte=0;
    for(nbit=0; nbit<=7; nbit++)
     {
      switch(nbit)                      
        {
      case 0:    shifter=1;   break;
      case 1:    shifter=2;   break;
      case 2:    shifter=4;   break;
      case 3:    shifter=8;   break;
      case 4:    shifter=16;  break;
      case 5:    shifter=32;  break;
      case 6:    shifter=64;  break;
      case 7:    shifter=128; break;            
        }
      k=savebase+14-2*nbit;
      workbyte = *k;
      if ((workbyte & ander) > 0 )
        dumbyte = dumbyte + shifter;
     }
        l=shfchr(dumbyte);
        chrrot[j] = l;
   }   
   return(chrrot);
 }  

 
plotby(b,x,y)
int b,x,y;
 {
  int i,j,k,l;

  j=x; k=y;

  for (i=7;  i>=0;  i--)
   {
    switch (i)
     {
      case 0: l=1;   break;
      case 1: l=2;   break;
      case 2: l=4;   break;
      case 3: l=8;   break;
      case 4: l=16;  break;
      case 5: l=32;  break;
      case 6: l=64;  break;
      case 7: l=128; break;
     }
    
    if ((b & l) > 0) 
      plot(j,k,1);
   
    if ((b & l) == 0)
      plot(j,k,0);
  
    j++;
  }
 }

plotch(c,x,y)
int *c,x,y;
 {
 /*  c=address of byte zero of the character   */

  int *i,j,k,l,m,byt;

i = c; j=x; k=y;

for(l=0; l<=7; l++)
 {
  byt = *i;
  plotby(byt,j,k);
  i++;  
  k--;   
 }      
}

twotal(c,x,y)
int *c,x,y;
 {
 /*  c=address of byte zero of the character   */

  int *i,j,k,l,m,n,byt;
  int ander;

i = c; j=x; k=y;

for(l=0; l<=7; l++)
 {
  byt = *i; j = x+1;
  plot(j++,k,(byt & 128)); plot(j++,k,(byt & 128));
  plot(j++,k,(byt & 64)); plot(j++,k,(byt & 64));
  plot(j++,k,(byt & 32)); plot(j++,k,(byt & 32));
  plot(j++,k,(byt & 16)); plot(j++,k,(byt & 16));
  plot(j++,k,(byt & 8)); plot(j++,k,(byt & 8));
  plot(j++,k,(byt & 4)); plot(j++,k,(byt & 4));
  plot(j++,k,(byt & 2)); plot(j++,k,(byt & 2));
  plot(j++,k,(byt & 1)); plot(j++,k,(byt & 1));
  i++;  
  k--;   
 }      
}

hstrg1(c,x,y)
int *c,x,y;              /* plot 8-bit wide chars horizontally */
{ 
  int k;
  char mch,*i;

  mch = 'A';  i = c;               
  while ( mch != '\0' )
   {
    mch = *i++;
    k = chrpat(mch);                                                  
    plotch(k,x,y);         
    x += 8; 
   }
 }


                    /*  horizontal string, double wide chars  */
hstrg2(c,x,y)
int *c,x,y;
{
  int k;
  char mch,*i;

  i=c; mch = 'A';                                
  while ( mch != '\0' )
   {
    mch = *i++;
    k = chrpat(mch);                                                  
    twotal(k,x,y);                     /* use double-wide letters */
    x += 16; 
   }
}

vstrg1(c,x,y)                /* vertical string, rotated 8 bit chars */
int *c,x,y;
{
 int k;  
 char mch,*i;

 mch = 'A';  i = c;
 while (mch != '\0')
  {
   mch = *i++;
   k = rotpat(mch);
   plotch(k,x,y);
   y += 8;
  }
}

  
vstrg2(c,x,y)                /* vertical string, rotated 16 bit chars */
int *c,x,y;
{
 int k;  
 char mch,*i;

 mch = 'A'; i=c;
 while (mch != '\0')
  {
   mch = *i++;
   k = rotpat(mch);
   twotal(k,x,y);
   y += 8;
  }
}
  
vstrg3(c,x,y)                /* vertical string, nonrotated 8 bit chars */
int *c,x,y;
{
 int k;  
 char mch,*i;

 mch = 'A'; i=c;
 while (mch != '\0')
  {
   mch = *i++;
   k = chrpat(mch);
   plotch(k,x,y);
   y -= 8;
  }
}


doline(x1,y1,x2,y2,color)
int x1,y1,x2,y2,color;
{
 int dx,dy,incr1,incr2,incr3,d,x,y,xend,yend;

 dx = (x2-x1);     if (dx < 0)  dx = -dx;
 dy = (y2-y1);     if (dy < 0)  dy = -dy;
 if (dy <= dx)
 {
  if (x1 > x2)
  {
   x=x2;
   y=y2;
   xend = x1;
   dy = y1 - y2;
  }
  else
  {
   x = x1;
   y = y1;
   xend = x2;
   dy = y2 - y1;
  }
  d = 2*dy - dx;
  incr1 = 2*dy;
  incr2 = 2*(dy - dx);
  incr3 = 2*(dy + dx);
  plot(x,y,color);
  while (x < xend)
  {
   x += 1;
   if (d >= 0)
   {
    if (dy <= 0)
    {
     d += incr1;
    }
    else
    {
     y += 1;
     d += incr2;
    }
   }
   else
   {
     if (dy >= 0)
     {
       d += incr1;
     }
     else
     {
      y -= 1;
      d += incr3;
      }
   }
   plot(x,y,color);
  }
 }
 else
 {
   if (y1 > y2)
   {
     y = y2;
     x = x2;
     yend = y1;
     dx = x1 - x2;
   }
   else
   {
     y = y1;
     x = x1;
     yend = y2;
   }
     d = 2*dx - dy;
     incr1 = 2*dx;
     incr2 = 2*(dx - dy);
     incr3 = 2*(dx + dy);
     plot(x,y,color);
     while (y < yend)
     {
      y += 1;
      if (d >= 0)
      {
       if (dx <= 0)
       {
        d += incr1;
       }
       else
       {
        x += 1;
        d += incr2;
       }
      }
      else
      {
       if (dx >= 0)
       {
        d += incr1;
       }
       else
       {
        x -= 1;
        d += incr3;
       }
      }
      plot(x,y,color);
     }
    }
 }


doscrn(k,l)
int *k,l;
{
int i,j,n;
char *m;

m=k;
for (i=0; i<=15; i++)    /* set up a file control block */ 
  scrnam[i] = 0;
for (i=1; i<=8; i++)
  scrnam[i] = ' ';
i=0; j=1;
while (*(m+i) != '.')     /* transfer body of the name */ 
 {
 *(scrnam+i+1) = *(m+i);
  i++;         
 }                            
      /* now for the extension  */
 scrnam[9] = 'S';
 scrnam[10] = 'C';
 scrnam[11] = 'R';
 vdcram(l);
}

savescrn(k)
int *k;
{
 doscrn(k,3);
}

getscrn(k)
int *k;
{
 doscrn(k,2);
}

#include "stdlib.c"
vdcram(l);
}

savescrn(k)
int *k;
{
 doscrn(k,3);
}

getscrn(k