From 09c01c4a43281f094629465cbaf2c2e2400cc09e Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Thu, 12 Nov 2020 11:13:18 -0500 Subject: [PATCH] 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. --- emul/z80/Makefile | 3 ++- emul/z80/sms.c | 2 +- emul/z80/sms_vdp.c | 69 ++++++++++++++++++++++++------------------------------ emul/z80/sms_vdp.h | 18 ++++---------- emul/z80/tms9918.c | 54 ++++++++++++++++++++++++++++++++++++++++++ emul/z80/tms9918.h | 24 +++++++++++++++++++ 6 files changed, 116 insertions(+), 54 deletions(-) create mode 100644 emul/z80/tms9918.c create mode 100644 emul/z80/tms9918.h diff --git a/emul/z80/Makefile b/emul/z80/Makefile index 99e2b03..0e573f3 100644 --- a/emul/z80/Makefile +++ b/emul/z80/Makefile @@ -1,7 +1,8 @@ TARGETS = forth rc2014 sms ti84 OBJS = emul.o z80.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 CDIR = ../../cvm STAGE = $(CDIR)/stage diff --git a/emul/z80/sms.c b/emul/z80/sms.c index 23b31d6..c2ce65a 100644 --- a/emul/z80/sms.c +++ b/emul/z80/sms.c @@ -48,7 +48,7 @@ static SPI spi; static uint8_t iord_vdp_cmd() { - return vdp_cmd_rd(&vdp); + return tms_cmd_rd(&vdp.tms); } static uint8_t iord_vdp_data() diff --git a/emul/z80/sms_vdp.c b/emul/z80/sms_vdp.c index 27ac7e1..86961d0 100644 --- a/emul/z80/sms_vdp.c +++ b/emul/z80/sms_vdp.c @@ -3,55 +3,47 @@ void vdp_init(VDP *vdp) { - memset(vdp->vram, 0, VDP_VRAM_SIZE); - memset(vdp->regs, 0, 0x10); - vdp->has_cmdlsb = false; - vdp->curaddr = 0; -} - -uint8_t vdp_cmd_rd(VDP *vdp) -{ - return 0; + tms_init(&vdp->tms); + memset(vdp->cram, 0, VDP_CRAM_SIZE); } void vdp_cmd_wr(VDP *vdp, uint8_t val) { - if (!vdp->has_cmdlsb) { - vdp->cmdlsb = 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); + if (!vdp->tms.has_cmdlsb) { + tms_cmd_wr(&vdp->tms, val); } else { - // VRAM - vdp->curaddr = ((val&0x3f) << 8) + vdp->cmdlsb; + if ((val & 0xc0) == 0xc0) { + // 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 res = vdp->vram[vdp->curaddr]; - if (vdp->curaddr < VDP_VRAM_SIZE) { - vdp->curaddr++; + TMS9918 *tms = &vdp->tms; + if (tms->curaddr < TMS_VRAM_SIZE) { + 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) { - vdp->vram[vdp->curaddr] = val; - if (vdp->curaddr < VDP_VRAM_SIZE) { - vdp->curaddr++; + TMS9918 *tms = &vdp->tms; + if (tms->curaddr < TMS_VRAM_SIZE) { + 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) { if (x >= VDP_SCREENW) { @@ -60,10 +52,11 @@ uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y) if (y >= VDP_SCREENH) { return 0; } + TMS9918 *tms = &vdp->tms; // 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); - 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; // is palette select bit on? if yes, use sprite palette instead 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); // Now, let's compose the result by pushing the right bit of our 4 bytes // into our result. - uint8_t palette_id = ((vdp->vram[offset] >> bitnum) & 1) + \ - (((vdp->vram[offset+1] >> bitnum) & 1) << 1) + \ - (((vdp->vram[offset+2] >> bitnum) & 1) << 2) + \ - (((vdp->vram[offset+3] >> bitnum) & 1) << 3); - uint8_t rgb = vdp->vram[0x4000+palettemod+palette_id]; + uint8_t palette_id = ((tms->vram[offset] >> bitnum) & 1) + \ + (((tms->vram[offset+1] >> bitnum) & 1) << 1) + \ + (((tms->vram[offset+2] >> bitnum) & 1) << 2) + \ + (((tms->vram[offset+3] >> bitnum) & 1) << 3); + uint8_t rgb = vdp->cram[palettemod+palette_id]; return rgb; } diff --git a/emul/z80/sms_vdp.h b/emul/z80/sms_vdp.h index e36e014..86d5b69 100644 --- a/emul/z80/sms_vdp.h +++ b/emul/z80/sms_vdp.h @@ -1,26 +1,16 @@ -#include -#include +#include "tms9918.h" -#define VDP_VRAM_SIZE 0x4020 +#define VDP_CRAM_SIZE 0x20 #define VDP_SCREENW (32*8) #define VDP_SCREENH (24*8) -// Offset of the name table -#define VDP_NTABLE_OFFSET 0x3800 - typedef struct { - // the last 0x20 is palette RAM - uint8_t vram[VDP_VRAM_SIZE]; - uint8_t regs[0x10]; - uint8_t cmdlsb; - bool has_cmdlsb; - uint16_t curaddr; + TMS9918 tms; + uint8_t cram[VDP_CRAM_SIZE]; } VDP; void vdp_init(VDP *vdp); -uint8_t vdp_cmd_rd(VDP *vdp); void vdp_cmd_wr(VDP *vdp, uint8_t val); uint8_t vdp_data_rd(VDP *vdp); 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); diff --git a/emul/z80/tms9918.c b/emul/z80/tms9918.c new file mode 100644 index 0000000..4cbdd1b --- /dev/null +++ b/emul/z80/tms9918.c @@ -0,0 +1,54 @@ +#include +#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 +} diff --git a/emul/z80/tms9918.h b/emul/z80/tms9918.h new file mode 100644 index 0000000..4c57ebc --- /dev/null +++ b/emul/z80/tms9918.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include + +#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);