Archive for September, 2012

Adventures in CGA lockstep

Sunday, September 30th, 2012





  2. Delay for A ccycles.
  4. Delay for B ccycles.















The CGA wait states

Saturday, September 29th, 2012

As part of my project to emulate an IBM PC or XT with cycle accuracy, I also wanted to emulate the CGA card with cycle accuracy. That meant figuring out exactly what the wait states are when accessing CGA memory. Here's what I found out.

When talking about this stuff it helps to have a common terminology to talk about the several units of timing involved. This is the terminology I use:

  • 1 hdot = ~70ns = 1/14.318MHz = 1 pixel time in 640-pixel mode
  • 1 ldot = 2 hdots = ~140ns = 1/7.159MHz = 1 pixel time in 320-pixel mode
  • 1 ccycle = 3 hdots = ~210ns = 1/4.77MHz = 1 CPU cycle
  • 1 cycle = 4 hdots = ~279ns = 1/3.58MHz = 1 NTSC color burst cycle
  • 1 hchar = 8 hdots = ~559ns = 1/1.79MHz = 1 character time in 80-column text mode
  • 1 lchar = 16 hdots = ~1.12us = 1/895KHz = 1 character time in 40-column text mode

The wait state algorithm for the original IBM CGA is basically "wait 1 hchar, then wait for the next lchar, then wait for the next ccycle". That works out at between 3 and 8 ccycles depending on the relative phase of the CPU and CGA clocks. There are actually 16 possible relative phases (one for each of the hdots within the lchar at which the CPU cycle starts).

One relative phase has a 3 ccycle wait state and there are 3 relative phases for each of the other 5 possible wait state lengths (4, 5, 6, 7 and 8 ccycles respectively). 1+3+3+3+3+3=16. So the average wait state is (3+4*3+5*3+6*3+7*3+8*3)/16 = 5.8125 ccycles, but you might measure a different average depending on how your piece of code ends up synchronizing with the CGA clock.

In a way it's rather unfortunate because with a slight hardware modification I think the 1 hchar wait state could have been eliminated, making the average wait state about 3 ccycles shorter and roughly doubling the average speed of the CGA memory access.

Also unfortunately, "rep stosw" gives almost the worst possible wait state behavior. I haven't tried it yet, but I suspect that it would be possible to write CGA code that self-synchronizes to get the best possible wait states (though of course that would probably only improve performance on machines that were cycle exact with the machine that it was tuned for).

A third unfortunate thing is that the wait states are the same whereever the raster is on the screen - they aren't disabled during the retrace interval or anything like that. There's a good reason for that though - the CRTC continues to strobe through the CGA RAM throughout the overscan/retrace areas for dynamic RAM refresh - allowing the CPU access to the full memory bandwidth could result in loss of video RAM data, since the CGA doesn't participate in the system DRAM refresh cycles (which is a good thing, because otherwise all those wait states would propagate to the entire memory system).

Multifunction gates

Friday, September 28th, 2012



Inputs 74LVC1G97 74LVC1G98
0 0 0 0 1
0 0 1 0 1
0 1 0 1 0
0 1 1 1 0
1 0 0 0 1
1 0 1 1 0
1 1 0 0 1
1 1 1 1 0






Inputs Harut Marut
0 0 0 0 1
0 0 1 0 1
0 1 0 1 0
0 1 1 1 0
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 0



doitclient ported to Windows

Thursday, September 27th, 2012

In order to write my cycle exact emulator, I need to run a lot of little "experiment" programs on my XT to determine exactly how long various things take. But the machine is bulky and noisy so I'd rather not keep it in the living room. In Seattle I kept it in the workshop downstairs. In Cornwall I'll probably keep it in the garage. I also have a modern PC next to it which is on the network and can reboot the XT, start programs on it and collect the results.

So, in order to remotely run programs on the XT I ultimately needed a way to remotely run programs on the modern PC. I had VNC and remote desktop on the modern PC so I could use that at a pinch, but I really wanted an automatable method - i.e. a command I could run on my laptop that would cause another command to be run on the modern PC. Under Linux this would be easy, but both the modern PC and my laptop run Windows.

I looked at a couple of ways of doing this, psexec and at least one other that I don't remember, but everything I tried was rubbish - either too slow, didn't work at all, or ran in a context which didn't include my network drive mappings (which made it kind of useless for running a program I had just built locally). I thought about writing a simple TCP client/server app to do what I wanted, then I decided to check to see if anyone had already written such a thing. Of course someone has, and I was not entirely surprised (nor at all displeased) to find out that the someone was Simon Tatham. Unfortunately DoIt has one minor problem which made it impossible to use as-is for my scenario - the client part (the part that runs on the machine which dispatches the commands) is a Unix program. Fortunately it's a pretty simple C program and I was able to port it to run on Windows with just a few changes. Here's the port, with a binary, diff, modified source code and a Visual Studio project file.

I suppose I could set up some wireless serial connections instead of using a separate PC which would make this entire post redundant. It'd probably even save money in electricity bills in the long run. For now, though, I decided to work with the hardware I have.

Buying up the junk

Wednesday, September 26th, 2012






eBay private bids

Tuesday, September 25th, 2012








How to decide if a website is trustworthy

Monday, September 24th, 2012

Occasionally people will send me an email they have received or a link to a website they've heard about and ask me if it's genuine or a scam. Usually it's easy to tell, but sometimes (even for the savvy) it's actually quite hard. The example that prompted this entry was a program that purported to speed up your computer by cleaning up orphaned temporary files and registry entries. This is an area that's ripe for scams - a program that does absolutely nothing could still seem to be effectual through the placebo effect. Also, running such a program is a vector by which all manner of nasty things could be installed. Yet there are genuine programs which do this sort of thing, and slowdown due to a massive (and massively fragmented) temporary directory is certainly possible.

Here are some methods one can use to try to figure out if something like this is trustworthy or not:

  • Trust network. Is it trusted by people you trust to be honest and knowledgeable about such things? I've never used CCleaner myself (I just clean up manually) but people I trust (and know to be knowledgeable about such things) say it's genuine. Similarly, think about how you came to find out about a program. If it was via an advert then that lends no credence (scammers can place adverts quite easily). If it was via a review in a trustworthy publication, that's does lend some credence.
  • Do you understand the business model? CCleaner's is quite clear (a functional free program with paid support). The program that prompted this entry had a free version which just detected problems - fixing the problems required buying the full version. This business model seems just like "scareware" - the free program always finds hundreds of problems (even on a perfectly clean system) because its purpose is to convince people to buy the full version. Being honest would be a disadvantage! Even if the program starts out honest, there's a tremendous incentive to gradually become less honest over time.
  • Does it seem too good to be true? If so, it almost certainly is. (Though exceptions exist.)
  • Is there a way to verify it? Availability of source code is certainly a good sign - it's something genuine programs can do demonstrate their honesty. A scam almost certainly wouldn't bother, because anyone who could examine the source code would not be taken in by it anyway. Though of course, once this starts being a factor a lot of people look for, it'll start being gamed. As far as I can tell, that hasn't happened at the time of writing, though. I think I would have heard about it if it had.
  • What does the internet say about it? Especially known-trustworthy sites that the scammer has no control over. Remember that scammers can put up their own good reviews, but getting bad ones taken down is much more difficult. So if there's a lot of posts in different places by different people saying that it's a scam, that's a pretty good signal that it's bad (not infallible though - someone might have a grudge against the authors of the program for reasons unrelated to whether it does what it's supposed to).

The future of the past and the past of the future

Sunday, September 23rd, 2012



Scan doubler reverse engineered

Saturday, September 22nd, 2012


Soon after I got it, I tried to make it work with my CGA card, but couldn't get anything to display on my VGA monitor. I didn't have an oscilloscope then so there wasn't really much I could do in way of diagnosis (I do have one now, but I still haven't diagnosed the problem due to my XT being en route from Seattle to the UK). For debugging purposes (and just because I was really curious about how it works) I decided to reverse engineer the card to a schematic. Here is the resulting schematic.

Interestingly, it only uses half of it's 2Kb of RAM. There are four 1024x4 bit NMC2148HN-3 SRAM chips, but address line A9 of each chip is grounded, so only the first half of each chip is ever actually read to or written from. One might be inclined to wonder why they didn't use half the number of RAM chips. The answer is memory bandwidth: for each CGA pixel (i.e. at a rate of 14.318MHz) the card has to write a pixel to RAM and read back two. Each pixel is 4 bits, so that's an access rate of 229 megabits per second, which would be too fast for two such chips by a factor of two. So the solution is to increase the bandwidth by parallelization - it turns out that accessing 16 bits at each cycle is enough, but that means having four chips instead of two.

Most of the rest of the card is pretty straightforward - just sequencing the read and write operations in the right order to the different chips, detecting the hsync pulses for genlocking and parallelizing the input pixels. There is one bit which involves logic gates coupled by capacitors - this seems to be a clever hack to double the 14.318MHz clock to generate a 28.636MHz VGA pixel clock (I haven't simulated it because I can't quite read the capacitor values - I think I'll need to unsolder them to measure them). Technically such a clock doubling probably isn't necessary, since the left pixels could be emitted on the low half of the clock and the right pixels on the high (or possibly vice-versa) but maybe the logic delays cause the pixels to interfere, or maybe it was just easier this way.

Purpose of U90 in XT second revision board

Friday, September 21st, 2012

This is an expanded version of a post I originally made over at the Vintage Computer Forums.

My plan to write a cycle exact PC/XT emulator is not going to work as well as I had hoped if it turns out that the various revisions of the PC and XT that IBM made over the years turn out not to even be cycle exact with respect to each other. So I took a look at the differences between the revisions to try to understand if there would be any such differences.

One particularly interesting revision occurred between the first and second revisions of the XT - a whole new chip (U90) was added. The designers of the first revision board had the forethought to leave a space where a standard 14-pin 74LSxx TTL logic IC could be placed, so that revisions requiring extra gates could be made without completely redesigning the board. In the second revision this spare space is populated, but I wasn't able to find any information online about what that change actually did, so I compared the schematics between the first-revision technical reference manual I had, and the updated schematic in the March 1986 technical reference. The difference seems to be this:

In the first revision, input D3 to U88 is -S0 AND -S1 AND -LOCK AND HRQDMA. In the second revision, this is changed to (-S0 AND -S1 AND -LOCK AND HRQDMA) OR (NOT (-DMACS' OR -XIOW')) (U90 is 2-input OR gates, probably a 74LS32). In other words, this input is forced high when writing to the DMA controller registers (IO ports 0x00-0x1f: the 8237). The output Q3 from U88 goes through a couple more flip-flops to HOLDA (the hold acknowledge input to the 8237).

So I guessed that this is some logic to fix a race condition between the CPU and the DMA controller. I suspected that there was a rare situation where the CPU writes something to the DMA controller at the same time that a DMA access happens, the CPU and the DMA controller end up waiting for each other and the system locks up completely. Sergey (of Sergey's XT fame) confirmed it - the logic finds passive CPU cycles when DMA transfer is requested, puts the CPU in wait mode and activates the DMA controller using the HOLDA signal.

I guess that this lockup doesn't happen every time the DMAC is accessed during a DMA transfer or the machine would hang in something like 1 in 18 floppy drive accesses due to the DRAM refresh DMAs. So presumably some "harmless" DMAs will also get delayed by a bus cycle when they happen at the same time as a DMAC transfer. That suggests that it should indeed be possible for software to determine (without checking the BIOS) whether it is running on a first or second revision XT board. And, in turn, if I rely on a piece of software running in an exact number of cycles on one machine it may run in a different number of cycles on the other, at least if the DMA controller is accessed.

For the demo application I'm thinking of, this probably doesn't matter too much - the only time I'm planning to access the DMA controller is to initiate floppy disk transfers to stream in the next part of the demo, and those DMAs will occur at unpredictable times anyway (since the floppy controller has its own crystal). However, it might be interesting to try to write a piece of software that uses small timing differences like these to get all sorts of information about exactly what computer it's running on. As well as this U90 change, it might be possible to tell PCs from XTs by checking the cassette hardware, and it may also be possible to distinguish between many of the different variants of the 8088.