tridoraemu,docs: emulate vgafb shifter/maskgen and new iomem layout
This commit is contained in:
parent
4d103f99ec
commit
e8e4b5dd24
3 changed files with 78 additions and 15 deletions
20
doc/vga.md
20
doc/vga.md
|
|
@ -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 |
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue