From a442c469351a4e8148b31337c53a0c1ec0db8b30 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 26 Feb 2020 09:43:50 -0500 Subject: [PATCH] sms/vdp: highlight cursor with inverted palette --- emul/hw/sms/sms.c | 3 +++ emul/hw/sms/vdp.c | 7 +++++- kernel/grid.asm | 22 +++++++++++++++--- kernel/sms/pad.asm | 4 ++-- kernel/sms/vdp.asm | 56 +++++++++++++++++++++++++++++----------------- 5 files changed, 66 insertions(+), 26 deletions(-) diff --git a/emul/hw/sms/sms.c b/emul/hw/sms/sms.c index 516042a..bde800d 100644 --- a/emul/hw/sms/sms.c +++ b/emul/hw/sms/sms.c @@ -108,6 +108,9 @@ void create_window() xcb_map_window(conn, win); } +// To make things simple with X11, we only support monochrome display, which is +// inverted: As soon as the color of the pixel is non-black, we show a black +// pixel. If the pixel is white, we show black. void draw_pixels() { xcb_get_geometry_reply_t *geom; diff --git a/emul/hw/sms/vdp.c b/emul/hw/sms/vdp.c index 2a7f789..a92c3ba 100644 --- a/emul/hw/sms/vdp.c +++ b/emul/hw/sms/vdp.c @@ -51,6 +51,7 @@ void vdp_data_wr(VDP *vdp, uint8_t val) } } +// Returns a 8-bit RGB value (0b00bbggrr) uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y) { if (x >= VDP_SCREENW) { @@ -63,6 +64,8 @@ uint8_t vdp_pixel(VDP *vdp, uint16_t x, uint16_t y) uint16_t offset = 0x3800 + ((y/8) << 6) + ((x/8) << 1); uint16_t tableval = vdp->vram[offset] + (vdp->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; // tile offset this time. Each tile is 0x20 bytes long. offset = tilenum * 0x20; // Each 4 byte is a row. Find row first. @@ -70,8 +73,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. - return ((vdp->vram[offset] >> bitnum) & 1) + \ + 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]; + return rgb; } diff --git a/kernel/grid.asm b/kernel/grid.asm index 16dd922..3665a88 100644 --- a/kernel/grid.asm +++ b/kernel/grid.asm @@ -119,7 +119,7 @@ gridPushScr: pop de ret -; Set character under cursor to A +; Set character under cursor to A. C is passed to GRID_SETCELL as-is. gridSetCur: push de push hl @@ -137,11 +137,27 @@ gridSetCur: pop de ret +; Call gridSetCur with C = 1. +gridSetCurH: + push bc + ld c, 1 + call gridSetCur + pop bc + ret + +; Call gridSetCur with C = 0. +gridSetCurL: + push bc + ld c, 0 + call gridSetCur + pop bc + ret + ; Clear character under cursor gridClrCur: push af ld a, ' ' - call gridSetCur + call gridSetCurL pop af ret @@ -210,7 +226,7 @@ gridPutC: cp ' ' ret c ; ignore unhandled control characters - call gridSetCur + call gridSetCurL push af ; --> lvl 1 ; Move cursor ld a, (GRID_CURX) diff --git a/kernel/sms/pad.asm b/kernel/sms/pad.asm index c64e1d7..4f17cb1 100644 --- a/kernel/sms/pad.asm +++ b/kernel/sms/pad.asm @@ -181,7 +181,7 @@ padGetC: ; no action button pressed, but because our pad status changed, update ; VDP before looping. ld a, (PAD_SELCHR) - call gridSetCur + call gridSetCurH jp padGetC .return: ld a, LF @@ -190,7 +190,7 @@ padGetC: .advance: ld a, (PAD_SELCHR) ; Z was already set from previous BIT instruction - ret + jp gridSetCurL .backspace: ld a, BS ; Z was already set from previous BIT instruction diff --git a/kernel/sms/vdp.asm b/kernel/sms/vdp.asm index f130609..ca30ce2 100644 --- a/kernel/sms/vdp.asm +++ b/kernel/sms/vdp.asm @@ -23,8 +23,8 @@ ; *** Code *** vdpInit: - ld hl, vdpInitData - ld b, vdpInitDataEnd-vdpInitData + ld hl, .initData + ld b, .initDataEnd-.initData ld c, VDP_CTLPORT otir @@ -47,10 +47,10 @@ vdpInit: out (VDP_CTLPORT), a ld a, 0xc0 out (VDP_CTLPORT), a - xor a ; palette 0: black - out (VDP_DATAPORT), a - ld a, 0x3f ; palette 1: white - out (VDP_DATAPORT), a + ld hl, .paletteData + ld b, .paletteDataEnd-.paletteData + ld c, VDP_DATAPORT + otir ; Define tiles xor a @@ -97,6 +97,28 @@ vdpInit: out (VDP_CTLPORT), a ret +; VDP initialisation data +.initData: +; 0x8x == set register X +.db 0b00000100, 0x80 ; Bit 2: Select mode 4 +.db 0b00000000, 0x81 +.db 0b11111111, 0x82 ; Name table: 0x3800 +.db 0b11111111, 0x85 ; Sprite table: 0x3f00 +.db 0b11111111, 0x86 ; sprite use tiles from 0x2000 +.db 0b11111111, 0x87 ; Border uses palette 0xf +.db 0b00000000, 0x88 ; BG X scroll +.db 0b00000000, 0x89 ; BG Y scroll +.db 0b11111111, 0x8a ; Line counter (why have this?) +.initDataEnd: +.paletteData: +; BG palette +.db 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +; Sprite palette (inverted colors) +.db 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +.paletteDataEnd: + ; Convert ASCII char in A into a tile index corresponding to that character. ; When a character is unknown, returns 0x5e (a '~' char). vdpConv: @@ -108,7 +130,8 @@ vdpConv: ld a, 0x5e ret -; grid routine. Sets cell at row D and column E to character A +; grid routine. Sets cell at row D and column E to character A. If C is one, we +; use the sprite palette. vdpSetCell: call vdpConv ; store A away @@ -141,18 +164,11 @@ vdpSetCell: ; We're ready to send our data now. Let's go ex af, af' out (VDP_DATAPORT), a + + ; Palette select is on bit 3 of MSB + ld a, 1 + and c + rla \ rla \ rla + out (VDP_DATAPORT), a ret -; VDP initialisation data -vdpInitData: -; 0x8x == set register X -.db 0b00000100, 0x80 ; Bit 2: Select mode 4 -.db 0b00000000, 0x81 -.db 0b11111111, 0x82 ; Name table: 0x3800 -.db 0b11111111, 0x85 ; Sprite table: 0x3f00 -.db 0b11111111, 0x86 ; sprite use tiles from 0x2000 -.db 0b11111111, 0x87 ; Border uses palette 0xf -.db 0b00000000, 0x88 ; BG X scroll -.db 0b00000000, 0x89 ; BG Y scroll -.db 0b11111111, 0x8a ; Line counter (why have this?) -vdpInitDataEnd: