BASIC/Monitor Firmware Routines
If doing size-coding it can be useful to call into routines in the
BASIC firmware. Some of the monitor routines can be assumed to always be
there. Usually you assume that Applesoft BASIC is there, though on the
original Apple II it had Woz's Integer BASIC instead which is not compatible.
There are nice routines for graphics (hi-res and lo-res) there, as well
as text and screen scrolling. My 64-byte flame demo takes advantage
of the text/lo-res duality and scrolls up the graphics by actually calling
into the firmware scroll-text routine.
You can find commented dis-assemblies of the firmware on line.
Here's one for
Applesoft
Here are some useful entry points:
- $F3E2 -- HGR -- set hi-res, page1, graphics/text split
- $F3D8 -- HGR2 -- set hi-res, page2, full graphics
- $F3F2 -- HCLR -- clear current screen to black
- $F457 -- HPLOT0 -- plot a hi-res point at (Y,X) = Horizontal, (A=Vertical)
- $F53A -- HGLIN -- draw from last plotted point to (A,X), (Y)
- $F6EC -- HCOLOR -- set color to X
- $FB36 -- TEXT -- set text mode
- $FC24 -- VTABZ -- with row in accumulator, make BASL:BASH ($28/$29)
point to that row in lo-res/text graphics memory.
Can then use LDA (BASL),Y style zero-page
addressing with it.
- $FC70 -- SCROLL -- scroll screen. Takes into account size of the
"text window" set by ZP registers
- $FCA8 -- WAIT -- wait for 1/2(26+27A+5A^2) us
- $FF3F -- Restore A/X/Y/P from locations in zero page
- $FF4A -- Save A/X/Y/P and stack pointer to zero page
Lo-res Plotting
To enable Lo-res manually:
bit SET_GR ; $C050 3 bytes
bit LORES ; $C056 3 bytes
bit FULLGR ; $C052 3 bytes
bit PAGE1 ; $C054 3 bytes
Instead you could call into ROM, Apple II has some well-defined
and stable entry points:
jsr SETGR ; $FB40 3 bytes (same as Applesoft GR)
; set Lo-res graphics, Page1
; split text/graphics, clear to black
To plot a point:
; Plot light green point at 10,10
lda #$CC ; load color hi/lo (light green here)
sta COLOR ; store to zero page $30
ldy #10
lda #10
jsr PLOT ; $F800 plots at screen location in Y, A
Those routines are slow. For fast plotting you want something like:
lda YPOS ; load y-coordinate
and #$FE ; make even
tay ; put in Y register
lda gr_offsets,Y ; get address from lookup
sta GBASL
lda gr_offsets+1,Y
sta GBASH ; if page-flipping, should add $0/$4
lda COLOR ; get color (note: 40x24 faster and smaller!)
; for 40x48 need to load, mask, logical-or
ldy XPOS ; load x-coordinate
sta (GBASL),Y
gr_offsets: .word $400,$480,$500,$580,$600,$680,$700,$780
.word $428,$4a8,$528,$5a8,$628,$6a8,$728,$7a8
.word $450,$4d0,$550,$5d0,$650,$6d0,$750,$7d0
However that wastes a lot of room. You can do a sort of hybrid where
when iterating across the screen you can calculate the row once and
then offset.
- Call GBASCALC which will set up
GBASL/GBASH
- (Calling PLOT once will also do this)
- Need to be sure MASK (ZP $2E) is set to $0F/$F0
for odd/even lines
- Now call PLOT1 and will plot at current Y-coord,
with X-coord in Y register
There are also Applesoft/ROM routines for
VLIN (to draw a vertical line) and HLIN (to draw a horizontal line).
You can use the text positioning firmware routines to set
the proper row pointer (usually in BASL:BASH $28/$29) rather than
having to have a lookup table to find the right address.
Also SETCOL to set the COLOR ($30) to have the same top/bottom nibble
(effectively multiplying the bottom 4 bits by 17).
Page Flipping
Page flipping makes for smooth animations (drawing offscreen).
Unfortunately the lo-res ROM routines not PAGE aware (the hi-res ones are).
It generally takes around 20 bytes or so.
ldx #0 ; x already 0
lda draw_page_smc+1 ; DRAW_PAGE
beq done_page
inx
done_page:
ldy PAGE0,X ; set display page to PAGE1 or PAGE2
eor #$4 ; flip draw page between $400/$800
sta draw_page_smc+1 ; DRAW_PAGE
Hi-res Plotting
Hi-res is complex enough that it's hard to do much when size constrained.
Using the ROM routines helps, and you can do some fancy effects if you
really take the time to learn what's going on.