I`ve recently spent some time trying to find a way to improve my VGA display board in order to make it capable of displaying 80 column text for future CP/M implementation. It would theoretically be possible, but modifications would include at least a new firmware for Atmega328 and XC9536XL, and also a new, smaller font – something like 5×7. It might also be needed to swap the AVR chip for something larger, like Atmega644.Generally, it would be quite a big challenge. As soon as I started making some brief calculations for this, an interesting idea came into my head: wy not try something completely different? Long ago, I remember doing some research about a standard PC ISA VGA cards, and throwing away that idea very quickly, as I realized, that VGA need to be initialized via it`s BIOS routines, in 80×86 code of course. I heard , that VGA can sometimes even call some routines in PC BIOS, so it would be really a dreadful job to make it do just anything barely useful in Z80 enviroment. However, as a vintage PC collector, I own some MDA/Hercules clone cards and monitors.I was aware that MDA/Hercules are quite simple designs, and after some quick research on MDA card and ISA bus I was pretty shure I`m able to make a standard MDA clone work for my C-Z80 computer. It took just a few hours from nothing to displaying lines of text on a monochrome monitor connected to MDA/Hercules clone!
Here is the card connected to the system:
The card itself is driven only by 8255 chip from my 8255/IDE interface card. Absolutely nothing more is required to make it work (except for some cables), also you don`t nedd to worry about synchronization of video memory access with actual video signals – the card does all this by itself (no snowing or jittery image). Here is a complete schematic of connections I made:
As you can see, the card needs 24 I/O lines and positive RESET signal, just exactly what 8255 offers. In fact, you can even let go 2 lines more – /IOR and /MEMR if you`re not planning to do any read operations from the card`s memory or I/O space. The video function of the card does not use any IRQs or DMAs, no external clock sources are needed,no data multiplexing or anything. Basically, the very minimum you need to do with the card to make it display text is:
- Setting the video memory or I/O address lines (12 lines in total for MDA, 15 for Hercules in full mode)
- Setting the data lines (values needed to be entered to I/O registers and pure video buffer data)
- Generating negative pulses on /IOW and /MEMW to feed the card with the data.
For full functionality, /MEMR and /IOR have to be implemented for read operations, and also IO CH RDY signal have to be connected to Z80`s /WAIT line in order to implement a full synchronization for I/O and memory operations.
Below I attach a sample test code. It uses 8255 chip at address 88d0h for communicating with MDA card. I only use MDA functionality here, as it is the easiest option, and require less address lines (only 12 for 4K video buffer). The code initializes the card according to original IBM`s hardware reference manual for “Monochrome Display and Printer Adapter”. After this, it clears the screen, displays some text, waits for a moment and repeats the process.
;Some basic delay routines DELAY_LONG: .equ 0597h DELAY: .equ 0589h ; IO addresses and pin connections used: ; ; 0ffd0h - 8255 base address in C-Z80 system ; 0ffd3h - 8255 control register ; 0ffd0h - PORT A (connected to lower address lines of MDA card A0 - A7) ; 0ffd1h - PORT B (connected to data lines of MDA card) ; 0ffd2h - PORT C (connected to upper addres lines of MDA card , and to control lines: ; C0=A8 PC1=A9, PC2=A10, PC3=A11, PC4=/MEMR PC5=/MEMW PC6=/IOR PC7=/IOW) ;The MDA card is also connected to +5V, GND and also positive RESET source. ;Card`s IRQ7, I/O CH RDY are not used here - leave unconnected ;Some signals are terminated: ; ;A12,A13,A14,A15,A18,AEN = GND ;A16,A17,A19 = +5V ; ; *** MAIN LOOP *** .org 0d000h start: call init_8255 call port_setup call registers_init repeat: call clear_screen ld ix,test_string1 ld hl,0 call line_write call DELAY_LONG call DELAY_LONG call DELAY_LONG call DELAY_LONG jp repeat ; *** SUBROUTINES *** init_8255: ; Basic inititalisation of 8255 chip: ; All ports as output, mode 0, ; port C = f0h (to set all control signals of MDA card to logic "1") ld bc,0ffd3h ld a,80h out (c),a ld bc,0ffd2h ld a,0f0h out (c),a ret port_setup: ; Seting up control port of 6845 CRT controller on MDA card (address 3b8h) ; According to "IBM Monochrome Display and Prnter Adapter" hardware reference manual ; this must be done before anything else. ; value "29h" means: ; High resolution mode: ON, Video Enable: ON, Enable Blink: ON ld bc,0ffd2h ld a,0f3h out (c),a ld bc,0ffd0h ld a,0b8h out (c),a ld bc,0ffd1h ld a,29h out (c),a call io_write ret registers_init: ; Bulk initialization of 6845 CRT controller`s registers ; 16 registers has to be initialised with fixed values ; recommended by IBM`s hadware manual for MDA card. ; Registers are selected by "Index Register" (3b4h) ; Values are entered to "Data Register" (3b5h) ld ix,init_data ld d,10h loop_regs: dec d ld a,(ix) ld e,a call reg_write inc ix ld a,0 cp d jr nz,loop_regs ret reg_write: ; writing value to 6845 register. ;Entry: ; ; D - register number ; E - value ld bc,0ffd2h ld a,0f3h out (c),a ld bc,0ffd0h ld a,0b4h out (c),a ld bc,0ffd1h ld a,d out (c),a call io_write ld bc,0ffd0h ld a,0b5h out (c),a ld bc,0ffd1h; ld a,e out (c),a call io_write; ret io_write: ; generate short negative pulse on /IOW line of MDA card ld bc,0ffd3h ld a,0eh out (c),a call DELAY ;just in case I/O operations would take too long. ld a,0fh out (c),a ret mem_write: ; generate short negative pulse on /MEMW line of MDA card ld bc,0ffd3h ld a,0ah out (c),a ld a,0bh out (c),a ret line_write: ;Write ASCIIZ buffer to MDA card`s video buffer. Assuming "normal" attribute. ;Entry: ; ; HL = Video RAM position - even address, counted from 0 ; IX = Start of ASCIIZ buffer of data ld bc,0ffd0h ld a,l out (c),a ld a,0f0h or h ld bc,0ffd2h out (c),a ld b,0 ld a,(ix) cp b ret z ld bc,0ffd1h out (c),a call mem_write inc hl ld bc,0ffd0h ld a,l out (c),a ld a,0f0h or h ld bc,0ffd2h out (c),a ld bc,0ffd1h ld a,07h ;normal attribute out (c),a call mem_write; ; delay - just for nice looking printout on screen call DELAY call DELAY call DELAY call DELAY call DELAY call DELAY inc hl inc ix jp line_write clear_screen: ;Fills the 4K video RAM with zeros ld hl,0f9fh continue_clear_screen: ld bc,0ffd0h ld a,l out (c),a ld a,0f0h or h ld bc,0ffd2h out (c),a ld bc,0ffd1h ld a,0 ;attribute out (c),a call mem_write dec hl ld bc,0ffd0h ld a,l out (c),a ld a,0f0h or h ld bc,0ffd2h out (c),a ld bc,0ffd1h ld a,0 ;empty char out (c),a call mem_write; ld a,h or l ret z jp continue_clear_screen; ;Fixed 6845 register values - taken from ;"IBM Monochrome Display and Printer Adapter" ;Hardware reference manual. init_data: .db 0,0,0,0,0ch,0bh,0dh,02h,19h,19h,06h,19h,0fh,52h,50h,61h ;Example text to be displayed test_string1: .db "Hello! This is MDA display adapter interfacing Z80 CPU! " .db "This is a test program showing how it is possible to use " .db "a standard IBM MDA display adapter with Z80 CPU system. " .db "This is actually a very simple job, as MDA adapters (and also CGA) " .db "have no BIOSes of their own - there is no need for emulating 80x86 code " .db "In order to set up the card`s chipset before regular use. Using MDA " .db "adapter is as simple as issuing few simple read/write operations to memory " .db "and I/O locations. It would be best to place the card`s interface directly " .db "into memory and I/O space of the Z80 CPU system - this would be rather easy, " .db "as there are just few I/O addressed in use , and 4KB of video RAM. However, " .db "for testing the MDA in my C-Z80 system, I used the most simple solution - " .db "8255 Programmable Peripheral Interface chip. " .db "This chip gives a total of 24 I/O lines, which is just enough to interface " .db "MDA card: we need 12 address lines, 8 bit data lines and 4 control signals. " .db "8255 can privide all of these. In addition we need a positive RESET signal - " .db "taken from 8255 itself, and of course +5V and GND lines. " .db "We assume that there is enough time for I/O and memory operations for MDA card " .db "So there is no checking of I/O CH RDY line for this simple test setup. " .db "It seems the display adapter has it`s own dual port access to video memory " .db "as there is no need for any sync while writing into the video buffer - " .db "there is no flickering or snowing while accessing the VRAM. " .db "Of course this greatly simplifies the interface design. " .db "The video troughput is acceptable, even with rather complex drive trough " .db "8255, not directly from CPU. Making a real interface with latches and " .db "buffers will icrease the speed even more. I`ll be working on this " .db "solution in near future. When the proper interface is ready, the display " .db "subsystem of C-Z80 computer will be ready for CP/M implementation." .db 0 .END
Here I attach some charts from logic analyzer:
There are /IOW/ /MEMW and IO CH RDY signals shown. On the first chart we can see a problem with 8255 itself – it seems, that transition between it`s operational modes causes some sort of noise on the /IOW and /MEMW lines, and therefore IO CH RDY line goes crazy. Before they finally settle down, some random data may be entered into card`s I/O and memory space. This sometimes leads to problems with initialisation – the card just display garbage on the screen. This can be fixed with more sophisticated circuit, or just by interfacing the card directly to Z80 bus. After the problematic first few microseconds, we can see the card`s initialisation process : one pulse for setting the 6845 control port, and 16 pairs of pulses for setting the required 16 registers of 6845. After this, a series of /MEMW pulses appear – the video buffer is being filled with data. You can see, that I/O pulses do not produce any wait states from the card (IO CH RDY stays high), so we are safe here. However, video memory access generates wait states from about 0.5 us to over 1.6 us (shown on later charts). This is not a problem for this circuit – with 8255 we can only make pulses as short as 4,6us, so we are also safe here – the card will easily deal with this data rate from the system itself. However, if we plan to interface the card in Z80 I/O and / or memory space, we need to take the IO CH RDY signal into account – a single /IOREQ pulse from Z80 @ 4Mhz is about 0,58us, so the charts clearly show, that a /WAIT signal has to be used when interfacing the card to Z80 system.
AS you can see, making an MDA/Hercules card to work for any 8-bit CPU is really easy. I can recommend some resources on the web that helped me during this experiment:
Very brief, and very helpful description of 8-bit ISA bus interfacing. Nothing more is really needed to start your own experiments with ISA bus:
http://ece.wpi.edu/~wrm/Courses/EE3803/Labs/isa/
Scanned PDF of IBM`s original Hardware Reference Manual for Monochrome Display and Printer adapter. Good manual, schematics included:
http://www.minuszerodegrees.net/oa/OA%20-%20IBM%20Monochrome%20Display%20and%20Printer%20Adapter.pdf
John Elliott`s page on MDA and Hercules hardware and programming tips. This document covers pretty much everything said in the previous one from IBM, but also explains many things in greater detail, and what`s more important: gives information about Hercules mode of monochrome clone cards, so it can be useful if someone wants to get more from the card than just plain MDA:
http://www.seasip.info/VintagePC/mda.html
I`m really happy that this setup actually works. MDA/Hercules display gives many new possibilities to an 8-bit system. However there are of course disadvantages: MDA/Hercules cards are not easy to come by, and can get quite expensive. For monitors – it`s even worse. There is some hope though: with simple passive adapter, a multiscan VGA monitor can be used , though they are also rare (NEC Multisync 3D for example). There can be also found some specialized LCD monitors and signal converters used as a replacement solutions for MDA CRTs in industrial machines. Last option is a good MDA/CGA clone card like ATI Small Wonder – it can output an MdA/Hercules display to a composite output.
In near future, I`m planning to interface the card directly to Z80 bus, and make a proper adapter for it.
LGB Gábor Lénárt said:
I’m really not sure about this, but since the idea also came into my mind some years ago … I had the hope that the CRT controller IC of the Hercules card can be programmed in a way, that it would be more or less a VGA timing. So maybe any VGA monitor can display the result then, but of course, you still may need some level conversion of signals (as far as I remember, VGA wants max of 0.7V as RGB signals, while Hercules is pure TTL, etc), etc, but that’s easy then. However I am still not sure if it’s possible at all … I am even not sure that CRT controller chip Motorola 6845 is similar to the so called “CRTC” stuff (I remember from programming VGA on hardware level).
LikeLike
ciernioo said:
Hi! Thanks for stopping by. I believe Hercules can`t be forced by software to output VGA timmings – it`s fixed clock frequencies won`t allow you do that. Here is an experiment by Nitrai Peter, ho tried changing the crystal on an MDA/Hercules to make it compatible with VGA monitor:
http://aknamunka.uw.hu/mdah/1st.html
Was it possible ? As he siad in conclusions: “Yes, a little.” – he got freezes and hangups during operation.However, I think maybe it could be possible to design a VGA timming compatible display circuit with 6845, but it would have to be done completly from scratch with proper timmings in mind. If I had this chip, I shurely would try doing it 🙂
LikeLike
LGB Gábor Lénárt said:
Thanks for your answer, I see. However still, the VGA card adoption still can be an option. Some old ISA bus designs for example. I don’t think you need the VGA BIOS stuff, what you need is to figure out which registers initialized for which values on a real PC, and you can do that from a Z80 too, without any need of the VGA BIOS then! Some registers can be read back to figure that out on a real PC hw with that card, but honestly, I would run a software emulator like bochs or something trying to use the card’s original VGA BIOS. Then I need only catch and log I/O register write operations done by the VGA BIOS, so then I can write my own routines to do the same in non-x86 assembly of course (Z80 in our case). There is no even need to disassembly/understand the VGA BIOS, as it would require some time, I think … Also most older VGA cards are register compatible with each other, so it’s even documented how it can be done. Maybe cards have some vendor specific extensions, SVGA, whatever, then you need to do extra work as well, but there the emulator trick can help, I think. If card is initialized well, then you need to write only the video RAM somehow, there is no need for any card specific operations anymore (unless some wants to change video mode later too?).
LikeLike
LGB Gábor Lénárt said:
Just one side note: http://tinyvga.com/avr-isa-vga
OK, it’s an Atmel AVR MCU not Z80, but the theory is not too different, I think ….
LikeLike
ciernioo said:
Hmm, I must say your thinking convinces me and makes me wondering maybe I`ve dropped the ISA VGA option too quickly. Like you say, there has to be no “magic” there in initialisation process of some popular old, standard designs like Trident or Cirrus Logic chipsets. One of possible approach woluld be to consult datasheets for these, the other wolud be like you suggest: capture some traffic with help of an emulator. I suppose one should be only watching for card`s I/0 actions, because what else could be needed there ? I see it like: start capture of I/O traffic to VGA card, then start a virtual PC and wait only unitl a standard text screen of POST appears. The VGA card should have been fully initialised by then. Last thing we need is to just copy the I/O exchange process without even trying to analizie it , and replicate it in Z80 system by just copying values from array in ROM…
Some things worries me though:
In the PDF schematics for the Atmega128 example you`ve mentoined I can see they are using /REFRESH signal from ISA bus – I really wouldn`t want to deal with this dynamic memory refresh crap. I don`t know if VGA card relies on host DRAM refresh mechanism, or if it has it`s own. But maybe it could be fixed by just replacing onboard DRAMS with SRAMs – 256 / 512K SRAMs are cheap today. Refresh signals could be ignored then.
Second thing – I`m not shure if VGA needs any IRQ handling, or it may just be ignored (I hope so) – I also see IRQ connected to Atmega on the schematics. Both of these can be easily verified on a real hardware – just isolate the questionable ISA card pins with tape (maybe some of them have to be pulled up or down), insert the card into slot and power up the PC to see what happens 🙂 I did this when I wondered whether I need OSC signal for CGA to work (It celarly showed I needed…)
On the other side, good news are:
AEN is grounded and DACK/DRQ signals are floating, so absolutely no DMA stuff to be worry about. It is also good that some old VGAs can operate in 8-bit slot , so less trouble with additional address and data lines.
Looking at the schematics of that Atmega+VGA project I can see that my own hardware is fully compatible with 8-bit VGA I could just plug one into 8-bit ISA slot in my system and start to experiment :). I think I`ll give it a shot after I finish implementing CP/M (nearly ready !). If you plan to make your own research on the VGA initialisation process in an emulator you wrote about – I would really be interested in looking into your results!
LikeLike
LGB Gábor Lénárt said:
IRQ is not needed – in my opinion. If I remember correctly, VGA supports the “old school” (like on Commodore 64) notion of “raster interrupt” ie generating IRQ on a given scanline if it’s programmed to do so – well, if I remember correctly (maybe not on any raster but on vsync, but it does not matter too much for us). Even if the card generates an IRQ, nothing happens if you simply don’t care.
Well, the DRAM refresh issue is indeed sounds not so good … Honestly I don’t like that either, I am not so “old school” to try to use DRAM ever, I prefer plain simple SRAM for my projects 🙂 I am not sure at all, if VGA needs that its RAM to be refreshed externally 😦 I think this is the only problematic part maybe!
Only catch with this “self made init stuff” that you may need to capture I/O traffic and “play back” with a custom Z80 code, so new brand of video card may won’t work without repeating this detective work. In theory VGA cards are register compatible, but other than the most simple – really VGA only – cards, they have some custom parts, may need to be initialized first and then – indeed – with some “standard” I/O work you can even change modes etc later too.
My other old idea is creating a Z80 (or 6502, or whatever) based PC, simply by using an old XT motherboard with different CPU 🙂 Of course it’s a harder task and needs maybe large amount of glue logic. Also it abuses the goal to build something own, but – I think – it’s also an interesting project but for some different reasons than building a really own computer 🙂 However the great thing with this: you have ready-to-use ISA slots, memory, whatever. I also thought about an AT motherboard with 65816 (ok, that is 65xx not Z80) as the available memory bus for addressing is the same (16Mbyte) though 65816 has only 8 bit data bus (not a problem as 80286 can issue byte level operations as well with a simple signal for that) even if it’s put into 16 bit mode which it has.
Other than the VGA card plan, my idea is to use a Parallax Propeller MCU. Ok, I must admit, this is some kind of “odd” feeling to use an MCU much more powerful than the main CPU (Z80 in our case) and sounds like more an emulation than a “real” hardware. But Propeller has 8 cores (“cogs” in their notion), custom video signal generation support (both composite and VGA) and has nice yet-to-be-discovered (for me, I mean …) tricky assembly language to program … I have even the plan to be able to program the Propeller from Z80 via I/O ports, so the feeling can remain at least, that Z80 is the “boss” 🙂 But btw, it can emulate ROM as well for start-up of the system, so in theory, maybe a three-chip design is possible or almost possible (Z80 + Propeller + SRAM). The problematic part here, that Propeller is a 3.3V part … I am not sure if CMOS Z80 can be driven on 3.3V instead of 5 … The logic level shifting is always a headache for me, and unneeded complexity (by contrast, modern 65xx CMOS designs – including 65C02 and 65C816 – works from somewhere 1.8V to 5V which is really a nice thing!).
Btw, sorry for my not so perfect English, hopefully it’s enough though 🙂
LikeLike
LGB Gábor Lénárt said:
Okey, sorry another comment 🙂 Hopefully you don’t mind if I flood you with comments, but I really like 8 bit systems, and questions like this 🙂 About the CP/M. What do you mean “implementing CP’M”? Writing a custom CBIOS for the original DR BDOS? Or implement a whole CP/M compatible OS (including BDOS) by your own? I tried both 🙂 The first was OK, the second … well, not so much 🙂 I wanted to write a full CP/M (v2.2) compatible system to be able to run on Linux, that is stdio/out stuff are “naturally imported” to a “standard” UNIX environment. Or something like that, eh 🙂
LikeLike
ciernioo said:
Hi! I meant to just run CP/M by customizing the BIOS. That`s all I want , mainly to gain access to all that sea of software that comes with it 🙂 Making everything from scratch is reeealy hard with software so complex like operating system or programming language. I`m satisfied with porting it o my hardware and make it work for me 🙂 My ROM monitor with FAT16 support gives me all the functionality I really need with the system. CP/M and it`s software does the rest.
Speaking about the VGA thing. I really hope it does not require the external refresh mechanism – if MDA/Hercules/CGA combos I`m using do not, so maybe VGAs also. I`ll find out soon enough! I also would not care much about comatibility of this “captured I/O exchange” initialisation. Sticking to all-time popular cards like Tridents / CL is enough for me. One can always try to go as compatible as possible, but: It could make you go nuts at some point, and you`ll loose the real goal from your sight. That`s what I`m thinking 🙂
I read about that propeller thingy. Looks like a very useful chip for many different projects, I`ll probably use it for something in the future, but for this Z80 project I would like to stay away from modern solutions as far as possible. I`m not feeling confortable for using the Atmega in my display, but well, it happend (CPLD is OK for me though – feels a little like Spectrum`s ULA 🙂 ) … At least the new display solution with old MDA/ VGA possibly , is much more apropriate for such design. The display I would like the most for my design would be build around some vintage video chip or designed like some standard solution like frame buffer with multiplexed data/address buses. pixel or character based display. We`ll see in the future. THe base design seems flexible enough to accomodate some different display in the future.
BTW: quite original approach with that Z80 system built around an XT board – I don`t remember seeing anything like that ever!
LikeLike