Hi all,
I thought a bit about the VGA controller, and here are the results:
The design goal is to implement a VGA controller with as little hardware as
possible. Since this won't be a standalone controller, we should use the
existing 3D pipeline, video controller and RAM. The most obviously useful
part is the video controller: if we somehow manage to get the VGA image into
a 32 bpp framebuffer, then we don't have to worry about timings or any
real-time aspects at all (we're doing VGA for compatibility, not for speed).
The second obvious part is the RAM, which should be used as VGA RAM and as
framebuffer for the video controller. With 256 KB of VGA RAM + 800*600*4
bytes of framebuffer, we're using less than 2% of the available 128MB.
The traditional way to reduce hardware usage is to replace the hardware with
a smaller CPU + ROM (see PICs, microcoded CPUs). Since we have lots of RAM,
the CPU can be pretty small. Attached is the smallest design I could come up
with. For every read or write to a mapped I/O or memory address, the CPU
executes a program from a fixed address (the methods in(), out(), read() and
write()). The execution stops when the last instruction doesn't have the
MASK_NEXT bit set. There are 2 registers: A[ddress] and V[alue]. They are
used as input to the executed program, and V is also used as output of
read() and in(). As the absolute minimum, we need 4 instructions:
- FETCH reads a byte from RAM into V.
- STORE writes a byte from V into RAM.
- JUMP performs an unconditional branch.
- 3D sends the contents of V to the rest of the chip as if it were a byte
from a privileged DMA stream. We already decided to have an I/O interface
for that, hopefully it can be reused here. It will be used to setup
resolutions and timings. Maybe for bitblts in text mode.
The fun starts with the address modes: the address for a read, write or jump
is a combination of a 27 bit immediate operand and the two registers A and
V. Bits 7-0 of the operand can be replaced with contents of V and bits 23-8
can be replaced with contents of A. This allows to use the FETCH instruction
and big chunks of RAM to perform following calculations:
MASK_USE_V | OP_FETCH: a 256 bytes block of RAM is used as a function that
takes V as parameter and places the result in V.
MASK_USE_A | OP_FETCH: a 16 MB block of RAM is used as up to 256 different
functions that take A as parameter and place the result in V.
MASK_USA_A | MASK_USE_V | OP_FETCH: a 16 MB block of RAM is used as a
function that takes A and V as arguments and places the result in V.
We have a total of 7 16 MB blocks at out disposal. (The 8th block is used
for framebuffers, VGA RAM, smaller lookup tables and code.) That should be
enough to implement the whole VGA functionality. If we allow a backdoor for
arbitrary writes to RAM, then it's even runtime-hackable, which can be used
to emulate any kind of old video hardware.
The attached files are an abstract C++ class implementing the hardware only.
Subclasses are supposed to implement the methods write_3d() and draw(). As
minimum functionality, write_3d() must remember the video settings
(framebuffer position and dimensions etc.) and draw() must update the real
output with the contents of the framebuffer. Also, the subclasses are
supposed to initialize the RAM with something useful. The four entry points
CODE_* should be filled with JUMP instructions to the actual code.
Next weekend, I'll try to program this thing.
Does anybody know any professional BrainFuck programmers? ;)
- Viktor Pracht
--
+++ Sparen beginnt mit GMX DSL: http://www.gmx.net/de/go/dsl
/* VGA simulator for the OpenGraphics project.
* Copyright (C) 2005 Viktor Pracht
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* In addition, Tech Source, Inc. is granted a permission to include
* derivatives of this code in its OpenGraphics product line.
*/
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
class VGA {
public:
byte in(word port);
void out(word port, byte value);
byte read(word offset);
void write(word offset, byte value);
protected:
byte VRAM[0x8000000];
virtual void draw() = 0;
virtual void write_3d(byte value) = 0;
static const dword CODE_IN;
static const dword CODE_OUT;
static const dword CODE_READ;
static const dword CODE_WRITE;
private:
dword A;
byte V;
void execute(dword address);
static const int SHIFT_V;
static const int SHIFT_A;
static const dword MASK_V;
static const dword MASK_A;
static const dword MASK_OFFSET;
static const dword MASK_NEXT;
static const dword MASK_USE_V;
static const dword MASK_USE_A;
static const dword MASK_OPCODE;
static const dword OP_FETCH;
static const dword OP_STORE;
static const dword OP_JUMP;
static const dword OP_3D;
};
/* VGA simulator for the OpenGraphics project.
* Copyright (C) 2005 Viktor Pracht
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* In addition, Tech Source, Inc. is granted a permission to include
* derivatives of this code in its OpenGraphics product line.
*/
#include "vga.h"
const dword VGA::CODE_IN = 0x00000000;
const dword VGA::CODE_OUT = 0x00000004;
const dword VGA::CODE_READ = 0x00000008;
const dword VGA::CODE_WRITE = 0x0000000C;
const int VGA::SHIFT_V = 0;
const int VGA::SHIFT_A = 8;
const dword VGA::MASK_V = 0x000000FF;
const dword VGA::MASK_A = 0x00FFFF00;
const dword VGA::MASK_OFFSET = 0x07000000;
const dword VGA::MASK_NEXT = 0x08000000;
const dword VGA::MASK_USE_V = 0x10000000;
const dword VGA::MASK_USE_A = 0x20000000;
const dword VGA::MASK_OPCODE = 0xC0000000;
const dword VGA::OP_FETCH = 0x00000000;
const dword VGA::OP_STORE = 0x40000000;
const dword VGA::OP_JUMP = 0x80000000;
const dword VGA::OP_3D = 0xC0000000;
byte VGA::in(word port) {
A = port - 0x3B0;
execute(CODE_IN);
return V;
}
void VGA::out(word port, byte value) {
A = port - 0x3B0;
V = value;
execute(CODE_OUT);
draw();
}
byte VGA::read(word offset) {
A = offset;
execute(CODE_READ);
return V;
}
void VGA::write(word offset, byte value) {
A = offset;
V = value;
execute(CODE_WRITE);
draw();
}
void VGA::execute(dword address) {
dword instr;
do {
instr = VRAM[address ] << 24 | VRAM[address + 1] << 16
| VRAM[address + 2] << 8 | VRAM[address + 3];
address += 4;
dword vram_addr = instr & MASK_OFFSET
| (instr & MASK_USE_A ? ((dword) A) << SHIFT_A : instr & MASK_A)
| (instr & MASK_USE_V ? ((dword) V) << SHIFT_V : instr & MASK_V);
switch (instr & MASK_OPCODE) {
case OP_FETCH:
V = VRAM[vram_addr];
break;
case OP_STORE:
VRAM[vram_addr] = V;
break;
case OP_JUMP:
address = vram_addr << 2;
break;
case OP_3D:
write_3d(V);
}
} while (instr & MASK_NEXT);
}
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)