{ These procedures and functions are for use with DHIRES.DVR. } { The only ones that use inline machine code are TxBytes and } { RxBytes, for doing block moves to and from the Apple. They } { need to be faster than the rest. -Rod Pederson } Const (*********************** Apple Addresses **********************) AuxPage = $c055; MainPage = $c054; ScrnBase = $2000; (*********************** Driver Constants *********************) (* Driver Commands *) (************ Colour Codes ************) readdvr = $fd; black = $00; dkblue = $80; writdvr = $fe; magenta = $10; purple = $90; othrdvr = $ff; brown = $20; grey2 = $a0; bw = $00; orange = $30; pink = $b0; colour = $01; dkgreen = $40; mdblue = $c0; gfx = $02; grey1 = $50; ltblue = $d0; txt = $03; green = $60; aqua = $e0; sndmode = $04; yellow = $70; white = $f0; clrg = $05; (**************************** Z80B Data ******************************) (**** Commands ****) (*** Z80 Routines ***) (*** Z80 Ports ***) RBytsCmd = $01; RdApByts = $FFEC; Z80Out = $00; WBytsCmd = $02; WrApByts = $FFEF; AplIn = $20; GotoCmd = $03; RdAplWrd = $FFE6; Ztatus = $40; RdBytCmd = $06; WrAplWrd = $FFE9; WrBytCmd = $07; RdAplByt = $FFE0; WrAplByt = $FFE3; Const dhrmode : byte = txt; Function ByteIn : byte; {ByteIn returns a byte written to the Z80 by the Apple.} {It continues to read the Z80 side of the status port } {until a byte is ready to be read, indicated by the } {port bit 7 being set . The value at the input port is } {assigned to the function return value. ByteIn should } {normally be used only by one of the higher level } {procedures defined further on in this include file. } begin while port[Ztatus] < $80 do; ByteIn := port[AplIn]; end; Procedure ByteOut (Val : byte); {ByteOut sends a byte from the Z80 to the Apple. } {It continues to read the Z80 side of the status port } {until the Apple is ready read, indicated by the status} {port bit 0 being set, at which time the port value is } {an odd number. The value of the byte parameter is } {assigned to the Z80-to-Apple output port. ByteOut will} {normally be used only by one of the higher level } {procedures defined further on in this include file. } begin while odd(port[Ztatus]) do; port[Z80Out] := Val; end; Procedure TxBytes (FmAdrs, ToAdrs, Count : integer); {FmAdrs is the address in the Z80 of a number of bytes} {to be sent to the Apple, ToAdrs is the address in the} {Apple to which the bytes are to be written. Count is} {the number of bytes to be transferred. Data is read } {from the Z80 and written to the Apple beginning with } {the lowest address. WrApByts is the PCPI bios routine} {that does the actual transfer of data. } begin ByteOut (WBytsCmd); ByteOut (Lo (ToAdrs)); ByteOut (Hi (ToAdrs)); ByteOut (Lo (Count)); ByteOut (Hi (Count)); inline ($2a/FmAdrs/ {ld hl,(FmAdrs) } $ed/$5b/Count/ {ld de,(Count) } $cd/WrApByts); {call WrApByts } end; Procedure RxBytes (FmAdrs, ToAdrs, Count : integer); {FmAdrs is the address in the Apple of a number of bytes} {to be transferred to the Z80, ToAdrs is the address in } {the Z80 to which the bytes are to be written. Count is} {the number of bytes to be transferred. Data is read } {from the Apple and written to the Z80 beginning with } {the lowest address. RdApByts is the PCPI bios routine } {that does the actual transfer of data. } begin ByteOut (RBytsCmd); ByteOut (Lo (FmAdrs)); ByteOut (Hi (FmAdrs)); ByteOut (Lo (Count)); ByteOut (Hi (Count)); inline ($2a/ToAdrs/ {ld hl,(ToAdrs) } $ed/$5b/Count/ {ld de,(Count) } $cd/RdApByts); {call RdApByts } end; Procedure WriteByte (ToAdrs : integer; DataByte : byte); {WriteByte is the equivalent of a 'POKE' into the Apple} {memory. ToAdrs is the address in the Apple to which } {DataByte will be written. } begin ByteOut (WrBytCmd); ByteOut (Lo(ToAdrs)); ByteOut (Hi(ToAdrs)); ByteOut (DataByte); end; Function ReadByte (FmAdrs : integer) : byte; {ReadByte is the equivalent of a 'PEEK' into the Apple} {memory. FmAdrs is the address in the Apple from which} {a byte is to be read. } begin ByteOut (RdBytCmd); ByteOut (Lo(FmAdrs)); ByteOut (Hi(FmAdrs)); ReadByte := ByteIn; end; Procedure DoAppleRoutine (GotoAdrs : integer); {GotoAdrs is the address in the Apple of a sub-routine} {to be executed by the Apple. The Apple will do the } {sub-routine (for instance a Monitor routine) and } {return to normal operation. } begin ByteOut (GotoCmd); ByteOut (Lo(GotoAdrs)); ByteOut (Hi(GotoAdrs)); end; Procedure grafmode (mode :byte); {Mode is a DHIRES.DVR 'other' command telling the driver} {to do either colour or black-and-white plotting. If an } {incorrect mode is supplied, the procedure will return } {having done nothing. The returned byte is ignored. } Var ans : byte; begin if ((mode = bw) or (mode = colour)) then begin ByteOut (othrdvr); ByteOut (mode); ans := ByteIn; dhrmode := mode; end; end; Procedure grafix; {The Apple is switched from text to double-high resolution} {graphics using a DHIRES.DVR 'other' command. The returned} {byte is ignored. } Var ans : byte; begin ByteOut (othrdvr); ByteOut (gfx); ans := ByteIn; end; Procedure text; {The Apple is switched from double-high resolution graphics} {to 80-column text using a DHIRES.DVR 'other' command. The } {returned byte is ignored. } Var ans : byte; begin ByteOut (othrdvr); ByteOut (txt); ans := ByteIn; dhrmode := txt; end; Procedure clrgraf (colour : byte); {The double-high resolution graphics screen is cleared to } {the colour specified using a DHIRES.DVR 'other' command. } {As usual, the returned byte is ignored. } Var ans : byte; begin ByteOut (othrdvr); ByteOut (clrg); ByteOut (colour); ans := ByteIn; end; Procedure graferror; {If an attempt is made to use the colour procedures and functions} {while in black-and-white mode, or vice-versa, this procedure } {be called to write an appropriate message to the text screen. It} {will display the message until 'ESC' is typed, at which point it} {will reset the mode actually selected and continue with the } {program. If the compiler 'C' option has been left on (this is } {the default) it can be used, here, to halt the program. } Var tmode : byte; c : char; begin tmode := dhrmode; text; write ('Cannot plot '); if dhrmode = colour then write ('colour in black-and-white mode. ') else if dhrmode = bw then write ('black-and-white in colour mode. ') else write ('unless the graphics mode is set. '); writeln ('"ESC" continues, "^C" halts.'); Repeat while not KeyPressed do; read (kbd,c); Until (c = #$1b) or (c = ^C); if c = ^C then halt; grafix; grafmode (tmode); end; Procedure bplot (x,y : integer); {A pixel is plotted on the black-and-white screen. The high } {byte of the x-coordinate is sent first because the DHIRES.DVR } {routine used to read the coordinates is also used to read the } {coordinates and colour in the colour mode. If not in black-and} {-white mode, an error message will be written to the text } {screen and nothing will be plotted. } begin if dhrmode <> bw then graferror else if (x>=0) and (x<560) and (y>=0) and (y<192) then begin ByteOut (writdvr); ByteOut (Hi(x)); ByteOut (Lo(y)); ByteOut (Lo(x)); end; end; Procedure unplot (x,y : integer); {The only difference between unplot and bplot is that the} {high bit of the high byte of the x-coordinate is set to } {indicate to DHIRES.DVR that the pixel is to be erased. } begin if dhrmode <> bw then graferror else if (x>=0) and (x<560) and (y>=0) and (y<192) then begin ByteOut (writdvr); ByteOut (Hi(x) or $80); ByteOut (Lo(y)); ByteOut (Lo(x)); end; end; Function bpset (x,y : integer) : byte; {The DHIRES.DVR 'read' entry point is used to determine whether} {or not a black-and-white pixel is set. It returns $00 if the } {pixel is not set, or if the coordinates given are outside the } {screen boundaries, otherwise it returns non-zero indicating } {that the pixel is set. } begin if dhrmode <> bw then graferror else begin if (x>=0) and (x<560) and (y>=0) and (y<192) then begin ByteOut (readdvr); ByteOut (Hi(x)); ByteOut (Lo(y)); ByteOut (Lo(x)); bpset := ByteIn; end else bpset := $00; end end; Procedure cplot (x,y : integer; c : byte); {A pixel is plotted at the x and y coordinates passed. } {The colours available on the Apple are defined as } {constants at the beginning of this include file. An } {attempt to plot colour in black-and-white mode will } {result in an error message. } begin if dhrmode <> colour then graferror else if (x>=0) and (x<140) and (y>=0) and (y<192) then begin ByteOut (writdvr); ByteOut (c); ByteOut (Lo(y)); ByteOut (Lo(x)); end; end; Function cpset (x,y : integer) : byte; {The colour set at the coordinates passed will be } {returned. Black is returned for coordinates } {outside the screen boundaries. An attempt to call} {cpset in black-and-white mode will result in an } {error message. } begin if dhrmode <> colour then graferror else begin if (x>=0) and (x<140) and (y>=0) and (y<192) then begin ByteOut (readdvr); ByteOut (Hi(x)); ByteOut (Lo(y)); ByteOut (Lo(x)); cpset := ByteIn; end else cpset := $00; end end; Procedure Upload (ToAdrs : integer); {A copy of the double-high resolution screen is copied from} {the Apple into the Z80 memory at ToAdrs. The auxilliary } {memory half of the screen is copied first, followed by the} {main memory half of the screen. It is important to leave } {the main memory turned on upon exiting a procedure. } begin WriteByte (AuxPage,$00); RxBytes (ScrnBase, ToAdrs, 8192); WriteByte (MainPage,$00); RxBytes (ScrnBase, ToAdrs+8192, 8192); end; Procedure Download (FmAdrs : integer); {A copy of the double-high resolution screen is copied from} {Z80 memory at FmAdrs to the Apple screen. The auxilliary } {memory half of the screen is copied first, followed by the} {main memory half of the screen. It is important to leave } {the main memory turned on upon exiting a procedure. } begin WriteByte (AuxPage,$00); TxBytes (FmAdrs, ScrnBase, 8192); WriteByte (MainPage,$00); TxBytes (FmAdrs+8192, ScrnBase, 8192); end;