596 lines
14 KiB
ArmAsm
596 lines
14 KiB
ArmAsm
;Hi-Res Character Generator
|
|
;v1.0 26 Jan 03--original release
|
|
;
|
|
;based on the Double Hi-Res Character Generator, v1.3
|
|
;
|
|
;Copyright (C) 1995-2003 by Scott Alfter
|
|
;scott@alfter.us
|
|
;http://alfter.us
|
|
;
|
|
;This program is free software; you can redistribute it and/or modify
|
|
;it under the terms of the GNU General Public License as published by
|
|
;the Free Software Foundation; either version 2 of the License, or
|
|
;(at your option) any later version.
|
|
;
|
|
;This program is distributed in the hope that it will be useful,
|
|
;but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;GNU General Public License for more details.
|
|
;
|
|
;You should have received a copy of the GNU General Public License
|
|
;along with this program; if not, write to the Free Software
|
|
;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
;
|
|
;Macros and pseudo-ops used in this source code are those used
|
|
;by the MicroSPARC/MindCraft Assembler:
|
|
;
|
|
; USE include macros from file
|
|
; UEN end of includes
|
|
; MUL don't expand macros in assembler output
|
|
; HEX include one or more hexadecimal bytes
|
|
; ] local label, or forward reference to a local label
|
|
; [ backward reference to a local label
|
|
; * at start of line: comment
|
|
; in operand: current address
|
|
; ; after operand: comment
|
|
; ^ logical AND
|
|
; xxx/ take high byte of xxx
|
|
; ADDR store a 16-bit quantity in little-endian format
|
|
; DFS allocate space
|
|
; ASC store the quoted string with the high bit set
|
|
;
|
|
;System requirements: 64K Apple II+, IIe, IIc, IIc+, IIGS, or compatible.
|
|
;
|
|
;Recommended use:
|
|
;1) Relocate your BASIC program above the Hi-Res buffer with something
|
|
; like this:
|
|
; IF PEEK(103)+PEEK(104)*256<>16385 THEN POKE 103,1:POKE 104,64:
|
|
; PRINT CHR$(4)"RUN FOOBAR"
|
|
;2) Load the character generator and font at their default locations:
|
|
; PRINT CHR$(4)"BLOAD HRCHARGEN":PRINT CHR$(4)"BLOAD CHARSET"
|
|
;3) Turn on the Hi-Res display:
|
|
; CALL 2816
|
|
; NOTE: Don't use HGR to do this...it won't give you the full screen
|
|
; for graphics, and it won't enable monochrome graphics on the IIGS.
|
|
;4) Redirect I/O to the character generator:
|
|
; PRINT CHR$(4)"PR#A$B06":PRINT CHR$(4)"IN#A$B0A"
|
|
;Normal PRINT, INPUT, and GET commands work. HTAB and VTAB work. HOME
|
|
;doesn't work, replace it with CALL 2816 or PRINT CHR$(12) to clear the
|
|
;screen and move the cursor to the upper left. Scrolling and inverse text
|
|
;are implemented. MouseText is not implemented. The control characters
|
|
;BEL, BS, LF, FF, and CR are implemented. It's worth noting that you can
|
|
;use this to enable lowercase text output on a II+ without a lowercase
|
|
;character-generator ROM.
|
|
;
|
|
;Entry points:
|
|
; dec hex description
|
|
;2816 B00 switch to HR display & clear screen
|
|
;2822 B06 character-output driver
|
|
;2826 B0A character-input driver
|
|
;2830 B0E load uncompressed HR image
|
|
;2833 B11 save uncompressed HR image
|
|
;2836 B14 load compressed HR image
|
|
;2839 B17 save compressed HR image
|
|
;
|
|
;Note that the routines that save files won't create them if they don't
|
|
;already exist. Use the CREATE command to create an empty binary file,
|
|
;like this:
|
|
; CREATE FOOBAR,TBIN
|
|
;Then stuff the filename to save (or load, for that matter) into the line
|
|
;buffer at 0x0200 with the length first and call the routine you want.
|
|
;For example, to load a compressed-image file called FOOBAR, use this:
|
|
; N$="FOOBAR":POKE 512,LEN(N$):FOR I=1 TO LEN(N$):POKE 512+I,ASC(MID$(N$,
|
|
; I,1)):NEXT:CALL 2830
|
|
;
|
|
;The uncompressed save/load routines are for compatibility with DHRCHARGEN;
|
|
;BSAVE and BLOAD are simpler and do the same job. The compressed save/load
|
|
;routines could be useful, though.
|
|
;
|
|
;The routines provided by BASIC for plotting Hi-Res graphics work with
|
|
;HRCHARGEN. I'd recommend using only white (HCOLOR=3) and black (HCOLOR=0)
|
|
;to plot graphics, since the generated text looks best on a monochrome
|
|
;display. It might be possible to create a font that looks good on a
|
|
;color display, but that is an exercise left to the reader. If you want
|
|
;to experiment with it, turn AN3 off (POKE 49247,0).
|
|
;
|
|
;The compression applied here is a simple scheme that works best with
|
|
;screens that have lots of black space; as many as 256 bytes of black
|
|
;area are crunched down to just two bytes; non-black areas are stored
|
|
;as is. With the simple graphics I created, this yielded compression
|
|
;anywhere from 3:1 to 11:1. Load and save times aren't too badly affected
|
|
;when you're working with floppy-disk storage. The delay is noticeable
|
|
;when you're working with hard-disk storage on an unaccelerated system,
|
|
;but it runs well enough with a hard drive and an accelerator.
|
|
;
|
|
;The source code was written for the MicroSPARC Assembler; it should be
|
|
;possible to adapt the source code to other assemblers without too much
|
|
;difficulty.
|
|
;
|
|
USE MACLIB
|
|
UEN
|
|
FONTADDR EQU $0800 ;location of bitmapped screen font info
|
|
STORE80 EQU $C000 ;80STORE--softswitch for making aux mem use easier
|
|
PAGE2 EQU $C054 ;select page 1/page 2 for text & graphics
|
|
TEXT EQU $C050 ;select graphics/text display
|
|
MIXED EQU $C052 ;select full-screen graphics or mixed text/graphics
|
|
HIRES EQU $C056 ;select Lo-Res/Hi-Res graphics
|
|
AN3 EQU $C05E ;enable monochrome Hi-Res on IIGS
|
|
COL80 EQU $C00C ;select 40/80-column display
|
|
KBD EQU $C000 ;keyboard buffer
|
|
KBDSTRB EQU $C010 ;keyboard strobe
|
|
XPOSN EQU $24
|
|
YPOSN EQU $25
|
|
HRBASE EQU $E6 ;Hi-Res base address (high byte, used by BASIC)
|
|
TMP1 EQU $FA
|
|
TMP2 EQU $FC
|
|
TMP3 EQU $FE
|
|
SCRNPTR EQU $3E
|
|
FONTPTR EQU $42
|
|
INVFLG EQU $32 ;monitor to tell if we should use normal or inverse
|
|
RNDSEED EQU $4E ;increment this while we wait for input
|
|
MLI EQU $BF00 ;ProDOS 8 MLI entry point
|
|
OPEN EQU $C8 ;selected MLI calls
|
|
READ EQU $CA
|
|
CLOSE EQU $CC
|
|
WRITE EQU $CB
|
|
COUT1 EQU $FDF0 ;we need this for the bell
|
|
ORG $0B00
|
|
JMP HRON ;turn on the Hi-Res display
|
|
RTS ;placeholder since we don't need MAIN2AUX
|
|
NOP
|
|
NOP
|
|
CLD ;COUT replacement (hook in with PR#A$xxxx)
|
|
JMP HRCOUT
|
|
CLD ;RDKEY replacement (hook in with IN#A$xxxx)
|
|
JMP HRRDKEY
|
|
JMP LOAD ;load uncompressed HR image named by buffer @ 0x0200
|
|
JMP SAVE ;save uncompressed HR image
|
|
JMP LOADC ;load compressed HR image
|
|
JMP SAVEC ;save compressed HR image
|
|
CHAR DFS 1
|
|
SAVEX DFS 1
|
|
SAVEY DFS 1
|
|
;
|
|
;Turn on HR and clear the screen
|
|
;
|
|
HRON STA MIXED ;turn on monochrome HR and clear screen
|
|
STA HIRES+1
|
|
STA AN3
|
|
STA TEXT
|
|
LDA #$20 ;set Hi-Res base so HPLOT will work
|
|
STA HRBASE
|
|
LDA #$2000/
|
|
STA TMP1+1
|
|
LDA #$2000
|
|
STA TMP1
|
|
STA XPOSN
|
|
STA YPOSN
|
|
TAY
|
|
]LOOP STA (TMP1),Y
|
|
INC TMP1
|
|
BNE [LOOP
|
|
INC TMP1+1
|
|
LDX TMP1+1
|
|
CPX #$4000/
|
|
BNE [LOOP
|
|
RTS
|
|
;
|
|
;HR character-output routine
|
|
;
|
|
HRCOUT STA CHAR
|
|
STX SAVEX
|
|
STY SAVEY
|
|
PHP
|
|
AND #$7F ;strip high bit
|
|
CMP #$20 ;printable character?
|
|
BCS ]GO
|
|
CMP #$0D ;CR?
|
|
BEQ ]RTN
|
|
CMP #$08 ;BS?
|
|
BEQ ]BS
|
|
CMP #$0C ;FF?
|
|
BEQ ]HOME
|
|
CMP #$07 ;BEL?
|
|
BEQ ]BELL
|
|
CMP #$0A ;LF?
|
|
BEQ ]LF
|
|
PLP ;not valid, so exit
|
|
LDX SAVEX
|
|
LDY SAVEY
|
|
RTS
|
|
]RTN LDA #0 ;CR: move cursor to left edge
|
|
STA XPOSN
|
|
]LF INC YPOSN ;CR/LF: move cursor down one line
|
|
LDA YPOSN
|
|
CMP #24 ;need to scroll?
|
|
BNE ]EXIT
|
|
LDA #23 ;put cursor at bottom line and scroll
|
|
STA YPOSN
|
|
JSR SCROLL
|
|
]EXIT LDX SAVEX
|
|
LDY SAVEY
|
|
PLP
|
|
RTS
|
|
]BELL ORA #$80 ;BEL: pass to COUT1 in ROM for sys beep
|
|
JSR COUT1
|
|
JMP [EXIT
|
|
]BS DEC XPOSN ;BS: move cursor back a space, possibly to
|
|
BPL [EXIT ;previous line
|
|
LDA #79
|
|
STA XPOSN
|
|
DEC YPOSN
|
|
BPL ]EXIT
|
|
LDA #0
|
|
STA YPOSN
|
|
]HOME JSR HRON ;FF: clear screen and move cursor to top
|
|
JMP [EXIT
|
|
]GO SBC #$20 ;get index into font
|
|
STA CHAR
|
|
LDA XPOSN ;get display coordinates
|
|
STA TMP2
|
|
LDA YPOSN
|
|
STA TMP2+1
|
|
JSR BASECALC
|
|
LDA CHAR
|
|
STA FONTPTR
|
|
LDA #0
|
|
STA FONTPTR+1
|
|
LDX #3 ;multiply by 8
|
|
]LOOP ASL FONTPTR
|
|
ROL FONTPTR+1
|
|
DEX
|
|
BNE [LOOP
|
|
CLC
|
|
LDA FONTPTR ;find address of character to draw
|
|
ADC #FONTADDR
|
|
STA FONTPTR
|
|
LDA FONTPTR+1
|
|
ADC #FONTADDR/
|
|
STA FONTPTR+1
|
|
LDY #0
|
|
LDX #0
|
|
]LOOP LDA (FONTPTR),Y ;get part of character from font
|
|
BIT INVFLG ;should it be drawn in inverse?
|
|
BMI ]NORMAL
|
|
EOR #$7F ;invert it
|
|
]NORMAL STA (SCRNPTR,X) ;write it to the screen
|
|
CLC ;move to the next line
|
|
LDA SCRNPTR+1
|
|
ADC #4
|
|
STA SCRNPTR+1
|
|
INY
|
|
CPY #8 ;we have 8 lines to draw
|
|
BNE [LOOP
|
|
INC XPOSN ;move cursor to next space
|
|
LDA XPOSN
|
|
CMP #40 ;move to next line if needed
|
|
BNE ]QUIT
|
|
LDA #0
|
|
STA XPOSN
|
|
INC YPOSN
|
|
LDA YPOSN
|
|
CMP #24 ;scroll if needed
|
|
BNE ]QUIT
|
|
LDA #23
|
|
STA YPOSN
|
|
JSR SCROLL
|
|
]QUIT PLP
|
|
LDX SAVEX
|
|
LDY SAVEY
|
|
RTS
|
|
;
|
|
;Put up a cursor, get keyboard input, and erase the cursor
|
|
;
|
|
HRRDKEY PHP
|
|
STX SAVEX
|
|
STY SAVEY
|
|
LDA XPOSN ;find memory address for cursor position
|
|
STA TMP2
|
|
LDA YPOSN
|
|
STA TMP2+1
|
|
JSR BASECALC
|
|
CLC ;invert the bottom two rows...this is the cursor
|
|
LDA SCRNPTR+1
|
|
ADC #24
|
|
STA SCRNPTR+1
|
|
LDX #0
|
|
LDA (SCRNPTR,X)
|
|
EOR #$7F
|
|
STA (SCRNPTR,X)
|
|
LDA SCRNPTR+1
|
|
ADC #4
|
|
STA SCRNPTR+1
|
|
LDA (SCRNPTR,X)
|
|
EOR #$7F
|
|
STA (SCRNPTR,X)
|
|
]LOOP INC RNDSEED ;bump the random seed
|
|
BNE ]CHECK
|
|
INC RNDSEED+1
|
|
]CHECK LDA KBD ;check keyboard
|
|
BPL [LOOP ;pressed?
|
|
PHA ;yes...save it while we erase the cursor
|
|
LDA #0
|
|
STA KBDSTRB ;clear keyboard
|
|
LDA (SCRNPTR,X) ;erase cursor
|
|
EOR #$7F
|
|
STA (SCRNPTR,X)
|
|
SEC
|
|
LDA SCRNPTR+1
|
|
SBC #4
|
|
STA SCRNPTR+1
|
|
LDA (SCRNPTR,X)
|
|
EOR #$7F
|
|
STA (SCRNPTR,X)
|
|
PLA ;get keypress back
|
|
PLP
|
|
LDX SAVEX
|
|
LDY SAVEY
|
|
RTS
|
|
;
|
|
;Calculate a screen address from X- and Y-coordinates
|
|
;input: X-coordinate in TMP2, Y-coordinate in TMP2+1
|
|
;
|
|
BASECALC LDA #$2000 ;screen starts at 0x2000
|
|
STA SCRNPTR
|
|
LDA #$2000/
|
|
STA SCRNPTR+1
|
|
LDA TMP2+1 ;INT(Y/8)*8
|
|
AND #$F8
|
|
PHA ;INT(Y/8)*40
|
|
ASL
|
|
ASL
|
|
CLC
|
|
ADC SCRNPTR
|
|
STA SCRNPTR
|
|
PLA
|
|
ADC SCRNPTR
|
|
STA SCRNPTR
|
|
LDA TMP2+1 ;Y-INT(Y/8)*8
|
|
AND #7
|
|
STA TMP1
|
|
LDA #0
|
|
STA TMP1+1
|
|
LDX #7
|
|
]LOOP ASL TMP1
|
|
ROL TMP1+1
|
|
DEX
|
|
BNE [LOOP
|
|
CLC ;INT(Y/8)*40+(Y-INT(Y/8)*8)*128
|
|
LDA SCRNPTR
|
|
ADC TMP1
|
|
STA SCRNPTR
|
|
LDA SCRNPTR+1
|
|
ADC TMP1+1
|
|
STA SCRNPTR+1
|
|
LDA TMP2 ;SCRNPTR=8192+INT(Y/8)*40+(Y-INT(Y/8)*8)*128+X
|
|
CLC
|
|
ADC SCRNPTR
|
|
STA SCRNPTR
|
|
RTS
|
|
;
|
|
;scroll the screen up 1 line
|
|
;
|
|
SCROLL LDA #0 ;start at top: move line 1 to line 0, etc.
|
|
STA TMP2
|
|
STA TMP2+1
|
|
]LOOP1 JSR BASECALC ;get destination address
|
|
LDA SCRNPTR ;save it
|
|
STA TMP3
|
|
LDA SCRNPTR+1
|
|
STA TMP3+1
|
|
INC TMP2+1 ;get source address
|
|
JSR BASECALC
|
|
LDX #8 ;eight rows of pixels in each line
|
|
]LOOP2 LDY #39 ;40 bytes in each line
|
|
]LOOP3 LDA (SCRNPTR),Y
|
|
STA (TMP3),Y
|
|
DEY ;do the rest of the row of pixels
|
|
BPL [LOOP3
|
|
CLC ;move down to the next row of pixels
|
|
LDA SCRNPTR+1
|
|
ADC #4
|
|
STA SCRNPTR+1
|
|
LDA TMP3+1
|
|
ADC #4
|
|
STA TMP3+1
|
|
DEX
|
|
BNE [LOOP2 ;repeat until we've done all eight rows
|
|
LDA TMP2+1
|
|
CMP #23 ;did we just move the bottom line up?
|
|
BCC [LOOP1
|
|
LDX #8 ;clear the bottom line
|
|
]LOOP1 SEC
|
|
LDA SCRNPTR+1
|
|
SBC #4
|
|
STA SCRNPTR+1
|
|
LDA #0
|
|
LDY #39
|
|
]LOOP2 STA (SCRNPTR),Y
|
|
DEY
|
|
BPL [LOOP2
|
|
DEX
|
|
BNE [LOOP1
|
|
RTS
|
|
;
|
|
;load HR image from disk into memory (pathname at 0x0200)
|
|
;
|
|
LOAD JSR MLI ;open file
|
|
DFC OPEN
|
|
ADDR OPENB
|
|
LDA OPENB+5 ;get reference number
|
|
STA READB+1 ;save it
|
|
STA CLOSEB+1
|
|
JSR MLI ;read the file
|
|
DFC READ
|
|
ADDR READB
|
|
JSR MLI ;close the file
|
|
DFC CLOSE
|
|
ADDR CLOSEB
|
|
RTS ;done
|
|
;
|
|
;save uncompressed HR image to disk
|
|
;
|
|
SAVE JSR MLI ;open file (must already exist)
|
|
DFC OPEN
|
|
ADDR OPENB
|
|
BNE ]ERROR
|
|
LDA OPENB+5 ;get reference number
|
|
STA WRITEB+1
|
|
STA CLOSEB+1
|
|
JSR MLI ;write the data
|
|
DFC WRITE
|
|
ADDR WRITEB
|
|
JSR MLI ;close
|
|
DFC CLOSE
|
|
ADDR CLOSEB
|
|
]ERROR RTS ;exit
|
|
;
|
|
;compress HR screen contents into a file (name @ 0x0200)
|
|
;
|
|
SAVEC LDA #$2078 ;zero out screen holes to maximize compresion
|
|
STA TMP1
|
|
LDA #$2078/
|
|
STA TMP1+1
|
|
]ZERO LDA #0
|
|
LDY #7
|
|
]LOOP STA (TMP1),Y
|
|
DEY
|
|
BPL [LOOP
|
|
CLC
|
|
LDA TMP1
|
|
ADC #$80
|
|
STA TMP1
|
|
LDA TMP1+1
|
|
ADC #$80/
|
|
STA TMP1+1
|
|
CMP #$4000/
|
|
BNE [ZERO
|
|
STA $3FFF ;make sure compressor doesn't go off-screen
|
|
JSR MLI ;open file (must already exist)
|
|
DFC OPEN
|
|
ADDR OPENB
|
|
BNE ]ERROR
|
|
LDA OPENB+5 ;get reference number
|
|
STA WRITECB+1 ;save it
|
|
STA CLOSEB+1
|
|
LDA #$2000
|
|
STA TMP1
|
|
LDA #$2000/
|
|
STA TMP1+1
|
|
]LOOP LDY #0 ;get screen byte
|
|
LDA (TMP1),Y
|
|
BEQ ]CRUNCH ;if zero, count 'em
|
|
STA CBUF ;put it in the output buffer
|
|
INY ;write one byte
|
|
STY WRITECB+4
|
|
STY CBUF+1
|
|
JSR MLI
|
|
DFC WRITE
|
|
ADDR WRITECB
|
|
BEQ ]NEXT
|
|
]CRUNCH INY ;count consecutive zeros
|
|
BEQ ]CRUNCHED ;up to 256
|
|
CMP (TMP1),Y
|
|
BEQ [CRUNCH
|
|
]CRUNCHED STA CBUF ;put the results in the output buffer
|
|
STY CBUF+1
|
|
LDA #2
|
|
STA WRITECB+4
|
|
JSR MLI ;write it
|
|
DFC WRITE
|
|
ADDR WRITECB
|
|
]NEXT CLC
|
|
LDA TMP1 ;increment counter
|
|
ADC CBUF+1
|
|
STA TMP1
|
|
LDA CBUF+1
|
|
BNE ]NOT256
|
|
SEC
|
|
]NOT256 LDA TMP1+1
|
|
ADC #0
|
|
STA TMP1+1
|
|
CMP #$4000/ ;end of screen buffer?
|
|
BNE [LOOP
|
|
JSR MLI ;close file and quit
|
|
DFC CLOSE
|
|
ADDR CLOSEB
|
|
]ERROR RTS
|
|
;
|
|
;load compressed picture
|
|
;
|
|
LOADC JSR MLI ;open file
|
|
DFC OPEN
|
|
ADDR OPENB
|
|
BNE ]ERROR
|
|
LDA OPENB+5 ;get reference number
|
|
STA READCB+1 ;save it
|
|
STA CLOSEB+1
|
|
LDA #$2000 ;start at beginning of scrn area
|
|
STA TMP1
|
|
LDA #$2000/
|
|
STA TMP1+1
|
|
]LOOP JSR MLI ;get a byte
|
|
DFC READ
|
|
ADDR READCB
|
|
LDA CBUF
|
|
BEQ ]EXPAND ;if zero, expand it out
|
|
LDY #0
|
|
STA (TMP1),Y ;write it to memory
|
|
INY
|
|
STY CBUF
|
|
BNE ]NEXT
|
|
]EXPAND JSR MLI ;get number of zeros
|
|
DFC READ
|
|
ADDR READCB
|
|
LDY CBUF
|
|
LDA #0
|
|
]EXPLP DEY ;write out the zeros
|
|
STA (TMP1),Y
|
|
BNE [EXPLP
|
|
]NEXT CLC ;increment counter
|
|
LDA TMP1
|
|
ADC CBUF
|
|
STA TMP1
|
|
LDA CBUF
|
|
BNE ]NOT256
|
|
SEC
|
|
]NOT256 LDA TMP1+1
|
|
ADC #0
|
|
STA TMP1+1
|
|
CMP #$4000/ ;end of screen?
|
|
BNE [LOOP
|
|
JSR MLI ;close file
|
|
DFC CLOSE
|
|
ADDR CLOSEB
|
|
]ERROR RTS ;exit
|
|
;
|
|
;parameter blocks for MLI calls
|
|
;
|
|
OPENB DFC 3
|
|
ADDR $200 ;pathname buffer
|
|
ADDR $1C00 ;I/O buffer (just below page 1)
|
|
DFS 1 ;file reference number
|
|
READB DFC 4
|
|
DFS 1 ;file reference number
|
|
ADDR $2000 ;load into 0x2000
|
|
ADDR $2000 ;load 0x2000 bytes
|
|
DFS 2
|
|
CLOSEB DFC 1
|
|
DFS 1 ;file reference number
|
|
WRITEB DFC 4
|
|
DFS 1 ;file reference number
|
|
ADDR $2000 ;save from 0x2000
|
|
ADDR $2000 ;save 0x2000 bytes
|
|
DFS 2 ;bytes written
|
|
WRITECB DFC 4
|
|
DFS 1 ;file reference number
|
|
ADDR CBUF ;output buffer
|
|
ADDR 0 ;bytes to write
|
|
DFS 2 ;bytes written
|
|
READCB DFC 4
|
|
DFS 1 ;file reference number
|
|
ADDR CBUF ;input buffer
|
|
ADDR 1 ;bytes to read
|
|
DFS 2 ;bytes read
|
|
CBUF DFS 2 ;buffer for read/write of compressed files
|