********************************************************************
* VDGInt - CoCo 3 VDG I/O module
*
* $Id$
*
* Ed.    Comments                                       Who YY/MM/DD
* ------------------------------------------------------------------
*   4    Quite a few changes:                           BGP 03/01/09
*        - Merged in CoCo 2 gfx code from original
*          OS-9 Level 2 code
*        - Incorporated code tweaks for 6809 and 6309
*          code from the vdgint_small and vdgint_tiny
*          source files
*        - Fixed long-standing cursor color bug
*        - Fixed long-standing F$SRtMem bug in CoCo 2
*          "graphics end" code $12 (see comments)

         nam   VDGInt
         ttl   CoCo 3 VDG I/O module

* Disassembled 98/09/31 12:15:57 by Disasm v1.6 (C) 1988 by RML

         ifp1
         use   defsfile
         use   vdgdefs
         endc

FFStSz   equ   512		flood fill stack size in bytes

tylg     set   Systm+Objct   
atrv     set   ReEnt+rev
rev      set   $01
edition  set   4

skip2    equ   $8C		cmpx instruction

         mod   eom,name,tylg,atrv,start,size

u0000    rmb   0
size     equ   .

         fcb   $07 

name     fcs   /VDGInt/
         fcb   edition

start    lbra  Read		actually more like INIZ...
         lbra  Write
         lbra  GetStat
         lbra  SetStat
         lbra  Term 

* Update Window
* Called from CC3IO
* Entry:  A = function code
*           0 = select new window to be active
*           1 = update mouse packet
*          >1 = only used by GRFINT/WINDINT
*         U = device memory pointer
*         X = path descriptor pointer

         tsta			zero?
         bne   L0035		branch if not
         ldb   <VD.DGBuf,u	get number of currently displayed buffer
         lbne  ShowS		branch if not zero
         ldd   <VD.TFlg1,u
         lbra  DispAlfa

L0035    deca  			set x,y size of window?
         beq   L003B		branch if so
         clrb  			no errors
         rts   

L003B    ldx   <D.CCMem		pointer to start of CC memory
         leax  <$54,x		to X,Y coor, X,Y window
         IFNE  H6309
         ldq   ,x
         stq   $04,x		get X,Y coordinate
         ELSE
         ldd   ,x
         std   $04,x
         ldd   $02,x
         std   $06,x
         ENDC
         clrb  
         rts   

* Terminate device
Term     pshs  u,y,x
         ldb   #$03
L004E    pshs  b
         lbsr  GetScrn		get screen table entry into X
         lbsr  FreeBlks		free blocks used by screen
         puls  b		get count
         decb  			decrement
         bne   L004E		branch until zero
         clr   <VD.Start,u	no screens in use
         ldd   #512		size of alpha screen
         ldu   <VD.ScrnA,u	get pointer to alpha screen
         beq   ClrStat		branch if none
         os9   F$SRtMem 	else return memory
ClrStat  ldb   #$E1		size of 1 page -$1D (SCF memory requirements)
         leax  <VD.Strt1,u	point to start of VDG statics
L006F    clr   ,x+		set stored byte to zero
         decb  			decrement
         bne   L006F		until zero
         bra   L00D5		and exit

* Read bytes from IN
* Actually, this is more like an INIZ of the device.
Read     pshs  u,y,x		save regs
         bsr   SetupPal		set up palettes
         lda   #$AF
         sta   <VD.CColr,u	default color cursor
         pshs  u
         ldd   #768		gets 1 page on an odd page boundary
         os9   F$SRqMem 	request from top of sys ram
         bcs   L00D6		error out of no system mem
         tfr   u,d		U = addr of memory
         tfr   u,x
         bita  #$01		test to see if on even page
         beq   IsEven		branch if even
         leax  >256,x		else point 100 bytes into mem
         bra   IsOdd		and free
IsEven   leau  >512,u		we only need 2 pages for the screen memory
IsOdd    ldd   #256		1 page return
         os9   F$SRtMem 	return system memory
         puls  u
         stx   <VD.ScrnA,u	save start address of the screen
         stx   <VD.CrsrA,u	and start cursor position
         leax  >512,x		point to end of screen
         stx   <VD.ScrnE,u	save it
         lda   #$60		get default character
         sta   <VD.CChar,u	put character under the cursor
         sta   <VD.Chr1,u	only referenced here ??
         lbsr  ClrScrn		clear the screen
         inc   <VD.Start,u	increment VDG screen in use
         ldd   <VD.Strt1,u	seemling useless??
         lbsr  L054C		set to true lowercase, screen size
         leax  <VD.NChar,u
         stx   <VD.EPlt1,u	where to get next character from
         stx   <VD.EPlt2,u
         ldu   <D.CCMem
         IFNE  H6309
         oim  #$02,<$24,u	set to VDGINT found
         ELSE
         ldb   <$24,u
         orb   #$02		set to VDGINT found
         stb   <$24,u
         ENDC
L00D5    clrb  
L00D6    puls  pc,u,y,x

SetupPal pshs  u,y,x,b,a
         lda   #$08
         sta   <VD.PlFlg,u
         leax  >L011A,pcr	default palette
         leay  <VD.Palet,u
L00E6    leau  >L00F8,pcr	CMP to RGB conversion
         IFNE  H6309
L00EA    tfr   u,w
         ELSE
L00EA    pshs  u
         ENDC
         leau  >L012A,pcr
         ldb   #16
L00F2    lda   ,x+
         IFNE  H6309
         jmp   ,w
         ELSE
         jmp   [,s]
         ENDC
L00F6    lda   a,u		remap to CMP values
L00F8    sta   ,y+		and save RGB data
         decb  
         bne   L00F2
         IFEQ  H6309
         leas  $02,s		clean up stack
         ENDC
L00FF    puls  pc,u,y,x,b,a

SetPals  pshs  u,y,x,b,a	puts palette data in.
         lda   >WGlobal+G.CrDvFl	is this screen active?
         beq   L00FF		0 = not active
         leax  <VD.Palet,u	point X to palette table
         ldy   #$FFB0		point Y to palette register
         lda   >WGlobal+G.MonTyp	universal RGB/CMP 0 = CMP, 1 = RGB, 2 = MONO
         bne   L00E6		if not 0 (CMP) don't re-map colors
         leau  >L00F6,pcr	else do re-map colors
         bra   L00EA

L011A    fcb   $12,$36,$09,$24	default palette data
         fcb   $3f,$1b,$2d,$26
         fcb   $00,$12,$00,$3f
         fcb   $00,$12,$00,$26

* converts CMP to RGB
L012A    fdb   $000c,$020e,$0709,$0510
         fdb   $1c2c,$0d1d,$0b1b,$0a2b
         fdb   $2211,$1221,$0301,$1332
         fdb   $1e2d,$1f2e,$0f3c,$2f3d
         fdb   $1708,$1506,$2716,$2636
         fdb   $192a,$1a3a,$1829,$2838
         fdb   $1404,$2333,$2535,$2434
         fdb   $203B,$313E,$3739,$3F30

* Entry: A = char to write
*        Y = path desc ptr
Write    equ   *
         IFNE  COCO2
         cmpa  #$0F
         ELSE
         cmpa  #$0E
         ENDC
         bls   Dispatch
         cmpa  #$1B		escape code?
         lbeq  Escape		yes, do escape immediately
         IFNE  COCO2
         cmpa  #$1E
         bcs   Do1E
         cmpa  #$1F
         bls   Dispatch
         ELSE
         cmpa  #$1F
         lbls  NoOp		ignore gfx codes if not CoCo 2 compatible
         ENDC
         tsta  
         bmi   L01BA
         ldb   <VD.CFlag,u
         beq   L019A
         cmpa  #$5E
         bne   L018A		re-map characters from ASCII-VDG
         clra
         bra   L01BA
L018A    cmpa  #$5F
         bne   L0192
         lda   #$1F
         bra   L01BA
L0192    cmpa  #$60
         bne   L01AA
         lda   #$67
         bra   L01BA

L019A    cmpa  #$7C		true lowercase
         bne   L01A2
         lda   #$21
         bra   L01BA
L01A2    cmpa  #$7E
         bne   L01AA
         lda   #$2D
         bra   L01BA
L01AA    cmpa  #$60
         bcs   L01B2		re-map ASCII
         suba  #$60
         bra   L01BA
L01B2    cmpa  #$40
         bcs   L01B8
         suba  #$40
L01B8    eora  #$40
L01BA    ldx   <VD.CrsrA,u
         sta   ,x+
         stx   <VD.CrsrA,u
         cmpx  <VD.ScrnE,u
         bcs   L01CA
         lbsr  SScrl		if at end of screen, scroll it
L01CA    lbsr  ShowCrsr		ends with a CLRB/RTS anyhow
NoOp     clrb  
         rts   

         IFNE  COCO2
Do1E     lbsr  ChkDvRdy
         bcc   Dispatch
         rts
         ENDC

Dispatch leax  >DCodeTbl,pcr
         lsla  
         ldd   a,x
         jmp   d,x

DCodeTbl fdb   NoOp-DCodeTbl		$00 - No Operation
         fdb   CurHome-DCodeTbl		$01 - Home Cursor
         fdb   CurXY-DCodeTbl		$02 - Move Cursor
         fdb   DelLine-DCodeTbl		$03 - Delete Line
         fdb   ErEOLine-DCodeTbl	$04 - Erase to End Of Line
         fdb   CrsrSw-DCodeTbl		$05 - Switch Cursor Color
         fdb   CurRght-DCodeTbl		$06 - Move Cursor Right
         fdb   NoOp-DCodeTbl		$07 - Bell (Handled by CC3IO)
         fdb   CurLeft-DCodeTbl		$08 - Move Cursor Left
         fdb   CurUp-DCodeTbl		$09 - Move Cursor Up
         fdb   CurDown-DCodeTbl		$0A - Move Cursor Down
         fdb   ErEOScrn-DCodeTbl	$0B - Erase to End Of Screen
         fdb   ClrScrn-DCodeTbl		$0C - Clear Screen
         fdb   Retrn-DCodeTbl		$0D - Carriage Return
         fdb   Do0E-DCodeTbl		$0E - Display Alpha Screen

         IFNE  COCO2
         fdb   Do0F-DCodeTbl		$0F - Display Graphics
         fdb   Do10-DCodeTbl		$10 - Preset Screen
         fdb   Do11-DCodeTbl		$11 - Set Color
         fdb   Do12-DCodeTbl		$12 - End Graphics
         fdb   Do13-DCodeTbl		$13 - Erase Graphics
         fdb   Do14-DCodeTbl		$14 - Home Graphics Cursor
         fdb   Do15-DCodeTbl		$15 - Set Graphics Cursor
         fdb   Do16-DCodeTbl		$16 - Draw Line
         fdb   Do17-DCodeTbl		$17 - Erase Line
         fdb   Do18-DCodeTbl		$18 - Set Point
         fdb   Do19-DCodeTbl		$19 - Erase Point
         fdb   Do1A-DCodeTbl		$1A - Draw Circle
         fdb   Escape-DCodeTbl		$1B - Escape
         fdb   Do1C-DCodeTbl		$1C - Erase Circle
         fdb   Do1D-DCodeTbl		$1D - Flood Fill
         fdb   NoOp-DCodeTbl		$1E - No Operation
         fdb   NoOp-DCodeTbl		$1F - No Operation
         ENDC

* Code fragment from original CoCo 3 VDGInt by Tandy - not referenced
*         comb
*         ldb   #E$Write
*         rts

* $1B does palette changes
Escape   ldx   <VD.EPlt1,u	now X points to VD.NChar
         lda   ,x		get char following
         cmpa  #$30		default color?
         bne   L0209		branch if not
         lbsr  SetupPal		do default palette
         lbra  L026E		put palette and exit

L0209    cmpa  #$31		change palette?
         IFNE  COCO2
         lbeq  PalProc		branch if so
         cmpa  #$21
         lbne  NoOp		return without error
         ldx   PD.RGS,y		get registers
         lda   R$A,x		get path
         ldx   <D.Proc		get current proc
         cmpa  >P$SelP,x	compare against selected path
         beq   L0249		branch if empty
         ldb   >P$SelP,x	else load selected path from process descriptor
         sta   >P$SelP,x	and store passed path
         pshs  y		save our path desc ptr
         bsr   L024A		get device table entry for path
         ldy   V$STAT,y		get driver statics
         ldx   <D.CCMem		get CoCo memory
         cmpy  <$20,x
         puls  y		restore our path desc ptr
         bne   L0248
         inc   <VD.DFlag,u
         ldy   <$20,x
         sty   <$22,x
         stu   <$20,x
L0248    clrb  
L0249    rts   

* Entry: A = path to process
L024A    leax  <P$Path,x	point to path table in process descriptor
         lda   b,x		get system path number
         ldx   <D.PthDBT	point to path descriptor base table
         os9   F$Find64 	put found path descriptor in Y
         ldy   PD.DEV,y		load Y with device table entry
         rts   
         ELSE
         bne   NoOp
         ENDC

PalProc  leax  <DoPals,pcr
         ldb   #$02
         lbra  GChar

DoPals   ldx   <VD.EPlt1,u
         ldd   ,x
         cmpa  #16		max 16 palettes
         lbhi  IllArg
         cmpb  #63		color has max. 63
         lbhi  IllArg
         leax  <VD.Palet,u	to palette buffer
         stb   a,x		save it
L026E    lbsr  SetPals
         clrb
         rts

*         anda  #$0F
*         andb  #$3F
*         leax  <VD.Palet,u
*         stb   a,x
*L026E    inc   <VD.DFlag,u
*         clrb  
*         rts   

* Screen scroll
SScrl    ldx   <VD.ScrnA,u
         IFNE  H6309
         ldd   #$2060
         leay  a,x		down one line
         ldw   #512-32
         tfm   y+,x+		scroll screen up
         stx   <VD.CrsrA,u	save new cursor address
         ELSE
         leax  <32,x
L0279    ldd   ,x++
         std   <-34,x
         cmpx  <VD.ScrnE,u
         bcs   L0279
         leax  <-32,x
         stx   <VD.CrsrA,u
         lda   #32
         ldb   #$60
         ENDC
L028D    stb   ,x+
         deca  
         bne   L028D
         rts   

* $0D - carriage return
Retrn    bsr   HideCrsr		hide cursor
         IFNE  H6309
         aim   #$E0,<VD.CrsAL,u
         ELSE
         tfr   x,d
         andb  #$E0		strip out bits 0-4
         stb   <VD.CrsAL,u	save updated cursor address
         ENDC
ShowCrsr ldx   <VD.CrsrA,u	get cursor address
         lda   ,x		get char at cursor position
         sta   <VD.CChar,u	save it
         lda   <VD.CColr,u	get cusor character
         beq   RtsOk		branch if none
L02A9    sta   ,x		else turn on cursor
RtsOk    clrb
         rts   

* $0A - moves cursor down
CurDown  bsr   HideCrsr		hide cursor
         leax  <32,x		move X down one line
         cmpx  <VD.SCrnE,u	at the end of the screen?
         bcs   L02C1		branch if not
         leax  <-32,x		else go back up one line
         pshs  x		save X
         lbsr  SScrl		and scroll the screen
         puls  x		and restore pointer
L02C1    stx   <VD.CrsrA,u	save cursor pointer
         bra   ShowCrsr		show cursor

* $08 - moves cursor left one
CurLeft  bsr   HideCrsr		hide cursor
         cmpx  <VD.ScrnA,u	compare against start of screen
         bls   ShowCrsr		ignore it if at the screen start
         leax  -$01,x		else back up one
         stx   <VD.CrsrA,u	save updated pointer
         bra   ShowCrsr		and show cur

* $06 - moves cursor right one
CurRght  bsr   HideCrsr		hide cursor
         leax  1,x		move to the right
         cmpx  <VD.SCrnE,u	compare against start of screen
         bcc   ShowCrsr		if past end, ignore it
         stx   <VD.CrsrA,u	else save updated pointer
         bra   ShowCrsr		and show cursor

* $0B - erase from current char to end of screen
ErEOScrn bsr   HideCrsr		kill the cursor
*         bra   L02E8		and clear the rest of the screen
         fcb   skip2

* $0C - clear screen & home cursor
ClrScrn  bsr   CurHome		home cursor (returns X pointing to start of screen)
         lda   #$60		get default char
ClrSLoop sta   ,x+		save at location
         cmpx  <VD.SCrnE,u	end of screen?
         bcs   ClrSLoop		branch if not
         bra   ShowCrsr		now show cursor

* $01 - Homes the cursor
CurHome  bsr   HideCrsr		hide cursor
         ldx   <VD.ScrnA,u	get pointer to screen
         stx   <VD.CrsrA,u	save as new cursor position
         bra   ShowCrsr		and show it

* Hides the cursor from the screen
* Exit: X = address of cursor
HideCrsr ldx   <VD.CrsrA,u	get address of cursor in X	
         lda   <VD.CChar,u	get value of char under cursor
         sta   ,x		put char in place of cursor
         clrb  			must be here, in general, for [...] BRA HideCrsr
         rts   

* $05 - turns cursor on/off, color
CrsrSw   lda   <VD.NChar,u	get next char
         suba  #C$SPAC		take out ASCII space
         bne   L0313		branch if not zero
         sta   <VD.CColr,u	else save cursor color zero (no cursor)
         bra   HideCrsr		and hide cursor
L0313    cmpa  #$0B		greater than $0B?
         bge   RtsOk		yep, just ignore byte
         cmpa  #$01		is it one?
         bgt   L031F		branch if greater
         lda   #$AF		else get default blue cursor color
         bra   L032F		and save cursor color
L031F    cmpa  #$02		is it two?
         bgt   L0327		branch if larger
         lda   #$A0		else get black cursor color
         bra   L032F		and save it
** BUG ** BUG ** BUG ** BUG
L0327    suba  #$03		** BUG FIXED ! **  !!! Was SUBB
         lsla			shift into upper nibble
         lsla  
         lsla  
         lsla  
         ora   #$8F
L032F    sta   <VD.CColr,u	save new cursor
         ldx   <VD.CrsrA,u	get cursor address
         lbra  L02A9		branch to save cursor in X

* $02 - moves cursor to X,Y
CurXY    ldb   #$02		we want to claim the next two chars
         leax  <DoCurXY,pcr	point to processing routine
         lbra  GChar		get two chars

DoCurXY  bsr   HideCrsr		hide cursor
         ldb   <VD.NChr2,u	get ASCII Y-pos
         subb  #C$SPAC		take out ASCII space
         lda   #32		go down
         mul   			multiply it
         addb  <VD.NChar,u	add in X-pos
         adca  #$00
         subd  #C$SPAC		take out another ASCII space
         addd  <VD.ScrnA,u	add top of screen address
         cmpd  <VD.ScrnE,u	at end of the screen?
         lbcc  RtsOk		exit if off the screen
         std   <VD.CrsrA,u	otherwise save new cursor address
         lbra  ShowCrsr		and show cursor

* $04 - clear characters to end of line
ErEOLine bsr   HideCrsr		hide cursor
         tfr   x,d		move current cursor position to D
         andb  #$1F		number of characters put on this line
         negb			negative
         bra   L0374		and clear one line
*         pshs  b
*         ldb   #32
*         subb  ,s+
*         bra   L0376		and clear one line

* $03 - erase line cursor is on
DelLine  lbsr  Retrn		do a carriage return
*         ldb   #32		B = $00 from Retrn
L0374    addb   #32		B = $00 from Retrn
L0376    lda   #$60		get default char
         ldx   <VD.CrsrA,u	get cursor address
L037B    sta   ,x+		save default char
         decb  			decrement
         bne   L037B		and branch if not end
         lbra  ShowCrsr		else show cursor

* $09 - moves cursor up one line
CurUp    lbsr  HideCrsr		hide cursor
         leax  <-32,x		move X up one line
         cmpx  <VD.ScrnA,u	compare against start of screen
         lbcs  ShowCrsr		branch if we went beyond
         stx   <VD.CrsrA,u	else store updated X
L0391    lbra  ShowCrsr		and show cursor

* $0E - switches from graphics to alpha mode
Do0E     equ   *
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb
         ENDC
DispAlfa pshs  x,y,a
         IFNE  COCO2
         stb   <VD.Alpha,u
         ENDC
         clr   <VD.DGBuf,u
         lda   >PIA1Base+2
         anda  #$07
         ora   ,s+
         tstb  
         bne   L03AD
         anda  #$EF
         ora   <VD.CFlag,u	lowercase flag
L03AD    sta   <VD.TFlg1,u	save VDG info
         tst   >WGlobal+G.CrDvFl	is this screen currently showing?
         lbeq  L0440
         sta   >PIA1Base+2	set lowercase in hardware
         ldy   #$FFC6		Ok, now set up via old CoCo 2 mode
         IFNE  COCO2
         tstb  
         bne   L03CB
         ENDC
* Set up VDG screen for text
         stb   -6,y		$FFC0
         stb   -4,y		$FFC2
         stb   -2,y		$FFC4
         lda   <VD.ScrnA,u
         IFNE  COCO2
         bra   L03D7
* Set up VDG screen for graphics
L03CB    stb   -6,y		$FFC0
         stb   -3,y		$FFC3
         stb   -1,y		$FFC5
         lda   <VD.SBAdd,u
         ENDC
L03D7    lbsr  SetPals
         ldb   <D.HINIT
         orb   #$80		set CoCo 2 compatible mode
         stb   <D.HINIT
         stb   >$FF90
         ldb   <D.VIDMD
         andb  #$78
         stb   >$FF98
         stb   <D.VIDMD
         pshs  a
         IFNE  H6309
         clrd
         ELSE
         clra
         clrb  
         ENDC
         std   >$FF99		set resolution AND border color
         std   <D.VIDRS
         puls  a
         tfr   a,b
         anda  #$1F
         pshs  a
         andb  #$E0
         lsrb  
         lsrb  
         lsrb  
         lsrb  
         ldx   <D.SysDAT
*         leax  a,x
         abx
         lda   $01,x		get block number to use
         pshs  a
         anda  #$F8		keep high bits only
         lsla
         lsla
         clrb
         std   <D.VOFF1		display it
         std   >$FF9D
         ldd   #$0F07
         sta   <D.VOFF2
         sta   >$FF9C
         puls  a
         asla  
         asla  
         asla  
         asla  
         asla  
         ora   ,s+
* Y now holds $FFC6, so we don't need to work with X here
*         ldx   #$FFC6
         lsra  
L0430    lsra  
         bcc   L041A
         leay   1,y
         sta   ,y+
         fcb   skip2		skip 2 bytes
L041A    sta   ,y++		rather than additional leax 1,x on next line
         decb  
         bne   L0430
L0440    clrb  
         puls  pc,y,x

GChar1   ldb   #$01
GChar    stb   <VD.NGChr,u
         stx   <VD.RTAdd,u
         clrb  
         rts   

         IFNE   COCO2
* $0F - display graphics
Do0F     leax  <DispGfx,pcr
         ldb   #$02
         bra   GChar

DispGfx  ldb   <VD.Rdy,u	memory already alloced?
         bne   L0468		branch if so
         lbsr  Get8KHi		else get an 8k block from high ram
         bcs   L0486		branch if error
         stb   <VD.GBuff,u	save starting block number
         stb   <VD.Blk,u
         tfr   d,x
         ldd   <D.Proc
         pshs  u,b,a
         ldd   <D.SysPrc	get system proc desc
         std   <D.Proc		make current
         ldb   #$01		one block
         os9   F$MapBlk 	map it in to our space
         tfr   u,x		get address into x
         puls  u,b,a		restore other regs
         std   <D.Proc		restore process pointer
         bcs   L0486		branch if error occurred
         stx   <VD.SBAdd,u	else store address of gfx mem
         inc   <VD.Rdy,u	we're ready
         lda   #$01
         ldb   #$20
         bsr   L04D9
         lbsr  Do13		erase gfx screen
L0468    lda   <VD.NChr2,u	get character after next
         sta   <VD.PMask,u	store color set (0-3)
         anda  #$03		mask off pertinent bytes
         leax  >Mode1Clr,pcr	point to mask byte table
         lda   a,x		get byte
         sta   <VD.Msk1,u	save mask byte here
         sta   <VD.Msk2,u	and here
         lda   <VD.NChar,u	get next char, mode byte (0-1)
         cmpa  #$01		compare against max
         bls   L0487		branch if valid
         comb  
         ldb   #E$BMode		else invalid mode specified, send error
L0486    rts   

L0487    tsta  			test user supplied mode byte
         beq   L04A7		branch if 256x192
         ldd   #$C003
         std   <VD.MCol,u
         lda   #$01
         sta   <VD.Mode,u	128x192 mode
         lda   #$E0
         ldb   <VD.NChr2,u
         andb  #$08	
         beq   L04A0
         lda   #$F0
L04A0    ldb   #$03
         leax  <L04EB,pcr
         bra   L04C4
L04A7    ldd   #$8001
         std   <VD.MCol,u
         lda   #$FF
         tst   <VD.Msk1,u
         beq   L04BA
         sta   <VD.Msk1,u
         sta   <VD.Msk2,u
L04BA    sta   <VD.Mode,u	256x192 mode
         lda   #$F0
         ldb   #$07
         leax  <L04EF,pcr
L04C4    stb   <VD.PixBt,u
         stx   <VD.MTabl,u
         ldb   <VD.NChr2,u
         andb  #$04
         lslb  
         pshs  b
         ora   ,s+
         ldb   #$01
         lbra  DispAlfa

L04D9    pshs  x,b,a
         clra  
         ldb   $02,s
         ldx   <D.SysMem
         leax  d,x
         puls  b,a
L04E4    sta   ,x+
         decb  
         bne   L04E4
         puls  pc,x

L04EB    fdb   $C030,$0C03

L04EF    fcb   $80,$40,$20,$10,$08,$04,$02,$01

* $11 - set color
Do11     leax  <SetColor,pcr
         lbra  GChar1
SetColor lda   <VD.NChar,u	get next char
         sta   <VD.NChr2,u	save in next after
L0503    clr   <VD.NChar,u	and clear next
         lda   <VD.Mode,u	which mode?
         bmi   L050E		branch if 256x192
         inc   <VD.NChar,u
L050E    lbra  L0468

* $12 - end graphics
Do12     ldx   <VD.SBAdd,u	get screen address
         beq   L051B		branch if empty
         clra  
         ldb   #$20
         bsr   L04D9
L051B    leay  <VD.GBuff,u	point Y to graphics buffer block numbers
         ldb   #$03		number of blocks starting at VD.GBuff
         pshs  u,b		save our static pointer, and counter (3)
L0522    lda   ,y+		get next block
         beq   L052D		if empty, continue
         clrb  			else clear B
         tfr   d,x		transfer D to X
         incb  			1 block to deallocate
         os9   F$DelRAM 	deallocate it
L052D    dec   ,s		dec counter
         bgt   L0522		if not zero, get more
* Note: this seems too be a bug.  Here, Y is pointing to VD.HiRes ($4D), which
* is the block number of any CoCo 3 Hi-Res screen.  This $0E command just
* deals with CoCo 2 graphics modes.  What I think should happen here is
* that the byte flood fill buffer should be checked for non-zero,
* then freed.  It looks as though this code would work IF the Hi-Res
* variables from $4D-$5B, which are CoCo 3 specific, didn't exist.  So
* this bug was introduced when the CoCo 3 specific static vars were added
* between VD.AGBuf and VD.FFMem
         ldu   VD.FFMem-VD.HiRes,y	get flood fill stack memory ptr
         beq   L053B
         ldd   #FFStSz			get flood fill stack size
         os9   F$SRtMem 
L053B    puls  u,b
         clr   <VD.Rdy,u
         lbra  Do0E

* $10 - preset screen to a specific color
Do10     leax  <PrstScrn,pcr
         lbra  GChar1

PrstScrn lda   <VD.NChar,u	get next char
         tst   <VD.Mode,u	which mode?
         bpl   L0559		branch if 128x192 4 color
         ldb   #$FF		assume we will clear with $FF
         anda  #$01		mask out all but 1 bit (2 colors)
         beq   Do13		erase graphic screen with color $00
         bra   L0564		else erase with color $FF
L0559    anda  #$03		mask out all but 2 bits (4 colors)
         leax  >Mode1Clr,pcr	point to color table
         ldb   a,x		get appropriate byte
         bra   L0564		and start the clearing

* $13 - erase graphics
Do13     clrb  
L0564    ldx   <VD.SBAdd,u
         IFNE  H6309
* Note: 6309 version clears from top to bottom
*       6809 version clears from bottom to top
         ldw   #$1800
         pshs  b
         tfm   s,x+
         puls  b
         ELSE
         leax  >$1801,x
L056B    stb   ,-x
         cmpx  <VD.SBAdd,u
         bhi   L056B
         ENDC

* $14 - home graphics cursor
Do14     equ   *
         IFNE  H6309
         clrd  
         ELSE
         clra  
         clrb  
         ENDC
         std   <VD.GCrsX,u
         rts   

* 128x192 4 color pixel table
Mode1Clr fcb   $00,$55,$aa,$ff

* Fix X/Y coords:
*  - if Y > 191 then cap it at 191
*  - adjust X coord if in 128x192 mode
FixXY    ldd   <VD.NChar,u	get next 2 chars
         cmpb  #192		Y greater than max?
         bcs   L0585		branch if lower than
         ldb   #191
L0585    tst   <VD.Mode,u	which mode?
         bmi   L058B		branch if 256x192
         lsra  			else divide X by 2
L058B    std   <VD.NChar,u	and save
         rts   

* $15 - set graphics cursor
Do15     leax  <SetGC,pcr
GChar2   ldb   #$02
         lbra  GChar

SetGC    bsr   FixXY		fix coords
         std   <VD.GCrsX,u	and save new gfx cursor pos
         clrb  
         rts   

* $19 - erase point
Do19     clr   <VD.Msk1,u
* $18 - set point
Do18     leax  <DrawPnt,pcr
         bra   GChar2

DrawPnt  bsr   FixXY		fix coords
         std   <VD.GCrsX,u	save as new gfx cursor pos
         bsr   DrwPt2
         lbra  L067C
DrwPt2   lbsr  XY2Addr
L05B3    tfr   a,b
         comb  
         andb  ,x
         stb   ,x
         anda  <VD.Msk1,u
         ora   ,x
         sta   ,x
         rts   

* $17 - erase line
Do17     clr   <VD.Msk1,u

* $16 - draw line
Do16     leax  <DrawLine,pcr
         bra   GChar2

DrawLine bsr   FixXY		fix up coords
         leas  -$0E,s
         std   $0C,s
         lbsr  XY2Addr
         stx   $02,s
         sta   $01,s
         ldd   <VD.GCrsX,u
         lbsr  XY2Addr
         sta   ,s
         IFNE  H6309
         clrd
         ELSE
         clra  
         clrb  
         ENDC
         std   $04,s
         lda   #$BF
         suba  <VD.GCrsY,u
         sta   <VD.GCrsY,u
         lda   #$BF
         suba  <VD.NChr2,u
         sta   <VD.NChr2,u
         lda   #$FF
         sta   $06,s
         clra  
         ldb   <VD.GCrsX,u
         subb  <VD.NChar,u
         sbca  #$00
         bpl   L0608
         IFNE  H6309X
         negd
         ELSE
         nega  
         negb  
         ENDC
         sbca  #$00
         neg   $06,s
L0608    std   $08,s
         bne   L0611
         ldd   #$FFFF
         std   $04,s
L0611    lda   #$E0
         sta   $07,s
         clra  
         ldb   <VD.GCrsY,u
         subb  <VD.NChr2,u
         sbca  #$00
         bpl   L0626
         IFNE  H6309X
         negd
         ELSE
         nega  
         negb  
         ENDC
         sbca  #$00
         neg   $07,s
L0626    std   $0A,s
         bra   L0632
L062A    sta   ,s
         ldd   $04,s
         subd  $0A,s
         std   $04,s
L0632    lda   ,s
         lbsr  L05B3
         cmpx  $02,s
         bne   L0641
         lda   ,s
         cmpa  $01,s
         beq   L0675
L0641    ldd   $04,s
         bpl   L064F
         addd  $08,s
         std   $04,s
         lda   $07,s
         leax  a,x
         bra   L0632
L064F    lda   ,s
         ldb   $06,s
         bpl   L0665
         lsla  
         ldb   <VD.Mode,u	which mode?
         bmi   L065C		branch if 256x192
         lsla  
L065C    bcc   L062A
         lda   <VD.MCol2,u
         leax  -$01,x
         bra   L062A
L0665    lsra  
         ldb   <VD.Mode,u	which mode?
         bmi   L066C		branch if 256x192
         lsra  
L066C    bcc   L062A
         lda   <VD.MCol,u
         leax  $01,x
         bra   L062A
L0675    ldd   $0C,s
         std   <VD.GCrsX,u
         leas  $0E,s
L067C    lda   <VD.Msk2,u
         sta   <VD.Msk1,u
         clrb  
         rts   

* $1C - erase circle
Do1C     clr   <VD.Msk1,u
* $1A - draw circle
Do1A     leax  <Circle,pcr
         lbra  GChar1

Circle   leas  -$04,s
         ldb   <VD.NChar,u	get radius
         stb   $01,s		store on stack
         clra  
         sta   ,s
         addb  $01,s
         adca  #$00
         IFNE  H6309X
         negd
         ELSE
         nega  
         negb  
         ENDC
         sbca  #$00
         addd  #$0003
         std   $02,s
L06AB    lda   ,s
         cmpa  $01,s
         bcc   L06DD
         ldb   $01,s
         bsr   L06EB
         clra  
         ldb   $02,s
         bpl   L06C5
         ldb   ,s
         IFNE  H6309X
         lsld
         lsld
         ELSE
         lslb  
         rola  
         lslb  
         rola  
         ENDC
         addd  #$0006
         bra   L06D5
L06C5    dec   $01,s
         clra  
         ldb   ,s
         subb  $01,s
         sbca  #$00
         IFNE  H6309X
         lsld
         lsld
         ELSE
         lslb  
         rola  
         lslb  
         rola  
         ENDC
         addd  #$000A
L06D5    addd  $02,s
         std   $02,s
         inc   ,s
         bra   L06AB
L06DD    lda   ,s
         cmpa  $01,s
         bne   L06E7
         ldb   $01,s
         bsr   L06EB
L06E7    leas  $04,s
         bra   L067C
L06EB    leas  -$08,s
         sta   ,s
         clra  
         std   $02,s
         IFNE  H6309X
         negd
         ELSE
         nega  
         negb  
         ENDC
         sbca  #$00
         std   $06,s
         ldb   ,s
         clra  
         std   ,s
         IFNE  H6309X
         negd
         ELSE
         nega  
         negb  
         ENDC
         sbca  #$00
         std   $04,s
         ldx   $06,s
         bsr   L0734
         ldd   $04,s
         ldx   $02,s
         bsr   L0734
         ldd   ,s
         ldx   $02,s
         bsr   L0734
         ldd   ,s
         ldx   $06,s
         bsr   L0734
         ldd   $02,s
         ldx   ,s
         bsr   L0734
         ldd   $02,s
         ldx   $04,s
         bsr   L0734
         ldd   $06,s
         ldx   $04,s
         bsr   L0734
         ldd   $06,s
         ldx   ,s
         bsr   L0734
         leas  $08,s
         rts   
L0734    pshs  b,a
         ldb   <VD.GCrsY,u
         clra  
         leax  d,x
         cmpx  #$0000
         bmi   L0746
         cmpx  #$00BF
         ble   L0748
L0746    puls  pc,b,a
L0748    ldb   <VD.GCrsX,u
         clra  
         tst   <VD.Mode,u	which mode?
         bmi   L0753		branch if 256x192
         IFNE  H6309X
         lsld
         ELSE
         lslb  			else multiply D by 2
         rola  
         ENDC
L0753    addd  ,s++
         tsta  
         beq   L0759
         rts   
L0759    pshs  b
         tfr   x,d
         puls  a
         tst   <VD.Mode,u	which mode?
         lbmi  DrwPt2		branch if 256x192
         lsra  			else divide a by 2
         lbra  DrwPt2

* $1D - flood fill
Do1D     clr   <VD.FF6,u
         leas  -$07,s
         lbsr  L08DD
         lbcs  L0878
         lda   #$FF
         sta   <VD.FFFlg,u
         ldd   <VD.GCrsX,u
         lbsr  L0883
         lda   <VD.FF1,u
         sta   <VD.FF2,u
         tst   <VD.Mode,u	which mode?
         bpl   L0793		branch if 128x192
         tsta  
         beq   L0799
         lda   #$FF
         bra   L0799
L0793    leax  >Mode1Clr,pcr
         lda   a,x
L0799    sta   <VD.FFMsk,u
         cmpa  <VD.Msk1,u
         lbeq  L0878
         ldd   <VD.GCrsX,u
L07A6    suba  #$01
         bcs   L07B1
         lbsr  L0883
         bcs   L07B1
         beq   L07A6
L07B1    inca  
         std   $01,s
L07B4    lbsr  L08B6
         adda  #$01
         bcs   L07C2
         lbsr  L0883
         bcs   L07C2
         beq   L07B4
L07C2    deca  
         ldx   $01,s
         lbsr  L0905
         neg   <VD.FFFlg,u
         lbsr  L0905
L07CE    lbsr  L092B
         lbcs  L0878
         tst   <VD.FFFlg,u
         bpl   L07E5
         subb  #$01
         bcs   L07CE
         std   $03,s
         tfr   x,d
         decb  
         bra   L07EF
L07E5    incb  
         cmpb  #$BF
         bhi   L07CE
         std   $03,s
         tfr   x,d
         incb  
L07EF    std   $01,s
         lbsr  L0883
         bcs   L07CE
L07F6    bne   L0804
         suba  #$01
         bcc   L07FF
         inca  
         bra   L0808
L07FF    lbsr  L0883
         bcc   L07F6
L0804    adda  #$01
         bcs   L07CE
L0808    cmpd  $03,s
         bhi   L07CE
         bsr   L0883
         bcs   L07CE
         bne   L0804
         std   $05,s
         cmpd  $01,s
         bcc   L082D
         ldd   $01,s
         decb  
         cmpd  $05,s
         beq   L082D
         neg   <VD.FFFlg,u
         ldx   $05,s
         lbsr  L0905
         neg   <VD.FFFlg,u
L082D    ldd   $05,s
L082F    std   $01,s
L0831    bsr   L0883
         bcs   L083D
         bne   L083D
         bsr   L08B6
         adda  #$01
         bcc   L0831
L083D    deca  
         ldx   $01,s
         lbsr  L0905
         std   $05,s
         adda  #$01
         bcs   L0858
L0849    cmpd  $03,s
         bcc   L0858
         adda  #$01
         bsr   L0883
         bcs   L0858
         bne   L0849
         bra   L082F
L0858    inc   $03,s
         inc   $03,s
         ldd   $03,s
         cmpa  #$02
         lbcs  L07CE
         ldd   $05,s
         cmpd  $03,s
         lbcs  L07CE
         neg   <VD.FFFlg,u
         ldx   $03,s
         lbsr  L0905
         lbra  L07CE
L0878    leas  $07,s
         clrb  
         ldb   <VD.FF6,u
         beq   L0882
L0880    orcc  #$01
L0882    rts   
L0883    pshs  b,a
         cmpb  #191
         bhi   L08B2
         tst   <VD.Mode,u	which mode?
         bmi   L0892		branch if 256x192
         cmpa  #$7F
         bhi   L08B2
L0892    lbsr  XY2Addr
         tfr   a,b
         andb  ,x
L0899    bita  #$01
         bne   L08A8
         lsra  
         lsrb  
         tst   <VD.Mode,u	which mode?
         bmi   L0899		branch if 256x192
         lsra  
         lsrb  
         bra   L0899
L08A8    stb   <VD.FF1,u
         cmpb  <VD.FF2,u
         andcc #^Carry
         puls  pc,b,a
L08B2    orcc  #Carry
         puls  pc,b,a
L08B6    pshs  b,a
         lbsr  XY2Addr
         bita  #$80
         beq   L08D8
         ldb   <VD.FFMsk,u
         cmpb  ,x
         bne   L08D8
         ldb   <VD.Msk1,u
         stb   ,x
         puls  b,a
         tst   <VD.Mode,u	which mode?
         bmi   L08D5		branch if 256x192
         adda  #$03
         rts   
L08D5    adda  #$07
         rts   
L08D8    lbsr  L05B3
         puls  pc,b,a
L08DD    ldx   <VD.FFSTp,u	get top of flood fill stack
         beq   AlcFFStk		if zero, we need to allocate stack
         stx   <VD.FFSPt,u	else reset flood fill stack ptr
L08E5    clrb  
         rts   

* Allocate Flood Fill Stack
AlcFFStk pshs  u		save U for now
         ldd   #FFStSz		get 512 bytes
         os9   F$SRqMem 	from system
         bcc   AllocOk		branch if ok
         puls  pc,u		else pull out with error
AllocOk  tfr   u,d		move pointer to alloced mem to D
         puls  u		get stat pointer we saved earlier
         std   <VD.FFMem,u	save pointer to alloc'ed mem
         addd  #FFStSz		point D to end of alloc'ed mem
         std   <VD.FFSTp,u	and save here as top of fill stack
         std   <VD.FFSPt,u	and here
         bra   L08E5		do a clean return

L0905    pshs  b,a
         ldd   <VD.FFSPt,u
         subd  #$0004
         cmpd  <VD.FFMem,u
         bcs   L0924
         std   <VD.FFSPt,u
         tfr   d,y
         lda   <VD.FFFlg,u
         sta   ,y
         stx   $01,y
         puls  b,a
         sta   $03,y
         rts   
L0924    ldb   #$F5
         stb   <VD.FF6,u
         puls  pc,b,a
L092B    ldd   <VD.FFSPt,u
         cmpd  <VD.FFSTp,u	top of flood fill stack?
         lbcc  L0880
         tfr   d,y
         addd  #$0004
         std   <VD.FFSPt,u
         lda   ,y
         sta   <VD.FFFlg,u
         ldd   $01,y
         tfr   d,x
         lda   $03,y
         andcc #^Carry
         rts   
         ENDC

GetStat  ldx   PD.RGS,y
         cmpa  #SS.AlfaS
         beq   Rt.AlfaS
         cmpa  #SS.ScSiz
         beq   Rt.ScSiz
         cmpa  #SS.Cursr
         beq   Rt.Cursr
         IFNE  COCO2
         cmpa  #SS.DSTAT
         lbeq  Rt.DSTAT
         ENDC
         cmpa  #SS.Palet
         lbeq  Rt.Palet
         comb  
         ldb   #E$UnkSvc
         rts   

* Returns window or screen size
Rt.ScSiz equ   *
         IFNE  H6309
         ldq   #$00200010	a fast cheat
         stq   R$X,x
         ELSE
*         ldb   <VD.Col,u
         ldd   #$0020
         std   R$X,x
*         ldb   <VD.Row,u
         ldb   #$10
         std   R$Y,x
         ENDC
         clrb  
         rts   

* Get palette information
Rt.Palet pshs  u,y,x
         leay  <VD.Palet,u	point to palette data in proc desc
         ldu   R$X,x		pointer to 16 byte palette buffer
         ldx   <D.Proc		current proc desc
         ldb   P$Task,x		destination task number
         clra 			from task 0 
         tfr   y,x
         ldy   #16		move 16 bytes
         os9   F$Move   
         puls  pc,u,y,x

* Return VDG alpha screen memory info
Rt.AlfaS ldd   <VD.ScrnA,u
         anda  #$E0		keep bits 4-6
         lsra  
         lsra  
         lsra  
         lsra  			move to bits 0-2
         ldy   <D.SysDAT
         ldd   a,y
         lbsr  L06E1		map it in the process' memory area
         bcs   L0521
         pshs  b,a		offset to block address
         ldd   <VD.ScrnA,u
         anda  #$1F		make sure it's within the block
         addd  ,s
         std   R$X,x		memory address of the buffer
         ldd   <VD.CrsrA,u
         anda  #$1F
         addd  ,s++
         std   R$Y,x		memory address of the cursor
         lda   <VD.Caps,u	save caps lock status in A and exit
         bra   L051E

* Returns VDG alpha screen cursor info
Rt.Cursr ldd   <VD.CrsrA,u
         subd  <VD.ScrnA,u
         pshs  b,a
         clra  
         andb  #$1F
         addb  #$20
         std   R$X,x		save column position in ASCII
         puls  b,a		then divide by 32
         lsra  
         rolb  
         rolb  
         rolb  
         rolb  
         clra  
         andb  #$0F		only 16 lines to a screen
         addb  #$20
         std   R$Y,x
         ldb   <VD.CFlag,u
         lda   <VD.CChar,u
         bmi   L051E
         cmpa  #$60
         bcc   L0509
         cmpa  #$20
         bcc   L050D
         tstb  
         beq   L0507
         cmpa  #$00
         bne   L04FF
         lda   #$5E
         bra   L051E		save it and exit

L04FF    cmpa  #$1F
         bne   L0507
         lda   #$5F
         bra   L051E
L0507    ora   #$20		turn it into ASCII from VDG codes
L0509    eora  #$40
         bra   L051E
L050D    tstb  
         bne   L051E
         cmpa  #$21		remap specific codes
         bne   L0518
         lda   #$7C
         bra   L051E
L0518    cmpa  #$2D
         bne   L051E
         lda   #$7E
L051E    sta   R$A,x
         clrb  
L0521    rts   

         IFNE  COCO2
Rt.DSTAT bsr   ChkDvRdy
         bcs   L0A4F
         ldd   <VD.GCrsX,u
         lbsr  XY2Addr
         tfr   a,b
         andb  ,x
L0A23    bita  #$01
         bne   L0A32
         lsra
         lsrb
         tst   <VD.Mode,u	which mode?
         bmi   L0A23		branch if 256x192
         lsra
         lsrb
         bra   L0A23
L0A32    pshs  b
         ldb   <VD.PMask,u
         andb  #$FC
         orb   ,s+
         ldx   PD.RGS,y
         stb   R$A,x
         ldd   <VD.GCrsX,u
         std   R$Y,x
         ldb   <VD.Blk,u
         lbsr  L06E1
         bcs   L0A4F
         std   R$X,x
L0A4E    clrb
L0A4F    rts

ChkDvRdy ldb   <VD.Rdy,u	is device ready?
         bne   L0A4E		branch if so
         lbra  NotReady		else return error

* Entry: A = X coor, B = Y coor
XY2Addr  pshs  y,b,a		save off
         ldb   <VD.Mode,u	get video mode
         bpl   L0A60		branch if 128x192 (divide A by 4)
         lsra			else divide A by 6
L0A60    lsra
         lsra
         pshs  a		save on stack
         ldb   #191		get max Y
         subb  $02,s		subtract from Y on stack
         lda   #32		bytes per line
         mul
         addb  ,s+		add offset on stack
         adca  #$00
         ldy   <VD.SBAdd,u	get base address
         leay  d,y		move D bytes into address
         lda   ,s		pick up original X coor
         sty   ,s		put offset addr on stack
         anda  <VD.PixBt,u
         ldx   <VD.MTabl,u
         lda   a,x
         puls  pc,y,x		X = offset address, Y = base
         ENDC

SetStat  ldx   PD.RGS,y
         cmpa  #SS.ComSt
         beq   Rt.ComSt
         IFNE  COCO2
         cmpa  #SS.AAGBf
         beq   Rt.AAGBf
         cmpa  #SS.SLGBf
         beq   Rt.SLGBf
         ENDC
         cmpa  #SS.ScInf	new NitrOS-9 call
         lbeq  Rt.ScInf
         cmpa  #SS.DScrn
         lbeq  Rt.DScrn
         cmpa  #SS.PScrn
         lbeq  Rt.PScrn
         cmpa  #SS.AScrn
         lbeq  Rt.AScrn
         cmpa  #SS.FScrn
         lbeq  Rt.FScrn
         comb  
         ldb   #E$UnkSvc
         rts   

* Allow switch between true/fake lowercase
Rt.ComSt ldd   R$Y,x
L054C    ldb   #$10		sets screen to lowercase
         bita  #$01		Y = 0 = true lowercase, Y = 1 = fake lower
         bne   L0553
         clrb  
L0553    stb   <VD.CFlag,u
         ldd   #$2010		32x16
         inc   <VD.DFlag,u
         std   <VD.Col,u
         rts   

         IFNE  COCO2
Rt.AAGBf ldb   <VD.Rdy,u
         beq   NotReady
         ldd   #$0201
         leay  <VD.AGBuf,u
         lbsr  L06C7
         bcs   L0AEB
         pshs  a
         lbsr  Get8KHi
         bcs   L0AEC
         stb   ,y
         lbsr  L06E1
         bcs   L0AEC
         std   R$X,x
         puls  b
         clra
         std   R$Y,x
L0AEB    rts
L0AEC    puls  pc,a

NotReady comb
         ldb   #E$NotRdy
         rts

Rt.SLGBf ldb   <VD.Rdy,u
         beq   NotReady
         ldd   R$Y,x
         cmpd  #$0002
         lbhi  IllArg
         leay  <VD.GBuff,u
         ldb   b,y
         lbeq  IllArg
         pshs  x
         stb   <VD.Blk,u
         lda   <VD.SBAdd,u
         anda  #$E0
         lsra
         lsra
         lsra
         lsra
         ldx   <D.SysPrc
         leax  <P$DATImg,x
         leax  a,x
         clra
         std   ,x
         ldx   <D.SysPrc
         os9   F$SetTsk
         puls  x
         ldd   R$X,x
         beq   L0B2B
         ldb   #$01
L0B2B    stb   <VD.DFlag,u
         clrb
         rts
         ENDC

DTabl    fcb   $14	0: 640x192, 2 color
         fcb   $02
         fcb   $15	1: 320x192, 4 color
         fcb   $02
         fcb   $16	2: 160x192, 16 color
         fcb   $02
         fcb   $1D	3: 640x192, 4 color
         fcb   $04
         fcb   $1E	4: 320x192, 16 color
         fcb   $04

* Allocates and maps a hires screen into process address
Rt.AScrn ldd   R$X,x
         cmpd  #$0004		screen type 0-4
         lbhi  IllArg
         pshs  y,x,b,a
         ldd   #$0303
         leay  <VD.HiRes,u	pointer to screen descriptor
         lbsr  L06C7		gets next free S.D.
         bcs   L05AF
         sta   ,s
         ldb   $01,s		screen type
         stb   $02,y		VD.SType
         leax  >DTabl,pcr
         lslb  
         abx     		point to display code, #blocks
         ldb   $01,x		get number of blocks
         stb   $01,y		VD.NBlk
         lda   #$FF		start off with zero screens allocated
BA010    inca			count up by one
         ldb   1,y		get number of blocks
         os9   F$AlHRam		allocate a screen
         bcs   DeAll		de-allocate ALL allocated blocks on error
         pshs  b		save starting block number of the screen
         andb  #$3F		keep block BL= block MOD 63
         pshs  b
         addb  1,y		add in the block size of the screen
         andb  #$3F		(BL+S) mod 63 < BL? (overlap 512k bank)
         cmpb  ,s+		is all of it in this bank? 
         blo   BA010		if not, allocate another screen
         puls  b		restore the block number for this screen
         stb   ,y		VD.HiRes - save starting block number
         bsr   DeMost           deallocate all of the other screens
         ldb   ,y		restore the starting block number again

         lda   $01,x		number of blocks
         lbsr  L06E3
         bcs   L05AF
         ldx   $02,s
         std   R$X,x
         ldb   ,s
         clra  
         std   R$Y,x
L05AF    leas  $02,s
         puls  pc,y,x
L05B3X   leas  $02,s

IllArg   comb  
         ldb   #E$IllArg
         rts   

* De-allocate the screens
DeAll    bsr   DeMost		de-allocate all of the screens
         bra   L05AF		restore stack and exit

DeMost   tsta
         beq   DA020		quick exit if zero additional screens

         ldb   1,y		get size of the screen to de-allocate
         pshs  a		save count of blocks for later
         pshs  d,y,x		save rest of regs
         leay  9,s		account for d,y,x,a,calling PC
         clra
DA010    ldb   ,y+		get starting block number
         tfr   d,x		in X
         ldb   1,s		get size of the screen to de-allocate
         OS9   F$DelRAM		de-allocate the blocks *** IGNORING ERRORS ***
         dec   ,s		count down
         bne   DA010
         puls  d,y,x		restore registers
         puls  a		and count of extra bytes on the stack
         leas  a,s		remove blocks from the stack
DA020    rts			and exit

* Get current screen info for direct writes - added in NitrOS-9
Rt.ScInf pshs  x		save caller's regs ptr
         ldd   R$Y,x		get screen
         bmi   L05C8
         bsr   L05DE
         bcs   L05DC
         lbsr  L06FF
         bcs   L05DC
L05C8    ldx   ,s		get caller's regs ptr from stack
         ldb   R$Y+1,x
         bmi   L05DB
         bsr   L05DE
         bcs   L05DC
         lbsr  L06E3
         bcs   L05DC
         ldx   ,s
         std   R$X,x
L05DB    clrb  
L05DC    puls  pc,x
L05DE    beq   L05F1
         cmpb  #$03
         bhi   L05F1
         bsr   GetScrn
         beq   L05F1
         ldb   ,x
         beq   L05F1
         lda   $01,x
         andcc #^Carry
         rts   
L05F1    bra   IllArg

* Convert screen to a different type
Rt.PScrn ldd   R$X,x
         cmpd  #$0004
         bhi   IllArg
         pshs  b,a		save screen type, and a zero
         leax  >DTabl,pcr
         lslb  
         incb  
         lda   b,x		get number of blocks the screen requires
         sta   ,s		kill 'A' on the stack
         ldx   PD.RGS,y
         bsr   L061B
         bcs   L05B3X
         lda   ,s
         cmpa  $01,x
         lbhi  L05B3X		if new one takes more blocks than old
         lda   $01,s
         sta   $02,x
         leas  $02,s
         bra   L0633
L061B    ldd   R$Y,x
         beq   L0633
         cmpd  #$0003
         lbgt  IllArg
         bsr   GetScrn		point X to 3 byte screen descriptor
         lbeq  IllArg
         clra  
         rts   

* Displays screen
Rt.DScrn bsr   L061B
         bcs   L063A
L0633    stb   <VD.DGBuf,u
         inc   <VD.DFlag,u
         clrb  
L063A    rts   

* Entry: B = screen 1-3
* Exit:  X = ptr to screen entry
*GetScrn  pshs  b,a
*         leax  <VD.GBuff,u
*         lda   #$03
*         mul   
*         leax  b,x
*         puls  pc,b,a
GetScrn   leax  <VD.GBuff,U	point X to screen descriptor table
          abx
          abx
          abx
          tst   ,x		is this screen valid? (0 = not)
          rts

* Frees memory of screen allocated by SS.AScrn
Rt.FScrn ldd   R$Y,x
         lbeq  IllArg
         cmpd  #$03
         lbhi  IllArg
         cmpb  <VD.DGBuf,u
         lbeq  IllArg		illegal arg if screen is being displayed
         bsr   GetScrn		point to buffer
         lbeq  IllArg		error if screen unallocated
* Entry: X = pointer to screen table entry
FreeBlks lda   $01,x		get number of blocks
         ldb   ,x		get starting block
         beq   L066D		branch if none
         pshs  a		else save count
         clra  			clear A
         sta   ,x		clear block # in entry
         tfr   d,x		put starting block # in X
         puls  b		get block numbers
         os9   F$DelRAM 	delete
L066D    rts   			and return

ShowS    cmpb  #$03		no more than 3 graphics buffers
         bhi   L066D
         bsr   GetScrn		point X to appropriate screen descriptor
         beq   L066D            branch if not allocated
         ldb   $02,x		VD.SType - screen type 0-4
         cmpb  #$04
         bhi   L066D
         lslb  
         pshs  x
         leax  >DTabl,pcr
         lda   b,x		get proper display code
         puls  x
         clrb
         std   >$FF99		set border color, too
         std   >D.VIDRS
         lda   >D.HINIT
         anda  #$7F		make coco 3 only mode
         sta   >D.HINIT
         sta   >$FF90
         lda   >D.VIDMD
         ora   #$80		graphics mode
         anda  #$F8		1 line/character row
         sta   >D.VIDMD
         sta   >$FF98
         lda   ,x		get block #
         lsla
         lsla
         clrb
         std   <D.VOFF1		display it
         std   >$FF9D
         clr   >D.VOFF2
         clr   >$FF9C
         lbra  SetPals

L06C7    clr   ,-s
         inc   ,s
L06CB    tst   ,y		check block #
         beq   L06D9		if not used yet
         leay  b,y		go to next screen descriptor
         inc   ,s
         deca  
         bne   L06CB
         comb  
         ldb   #E$BMode
L06D9    puls  pc,a

* Get B 8K blocks from high RAM
Get8KHi  ldb   #$01
L06DDX   os9   F$AlHRAM 	allocate a screen
         rts

L06E1    lda   #$01		map screen into memory
L06E3    pshs  u,x,b,a
         bsr   L0710
         bcc   L06F9
         clra  
         ldb   $01,s
         tfr   d,x
         ldb   ,s
         os9   F$MapBlk 
         stb   $01,s		save error code if any
         tfr   u,d
         bcs   L06FD
L06F9    leas  $02,s		destroy D on no error
         puls  pc,u,x

L06FD    puls  pc,u,x,b,a	if error, then restore D

L06FF    pshs  y,x,a		deallocate screen
         bsr   L0710
         bcs   L070E
         ldd   #DAT.Free	set memory to unused
L0708    std   ,x++
         dec   ,s
         bne   L0708
L070E    puls  pc,y,x,a

L0710    equ   *
         IFNE  H6309
         pshs  a
         lde   #$08
         ELSE
         pshs  b,a
         lda   #$08		number of blocks to check
         sta   $01,s
         ENDC
         ldx   <D.Proc
         leax  <P$DATImg+$10,x	to end of CoCo's DAT image map
         clra  
         addb  ,s
         decb  
L071F    cmpd  ,--x
         beq   L072A
         IFNE  H6309
         dece
         ELSE
         dec   $01,s
         ENDC
         bne   L071F
         bra   L0743
L072A    equ   *
         IFNE  H6309
         dece
         ELSE
         dec   $01,s
         ENDC
         dec   ,s
         beq   L0738
         decb  
         cmpd  ,--x
         beq   L072A
         bra   L0743
L0738    equ   *
         IFNE  H6309
         tfr   e,a
         ELSE
         lda   $01,s		get lowest block number found
         ENDC
         lsla  
         lsla  
         lsla  
         lsla  
         lsla  			multiply by 32 (convert to address)
         clrb  			clear carry
         IFNE  H6309
         puls  b,pc
L0743    puls  a
         ELSE
         leas  $02,s
         rts   
L0743    puls  b,a
         ENDC
         comb  
         ldb   #E$BPAddr	bad page address
         rts   

         emod
eom      equ   *
         end
