Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving the Graphics Gremlin #16

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
28 changes: 13 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# The Graphics Gremlin - a Retro ISA Video Card

The Graphics Gremlin is an FPGA-based ISA video card specifically designed to emulate certain old video standards. This initial release emulates the original IBM PC monochrome graphics adapter (MDA) as well as the original IBM color graphics adapter (CGA). Since the logic is defined by the bitstream loaded into the FPGA, new emulations may be available in the future to support other video standards.
The Graphics Gremlin is an FPGA-based ISA video card specifically designed to emulate certain old video standards. This initial release emulates the original IBM PC hercules graphics card (HGC) as well as the original IBM color graphics adapter (CGA). Since the logic is defined by the bitstream loaded into the FPGA, new emulations may be available in the future to support other video standards.
spark2k06 marked this conversation as resolved.
Show resolved Hide resolved

![Graphics Gremlin PCB photo](https://github.com/schlae/graphics-gremlin/blob/main/images/gremlin.jpg)

But why emulate an old video card when they are still fairly easy to find online? Cards aren't hard to find, but monitors that can sync to the unusual frequencies used by MDA (18KHz) and CGA (15KHz) are much harder to find, and these frequencies are rarely supported by modern LCD monitors or video capture hardware.
But why emulate an old video card when they are still fairly easy to find online? Cards aren't hard to find, but monitors that can sync to the unusual frequencies used by HGC (18KHz) and CGA (15KHz) are much harder to find, and these frequencies are rarely supported by modern LCD monitors or video capture hardware.

For both MDA and CGA, the Graphics Gremlin has a VGA port that can deliver video running at standard (31KHz) frequencies that are well supported by LCD monitors, VGA-to-HDMI converters, and USB capture devices.
For both HGC and CGA, the Graphics Gremlin has a VGA port that can deliver video running at standard (31KHz) frequencies that are well supported by LCD monitors, VGA-to-HDMI converters, and USB capture devices.

Here are the design files. The BOM includes Mouser Electronics parts numbers for everything except for the 0.1" headers which are typically cut to length anyway.

Expand Down Expand Up @@ -88,17 +88,17 @@ The bitstream is selected using switches 3 and 4:

| 3 | 4 | Description | Default |
| ------ | ------ | ------------ | ------- |
| open | open | Bitstream 0 | MDA (VGA compatible signal) |
| open | closed | Bitstream 1 | MDA (MDA monitors only) |
| open | open | Bitstream 0 | HGC (VGA compatible signal) |
| open | closed | Bitstream 1 | HGC (MDA monitors only) |
| closed | open | Bitstream 2 | CGA (both VGA and CGA compatible signals) |
| closed | closed | Bitstream 3 | Not used |

For example, if you want to use MDA with a VGA monitor, set switches 3 and 4
For example, if you want to use HGC with a VGA monitor, set switches 3 and 4
to the open (up) position. (CGA has support for both VGA and CGA monitors built in since it implements a line doubler.)

The remaining two switches have a function that is bitstream-dependent.

| Switch | MDA (VGA comp.) | MDA | CGA |
| Switch | HGC (VGA comp.) | HGC | CGA |
| ------ | --------------- | --- | --- |
| 1 | Not used | Not used | closed=composite mode. open=VGA mode |
| 2 | Not used | Not used | closed=thin font. open=normal font |
Expand All @@ -125,18 +125,18 @@ Unlike the namesake video cards of old, the FPGA comes up with the internal card

Checking these first can help you narrow down the source of the problem.

To confirm proper operation on the ISA bus, it's helpful to set up a PC with a VGA card (or CGA card) and the Graphics Gremlin configured for MDA. These can coexist on the same PC.
To confirm proper operation on the ISA bus, it's helpful to set up a PC with a VGA card (or CGA card) and the Graphics Gremlin configured for HGC. These can coexist on the same PC.

Boot up the PC and run the DOS DEBUG program. Then see if you can access the CRTC registers. Unlike the original MDA card, these can be read back. Note: if you use the VGA compatible MDA mode, then these registers cannot be written to.
Boot up the PC and run the DOS DEBUG program. Then see if you can access the CRTC registers. Unlike the original HGC card, these can be read back. Note: if you use the VGA compatible HGC mode, then these registers cannot be written to.

```
o 3b4 0
i 3b5
```

This should return a number that is not 0 or FF. (The exact number depends on which MDA bitstream you are using).
This should return a number that is not 0 or FF. (The exact number depends on which HGC bitstream you are using).

If that works, then check to see if you can read and write the MDA video memory area:
If that works, then check to see if you can read and write the HGC video memory area:

`e b000:0000 55 aa 55 aa`...

Expand All @@ -155,15 +155,13 @@ In general, use a logical process of elimination to find where the fault (or fau

## Emulation Accuracy

The logic for both the MDA and CGA cards is as close as I could get it to match the schematics available in the technical reference manuals, with two exceptions. The VRAM interface is specific to the 8-bit SRAM chip that I am using instead of the 16-bit SRAM on the original MDA or the 16-bit DRAM used on the CGA, so it had to be quite different from the originals. As a result, the sequencer state machine had to be designed from scratch. There are some other minor differences mostly to support the nonstandard VGA-compatible signal outputs.
The logic for both the HGC and CGA cards is as close as I could get it to match the schematics available in the technical reference manuals, with two exceptions. The VRAM interface is specific to the 8-bit SRAM chip that I am using instead of the 16-bit SRAM on the original HGC or the 16-bit DRAM used on the CGA, so it had to be quite different from the originals. As a result, the sequencer state machine had to be designed from scratch. There are some other minor differences mostly to support the nonstandard VGA-compatible signal outputs.
spark2k06 marked this conversation as resolved.
Show resolved Hide resolved

Accuracy is a work in progress. Certain demos, like 8088MPH, that require cycle-accurate operation on a 4.77MHz PC, don't work 100% correctly. The causes of this aren't yet fully understood.

## Future Plans

Although the card supports just MDA and CGA, I'd like to support other video standards in the future. EGA and even VGA would be nice, but there are two huge challenges associated with that: they use custom gate array chips and they also use a 32-bit memory bus. This means I would need to quadruple the pixel clock to produce four 8-bit fetches from the SRAM. Due to this bus bandwidth limitation, Super VGAs are totally off the table.

Other people have requested support for Hercules, Tandy, and PCjr graphics, which I might get around to implementing someday.
Although the card supports just HGC and CGA, I'd like to support other video standards in the future. EGA and even VGA would be nice, but there are two huge challenges associated with that: they use custom gate array chips and they also use a 32-bit memory bus. This means I would need to quadruple the pixel clock to produce four 8-bit fetches from the SRAM. Due to this bus bandwidth limitation, Super VGAs are totally off the table.
spark2k06 marked this conversation as resolved.
Show resolved Hide resolved

There are also some neat non-graphics uses for the card. With some clever programming, the card could be turned into a memory card to extend the RAM in some of the older IBM PC and XT machines (XMS RAM). It could also emulate an expanded memory card for machines that can't run EMM386. BIOS extension ROMs stored in the NOR flash chip could also be mapped to ROM areas in the PC memory map, which might also be useful.

Expand Down
Binary file added SW/CGAVIDEO.COM
Binary file not shown.
1 change: 1 addition & 0 deletions SW/TDYKBD.COM
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�a @�a�
1 change: 1 addition & 0 deletions SW/TDYVIDEO.COM
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�p���
6 changes: 3 additions & 3 deletions verilog/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#

PROJ = isavideo
IMAGES = mda70_top mda_top cga_top
SOURCES = mda70_top.v mda_top.v mda.v crtc6845.v mda_vgaport.v mda_vram.v mda_attrib.v mda_sequencer.v mda_pixel.v cga_top.v cga.v cga_vgaport.v cga_sequencer.v cga_pixel.v cga_attrib.v cga_vram.v cga_composite.v cga_scandoubler.v
IMAGES = hgc70_top hgc_top cga_top
SOURCES = hgc70_top.v hgc_top.v hgc.v crtc6845.v hgc_vgaport.v hgc_vram.v hgc_attrib.v hgc_sequencer.v hgc_pixel.v cga_top.v cga.v cga_vgaport.v cga_sequencer.v cga_pixel.v cga_attrib.v cga_vram.v cga_composite.v cga_scandoubler.v
PIN_DEF = gremlin.pcf
DEVICE = hx8k
ODIR = build
Expand All @@ -21,7 +21,7 @@ all: $(addprefix $(ODIR)/,$(addsuffix .rpt,$(IMAGES))) $(ODIR)/$(PROJ).binm
# removed %.v
$(ODIR)/%.json: $(SOURCES)
yosys -p 'synth_ice40 -top $(basename $(notdir $@)) -json $@' $(SOURCES) -E $(basename $(notdir $@)).d
# yosys -p 'synth_ice40 -top mda_top -json $@' $(SOURCES) -E $(DEPS)
# yosys -p 'synth_ice40 -top hgc_top -json $@' $(SOURCES) -E $(DEPS)
# @echo yosys -p 'synth_ice40 -top isavideo -json $@' $^ -E $(DEPS)
echo $@

Expand Down
24 changes: 12 additions & 12 deletions verilog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@

(Click here for the [main README](https://github.com/schlae/graphics-gremlin/blob/main/README.md))

The FPGA code is divided into two major sets of files, those for CGA graphics and those for MDA graphics. At some point I'll tidy up and make a nice organized directory tree, but for now they're all in the same place.
The FPGA code is divided into two major sets of files, those for CGA graphics and those for HGC graphics. At some point I'll tidy up and make a nice organized directory tree, but for now they're all in the same place.

* mda\_top.v: The top level file instantiating the MDA graphics logic
* mda70\_top.v: An alternative top level file for VGA compatible MDA graphics
* mda.v: Implements MDA ISA interface, IO registers and instantiates the CRTC, SRAM interface, sequencer, and pixel engine
* hgc\_top.v: The top level file instantiating the HGC graphics logic
* hgc70\_top.v: An alternative top level file for VGA compatible HGC graphics
* hgc.v: Implements HGC ISA interface, IO registers and instantiates the CRTC, SRAM interface, sequencer, and pixel engine
* crtc6845.v: This is my mostly-accurate recreation of the old Motorola 6845 CRT controller chip. It generates all the sync timings as well as the character and row addresses. There are probably slight differences between it and the real thing.
* mda\_sequencer.v: Controls timing across the entire card, deciding when to fetch SRAM data, look up character bits from the character ROM, and allow ISA bus access to the SRAM
* mda\_vram.v: Implements the state machine to arbitrate ISA bus and pixel engine access to the video ram (external SRAM)
* mda\_pixel.v: This is the pixel engine. It takes data coming from the SRAM, looks up the pixels in the character ROM, and shifts the data out one pixel at a time.
* mda\_attrib.v: The attribute generator applies video attributes to the raw pixel data, including brightness, underline, inverse video, blinking. It also applies the blinking cursor.
* mda\_vgaport.v: This module turns the digital MDA video signals into numbers to drive the resistor ladder DAC connected to the VGA port. If you (gasp) dislike amber monochrome monitors, then you can hack this code to make it green or white.
* hgc\_sequencer.v: Controls timing across the entire card, deciding when to fetch SRAM data, look up character bits from the character ROM, and allow ISA bus access to the SRAM
* hgc\_vram.v: Implements the state machine to arbitrate ISA bus and pixel engine access to the video ram (external SRAM)
* hgc\_pixel.v: This is the pixel engine. It takes data coming from the SRAM, looks up the pixels in the character ROM, and shifts the data out one pixel at a time.
* hgc\_attrib.v: The attribute generator applies video attributes to the raw pixel data, including brightness, underline, inverse video, blinking. It also applies the blinking cursor.
* hgc\_vgaport.v: This module turns the digital HGC video signals into numbers to drive the resistor ladder DAC connected to the VGA port. If you (gasp) dislike amber monochrome monitors, then you can hack this code to make it green or white.

CGA graphics logic is similar to MDA and shares the same crtc6845.v logic, but the cards are different enough that I couldn't share more.
CGA graphics logic is similar to HGC and shares the same crtc6845.v logic, but the cards are different enough that I couldn't share more.
* cga\_top.v: Instantiates top level CGA logic.
* cga.v: Implements the ISA bus interface, CGA control registers, wait state generator, and most of the other CGA modules
* cga\_sequencer.v: Generates most of the timing signals used on the card, including memory fetches and pixel engine timing.
* cga\_vram.v: Implements a very basic address MUX for the SRAM interface. This actually causes too much CGA snow, and should be improved using the MDA VRAM interface as a model.
* cga\_vram.v: Implements a very basic address MUX for the SRAM interface. This actually causes too much CGA snow, and should be improved using the HGC VRAM interface as a model.
* cga\_pixel.v: The CGA pixel engine takes data from the SRAM, does a character lookup (text mode only), and shifts the data out 1 or 2 bits at a time, depending on the video mode.
* cga\_attrib.v: The attribute generator applies video attributes to the raw pixels data, including color, brightness, and blinking.
* cga\_composite.v: Contains the flip flops used to generate NTSC composite color as well as new sync pulses. The output is a 7-bit signal passed off to the green DAC channel for the RCA jack on the card.
* cga\_scandoubler.v: A very basic scan doubler to convert 15.7KHz CGA video to 31.4KHz VGA video. To save memory, this is done using 4-bit digital RGBI signals.
* cga\_vgaport.v: This module takes RGBI digital video from the scan doubler and turns it into numbers that drive the resistor ladder DAC connected to the VGA port. It produces CGA brown instead of dark yellow.

Other miscellaneous files include:
* cga.hex and mda.hex: character ROM
* cga.hex and hgc.hex: character ROM
* gremlin.pcf: The pin constraints file that determines what signals are tied to what pins on the FPGA
* isavideo\_t.v: A sloppy test bench that I used to validate and troubleshoot the rest of the logic.
* is61c5128\_t.v: A behavorial Verilog model of the SRAM chip.
Expand Down
Loading