Added a 320x200x256 TGI driver to the Commander X16 library.

Made the mandelbrot sample program handle the X16's 256 colors.
This commit is contained in:
Greg King 2020-07-15 17:11:38 -04:00
parent 72fff0cfbc
commit 4296cbaf82
6 changed files with 465 additions and 22 deletions

View File

@ -16,9 +16,12 @@ compiler.
<sect>Overview<p>
The Commander X16 is a modern small computer with firmware that is based on
the ROMs in Commodore's VIC-20 and 64C. It has a couple of I/O chips
(WDC65C22 VIA) that are like the ones in the VIC-20.
The Commander X16 is a modern small computer with firmware that is based partly
on the ROMs in Commodore's VIC-20 and 64C. It has a couple of I/O chips
(WDC65C22 VIA) that are like the ones in the VIC-20. It supports file storage
on Secure Digital cards. It allows two joysticks and a mouse. It has three
sound devices. It's VGA screen has twice the range of the C64 (similar to the
C128's 80-column screen), with 256 colors.
This file contains an overview of the CX16 run-time system as it comes with the
cc65 C compiler. It describes the memory layout, CX16-specific header files,
@ -108,7 +111,7 @@ cl65 -o file.prg -t cx16 -C cx16-asm.cfg source.s
To generate code that loads to &dollar;A000:
<tscreen><verb>
cl65 -o file.prg -Wl -S,$A000 -t cX16 -C cX16-asm.cfg source.s
cl65 -o file.prg -Wl -S,$A000 -t cx16 -C cx16-asm.cfg source.s
</verb></tscreen>
It also is possible to add a small BASIC header to the program, that uses SYS
@ -208,12 +211,22 @@ structures, accessing the struct fields will access the chip registers.
<sect>Loadable drivers<p>
The names in the parentheses denote the symbols to be used for static linking of the drivers.
The names in the parentheses denote the symbols to be used for static linking
of the drivers. The names fit into the 8.3 character limit of the SD-Card's
FAT32 file-system.
<sect1>Graphics drivers<p>
No graphics drivers are available currently for the CX16.
The default drivers, <tt/tgi_stddrv (tgi_static_stddrv)/,
point to <tt/cx320p1.tgi (cx320p1_tgi)/.
<descrip>
<tag><tt/cx320p1.tgi (cx320p1_tgi)/</tag>
This driver features a resolution of 320 across and 200 down with 256 colors,
and a slightly adjustable palette (the order of the colors can be changed in
a way that's compatible with some of the other color drivers).
</descrip><p>
<sect1>Extended memory drivers<p>
@ -224,10 +237,10 @@ No extended memory drivers are available currently for the CX16.
<sect1>Joystick drivers<p>
The default drivers, <tt/joy_stddrv (joy_static_stddrv)/,
point to <tt/cX16-std.joy (cx16_std_joy)/.
point to <tt/cx16-std.joy (cx16_std_joy)/.
<descrip>
<tag><tt/cX16-std.joy (cX16_std_joy)/</tag>
<tag><tt/cx16-std.joy (cx16_std_joy)/</tag>
Supports up to two NES (and SNES) controllers connected to the joystick ports
of the CX16. It reads the four directions, and the <bf/A/, <bf/B/,
<bf/Select/, and <bf/Start/ buttons. Buttons <bf/A/ and <bf/B/ are
@ -238,15 +251,15 @@ point to <tt/cX16-std.joy (cx16_std_joy)/.
<sect1>Mouse drivers<p>
The default drivers, <tt/mouse_stddrv (mouse_static_stddrv)/,
point to <tt/cX16-std.mou (cx16_std_mou)/.
point to <tt/cx16-std.mou (cx16_std_mou)/.
<descrip>
<tag><tt/cX16-std.mou (cX16_std_mou)/</tag>
<tag><tt/cx16-std.mou (cx16_std_mou)/</tag>
Supports a standard 3-button mouse connected to the PS/2 mouse port of the
Commander X16.
Currently (r35), this driver doesn't support <tt/mouse_move()/
and <tt/mouse_setbox()/.
Currently, this driver doesn't support <tt/mouse_move()/ and
<tt/mouse_setbox()/.
</descrip><p>

View File

@ -111,6 +111,25 @@
#define COLOR_LIGHTBLUE 0x0E
#define COLOR_GRAY3 0x0F
/* TGI color defines */
#define TGI_COLOR_BLACK COLOR_BLACK
#define TGI_COLOR_WHITE COLOR_WHITE
#define TGI_COLOR_RED COLOR_RED
#define TGI_COLOR_CYAN COLOR_CYAN
#define TGI_COLOR_VIOLET COLOR_VIOLET
#define TGI_COLOR_PURPLE COLOR_PURPLE
#define TGI_COLOR_GREEN COLOR_GREEN
#define TGI_COLOR_BLUE COLOR_BLUE
#define TGI_COLOR_YELLOW COLOR_YELLOW
#define TGI_COLOR_ORANGE COLOR_ORANGE
#define TGI_COLOR_BROWN COLOR_BROWN
#define TGI_COLOR_LIGHTRED COLOR_LIGHTRED
#define TGI_COLOR_GRAY1 COLOR_GRAY1
#define TGI_COLOR_GRAY2 COLOR_GRAY2
#define TGI_COLOR_LIGHTGREEN COLOR_LIGHTGREEN
#define TGI_COLOR_LIGHTBLUE COLOR_LIGHTBLUE
#define TGI_COLOR_GRAY3 COLOR_GRAY3
/* NES controller masks for joy_read() */
#define JOY_BTN_1_MASK 0x80
@ -280,8 +299,9 @@ struct __emul {
/* The addresses of the static drivers */
extern void cx16_std_joy[]; /* Referred to by joy_static_stddrv[] */
extern void cx16_std_mou[]; /* Referred to by mouse_static_stddrv[] */
extern void cx16_std_joy[]; /* Referenced by joy_static_stddrv[] */
extern void cx16_std_mou[]; /* Referenced by mouse_static_stddrv[] */
extern void cx320p1_tgi[]; /* Referenced by tgi_static_stddrv[] */

401
libsrc/cx16/tgi/cx320p1.s Normal file
View File

@ -0,0 +1,401 @@
;
; Graphics driver for the 320 pixels across, 200 pixels down, 256 colors mode
; on the Commander X16
;
; 2020-07-02, Greg King <gregdk@users.sf.net>
;
.include "zeropage.inc"
.include "tgi-kernel.inc"
.include "tgi-error.inc"
.include "cbm_kernal.inc"
.include "cx16.inc"
.macpack generic
.macpack module
; Macro that copies a word into a pseudo-register
.mac setReg reg, src
lda src
ldx src+1
sta gREG::reg
stx gREG::reg+1
.endmac
; ------------------------------------------------------------------------
; Header. Includes jump table and constants.
module_header _cx320p1_tgi ; 320 pixels across, 1 pixel per byte
; First part of the header is a structure that has a signature,
; and defines the capabilities of the driver.
.byte $74, $67, $69 ; ASCII "tgi"
.byte TGI_API_VERSION ; TGI API version number
.addr $0000 ; Library reference
.word 320 ; X resolution
.word 200 ; Y resolution
.byte <$0100 ; Number of drawing colors
.byte 1 ; Number of screens available
.byte 8 ; System font X size
.byte 8 ; System font Y size
.word $0100 ; Aspect ratio (based on VGA display)
.byte 0 ; TGI driver flags
; Next, comes the jump table. Currently, all entries must be valid,
; and may point to an RTS for test versions (function not implemented).
.addr INSTALL
.addr UNINSTALL
.addr INIT
.addr DONE
.addr GETERROR
.addr CONTROL
.addr CLEAR
.addr SETVIEWPAGE
.addr SETDRAWPAGE
.addr SETCOLOR
.addr SETPALETTE
.addr GETPALETTE
.addr GETDEFPALETTE
.addr SETPIXEL
.addr GETPIXEL
.addr LINE
.addr BAR
.addr TEXTSTYLE
.addr OUTTEXT
; ------------------------------------------------------------------------
; Constant
GRAPH320 = $80
; ------------------------------------------------------------------------
; Data
; Variables mapped to the zero-page segment variables. Some of these are
; used for passing parameters to the driver.
X1 := ptr1
Y1 := ptr2
X2 := ptr3
Y2 := ptr4
; Absolute variables used in the code
.bss
; The colors are indicies into a TGI palette. The TGI palette is indicies into
; VERA's palette. Vera's palette is a table of Red, Green, and Blue levels.
; The first 16 RGB elements mimic the Commodore 64's colors.
defpalette: .res $0100
palette: .res $0100
bcolor := palette + 0 ; Background color
color: .res 1 ; Stroke and fill index
mode: .res 1 ; Old text mode
.data
error: .byte TGI_ERR_OK ; Error code
.code
; ------------------------------------------------------------------------
; INSTALL routine. Is called after the driver is loaded into memory. May
; initialize anything that has to be done just once. Is probably empty
; most of the time.
;
; Must set an error code: NO
INSTALL:
; Create the default palette.
ldx #$00
: txa
sta defpalette,x
inx
bnz :-
; Fall through.
; ------------------------------------------------------------------------
; UNINSTALL routine. Is called before the driver is removed from memory. May
; clean up anything done by INSTALL, but is probably empty most of the time.
;
; Must set an error code: NO
UNINSTALL:
rts
; ------------------------------------------------------------------------
; INIT: Changes an already installed device from text mode to graphics
; mode.
; Note that INIT/DONE may be called multiple times while the driver
; is loaded, while INSTALL is called only once; so, any code that is needed
; to initiate variables and so on must go here. Setting the palette is not
; needed because that is called by the graphics kernel later.
; The graphics kernel never will call INIT when a graphics mode already is
; active, so there is no need to protect against that.
;
; Must set an error code: YES
INIT: stz error ; #TGI_ERR_OK
; Save the current text mode.
lda SCREEN_MODE
sta mode
; Switch into (320 x 200 x 256) graphics mode.
lda #GRAPH320
jmp SCREEN_SET_MODE
; ------------------------------------------------------------------------
; DONE: Will be called to switch the graphics device back into text mode.
; The graphics kernel never will call DONE when no graphics mode is active,
; so there is no need to protect against that.
;
; Must set an error code: NO
DONE:
; Work around a prerelease 37 Kernal bug.
; VERA (graphics) layer 0 isn't disabled by SCREEN_SET_MODE.
stz VERA::CTRL
lda VERA::DISP::VIDEO
and #<~VERA::DISP::ENABLE::LAYER0
sta VERA::DISP::VIDEO
lda mode
jmp SCREEN_SET_MODE
; ------------------------------------------------------------------------
; GETERROR: Return the error code in .A, and clear it.
GETERROR:
lda error
stz error
rts
; ------------------------------------------------------------------------
; CONTROL: Platform-/driver-specific entry point.
;
; Must set an error code: YES
CONTROL:
lda #TGI_ERR_INV_FUNC
sta error
rts
; ------------------------------------------------------------------------
; CLEAR: Clear the screen.
;
; Must set an error code: NO
CLEAR := GRAPH_CLEAR
; ------------------------------------------------------------------------
; SETVIEWPAGE: Set the visible page. Called with the new page in .A (0..n-1).
; The page number already is checked to be valid by the graphics kernel.
;
; Must set an error code: NO (will be called only if page OK)
SETVIEWPAGE:
; Fall through.
; ------------------------------------------------------------------------
; SETDRAWPAGE: Set the drawable page. Called with the new page in .A (0..n-1).
; The page number already is checked to be valid by the graphics kernel.
;
; Must set an error code: NO (will be called only if page OK)
SETDRAWPAGE:
rts
; ------------------------------------------------------------------------
; SETPALETTE: Set the palette (not available with all drivers/hardware).
; A pointer to the palette is passed in ptr1. Must set an error if palettes
; are not supported
;
; Must set an error code: YES
SETPALETTE:
stz error ; #TGI_ERR_OK
ldy #$00
: lda (ptr1),y
sta palette,y
iny
bnz :-
lda color ; Get stroke and fill index
; Fall through.
; ------------------------------------------------------------------------
; SETCOLOR: Set the drawing color (in .A). The new color already is checked
; to be in a valid range (0..maxcolor).
;
; Must set an error code: NO (will be called only if color OK)
SETCOLOR:
tax
sta color
lda palette,x ; Set stroke and fill color
tax
ldy bcolor ; Get background color
jmp GRAPH_SET_COLORS
; ------------------------------------------------------------------------
; GETPALETTE: Return the current palette in .XA. Even drivers that cannot
; set the palette should return the default palette here, so there's no
; way for this function to fail.
;
; Must set an error code: NO
GETPALETTE:
lda #<palette
ldx #>palette
rts
; ------------------------------------------------------------------------
; GETDEFPALETTE: Return the default palette for the driver in .XA. All
; drivers should return something reasonable here, even drivers that don't
; support palettes, otherwise the caller has no way to determine the colors
; of the (not changable) palette.
;
; Must set an error code: NO (all drivers must have a default palette)
GETDEFPALETTE:
lda #<defpalette
ldx #>defpalette
rts
; ------------------------------------------------------------------------
; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing
; color. The co-ordinates passed to this function never are outside the
; visible screen area, so there is no need for clipping inside this function.
;
; Must set an error code: NO
SETPIXEL:
jsr Point
jsr FB_CURSOR_POSITION
ldx color
lda palette,x
jmp FB_SET_PIXEL
; ------------------------------------------------------------------------
; GETPIXEL: Read the color value of a pixel, and return it in .XA. The
; co-ordinates passed to this function never are outside the visible screen
; area, so there is no need for clipping inside this function.
GETPIXEL:
jsr Point
jsr FB_CURSOR_POSITION
jsr FB_GET_PIXEL
ldx #>$0000
rts
; ------------------------------------------------------------------------
; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
; X2/Y2 = ptr3/ptr4, using the current drawing color.
;
; Must set an error code: NO
LINE: jsr Point
setReg r2, X2
setReg r3, Y2
jmp GRAPH_DRAW_LINE
; ------------------------------------------------------------------------
; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where
; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4, using the current drawing color.
; Contrary to most other functions, the graphics kernel will sort and clip
; the co-ordinates before calling the driver; so on entry, the following
; conditions are valid:
; X1 <= X2
; Y1 <= Y2
; (X1 >= 0) && (X1 < XRES)
; (X2 >= 0) && (X2 < XRES)
; (Y1 >= 0) && (Y1 < YRES)
; (Y2 >= 0) && (Y2 < YRES)
;
; Must set an error code: NO
BAR:
; Set the starting corner.
jsr Point
; Set the width.
lda X2
sub X1
sta gREG::r2
lda X2+1
sbc X1+1
sta gREG::r2+1
; Set the height.
lda Y2
sub Y1
sta gREG::r3
lda Y2+1
sbc Y1+1
sta gREG::r3+1
; Set the corner radius.
stz gREG::r4
stz gREG::r4+1
sec ; Fill the rectangle
jmp GRAPH_DRAW_RECT
; ------------------------------------------------------------------------
; TEXTSTYLE: Set the style used when calling OUTTEXT. Text scaling in X and Y
; directions are passed in .X and .Y, the text direction is passed in .A.
;
; Must set an error code: NO
TEXTSTYLE:
rts
; ------------------------------------------------------------------------
; OUTTEXT: Output text at X/Y = ptr1/ptr2 using the current color and the
; current text style. The text to output is given as a zero-terminated
; string with address in ptr3.
;
; Must set an error code: NO
OUTTEXT:
jsr Point
ldy #$00
@next: lda (ptr3),y
bze @end
phy
jsr GRAPH_PUT_CHAR
ply
iny
bnz @next
@end: rts
; ------------------------------------------------------------------------
; Point: Set the arguments for the first point of a Kernal graphics function.
Point: setReg r0, X1
setReg r1, Y1
rts

View File

@ -1,10 +1,11 @@
;
; Address of the static standard TGI driver
;
; 2019-12-22, Greg King
; 2020-06-04, Greg King
;
; const void tgi_static_stddrv[];
;
.import _cx16_320x8b_tgi
.export _tgi_static_stddrv := _cx16_320x8b_tgi
.import _cx320p1_tgi ; 320 pixels across, 1 pixel per byte
.export _tgi_static_stddrv := _cx320p1_tgi

View File

@ -1,12 +1,14 @@
;
; Name of the standard TGI driver
;
; 2019-12-22, Greg King
; 2020-06-04, Greg King
;
; const char tgi_stddrv[];
;
.export _tgi_stddrv
; A FAT32 8+3 file-name (for SD cards)
.rodata
_tgi_stddrv: .asciiz "cx16-320x8b.tgi"
_tgi_stddrv: .asciiz "cx320p1.tgi"

View File

@ -51,6 +51,7 @@ void mandelbrot (signed short x1, signed short y1, signed short x2,
register signed short r, r1, i;
register signed short xs, ys, xx, yy;
register signed short x, y;
register unsigned char maxcol = MAXCOL;
/* Calc stepwidth */
xs = ((x2 - x1) / (SCREEN_X));
@ -76,10 +77,15 @@ void mandelbrot (signed short x1, signed short y1, signed short x2,
if (count == maxiterations) {
tgi_setcolor (0);
} else {
if (MAXCOL == 2) {
switch (maxcol) {
case 2:
tgi_setcolor (1);
} else {
tgi_setcolor (count % MAXCOL);
break;
case 0: /* 256 colors */
tgi_setcolor (count);
break;
default:
tgi_setcolor (count % maxcol);
}
}
/* Set pixel */