mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 12:58:09 +11:00
emul/z80: extract tms9918 unit from sms_vdp
I'm planning on supporting Text Mode soon, and SMS' VDP, when mode 4 is not active, behaves mostly like a regular TMS9918. By having this behavior in a separate unit, we'll be able to use it in other systems.
This commit is contained in:
parent
c7d8de25b2
commit
09c01c4a43
@ -1,7 +1,8 @@
|
|||||||
TARGETS = forth rc2014 sms ti84
|
TARGETS = forth rc2014 sms ti84
|
||||||
OBJS = emul.o z80.o
|
OBJS = emul.o z80.o
|
||||||
RC2014_OBJS = $(OBJS) sio.o acia.o sdc.o rc2014_spi.o
|
RC2014_OBJS = $(OBJS) sio.o acia.o sdc.o rc2014_spi.o
|
||||||
SMS_OBJS = $(OBJS) sms_vdp.o sms_ports.o sms_pad.o ps2_kbd.o sdc.o sms_spi.o
|
SMS_OBJS = $(OBJS) tms9918.o sms_vdp.o sms_ports.o sms_pad.o ps2_kbd.o sdc.o \
|
||||||
|
sms_spi.o
|
||||||
TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o
|
TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o
|
||||||
CDIR = ../../cvm
|
CDIR = ../../cvm
|
||||||
STAGE = $(CDIR)/stage
|
STAGE = $(CDIR)/stage
|
||||||
|
@ -48,7 +48,7 @@ static SPI spi;
|
|||||||
|
|
||||||
static uint8_t iord_vdp_cmd()
|
static uint8_t iord_vdp_cmd()
|
||||||
{
|
{
|
||||||
return vdp_cmd_rd(&vdp);
|
return tms_cmd_rd(&vdp.tms);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t iord_vdp_data()
|
static uint8_t iord_vdp_data()
|
||||||
|
@ -3,55 +3,47 @@
|
|||||||
|
|
||||||
void vdp_init(VDP *vdp)
|
void vdp_init(VDP *vdp)
|
||||||
{
|
{
|
||||||
memset(vdp->vram, 0, VDP_VRAM_SIZE);
|
tms_init(&vdp->tms);
|
||||||
memset(vdp->regs, 0, 0x10);
|
memset(vdp->cram, 0, VDP_CRAM_SIZE);
|
||||||
vdp->has_cmdlsb = false;
|
|
||||||
vdp->curaddr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t vdp_cmd_rd(VDP *vdp)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vdp_cmd_wr(VDP *vdp, uint8_t val)
|
void vdp_cmd_wr(VDP *vdp, uint8_t val)
|
||||||
{
|
{
|
||||||
if (!vdp->has_cmdlsb) {
|
if (!vdp->tms.has_cmdlsb) {
|
||||||
vdp->cmdlsb = val;
|
tms_cmd_wr(&vdp->tms, val);
|
||||||
vdp->has_cmdlsb = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vdp->has_cmdlsb = false;
|
|
||||||
if ((val & 0xc0) == 0x80) {
|
|
||||||
// set register
|
|
||||||
vdp->regs[val&0xf] = vdp->cmdlsb;
|
|
||||||
} else if ((val & 0xc0) == 0xc0) {
|
|
||||||
// palette RAM
|
|
||||||
vdp->curaddr = 0x4000 + (vdp->cmdlsb&0x1f);
|
|
||||||
} else {
|
} else {
|
||||||
// VRAM
|
if ((val & 0xc0) == 0xc0) {
|
||||||
vdp->curaddr = ((val&0x3f) << 8) + vdp->cmdlsb;
|
// palette RAM
|
||||||
|
// curaddr > VRAM == addr in CRAM
|
||||||
|
vdp->tms.curaddr = TMS_VRAM_SIZE + (vdp->tms.cmdlsb&0x1f);
|
||||||
|
} else {
|
||||||
|
tms_cmd_wr(&vdp->tms, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t vdp_data_rd(VDP *vdp)
|
uint8_t vdp_data_rd(VDP *vdp)
|
||||||
{
|
{
|
||||||
uint8_t res = vdp->vram[vdp->curaddr];
|
TMS9918 *tms = &vdp->tms;
|
||||||
if (vdp->curaddr < VDP_VRAM_SIZE) {
|
if (tms->curaddr < TMS_VRAM_SIZE) {
|
||||||
vdp->curaddr++;
|
return tms_data_rd(&vdp->tms);
|
||||||
|
} else if (tms->curaddr - TMS_VRAM_SIZE < VDP_CRAM_SIZE) {
|
||||||
|
return vdp->cram[tms->curaddr++-TMS_VRAM_SIZE];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vdp_data_wr(VDP *vdp, uint8_t val)
|
void vdp_data_wr(VDP *vdp, uint8_t val)
|
||||||
{
|
{
|
||||||
vdp->vram[vdp->curaddr] = val;
|
TMS9918 *tms = &vdp->tms;
|
||||||
if (vdp->curaddr < VDP_VRAM_SIZE) {
|
if (tms->curaddr < TMS_VRAM_SIZE) {
|
||||||
vdp->curaddr++;
|
tms_data_wr(&vdp->tms, val);
|
||||||
|
} else if (tms->curaddr - TMS_VRAM_SIZE < VDP_CRAM_SIZE) {
|
||||||
|
vdp->cram[tms->curaddr++-TMS_VRAM_SIZE] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a 8-bit RGB value (0b00bbggrr)
|
|
||||||
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) {
|
if (x >= VDP_SCREENW) {
|
||||||
@ -60,10 +52,11 @@ uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y)
|
|||||||
if (y >= VDP_SCREENH) {
|
if (y >= VDP_SCREENH) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
TMS9918 *tms = &vdp->tms;
|
||||||
// name table offset
|
// name table offset
|
||||||
uint16_t offset = (vdp->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);
|
||||||
uint16_t tableval = vdp->vram[offset] + (vdp->vram[offset+1] << 8);
|
uint16_t tableval = tms->vram[offset] + (tms->vram[offset+1] << 8);
|
||||||
uint16_t tilenum = tableval & 0x1ff;
|
uint16_t tilenum = tableval & 0x1ff;
|
||||||
// is palette select bit on? if yes, use sprite palette instead
|
// is palette select bit on? if yes, use sprite palette instead
|
||||||
uint8_t palettemod = tableval & 0x800 ? 0x10 : 0;
|
uint8_t palettemod = tableval & 0x800 ? 0x10 : 0;
|
||||||
@ -74,10 +67,10 @@ uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y)
|
|||||||
uint8_t bitnum = 7 - (x%8);
|
uint8_t bitnum = 7 - (x%8);
|
||||||
// Now, let's compose the result by pushing the right bit of our 4 bytes
|
// Now, let's compose the result by pushing the right bit of our 4 bytes
|
||||||
// into our result.
|
// into our result.
|
||||||
uint8_t palette_id = ((vdp->vram[offset] >> bitnum) & 1) + \
|
uint8_t palette_id = ((tms->vram[offset] >> bitnum) & 1) + \
|
||||||
(((vdp->vram[offset+1] >> bitnum) & 1) << 1) + \
|
(((tms->vram[offset+1] >> bitnum) & 1) << 1) + \
|
||||||
(((vdp->vram[offset+2] >> bitnum) & 1) << 2) + \
|
(((tms->vram[offset+2] >> bitnum) & 1) << 2) + \
|
||||||
(((vdp->vram[offset+3] >> bitnum) & 1) << 3);
|
(((tms->vram[offset+3] >> bitnum) & 1) << 3);
|
||||||
uint8_t rgb = vdp->vram[0x4000+palettemod+palette_id];
|
uint8_t rgb = vdp->cram[palettemod+palette_id];
|
||||||
return rgb;
|
return rgb;
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,16 @@
|
|||||||
#include <stdint.h>
|
#include "tms9918.h"
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#define VDP_VRAM_SIZE 0x4020
|
#define VDP_CRAM_SIZE 0x20
|
||||||
#define VDP_SCREENW (32*8)
|
#define VDP_SCREENW (32*8)
|
||||||
#define VDP_SCREENH (24*8)
|
#define VDP_SCREENH (24*8)
|
||||||
// Offset of the name table
|
|
||||||
#define VDP_NTABLE_OFFSET 0x3800
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// the last 0x20 is palette RAM
|
TMS9918 tms;
|
||||||
uint8_t vram[VDP_VRAM_SIZE];
|
uint8_t cram[VDP_CRAM_SIZE];
|
||||||
uint8_t regs[0x10];
|
|
||||||
uint8_t cmdlsb;
|
|
||||||
bool has_cmdlsb;
|
|
||||||
uint16_t curaddr;
|
|
||||||
} VDP;
|
} VDP;
|
||||||
|
|
||||||
void vdp_init(VDP *vdp);
|
void vdp_init(VDP *vdp);
|
||||||
uint8_t vdp_cmd_rd(VDP *vdp);
|
|
||||||
void vdp_cmd_wr(VDP *vdp, uint8_t val);
|
void vdp_cmd_wr(VDP *vdp, uint8_t val);
|
||||||
uint8_t vdp_data_rd(VDP *vdp);
|
uint8_t vdp_data_rd(VDP *vdp);
|
||||||
void vdp_data_wr(VDP *vdp, uint8_t val);
|
void vdp_data_wr(VDP *vdp, uint8_t val);
|
||||||
// result is a RGB value
|
|
||||||
uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y);
|
uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y);
|
||||||
|
54
emul/z80/tms9918.c
Normal file
54
emul/z80/tms9918.c
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include "tms9918.h"
|
||||||
|
|
||||||
|
void tms_init(TMS9918 *tms)
|
||||||
|
{
|
||||||
|
memset(tms->vram, 0, TMS_VRAM_SIZE);
|
||||||
|
memset(tms->regs, 0, 0x10);
|
||||||
|
tms->has_cmdlsb = false;
|
||||||
|
tms->curaddr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tms_cmd_rd(TMS9918 *tms)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tms_cmd_wr(TMS9918 *tms, uint8_t val)
|
||||||
|
{
|
||||||
|
if (!tms->has_cmdlsb) {
|
||||||
|
tms->cmdlsb = val;
|
||||||
|
tms->has_cmdlsb = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tms->has_cmdlsb = false;
|
||||||
|
if ((val & 0xc0) == 0x80) {
|
||||||
|
// set register
|
||||||
|
tms->regs[val&0xf] = tms->cmdlsb;
|
||||||
|
} else {
|
||||||
|
// VRAM
|
||||||
|
tms->curaddr = ((val&0x3f) << 8) + tms->cmdlsb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tms_data_rd(TMS9918 *tms)
|
||||||
|
{
|
||||||
|
if (tms->curaddr < TMS_VRAM_SIZE) {
|
||||||
|
return tms->vram[tms->curaddr++];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tms_data_wr(TMS9918 *tms, uint8_t val)
|
||||||
|
{
|
||||||
|
if (tms->curaddr < TMS_VRAM_SIZE) {
|
||||||
|
tms->vram[tms->curaddr++] = 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
|
||||||
|
}
|
24
emul/z80/tms9918.h
Normal file
24
emul/z80/tms9918.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define TMS_VRAM_SIZE 0x4000
|
||||||
|
// Offset of the name table
|
||||||
|
#define TMS_NTABLE_OFFSET 0x3800
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t vram[TMS_VRAM_SIZE];
|
||||||
|
uint8_t regs[0x10];
|
||||||
|
uint8_t cmdlsb;
|
||||||
|
bool has_cmdlsb;
|
||||||
|
uint16_t curaddr;
|
||||||
|
} TMS9918;
|
||||||
|
|
||||||
|
void tms_init(TMS9918 *tms);
|
||||||
|
uint8_t tms_cmd_rd(TMS9918 *tms);
|
||||||
|
void tms_cmd_wr(TMS9918 *tms, uint8_t val);
|
||||||
|
uint8_t tms_data_rd(TMS9918 *tms);
|
||||||
|
void tms_data_wr(TMS9918 *tms, uint8_t val);
|
||||||
|
// result is a RGB value
|
||||||
|
uint8_t tms_pixel(TMS9918 *tms, uint16_t x, uint16_t y);
|
Loading…
Reference in New Issue
Block a user