sms: add support for VDP's text mode
Because that mode behaves exactly like in a regular TMS9918, a new driver for TMS9918 has been added in blkfs and SMS' VDP now uses it. Also, fix broken 5x7 font.
This commit is contained in:
parent
09c01c4a43
commit
d1718a90c7
@ -1,16 +1,11 @@
|
||||
VDP Driver
|
||||
|
||||
Implement (emit) on the console. Characters start at the top
|
||||
left. Every (emit) call converts the ASCII char received to its
|
||||
internal font, then put that char on screen, advancing the
|
||||
cursor by one. When reaching the end of the line (33rd char),
|
||||
wrap to the next.
|
||||
|
||||
In the future, there's going to be a scrolling mechanism when
|
||||
we reach the bottom of the screen, but for now, when the end of
|
||||
the screen is reached, we wrap up to the top.
|
||||
|
||||
When reaching a new line, we clear that line and the next to
|
||||
help readability.
|
||||
|
||||
Load range: 623-628
|
||||
( VDP Driver. requires TMS9918 driver. Load range B602-B604. )
|
||||
CREATE _idat
|
||||
0b00000100 C, 0x80 C, ( Bit 2: Select mode 4 )
|
||||
0b00000000 C, 0x81 C,
|
||||
0b00001111 C, 0x82 C, ( Name table: 0x3800, *B0 must be 1* )
|
||||
0b11111111 C, 0x85 C, ( Sprite table: 0x3f00 )
|
||||
0b11111111 C, 0x86 C, ( sprite use tiles from 0x2000 )
|
||||
0b11111111 C, 0x87 C, ( Border uses palette 0xf )
|
||||
0b00000000 C, 0x88 C, ( BG X scroll )
|
||||
0b00000000 C, 0x89 C, ( BG Y scroll )
|
||||
0b11111111 C, 0x8a C, ( Line counter (why have this?) )
|
||||
|
@ -1,9 +1,14 @@
|
||||
CODE _ctl ( a -- sends LSB then MSB )
|
||||
HL POP, chkPS,
|
||||
A L LDrr, VDP_CTLPORT OUTiA,
|
||||
A H LDrr, VDP_CTLPORT OUTiA,
|
||||
;CODE
|
||||
CODE _data
|
||||
HL POP, chkPS,
|
||||
A L LDrr, VDP_DATAPORT OUTiA,
|
||||
;CODE
|
||||
: _zero ( x -- send 0 _data x times )
|
||||
( x ) 0 DO 0 _data LOOP ;
|
||||
( Each row in ~FNT is a row of the glyph and there is 7 of
|
||||
them. We insert a blank one at the end of those 7. For each
|
||||
row we set, we need to send 3 zero-bytes because each pixel in
|
||||
the tile is actually 4 bits because it can select among 16
|
||||
palettes. We use only 2 of them, which is why those bytes
|
||||
always stay zero. )
|
||||
: _sfont ( a -- Send font to VDP )
|
||||
7 0 DO C@+ _data 3 _zero LOOP DROP
|
||||
( blank row ) 4 _zero ;
|
||||
: CELL! ( tilenum pos )
|
||||
2 * 0x7800 OR _ctl ( tilenum )
|
||||
0x5e MOD _data 1 _zero ;
|
||||
|
@ -1,9 +1,11 @@
|
||||
CODE _blank ( this is way too slow in Forth )
|
||||
A XORr, VDP_CTLPORT OUTiA,
|
||||
A 0x40 LDri, VDP_CTLPORT OUTiA,
|
||||
HL 0x4000 LDdi,
|
||||
BEGIN,
|
||||
A XORr, VDP_DATAPORT OUTiA,
|
||||
HL DECd, HLZ,
|
||||
JRNZ, AGAIN,
|
||||
;CODE
|
||||
: VDP$
|
||||
9 0 DO _idat I 2 * + @ _ctl LOOP _blank
|
||||
( palettes )
|
||||
0xc000 _ctl
|
||||
( BG ) 1 _zero 0x3f _data 14 _zero
|
||||
( sprite, inverted colors ) 0x3f _data 15 _zero
|
||||
0x4000 _ctl 0x5e 0 DO ~FNT I 7 * + _sfont LOOP
|
||||
( bit 6, enable display, bit 7, ?? ) 0x81c0 _ctl ;
|
||||
|
||||
: COLS 32 ;
|
||||
: LINES 24 ;
|
||||
|
@ -1,10 +0,0 @@
|
||||
CREATE _idat
|
||||
0b00000100 C, 0x80 C, ( Bit 2: Select mode 4 )
|
||||
0b00000000 C, 0x81 C,
|
||||
0b00001111 C, 0x82 C, ( Name table: 0x3800, *B0 must be 1* )
|
||||
0b11111111 C, 0x85 C, ( Sprite table: 0x3f00 )
|
||||
0b11111111 C, 0x86 C, ( sprite use tiles from 0x2000 )
|
||||
0b11111111 C, 0x87 C, ( Border uses palette 0xf )
|
||||
0b00000000 C, 0x88 C, ( BG X scroll )
|
||||
0b00000000 C, 0x89 C, ( BG Y scroll )
|
||||
0b11111111 C, 0x8a C, ( Line counter (why have this?) )
|
@ -1,12 +0,0 @@
|
||||
: _zero ( x -- send 0 _data x times )
|
||||
( x ) 0 DO 0 _data LOOP ;
|
||||
|
||||
( Each row in ~FNT is a row of the glyph and there is 7 of
|
||||
them. We insert a blank one at the end of those 7. For each
|
||||
row we set, we need to send 3 zero-bytes because each pixel in
|
||||
the tile is actually 4 bits because it can select among 16
|
||||
palettes. We use only 2 of them, which is why those bytes
|
||||
always stay zero. )
|
||||
: _sfont ( a -- Send font to VDP )
|
||||
7 0 DO C@+ _data 3 _zero LOOP DROP
|
||||
( blank row ) 4 _zero ;
|
@ -1,3 +0,0 @@
|
||||
: CELL! ( tilenum pos )
|
||||
2 * 0x7800 OR _ctl ( tilenum )
|
||||
0x5e MOD _data 1 _zero ;
|
@ -1,11 +0,0 @@
|
||||
: VDP$
|
||||
9 0 DO _idat I 2 * + @ _ctl LOOP _blank
|
||||
( palettes )
|
||||
0xc000 _ctl
|
||||
( BG ) 1 _zero 0x3f _data 14 _zero
|
||||
( sprite, inverted colors ) 0x3f _data 15 _zero
|
||||
0x4000 _ctl 0x5e 0 DO ~FNT I 7 * + _sfont LOOP
|
||||
( bit 6, enable display, bit 7, ?? ) 0x81c0 _ctl ;
|
||||
|
||||
: COLS 32 ;
|
||||
: LINES 24 ;
|
@ -4,8 +4,8 @@
|
||||
0xddca CONSTANT PS_ADDR
|
||||
RS_ADDR 0x80 - CONSTANT SYSVARS
|
||||
0xc000 CONSTANT HERESTART
|
||||
0xbf CONSTANT VDP_CTLPORT
|
||||
0xbe CONSTANT VDP_DATAPORT
|
||||
0xbf CONSTANT TMS_CTLPORT
|
||||
0xbe CONSTANT TMS_DATAPORT
|
||||
SYSVARS 0x70 + CONSTANT GRID_MEM
|
||||
SYSVARS 0x72 + CONSTANT CPORT_MEM
|
||||
0x3f CONSTANT CPORT_CTL
|
||||
@ -27,7 +27,8 @@ CURRENT @ XCURRENT !
|
||||
283 335 LOADR ( boot.z80 )
|
||||
353 LOAD ( xcomp core low )
|
||||
CREATE ~FNT CPFNT7x7
|
||||
603 608 LOADR ( VDP )
|
||||
470 472 LOADR ( TMS9918 )
|
||||
602 604 LOADR ( VDP )
|
||||
402 404 LOADR ( Grid )
|
||||
625 626 LOADR ( SMS ports )
|
||||
612 617 LOADR ( PAD )
|
||||
|
@ -5,8 +5,8 @@
|
||||
0xddca CONSTANT PS_ADDR
|
||||
RS_ADDR 0x80 - CONSTANT SYSVARS
|
||||
0xc000 CONSTANT HERESTART
|
||||
0xbf CONSTANT VDP_CTLPORT
|
||||
0xbe CONSTANT VDP_DATAPORT
|
||||
0xbf CONSTANT TMS_CTLPORT
|
||||
0xbe CONSTANT TMS_DATAPORT
|
||||
SYSVARS 0x70 + CONSTANT GRID_MEM
|
||||
SYSVARS 0x72 + CONSTANT CPORT_MEM
|
||||
0x3f CONSTANT CPORT_CTL
|
||||
@ -28,7 +28,8 @@ CURRENT @ XCURRENT !
|
||||
283 335 LOADR ( boot.z80 )
|
||||
353 LOAD ( xcomp core low )
|
||||
CREATE ~FNT CPFNT7x7
|
||||
603 608 LOADR ( VDP )
|
||||
470 472 LOADR ( TMS9918 )
|
||||
602 604 LOADR ( VDP )
|
||||
402 404 LOADR ( Grid )
|
||||
625 626 LOADR ( SMS ports )
|
||||
620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR
|
||||
|
@ -6,8 +6,8 @@
|
||||
0xddca CONSTANT PS_ADDR
|
||||
RS_ADDR 0x80 - CONSTANT SYSVARS
|
||||
0xc000 CONSTANT HERESTART
|
||||
0xbf CONSTANT VDP_CTLPORT
|
||||
0xbe CONSTANT VDP_DATAPORT
|
||||
0xbf CONSTANT TMS_CTLPORT
|
||||
0xbe CONSTANT TMS_DATAPORT
|
||||
SYSVARS 0x70 + CONSTANT GRID_MEM
|
||||
SYSVARS 0x72 + CONSTANT CPORT_MEM
|
||||
0x3f CONSTANT CPORT_CTL
|
||||
@ -29,7 +29,8 @@ CURRENT @ XCURRENT !
|
||||
283 335 LOADR ( boot.z80 )
|
||||
353 LOAD ( xcomp core low )
|
||||
CREATE ~FNT CPFNT7x7
|
||||
603 608 LOADR ( VDP )
|
||||
470 472 LOADR ( TMS9918 )
|
||||
602 604 LOADR ( VDP )
|
||||
402 404 LOADR ( Grid )
|
||||
625 626 LOADR ( SMS ports )
|
||||
620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR
|
||||
|
42
arch/z80/sms/xcomptextmode.fs
Normal file
42
arch/z80/sms/xcomptextmode.fs
Normal file
@ -0,0 +1,42 @@
|
||||
( xcomp using the Text Mode if the VDP. Only works on actual
|
||||
SMS. The Megadrive's VDP doesn't have TMS9918 modes in it. )
|
||||
( 8K of onboard RAM )
|
||||
0xdd00 CONSTANT RS_ADDR
|
||||
( Memory register at the end of RAM. Must not overwrite )
|
||||
0xddca CONSTANT PS_ADDR
|
||||
RS_ADDR 0x80 - CONSTANT SYSVARS
|
||||
0xc000 CONSTANT HERESTART
|
||||
0xbf CONSTANT TMS_CTLPORT
|
||||
0xbe CONSTANT TMS_DATAPORT
|
||||
SYSVARS 0x70 + CONSTANT GRID_MEM
|
||||
SYSVARS 0x72 + CONSTANT CPORT_MEM
|
||||
0x3f CONSTANT CPORT_CTL
|
||||
0xdc CONSTANT CPORT_D1
|
||||
0xdd CONSTANT CPORT_D2
|
||||
SYSVARS 0x73 + CONSTANT PS2_MEM
|
||||
5 LOAD ( z80 assembler )
|
||||
: ZFILL, ( u ) 0 DO 0 A, LOOP ;
|
||||
262 LOAD ( xcomp )
|
||||
523 LOAD ( font compiler )
|
||||
282 LOAD ( boot.z80.decl )
|
||||
270 LOAD ( xcomp overrides )
|
||||
|
||||
DI, 0x100 JP, 0x62 ZFILL, ( 0x66 )
|
||||
RETN, 0x98 ZFILL, ( 0x100 )
|
||||
( All set, carry on! )
|
||||
CURRENT @ XCURRENT !
|
||||
0x100 BIN( !
|
||||
283 335 LOADR ( boot.z80 )
|
||||
353 LOAD ( xcomp core low )
|
||||
CREATE ~FNT CPFNT5x7
|
||||
470 472 LOADR ( VDP )
|
||||
402 404 LOADR ( Grid )
|
||||
625 626 LOADR ( SMS ports )
|
||||
620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR
|
||||
390 LOAD ( xcomp core high )
|
||||
(entry) _
|
||||
( Update LATEST )
|
||||
PC ORG @ 8 + !
|
||||
," TMS$ 0 0 AT-XY PS2$ (im1) " EOT,
|
||||
ORG @ 0x100 - 256 /MOD 2 PC! 2 PC!
|
||||
H@ 256 /MOD 2 PC! 2 PC!
|
3
blk/001
3
blk/001
@ -9,4 +9,5 @@ MASTER INDEX
|
||||
400 AT28 EEPROM driver 401 Grid subsystem
|
||||
410 PS/2 keyboard subsystem 418 Z80 SPI Relay driver
|
||||
420 SD Card subsystem 440 8086 boot code
|
||||
470-519 unused 520 Fonts
|
||||
470 Z80 TMS9918 driver
|
||||
480-519 unused 520 Fonts
|
||||
|
12
blk/470
Normal file
12
blk/470
Normal file
@ -0,0 +1,12 @@
|
||||
( Z80 driver for TMS9918. Implements grid protocol. Requires
|
||||
TMS_CTLPORT, TMS_DATAPORT and ~FNT from the Font compiler at
|
||||
B520. Load range B470-472 )
|
||||
CODE _ctl ( a -- sends LSB then MSB )
|
||||
HL POP, chkPS,
|
||||
A L LDrr, TMS_CTLPORT OUTiA,
|
||||
A H LDrr, TMS_CTLPORT OUTiA,
|
||||
;CODE
|
||||
CODE _data
|
||||
HL POP, chkPS,
|
||||
A L LDrr, TMS_DATAPORT OUTiA,
|
||||
;CODE
|
9
blk/471
Normal file
9
blk/471
Normal file
@ -0,0 +1,9 @@
|
||||
CODE _blank ( this is way too slow in Forth )
|
||||
A XORr, TMS_CTLPORT OUTiA,
|
||||
A 0x40 LDri, TMS_CTLPORT OUTiA,
|
||||
HL 0x4000 LDdi,
|
||||
BEGIN,
|
||||
A XORr, TMS_DATAPORT OUTiA,
|
||||
HL DECd, HLZ,
|
||||
JRNZ, AGAIN,
|
||||
;CODE
|
16
blk/472
Normal file
16
blk/472
Normal file
@ -0,0 +1,16 @@
|
||||
( Each row in ~FNT is a row of the glyph and there is 7 of
|
||||
them. We insert a blank one at the end of those 7. )
|
||||
: _sfont ( a -- Send font to TMS )
|
||||
7 0 DO C@+ _data LOOP DROP
|
||||
( blank row ) 0 _data ;
|
||||
: CELL! ( tilenum pos )
|
||||
0x7800 OR _ctl ( tilenum )
|
||||
0x5e MOD _data ;
|
||||
: COLS 40 ; : LINES 24 ;
|
||||
: TMS$
|
||||
0x8100 _ctl ( blank screen ) _blank
|
||||
0x4000 _ctl 0x5e 0 DO ~FNT I 7 * + _sfont LOOP
|
||||
0x820e _ctl ( name table 0x3800 )
|
||||
0x8400 _ctl ( patter table 0x0000 )
|
||||
0x87f0 _ctl ( colors 0 and 1 )
|
||||
0x8000 _ctl 0x81d0 _ctl ( text mode, display on ) ;
|
4
blk/523
4
blk/523
@ -9,7 +9,7 @@
|
||||
DUP I 5 * + _g
|
||||
LOOP ;
|
||||
: CPFNT5x7
|
||||
0 , 0 , 0 C, ( space char )
|
||||
534 532 DO I BLK@ BLK( 12 _l 448 + 12 _l DROP LOOP ( 72 )
|
||||
0 , 0 , 0 , 0 C, ( space char )
|
||||
535 532 DO I BLK@ BLK( 12 _l 448 + 12 _l DROP LOOP ( 72 )
|
||||
535 BLK@ BLK( 12 _l 448 + 10 _l DROP ( 94! )
|
||||
;
|
||||
|
@ -34,7 +34,7 @@ static xcb_gcontext_t fg;
|
||||
static xcb_drawable_t win;
|
||||
|
||||
// pixels to draw. We draw them in one shot.
|
||||
static xcb_rectangle_t rectangles[VDP_SCREENW*VDP_SCREENH];
|
||||
static xcb_rectangle_t rectangles[(32*8)*(24*8)];
|
||||
|
||||
static Machine *m;
|
||||
static VDP vdp;
|
||||
@ -144,19 +144,19 @@ void draw_pixels()
|
||||
xcb_clear_area(
|
||||
conn, 0, win, 0, 0, geom->width, geom->height);
|
||||
// Figure out inner size to maximize our screen's aspect ratio
|
||||
int psize = geom->height / VDP_SCREENH;
|
||||
if (geom->width / VDP_SCREENW < psize) {
|
||||
int psize = geom->height / vdp.tms.height;
|
||||
if (geom->width / vdp.tms.width < psize) {
|
||||
// width is the constraint
|
||||
psize = geom->width / VDP_SCREENW;
|
||||
psize = geom->width / vdp.tms.width;
|
||||
}
|
||||
int innerw = psize * VDP_SCREENW;
|
||||
int innerh = psize * VDP_SCREENH;
|
||||
int innerw = psize * vdp.tms.width;
|
||||
int innerh = psize * vdp.tms.height;
|
||||
int innerx = (geom->width - innerw) / 2;
|
||||
int innery = (geom->height - innerh) / 2;
|
||||
free(geom);
|
||||
int drawcnt = 0;
|
||||
for (int i=0; i<VDP_SCREENW; i++) {
|
||||
for (int j=0; j<VDP_SCREENH; j++) {
|
||||
for (int i=0; i<vdp.tms.width; i++) {
|
||||
for (int j=0; j<vdp.tms.height; j++) {
|
||||
if (vdp_pixel(&vdp, i, j)) {
|
||||
int x = innerx + (i*psize);
|
||||
int y = innery + (j*psize);
|
||||
|
@ -1,6 +1,11 @@
|
||||
#include <string.h>
|
||||
#include "sms_vdp.h"
|
||||
|
||||
static bool _is_mode4(VDP *vdp)
|
||||
{
|
||||
return (vdp->tms.regs[0]&0x4);
|
||||
}
|
||||
|
||||
void vdp_init(VDP *vdp)
|
||||
{
|
||||
tms_init(&vdp->tms);
|
||||
@ -18,6 +23,7 @@ void vdp_cmd_wr(VDP *vdp, uint8_t val)
|
||||
vdp->tms.curaddr = TMS_VRAM_SIZE + (vdp->tms.cmdlsb&0x1f);
|
||||
} else {
|
||||
tms_cmd_wr(&vdp->tms, val);
|
||||
vdp->tms.width = _is_mode4(vdp) ? 32*8 : 40*6;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,13 +52,16 @@ void vdp_data_wr(VDP *vdp, uint8_t val)
|
||||
|
||||
uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y)
|
||||
{
|
||||
if (x >= VDP_SCREENW) {
|
||||
return 0;
|
||||
}
|
||||
if (y >= VDP_SCREENH) {
|
||||
return 0;
|
||||
}
|
||||
TMS9918 *tms = &vdp->tms;
|
||||
if (!_is_mode4(vdp)) {
|
||||
return tms_pixel(tms, x, y);
|
||||
}
|
||||
if (x >= tms->width) {
|
||||
return 0;
|
||||
}
|
||||
if (y >= tms->height) {
|
||||
return 0;
|
||||
}
|
||||
// name table offset
|
||||
uint16_t offset = (tms->regs[2] & 0xe) << 10;
|
||||
offset += ((y/8) << 6) + ((x/8) << 1);
|
||||
|
@ -1,8 +1,6 @@
|
||||
#include "tms9918.h"
|
||||
|
||||
#define VDP_CRAM_SIZE 0x20
|
||||
#define VDP_SCREENW (32*8)
|
||||
#define VDP_SCREENH (24*8)
|
||||
|
||||
typedef struct {
|
||||
TMS9918 tms;
|
||||
|
@ -1,12 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "tms9918.h"
|
||||
|
||||
static uint8_t COLORS[0x10] = { // TODO: put actual color codes
|
||||
0, // transparent
|
||||
0, // black
|
||||
1, // medium green
|
||||
1, // light green
|
||||
1, // dark blue
|
||||
1, // light blue
|
||||
1, // dark red
|
||||
1, // cyan
|
||||
1, // medium red
|
||||
1, // light red
|
||||
1, // dark yellow
|
||||
1, // light yellow
|
||||
1, // dark green
|
||||
1, // magenta
|
||||
1, // gray
|
||||
1, // white
|
||||
};
|
||||
|
||||
void tms_init(TMS9918 *tms)
|
||||
{
|
||||
memset(tms->vram, 0, TMS_VRAM_SIZE);
|
||||
memset(tms->regs, 0, 0x10);
|
||||
tms->has_cmdlsb = false;
|
||||
tms->curaddr = 0;
|
||||
tms->width = 40*6;
|
||||
tms->height = 24*8;
|
||||
}
|
||||
|
||||
uint8_t tms_cmd_rd(TMS9918 *tms)
|
||||
@ -50,5 +72,19 @@ void tms_data_wr(TMS9918 *tms, uint8_t val)
|
||||
// Returns a 8-bit RGB value (0b00bbggrr)
|
||||
uint8_t tms_pixel(TMS9918 *tms, uint16_t x, uint16_t y)
|
||||
{
|
||||
return 0; // no TMS9918 mode implemented yet
|
||||
if ((tms->regs[1]&0x18) == 0x10 && (tms->regs[0]&0x40) == 0) {
|
||||
// Text mode
|
||||
uint16_t nameoff = (tms->regs[2] & 0xf) << 10;
|
||||
uint16_t patternoff = (tms->regs[4] & 0x7) << 11;
|
||||
uint8_t nameid = tms->vram[nameoff+(((y/8) * 40) + (x/6))];
|
||||
uint8_t patternline = tms->vram[patternoff+(nameid*8)+(y%8)];
|
||||
uint8_t color = tms->regs[7];
|
||||
if ((patternline>>(8-(x%6)))&1) {
|
||||
color >>= 4;
|
||||
}
|
||||
color &= 0xf;
|
||||
return color;
|
||||
} else { // unsupported mode
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ typedef struct {
|
||||
uint8_t cmdlsb;
|
||||
bool has_cmdlsb;
|
||||
uint16_t curaddr;
|
||||
uint16_t width; // in pixels
|
||||
uint16_t height; // in pixels
|
||||
} TMS9918;
|
||||
|
||||
void tms_init(TMS9918 *tms);
|
||||
|
Loading…
Reference in New Issue
Block a user