1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-27 09:38:06 +11:00

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:
Virgil Dupras 2020-11-13 12:15:20 -05:00
parent 09c01c4a43
commit d1718a90c7
21 changed files with 193 additions and 99 deletions

View File

@ -1,16 +1,11 @@
VDP Driver ( VDP Driver. requires TMS9918 driver. Load range B602-B604. )
CREATE _idat
Implement (emit) on the console. Characters start at the top 0b00000100 C, 0x80 C, ( Bit 2: Select mode 4 )
left. Every (emit) call converts the ASCII char received to its 0b00000000 C, 0x81 C,
internal font, then put that char on screen, advancing the 0b00001111 C, 0x82 C, ( Name table: 0x3800, *B0 must be 1* )
cursor by one. When reaching the end of the line (33rd char), 0b11111111 C, 0x85 C, ( Sprite table: 0x3f00 )
wrap to the next. 0b11111111 C, 0x86 C, ( sprite use tiles from 0x2000 )
0b11111111 C, 0x87 C, ( Border uses palette 0xf )
In the future, there's going to be a scrolling mechanism when 0b00000000 C, 0x88 C, ( BG X scroll )
we reach the bottom of the screen, but for now, when the end of 0b00000000 C, 0x89 C, ( BG Y scroll )
the screen is reached, we wrap up to the top. 0b11111111 C, 0x8a C, ( Line counter (why have this?) )
When reaching a new line, we clear that line and the next to
help readability.
Load range: 623-628

View File

@ -1,9 +1,14 @@
CODE _ctl ( a -- sends LSB then MSB ) : _zero ( x -- send 0 _data x times )
HL POP, chkPS, ( x ) 0 DO 0 _data LOOP ;
A L LDrr, VDP_CTLPORT OUTiA, ( Each row in ~FNT is a row of the glyph and there is 7 of
A H LDrr, VDP_CTLPORT OUTiA, them. We insert a blank one at the end of those 7. For each
;CODE row we set, we need to send 3 zero-bytes because each pixel in
CODE _data the tile is actually 4 bits because it can select among 16
HL POP, chkPS, palettes. We use only 2 of them, which is why those bytes
A L LDrr, VDP_DATAPORT OUTiA, always stay zero. )
;CODE : _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 ;

View File

@ -1,9 +1,11 @@
CODE _blank ( this is way too slow in Forth ) : VDP$
A XORr, VDP_CTLPORT OUTiA, 9 0 DO _idat I 2 * + @ _ctl LOOP _blank
A 0x40 LDri, VDP_CTLPORT OUTiA, ( palettes )
HL 0x4000 LDdi, 0xc000 _ctl
BEGIN, ( BG ) 1 _zero 0x3f _data 14 _zero
A XORr, VDP_DATAPORT OUTiA, ( sprite, inverted colors ) 0x3f _data 15 _zero
HL DECd, HLZ, 0x4000 _ctl 0x5e 0 DO ~FNT I 7 * + _sfont LOOP
JRNZ, AGAIN, ( bit 6, enable display, bit 7, ?? ) 0x81c0 _ctl ;
;CODE
: COLS 32 ;
: LINES 24 ;

View File

@ -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?) )

View File

@ -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 ;

View File

@ -1,3 +0,0 @@
: CELL! ( tilenum pos )
2 * 0x7800 OR _ctl ( tilenum )
0x5e MOD _data 1 _zero ;

View File

@ -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 ;

View File

@ -4,8 +4,8 @@
0xddca CONSTANT PS_ADDR 0xddca CONSTANT PS_ADDR
RS_ADDR 0x80 - CONSTANT SYSVARS RS_ADDR 0x80 - CONSTANT SYSVARS
0xc000 CONSTANT HERESTART 0xc000 CONSTANT HERESTART
0xbf CONSTANT VDP_CTLPORT 0xbf CONSTANT TMS_CTLPORT
0xbe CONSTANT VDP_DATAPORT 0xbe CONSTANT TMS_DATAPORT
SYSVARS 0x70 + CONSTANT GRID_MEM SYSVARS 0x70 + CONSTANT GRID_MEM
SYSVARS 0x72 + CONSTANT CPORT_MEM SYSVARS 0x72 + CONSTANT CPORT_MEM
0x3f CONSTANT CPORT_CTL 0x3f CONSTANT CPORT_CTL
@ -27,7 +27,8 @@ CURRENT @ XCURRENT !
283 335 LOADR ( boot.z80 ) 283 335 LOADR ( boot.z80 )
353 LOAD ( xcomp core low ) 353 LOAD ( xcomp core low )
CREATE ~FNT CPFNT7x7 CREATE ~FNT CPFNT7x7
603 608 LOADR ( VDP ) 470 472 LOADR ( TMS9918 )
602 604 LOADR ( VDP )
402 404 LOADR ( Grid ) 402 404 LOADR ( Grid )
625 626 LOADR ( SMS ports ) 625 626 LOADR ( SMS ports )
612 617 LOADR ( PAD ) 612 617 LOADR ( PAD )

View File

@ -5,8 +5,8 @@
0xddca CONSTANT PS_ADDR 0xddca CONSTANT PS_ADDR
RS_ADDR 0x80 - CONSTANT SYSVARS RS_ADDR 0x80 - CONSTANT SYSVARS
0xc000 CONSTANT HERESTART 0xc000 CONSTANT HERESTART
0xbf CONSTANT VDP_CTLPORT 0xbf CONSTANT TMS_CTLPORT
0xbe CONSTANT VDP_DATAPORT 0xbe CONSTANT TMS_DATAPORT
SYSVARS 0x70 + CONSTANT GRID_MEM SYSVARS 0x70 + CONSTANT GRID_MEM
SYSVARS 0x72 + CONSTANT CPORT_MEM SYSVARS 0x72 + CONSTANT CPORT_MEM
0x3f CONSTANT CPORT_CTL 0x3f CONSTANT CPORT_CTL
@ -28,7 +28,8 @@ CURRENT @ XCURRENT !
283 335 LOADR ( boot.z80 ) 283 335 LOADR ( boot.z80 )
353 LOAD ( xcomp core low ) 353 LOAD ( xcomp core low )
CREATE ~FNT CPFNT7x7 CREATE ~FNT CPFNT7x7
603 608 LOADR ( VDP ) 470 472 LOADR ( TMS9918 )
602 604 LOADR ( VDP )
402 404 LOADR ( Grid ) 402 404 LOADR ( Grid )
625 626 LOADR ( SMS ports ) 625 626 LOADR ( SMS ports )
620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR 620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR

View File

@ -6,8 +6,8 @@
0xddca CONSTANT PS_ADDR 0xddca CONSTANT PS_ADDR
RS_ADDR 0x80 - CONSTANT SYSVARS RS_ADDR 0x80 - CONSTANT SYSVARS
0xc000 CONSTANT HERESTART 0xc000 CONSTANT HERESTART
0xbf CONSTANT VDP_CTLPORT 0xbf CONSTANT TMS_CTLPORT
0xbe CONSTANT VDP_DATAPORT 0xbe CONSTANT TMS_DATAPORT
SYSVARS 0x70 + CONSTANT GRID_MEM SYSVARS 0x70 + CONSTANT GRID_MEM
SYSVARS 0x72 + CONSTANT CPORT_MEM SYSVARS 0x72 + CONSTANT CPORT_MEM
0x3f CONSTANT CPORT_CTL 0x3f CONSTANT CPORT_CTL
@ -29,7 +29,8 @@ CURRENT @ XCURRENT !
283 335 LOADR ( boot.z80 ) 283 335 LOADR ( boot.z80 )
353 LOAD ( xcomp core low ) 353 LOAD ( xcomp core low )
CREATE ~FNT CPFNT7x7 CREATE ~FNT CPFNT7x7
603 608 LOADR ( VDP ) 470 472 LOADR ( TMS9918 )
602 604 LOADR ( VDP )
402 404 LOADR ( Grid ) 402 404 LOADR ( Grid )
625 626 LOADR ( SMS ports ) 625 626 LOADR ( SMS ports )
620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR 620 LOAD ( PAD ) : (ps2kc) (ps2kcA) ; 411 414 LOADR

View 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!

View File

@ -9,4 +9,5 @@ MASTER INDEX
400 AT28 EEPROM driver 401 Grid subsystem 400 AT28 EEPROM driver 401 Grid subsystem
410 PS/2 keyboard subsystem 418 Z80 SPI Relay driver 410 PS/2 keyboard subsystem 418 Z80 SPI Relay driver
420 SD Card subsystem 440 8086 boot code 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
View 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
View 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
View 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 ) ;

View File

@ -9,7 +9,7 @@
DUP I 5 * + _g DUP I 5 * + _g
LOOP ; LOOP ;
: CPFNT5x7 : CPFNT5x7
0 , 0 , 0 C, ( space char ) 0 , 0 , 0 , 0 C, ( space char )
534 532 DO I BLK@ BLK( 12 _l 448 + 12 _l DROP LOOP ( 72 ) 535 532 DO I BLK@ BLK( 12 _l 448 + 12 _l DROP LOOP ( 72 )
535 BLK@ BLK( 12 _l 448 + 10 _l DROP ( 94! ) 535 BLK@ BLK( 12 _l 448 + 10 _l DROP ( 94! )
; ;

View File

@ -34,7 +34,7 @@ static xcb_gcontext_t fg;
static xcb_drawable_t win; static xcb_drawable_t win;
// pixels to draw. We draw them in one shot. // 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 Machine *m;
static VDP vdp; static VDP vdp;
@ -144,19 +144,19 @@ void draw_pixels()
xcb_clear_area( xcb_clear_area(
conn, 0, win, 0, 0, geom->width, geom->height); conn, 0, win, 0, 0, geom->width, geom->height);
// Figure out inner size to maximize our screen's aspect ratio // Figure out inner size to maximize our screen's aspect ratio
int psize = geom->height / VDP_SCREENH; int psize = geom->height / vdp.tms.height;
if (geom->width / VDP_SCREENW < psize) { if (geom->width / vdp.tms.width < psize) {
// width is the constraint // width is the constraint
psize = geom->width / VDP_SCREENW; psize = geom->width / vdp.tms.width;
} }
int innerw = psize * VDP_SCREENW; int innerw = psize * vdp.tms.width;
int innerh = psize * VDP_SCREENH; int innerh = psize * vdp.tms.height;
int innerx = (geom->width - innerw) / 2; int innerx = (geom->width - innerw) / 2;
int innery = (geom->height - innerh) / 2; int innery = (geom->height - innerh) / 2;
free(geom); free(geom);
int drawcnt = 0; int drawcnt = 0;
for (int i=0; i<VDP_SCREENW; i++) { for (int i=0; i<vdp.tms.width; i++) {
for (int j=0; j<VDP_SCREENH; j++) { for (int j=0; j<vdp.tms.height; j++) {
if (vdp_pixel(&vdp, i, j)) { if (vdp_pixel(&vdp, i, j)) {
int x = innerx + (i*psize); int x = innerx + (i*psize);
int y = innery + (j*psize); int y = innery + (j*psize);

View File

@ -1,6 +1,11 @@
#include <string.h> #include <string.h>
#include "sms_vdp.h" #include "sms_vdp.h"
static bool _is_mode4(VDP *vdp)
{
return (vdp->tms.regs[0]&0x4);
}
void vdp_init(VDP *vdp) void vdp_init(VDP *vdp)
{ {
tms_init(&vdp->tms); 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); vdp->tms.curaddr = TMS_VRAM_SIZE + (vdp->tms.cmdlsb&0x1f);
} else { } else {
tms_cmd_wr(&vdp->tms, val); 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) 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; 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 // name table offset
uint16_t offset = (tms->regs[2] & 0xe) << 10; uint16_t offset = (tms->regs[2] & 0xe) << 10;
offset += ((y/8) << 6) + ((x/8) << 1); offset += ((y/8) << 6) + ((x/8) << 1);

View File

@ -1,8 +1,6 @@
#include "tms9918.h" #include "tms9918.h"
#define VDP_CRAM_SIZE 0x20 #define VDP_CRAM_SIZE 0x20
#define VDP_SCREENW (32*8)
#define VDP_SCREENH (24*8)
typedef struct { typedef struct {
TMS9918 tms; TMS9918 tms;

View File

@ -1,12 +1,34 @@
#include <stdio.h>
#include <string.h> #include <string.h>
#include "tms9918.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) void tms_init(TMS9918 *tms)
{ {
memset(tms->vram, 0, TMS_VRAM_SIZE); memset(tms->vram, 0, TMS_VRAM_SIZE);
memset(tms->regs, 0, 0x10); memset(tms->regs, 0, 0x10);
tms->has_cmdlsb = false; tms->has_cmdlsb = false;
tms->curaddr = 0; tms->curaddr = 0;
tms->width = 40*6;
tms->height = 24*8;
} }
uint8_t tms_cmd_rd(TMS9918 *tms) 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) // Returns a 8-bit RGB value (0b00bbggrr)
uint8_t tms_pixel(TMS9918 *tms, uint16_t x, uint16_t y) 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;
}
} }

View File

@ -13,6 +13,8 @@ typedef struct {
uint8_t cmdlsb; uint8_t cmdlsb;
bool has_cmdlsb; bool has_cmdlsb;
uint16_t curaddr; uint16_t curaddr;
uint16_t width; // in pixels
uint16_t height; // in pixels
} TMS9918; } TMS9918;
void tms_init(TMS9918 *tms); void tms_init(TMS9918 *tms);