tridoraemu,docs: emulate vgafb shifter/maskgen and new iomem layout

This commit is contained in:
slederer 2026-02-08 01:58:50 +01:00
parent 4d103f99ec
commit e8e4b5dd24
3 changed files with 78 additions and 15 deletions

View file

@ -9,11 +9,11 @@ Registers
| _FB_PS_ | $90C | Palette Select | | _FB_PS_ | $90C | Palette Select |
| _FB_PD_ | $910 | Palette Data | | _FB_PD_ | $910 | Palette Data |
| _FB_CTL_ | $914 | Control Register | | _FB_CTL_ | $914 | Control Register |
| _FB_SHIFTER | $918 | Shift Assist Register | | _FB_SHIFTER_ | $918 | Shift Assist Register |
| _FB_SHIFTCOUNT | $91C | Shift Count Register | | _FB_SHIFTCOUNT_ | $91C | Shift Count Register |
| _FB_SHIFTERM | $920 | Shifted Mask Register | | _FB_SHIFTERM_ | $920 | Shifted Mask Register |
| _FB_SHIFTERSP | $924 | Shifter Spill Register | | _FB_SHIFTERSP_ | $924 | Shifter Spill Register |
| _FB_MASKGEN | $928 | Mask Generator Register | | _FB_MASKGEN_ | $928 | Mask Generator Register |
## Pixel Data ## Pixel Data
Pixel data is organized in 32-bit-words. With four bits per pixel, one word Pixel data is organized in 32-bit-words. With four bits per pixel, one word
@ -121,12 +121,12 @@ For each four bits of a pixel, the corresponding four mask bits
are all set to one if the pixel value is not zero. are all set to one if the pixel value is not zero.
This can be used to combine foreground and background pixel data This can be used to combine foreground and background pixel data
with a pixel value of zero for a transparent background color. where a pixel value of zero is used to indicate a transparent foreground pixel.
Usually, the mask will be inverted with a *NOT* instruction Usually, the mask will be inverted with a *NOT* instruction.
to clear all pixels in the background that are set in the foreground The result can then be used to clear all pixels in the background
with an *AND* instruction that are set in the foreground, using an *AND* instruction.
before *ORing* foreground and background together. As the last step, foreground and masked background data can be combined with an *OR* instruction.
Example in hexadecimal, each digit is a pixel: Example in hexadecimal, each digit is a pixel:
| Pixel Data | Mask | | Pixel Data | Mask |

View file

@ -249,6 +249,7 @@ func (c *CPU) step() error {
var name string var name string
if (insWord & 1) == 1 { if (insWord & 1) == 1 {
name = "STORE.B" name = "STORE.B"
operand &= ^1
ea = c.BP + word(operand) ea = c.BP + word(operand)
} else { } else {
name = "STORE" name = "STORE"

View file

@ -10,11 +10,16 @@ import (
const VmemWords = 32768 const VmemWords = 32768
const PaletteSlots = 16 const PaletteSlots = 16
const FB_RA = 0 const FB_RA = 0
const FB_WA = 1 const FB_WA = 4
const FB_IO = 2 const FB_IO = 8
const FB_PS = 3 const FB_PS = 12
const FB_PD = 4 const FB_PD = 16
const FB_CTL= 5 const FB_CTL= 20
const FB_SHIFTER = 24
const FB_SHIFTCOUNT = 28
const FB_SHIFTERM = 32
const FB_SHIFTERSP = 36
const FB_MASKGEN = 40
const PixelMask = 0b11110000000000000000000000000000 const PixelMask = 0b11110000000000000000000000000000
const PixelPerWord = 8 const PixelPerWord = 8
@ -33,6 +38,9 @@ type Framebuffer struct {
vmem [VmemWords]word vmem [VmemWords]word
readCount int readCount int
paletteChanged bool paletteChanged bool
shiftAssistData word
shiftAssistCount int
maskGenData word
} }
func (f *Framebuffer) initialize() { func (f *Framebuffer) initialize() {
@ -53,6 +61,11 @@ func (f *Framebuffer) read(byteaddr word) (word, error) {
case FB_PS: result = f.paletteSlot case FB_PS: result = f.paletteSlot
case FB_PD: result = f.readPalette() case FB_PD: result = f.readPalette()
case FB_CTL: result = f.readCtl() case FB_CTL: result = f.readCtl()
case FB_SHIFTER: result = f.readShiftAssist()
case FB_SHIFTCOUNT: result = 0xFFFFFFF
case FB_SHIFTERM: result = f.readShifterM()
case FB_SHIFTERSP: result = f.readShifterSp()
case FB_MASKGEN: result = f.readMaskGen()
default: default:
} }
return result, nil return result, nil
@ -67,6 +80,11 @@ func (f *Framebuffer) write(value word, byteaddr word) (error) {
case FB_PS: f.paletteSlot = value case FB_PS: f.paletteSlot = value
case FB_PD: f.writePalette(value) case FB_PD: f.writePalette(value)
case FB_CTL: f.writeCtl(value) case FB_CTL: f.writeCtl(value)
case FB_SHIFTER: f.writeShiftAssist(value)
case FB_SHIFTCOUNT: f.writeShiftCount(value)
case FB_SHIFTERM:
case FB_SHIFTERSP:
case FB_MASKGEN: f.writeMaskGen(value)
default: default:
} }
@ -152,3 +170,47 @@ func (f *Framebuffer) readCtl() word {
func (f *Framebuffer) writeCtl(value word) { func (f *Framebuffer) writeCtl(value word) {
} }
func (f *Framebuffer) writeShiftAssist(value word) {
f.shiftAssistData = value
f.shiftAssistCount = 0
}
func (f *Framebuffer) readShiftAssist() word {
return f.shiftAssistData >> (f.shiftAssistCount * 4)
}
func (f *Framebuffer) writeShiftCount(value word) {
f.shiftAssistCount = int(value & 0x7)
}
func (f *Framebuffer) readShifterM() word {
return convertToMask(f.readShiftAssist())
}
func pixelToMask(pixels word, mask word) word {
if (pixels & mask) != 0 { return mask } else { return 0 }
}
func convertToMask(pixels word) word {
return pixelToMask(pixels, 0xF0000000) |
pixelToMask(pixels, 0x0F000000) |
pixelToMask(pixels, 0x00F00000) |
pixelToMask(pixels, 0x000F0000) |
pixelToMask(pixels, 0x0000F000) |
pixelToMask(pixels, 0x00000F00) |
pixelToMask(pixels, 0x000000F0) |
pixelToMask(pixels, 0x0000000F)
}
func (f *Framebuffer) readShifterSp() word {
return word(f.shiftAssistData << ((8-f.shiftAssistCount)*4))
}
func (f *Framebuffer) writeMaskGen(value word) {
f.maskGenData = value
}
func (f *Framebuffer) readMaskGen() word {
return convertToMask(f.maskGenData)
}