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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 15 additions & 17 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 monochrome graphics adapter (MDA) and the Hercules Graphics Mode (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.

![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 MDA/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 MDA/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 @@ -91,15 +91,17 @@ The bitstream is selected using switches 3 and 4:
| open | open | Bitstream 0 | MDA (VGA compatible signal) |
| open | closed | Bitstream 1 | MDA (MDA monitors only) |
| closed | open | Bitstream 2 | CGA (both VGA and CGA compatible signals) |
| closed | closed | Bitstream 3 | Not used |
| closed | closed | Bitstream 3 | Sound (Adlib & CMS) |

For example, if you want to use MDA with a VGA monitor, set switches 3 and 4
For example, if you want to use MDA/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.)

Bitstream 3 is reserved for exclusive use with sound cards via the RCA connector, initially Adlib and Game Blaster (CMS) has been implemented.

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

| Switch | MDA (VGA comp.) | MDA | CGA |
| ------ | --------------- | --- | --- |
| Switch | MDA/HGC (VGA comp.) | MDA/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 +127,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 MDA/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 MDA/HGC card, these can be read back. Note: if you use the VGA compatible MDA/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 MDA/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 MDA/HGC video memory area:

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

Expand All @@ -155,22 +157,18 @@ 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 MDA/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 MDA/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.

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 MDA/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.

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.

The card could act as a fancy POST card, perhaps even with a mini bus analyzer built in (using a connected VGA monitor).

It's even theoretically possible to implement a sound card using the composite video jack (and 7-bit resistor DAC) as the sound output.

## License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
International License. See [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/).
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���
4 changes: 2 additions & 2 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 = mda70_top mda_top cga_top sound_top
SOURCES = mda70_top.v mda_top.v mda.v UM6845R.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 sound_top.v sound.v saa1099.v ./jtopl/hdl/jtopl2.v ./jtopl/hdl/jtopl.v ./jtopl/hdl/jtopl_acc.v ./jtopl/hdl/jtopl_op.v ./jtopl/hdl/jtopl_eg.v ./jtopl/hdl/jtopl_pg.v ./jtopl/hdl/jtopl_lfo.v ./jtopl/hdl/jtopl_timers.v ./jtopl/hdl/jtopl_mmr.v ./jtopl/hdl/jtopl_reg.v ./jtopl/hdl/jtopl_div.v ./jtopl/hdl/jtopl_sh_rst.v ./jtopl/hdl/jtopl_pg_comb.v ./jtopl/hdl/jtopl_noise.v ./jtopl/hdl/jtopl_sh.v ./jtopl/hdl/jtopl_eg_comb.v ./jtopl/hdl/jtopl_eg_cnt.v ./jtopl/hdl/jtopl_exprom.v ./jtopl/hdl/jtopl_logsin.v ./jtopl/hdl/jtopl_single_acc.v ./jtopl/hdl/jtopl_eg_final.v ./jtopl/hdl/jtopl_eg_pure.v ./jtopl/hdl/jtopl_eg_step.v ./jtopl/hdl/jtopl_eg_ctrl.v ./jtopl/hdl/jtopl_pg_rhy.v ./jtopl/hdl/jtopl_pg_sum.v ./jtopl/hdl/jtopl_pg_inc.v ./jtopl/hdl/jtopl_pm.v ./jtopl/hdl/jtopl_reg_ch.v ./jtopl/hdl/jtopl_csr.v ./jtopl/hdl/jtopl_slot_cnt.v
PIN_DEF = gremlin.pcf
DEVICE = hx8k
ODIR = build
Expand Down
12 changes: 6 additions & 6 deletions verilog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

(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 MDA/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
* mda\_top.v: The top level file instantiating the MDA/HGC graphics logic
* mda70\_top.v: An alternative top level file for VGA compatible MDA/HGC graphics
* mda.v: Implements MDA/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.

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 MDA/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.
Expand Down
Loading