VERSIONSTRING equ "Gfx v2.05" ! ! Filename: gfx.asm ! Module name: Gfx ! Description: standard mode video driver ! ! Commands: ! string QueryVersion () - query version string ! SetMode (byte onoff) - turn standard mode on or off ! Clear () - clear the screen ! Dump (byte[30] bitmap) - write bitmap to display ! DumpResource (byte rezID) - write bitmap resource to display ! Shift (byte how) - shift or scroll the display one notch ! ScrollStop () - stop auto-scrolling display ! ScrollSpeed (byte speed) - set scroll speed ! ScrollStart (byte how, word duration) - start auto-scrolling display ! ScrollCstring (cstring string) - scroll C string ! ScrollPstring (pstring string) - scroll Pascal string ! ScrollStringResource (byte rezID) - scroll resource string ! UseFontResource (byte rezID) - use a font ! SetScrollRange (byte firstcolumn, byte length) - set scroll range ! ! IPC: ! IPC_Gfx_SetModeOff ! ! Timers: ! TIMER_Gfx - timer for scrolling display ! ! Hooks: ! HOOK_GFX - video refresh hook ! ! Comments: ! none ! ! Hardware notes: ! To set the currently active column, write the column number to ! PORT_Gfx_Column. To set which lights are lit in that column, ! write to PORT_Gfx_Data, active high, bit 0 is at the top. ! ! History: ! bv 9/12/98 - initial revision ! bv 5/30/99 - converted to CokeOS v3 module ! bv 6/16/99 - updated for new response style ! bv 6/22/99 - updated for new hook style, added scroll range ! bv 7/16/99 - updated for new IPC style ! bv 7/25/99 - added IPC_Gfx_SetModeOff ! bv 10/3/99 - allowed ScrollStringResource to scroll more than 256 chars include ; constants GFX_REFRESHDELAY equ 64 ; 250 KHz / 64 / 30 = 120 Hz screen refresh GFX_DEFAULTSPEED equ 4 ; EntryPoint EntryPoint subroutine cmpa #IPC_Coke_Hello beq .init cmpa #IPC_Coke_Goodbye beq .free cmpa #IPC_Gfx_SetModeOff beq .off sec rts .init ldx #CommandTable ; install command table jsr Coke_InstallCommandTable ldaa #ID_Gfx ; install IPC ldx #EntryPoint jsr Coke_RegisterIPC ldd #GFX_DEFAULTSPEED ; set default scroll speed std video_scrollspeed16 clr video_firstcolumn ; init scroll range ldaa #29 staa video_lastcolumn inca staa video_length clr video_numchars ; no font yet ldd #video_buffer ; init cursor pos std video_cursorpos clr video_on ; not active yet clc rts .free ldx #CommandTable ; remove command table jsr Coke_RemoveCommandTable ldaa #ID_Gfx ; remove IPC jsr Coke_UnregisterIPC ldaa #TIMER_Gfx ; remove timer jsr Coke_RemoveTimer tst video_on ; is the mode active? beq .noton ldx #RefreshHookEnd ; if so, remove the hook ldaa #HOOK_GFX jsr Coke_RemoveHook .noton clc rts .off psha pshx tst video_on ; is it already off? beq .offnoton ; if so, ignore clr video_on ; if not, clear it ldaa #HOOK_GFX ldx #RefreshHookEnd jsr Coke_RemoveHook ; remove the hook function .offnoton pulx pula clc rts ; SetCursor sets the cursor position for subsequent ; drawing operations. ; horizontal cursor position (from zero) is in b. SetCursor subroutine pshx ldx #video_buffer ; get start of video buffer abx ; add cursor pos stx video_cursorpos ; store it pulx rts ; ShiftLeft shifts the screen to the left, without wrap-around. ; The right-most column is zeroed. ShiftLeft subroutine psha pshb pshx ldx #video_buffer ldab video_firstcolumn abx ; set x to start of scroll range ldab video_length ; get number of lines to do decb beq .done .shiftloop ldaa 1,x ; get column staa 0,x ; move it left inx ; increment x decb ; dec counter bne .shiftloop clr 0,x ; clear rightmost column .done pulx pulb pula rts ; ShiftRight shifts the screen to the right, without wrap-around. ; The left-most column is zeroed. ShiftRight subroutine psha pshb pshx ldx #video_buffer ldab video_lastcolumn decb abx ; set x to next to end of scroll range ldab video_length ; get number of lines to do decb beq .done .shiftloop ldaa 0,x ; get column staa 1,x ; move it right dex ; dec x decb ; dec counter bne .shiftloop clr 1,x ; clear leftmost column .done pulx pulb pula rts ; ScrollLeft scrolls the screen left, with wrap-around. ScrollLeft subroutine psha pshb pshx ldx #video_buffer ldab video_firstcolumn abx ; set x to start of scroll range ldaa 0,x ; get the line jsr ShiftLeft ; do the shift ldab video_length ; go to the end of the scroll range decb abx staa 0,x ; store the line pulx pulb pula rts ; ScrollRight scrolls the screen right, with wrap-around. ScrollRight subroutine psha pshb pshx ldx #video_buffer ldab video_lastcolumn abx ; set x to end of scroll range ldaa 0,x ; get the line jsr ShiftRight ; do the shift ldx #video_buffer ldab video_firstcolumn abx ; set x to start of scroll range staa 0,x ; store the line pulx pulb pula rts ; DoShift does a shift. ; how code in a DoShift subroutine cmpa #SHIFT_ShiftLeft beq .shl cmpa #SHIFT_ShiftRight beq .shr cmpa #SHIFT_ScrollLeft beq .scrl cmpa #SHIFT_ScrollRight beq .scrr rts .shl jsr ShiftLeft rts .scrl jsr ScrollLeft rts .shr jsr ShiftRight rts .scrr jsr ScrollRight rts ; UseChar resets the char line pointer to the start of the ; requested char. If the char doesn't exist, a space is drawn. ; char to use is in b. UseChar subroutine pshx pshb psha cmpb video_numchars ; does the char exist? bhs .badchar ; if so, put in a space clra ; clear high byte asld ; multiply by two addd video_fontptr ; add offset to start of table xgdx ; put into x ldd 0,x ; get pointer to start of char .putptr std video_charptr ; store the pointer .exit pula pulb pulx rts .badchar ldd #.dummychar bra .putptr .dummychar dc.b $80 ; DrawCharLine draws one line of the char at the cursor position, ; and updates the pointer (but does NOT change the cursor position!) ; If it draws the final line of the char, carry is returned set. ; Otherwise, carry is clear. DrawCharLine subroutine pshx psha ldx video_charptr ; get the pointer to the line clc ldaa 0,x ; get the goods bpl .notlast ; if high bit is set, that's the last char anda #$7f ; if so, remove high bit sec ; and set carry for return .notlast inx ; update the char ptr stx video_charptr ; store it ldx video_cursorpos ; get the cursor position staa 0,x ; store the line pula pulx rts ; DrawChar draws an entire char at the cursor position. ; It doesn't check for drawing outside the buffer. ; char to use is in b DrawChar subroutine jsr UseChar ; use the char .drawloop jsr DrawCharLine ; draw a line ldx video_cursorpos ; increment the cursor position inx stx video_cursorpos bcc .drawloop ; if not the end, go again. rts ; otherwise, go home ; ScrollReset sets the pointers to the start and end of the buffer, and ; gets a head start on setting up the char. ScrollReset subroutine pshb pshx ldx #string_buffer ; get the buf ptr stx string_ptr ; put it there ldab 0,x ; get the first char jsr UseChar ; set it up ldab string_length ; get the string length abx ; add it to the ptr stx string_scrollend ; store it as the place to end ldab video_lastcolumn ; set cursor to right side of range jsr SetCursor pulx pulb rts ; ScrollMem is like ScrollReset, but it takes a pointer to the ; start of a string in memory, and prepares to scroll that instead. ; The string can be more than 256 chars. ; pointer to string in x, length in d. ScrollMem subroutine psha pshb stx string_ptr ; put x as the string ptr addd string_ptr ; add the length std string_scrollend ; that's the ending ptr ldab 0,x ; get the first char of the string jsr UseChar ; set it up ldab video_lastcolumn ; set cursor to right side of display jsr SetCursor pulb pula rts ; ScrollString shifts the screen left and fills in the right-most column. ; When it finishes with the last character, it returns with carry set. ; Otherwise, carry is clear. ScrollString pshb pshx ldx string_ptr ; get the current ptr cpx string_scrollend ; is there nothing to do? blo .notdone ; if not, continue .nomore sec ; if so, set carry pulx pulb rts ; and leave .notdone jsr ShiftLeft ; shift the screen left jsr DrawCharLine ; draw a line (assume cursor is set) bcc .goaway ; if not the last line, go home inx ; if char is done, inc string ptr stx string_ptr ; store it cpx string_scrollend ; is it the end? bhs .nomore ; if so, return with carry set ldab 0,x ; if not, get the new character jsr UseChar ; tell the driver to use it .goaway clc ; good exit pulx pulb rts ; Command_SetMode (byte onoff) Command_SetMode subroutine jsr Coke_GetChar ; get onoff tsta ; turning on or off? beq .off tst video_on ; is it already on? bne .done ; if so, ignore ldaa #IPC_Gfx_SetModeOff ; turn off all other graphics modes ldab #IPCFLAG_Broadcast ; send to all jsr Coke_CallIPC ldaa #1 staa video_on ; turn us on, baby! clr video_column ; clear the column ldd #GFX_REFRESHDELAY ; get the standard mode refresh rate std gfxdelay ; put it in the system variable ldaa #HOOK_GFX ldx #RefreshHookEnd jsr Coke_InstallHook ; install the hook function bra .done .off tst video_on ; is it already off? beq .done ; if so, ignore clr video_on ; if not, clear it ldaa #HOOK_GFX ldx #RefreshHookEnd jsr Coke_RemoveHook ; remove the hook function .done ldaa #COKE_ACK rts ; Command_Clear () Command_Clear subroutine clra ; clear out a ldab #30 ldx #video_buffer+29 ; go to end of buffer .clearloop staa 0,x ; store a zero dex ; decrement decb ; dec counter bne .clearloop ; if not done, keep going ldaa #COKE_ACK rts ; Command_Dump (30 bytes) Command_Dump subroutine ldx #video_buffer ; get pointer to video buffer ldab #30 ; do thirty lines .loop jsr Coke_GetChar ; get the data staa 0,x ; store it in the buffer inx ; next line decb ; dec counter bne .loop ; if not done, loop ldaa #COKE_ACK rts ; Command_DumpResource (byte rezid) Command_DumpResource subroutine jsr Coke_GetChar ; get rez id tab ; put into b jsr Resource_GetResource ; get the resource ptr bcs .nope ; if bad resource ptr, then abort ldy #video_buffer ; get ptr to buf ldab #30 ; do 30 bytes .loop ldaa 0,x ; get byte from resource file staa 0,y ; put it into buffer inx ; next byte iny decb ; dec counter bne .loop ; if not done, loop .nope ldaa #COKE_ACK rts ; Command_Shift (byte how) Command_Shift subroutine jsr Coke_GetChar ; get how byte jsr DoShift ; do it ldaa #COKE_ACK rts ; Command_ScrollStop () Command_ScrollStop subroutine ldaa #TIMER_Gfx ; get our timer id jsr Coke_RemoveTimer ; kill the timer ldaa #COKE_ACK rts ; Command_ScrollSpeed (byte speed) Command_ScrollSpeed subroutine jsr Coke_GetChar ; get the param staa video_scrollspeed ; store it ldaa #COKE_ACK rts ; Command_ScrollStart (byte how, word duration) Command_ScrollStart subroutine jsr Coke_GetChar ; get the param staa video_scrollhow ; store it jsr Coke_GetChar ; get duration tab jsr Coke_GetChar std video_scrollduration ; store it ldaa #TIMER_Gfx ldx #ScrollTimerFunction ldy video_scrollspeed16 jsr Coke_SetTimer ; set the timer ldaa #COKE_ACK rts ; Command_ScrollCstring (null-terminated string) Command_ScrollCstring subroutine ldx #string_buffer ; x at the start of the buffer clrb ; b is current length .getloop jsr Coke_GetChar ; get a char tsta ; is it zero? beq .endloop ; if so, time to go staa 0,x ; if not, write to the buffer inx ; inc the buffer ptr cmpb #$ff ; is it max length? beq .endloop ; if so, jump outa here incb ; inc the length bra .getloop ; keep going .endloop stab string_length ; set the new string length tstb ; is b zero? beq .nope ; if so, do nothing jsr ScrollReset ; set the scrolly thing to the string ldaa #TIMER_Gfx ; get timer id ldx #StringTimerFunction ; get ptr to timer proc ldy video_scrollspeed16 ; get speed jsr Coke_SetTimer ; do the timer .nope ldaa #COKE_ACK rts ; Command_ScrollPstring (byte length) (string) Command_ScrollPstring subroutine ldx #string_buffer ; get buffer ptr jsr Coke_GetChar ; get length staa string_length ; store it tab ; put in b for counting beq .nope ; if zero, ignore .getloop jsr Coke_GetChar ; get char staa 0,x ; store it in buf inx ; inc ptr decb ; dec counter bne .getloop ; loop jsr ScrollReset ; set the scrolly thing to the string ldaa #TIMER_Gfx ; get timer id ldx #StringTimerFunction ; get ptr to timer proc ldy video_scrollspeed16 ; get speed jsr Coke_SetTimer ; do the timer .nope ldaa #COKE_ACK rts ; Command_ScrollStringResource (byte rez id) Command_ScrollStringResource subroutine jsr Coke_GetChar ; get rez id tab ; put in b jsr Resource_GetResource ; get rez ptr bcs .done ; if invalid rez, get outa here jsr Resource_GetLength ; get size in d tstb ; is the length zero? bne .doit tsta beq .done .doit jsr ScrollMem ; set scrolly thing to mem thing ldaa #TIMER_Gfx ; get timer id ldx #StringTimerFunction ; get ptr to timer proc ldy video_scrollspeed16 ; get speed jsr Coke_SetTimer ; do the timer .done ldaa #COKE_ACK rts ; Command_UseFontResource (rez id) Command_UseFontResource subroutine jsr Coke_GetChar ; get rez id tab ; put in b jsr Resource_GetResource ; get the rez ptr bcs .badresid ; if bad resource id, fail ldaa 0,x ; get num chars staa video_numchars ; store it stx video_scratch ; store top of file inx ; go to start of table stx video_fontptr ; store it tsta ; any chars? beq .done ; if not, we're done psha ; stash num chars jsr Resource_GetAttributes ; get attributes byte bita #RFLAG_INITIALIZED ; has it been relocated? bne .alreadyinit ; if relocated, we're done oraa #RFLAG_INITIALIZED ; if not, set the flag jsr Resource_SetAttributes pula ; get back num chars .loop ldab 1,x ; get lobyte of char offset addb video_scratch+1 ; add loybyte of resource ptr stab 1,x ; store lobyte ldab 0,x ; get hibyte of char offset adcb video_scratch ; add hibyte of rez ptr (with carry) stab 0,x ; store hibyte inx ; next table entry inx deca ; dec counter bne .loop bra .done .alreadyinit pula .done ldaa #COKE_ACK rts .badresid ldab #ERROR_Coke_BadResourceID ldaa #COKE_FAIL rts ; Command_SetScrollRange (byte firstcolumn, byte length) Command_SetScrollRange subroutine jsr Coke_GetChar ; get firstcolumn cmpa #30 ; is it too big? bhs .nofirstcol ; if so, don't use it staa video_firstcolumn ; if not, store it .nofirstcol jsr Coke_GetChar ; get length tsta ; is it zero length? beq .bad ; if so, use full screen. adda video_firstcolumn ; add firstcolumn cmpa #30 ; is it too big? bls .nottoobig ; if not, use it .bad ldaa #30 ; if so, go to end .nottoobig staa video_lastcolumn ; store it dec video_lastcolumn ; adjust last column suba video_firstcolumn ; subtract first column staa video_length ; get length back and store it ldaa #COKE_ACK rts ; ScrollTimerFunction scrolls the display or something. ScrollTimerFunction subroutine psha pshx ldaa video_scrollhow ; get the how code jsr DoShift ; do something with it ldx video_scrollduration ; get duration beq .done ; if zero, go forever dex ; dec stx video_scrollduration ; store it bne .done ; if zero now, stop timer ldaa #TIMER_Gfx jsr Coke_RemoveTimer .done pulx pula rts ; StringTimerFunction scrolls the string across the display StringTimerFunction subroutine jsr ScrollString ; do it bcc .done ; was that the end? psha ldaa #TIMER_Gfx ; if so, kill the timer jsr Coke_RemoveTimer pula .done rts ; RefreshHookFunction is called during an interrupt proc to multiplex the ; display. The "asl"s compensate for the hardware flaw. RefreshHookFunction subroutine ldab video_column ; get the current column number decb ; decrement bpl .nocolwrap ; did it go negative? ldab #29 ; if so, go to the end (of the physical screen) .nocolwrap stab video_column ; store it in the variable tba ldx #video_buffer ; get offset to video buffer abx ; and add column number asla ; compensate for hardware flaw ldab 0,x ; get the data in the buffer aslb ; compensate for hardware flaw staa PORT_Gfx_Column ; also set the display to that column stab PORT_Gfx_Data ; send the data out to the display RefreshHookEnd _endhook RefreshHookFunction ; version stuff _versionstuff ; Command table CommandTable subroutine dc.b CMD_Gfx_QueryVersion dc.w Command_QueryVersion dc.b CMD_Gfx_SetMode dc.w Command_SetMode dc.b CMD_Gfx_Clear dc.w Command_Clear dc.b CMD_Gfx_Dump dc.w Command_Dump dc.b CMD_Gfx_DumpResource dc.w Command_DumpResource dc.b CMD_Gfx_Shift dc.w Command_Shift dc.b CMD_Gfx_ScrollStop dc.w Command_ScrollStop dc.b CMD_Gfx_ScrollSpeed dc.w Command_ScrollSpeed dc.b CMD_Gfx_ScrollStart dc.w Command_ScrollStart dc.b CMD_Gfx_ScrollCstring dc.w Command_ScrollCstring dc.b CMD_Gfx_ScrollPstring dc.w Command_ScrollPstring dc.b CMD_Gfx_ScrollStringResource dc.w Command_ScrollStringResource dc.b CMD_Gfx_UseFontResource dc.w Command_UseFontResource dc.b CMD_Gfx_SetScrollRange dc.w Command_SetScrollRange dc.b 0 ; data segment video_buffer ds 30 video_cursorpos ds 2 video_column ds 1 video_on ds 1 video_charptr ds 2 video_scrollspeed16 ds 1 video_scrollspeed ds 1 video_scrollduration ds 2 video_scrollhow ds 1 video_fontptr ds 2 video_numchars ds 1 video_firstcolumn ds 1 video_lastcolumn ds 1 video_length ds 1 video_scratch ds 2 string_buffer ds 256 string_length ds 1 string_ptr ds 2 string_scrollend ds 2