• Please review our updated Terms and Rules here

Project to create an ATX 80286 mainboard based on the IBM 5170

Thanks for the explanation. I went back and forth the past couple days between your posts and the 80286 hardware reference manual from intel to brush up on some of the details. I still don't have the full system understanding in my head but I can see lots of the suggested circuit diagrams for how to synchronize different signals - RESET and CLK, wait state generation circuits, things like that.. when using different discrete parts, every chip has its own timing specs. I can see how if one component runs faster or slower, the order can be changed and that might cause a lot of trouble, since different components' periods may be getting shorter but delays or propagation here or there might be static. I assume your REV A design was pretty similar to the suggested designs from intel, using 82C284/82288 etc and it sounds like the current CPLD designs started with essentially a lot of the same logic.

I was looking at the diagrams and it seems ARDY/ARDYEN and such are essentially contained entirely in the chipset, or CPLD in your case, and are not literal pins on the 80286 or ISA bus, so I wondered if a completely different design might be possible, since this logic is all self contained in the CPLD and does not need to necessarily match the same design anymore. It sounds like you talked about this as well though and have been making improvements.

I will refer back to the manual once in a while as I'd like to have a better understanding of some of the aspects of the 286 system design - especially asynchronous bus operation and wait states. However there's also a lot of extra stuff in there I don't need to worry about like multibus and multiprocessor stuff.

For an FPGA version of the design, would you be using modern FPGAs or something earlier? You mentioned BGA, which leads me to believe its not something too old. I don't know if there are design considerations (voltages, etc) that make modern FPGAs less desirable. I know you said you want to work on a 486 design, I would hope the AT/286 design provides a good starting point.

---

Oh yes, do let me know at which point you do need an EMS driver for our EMS design. I had somewhat forgotten about it amongst everything else going on, but I can probably prepare one in just a an hour or so of work, however the testing process might involve some back and forth so it doesn't make sense to get it ready until you are ready for it. I also understand if you aren't looking to work on it at the moment.
 
With the REV3D project basically the CPLD stage development of the project has been finalized.
I mean, the REV3D mainboard is fully functional in itself without needing too many modifications.
Basically only the transceiver going to the slower onboard IO devices needs to be bypassed.
I will create a modified version of the REV3D board design which has that transceiver removed, just to get a version out which would not need manual modifications.

In the mean time I am moving on in my process to continue the PC/AT project development with the FPGA stage now.
So I will be referencing this FPGA design stage as the REV4 design because it's basically a continued version of the CPLD designs except now using an FPGA.
The new system will again be based on the 286 initially. I was still encountering some level of compilation difficulties in the REV3D system controller which complicated the process to get forward with the system control development. Even though I already had stripped out the DMA arbitration and clock divisions and moved these to the address bus driver and IO decoder CPLDs, apparently still the logic of the system controller was getting cramped when working on new ideas. Each time when compiling a new version with even the slightest change, I will need to consider that quartus may be deciding to assign completely different logic in the chip which will introduce different timing that doesn't even function to get a full POST.

Hopefully we can get an FPGA system going so we can then really work on exploring the limits of 286 system control.
I doubt that I would be able to reach register limits when using a suitable FPGA chip.
And the logic speeds should be really fast so all decoding can be valid and stable on the clock transitions.
I also will look into using a faster clock input like 100MHz so we can increase the accuracy and resolution of the system control timing if needed.
The FPGAs also have more advanced clock management and support for clock multiplexing, and a lot more clock inputs and global clock distribution inside the chip so let's hope that this will all work out in our advantage to improve overall clock and signal timing.

Anyway, I am having ideas to generate completely custom clock wave shapes going to the 286. So any sensitive part of the 286 cycle will be able to be fine tuned.
The FPGA will be able to do much more advanced cycle type decoding and will be much more capable to apply programmed system control sequences.
I will definitely look into this in much detail, and I will also explore the resulting VHDL code that you can generate with quartus.
With so many registers and internal data storage the logic can start to become more and more like an actual program.
And we can use clocking mechanisms and super fast decoder gates to lock all the timings in, theoretically such types of mechanisms should be able to structurally run at much higher speeds.
This just feels a lot more "unlimited" than the CPLDs which pose a lot of challenges to create a complete PC/AT design.

We will include the IDE ports and LPT port inside the FPGA, this time we should be able to create an entire LPT port without any trouble with the OE functions.
Anyway, I will work on this and if quartus is able to compile it, that should be fine at least in terms of logic limitations.

So I will also be using the 286, which I am somewhat familiar with, to get started with using FPGAs in a PC/AT design.
So we will know that the 286 functionality is already covered, so the only remaining focus will be on getting an FPGA version created up to functional level.

Since the new design aims to integrate all the PC/AT logic and other system expansions inside a single FPGA, so this will need to be a chip with many pins available.
Of course I will again include a POST display output in the design. These LED displays use so little current, they can be directly driven by the FPGA pins without logic voltage changes.

For getting started to base a quartus project on and be able to compile the design, I selected the EP2C50F672C6 which is a Cyclone 2 generation chip.
I checked and this chip is available on ebay for a reasonable price from a Chinese supplier. The single chip will cost less than the combined price of the CPLDs and offers 100 times more capacity, if not more.

I already suspect that the chip is probably a little bit large and I will evaluate this again later. Also I will be doing tests creating a layout to find out how many PCB layers would be needed, which will be a factor.
I will need to look at buried vias and such which can substantially increase the trace density to be able to get out of the very dense direct chip area.
When having too much trace density the design may end up needing too many layers, I will need to get some example layouts created to get some more practical impressions of what would be involved in terms of PCB layers. Hopefully 6 layers are going to suffice. I would like to at least keep a very large amount of logic cells available for future development after the basic system functionality has been reached.
If trace density would end up being too high for the type of board I want to manufacture, I may scale down the numbers of pins, or I still may use a smaller adapter PCB which can be soldered on top of the mainboard just to get the connections out if this gets us around the issue of needing a very expensive board with many layers. If necessary we can get more creative in this area. The minimal requirement would be full integration of a PC/AT system in a single FPGA and I will actually like to realize a design with a lot of extra features and options.

With this design stage for example at the very least we will no longer need to use the external 74LS612 DMA page mapper chip, and we will no longer need external SRAM anymore for creating the EMS page register storage to do EMS address translation. The FPGA will be able to easily handle all the necessary page memory functions. Also since the FPGA will interface the memory to the 286, we are now able to select more modern types of memory of lower logic voltage types which are more suited to directly connect to the FPGA. It would be great if we can find some affordable fast memory type that can connect directly to this generation of FPGA and would be easy and fast to use.

Anyway I have a lot of stuff to sort out first for the FPGA design.
I looked around in quartus because there are a lot more options now with a FPGA and found that in the pin planner window that it's possible to choose the logic voltage per pin.
So the I/O voltage can probably be varied per group of pins which are using the same IO supply voltage pins.
I noticed that when changing pins to 3.3V IO voltage, the drive current is then also higher, 24mA. That would be an advantage, and 3.3V is a convenient voltage which is directly available from the ATX PSU.
In that case it would only be needed to create a core supply voltage of 1.2 V on the mainboard somehow.
Currently the quartus design project contains 221 pins in total after compilation, and the selected FPGA offers 450 IO pins.
Whether we can keep that number of pins and be able to use all of these also depends on the layout if we can succeed to connect the entire chip using 6 PCB layers.
As soon as I have sorted out more information and details, I will share everything here.
And of course the resulting designs will be shared on GitHub as well.

Kind regards,

Rodney
 
Thanks for the explanation. I went back and forth the past couple days between your posts and the 80286 hardware reference manual from intel to brush up on some of the details. I still don't have the full system understanding in my head but I can see lots of the suggested circuit diagrams for how to synchronize different signals - RESET and CLK, wait state generation circuits, things like that.. when using different discrete parts, every chip has its own timing specs. I can see how if one component runs faster or slower, the order can be changed and that might cause a lot of trouble, since different components' periods may be getting shorter but delays or propagation here or there might be static. I assume your REV A design was pretty similar to the suggested designs from intel, using 82C284/82288 etc and it sounds like the current CPLD designs started with essentially a lot of the same logic.
Absolutely right Patrick,

When using discrete parts that is the biggest problem and challenge that each part may have different timing. I also found differences between manufacturers in the timing of the same TTL chip. And using TTL logic, when needing large numbers of logic for more advanced ideas it will increase the board size a lot. Anyway, for sure a lot can be done with TTL chips however the total size of the board(s) will get bigger. It's just not really practical though also a kind of challenge of course. Anyway it's hard to tweak and modify for sure after building something.
So using a CPLD is one big step forward because gates inside the chip operate at the same speeds, however the compiler will create the design somewhat fluidly and putting logic into different constructions does change the actual timing. So it's never really ideal frankly and always a matter of testing, especially when the logic speeds are starting to run outside of the tolerable limits for the 286 to function, when raising the clock speed. Regardless there is at least a lot more logic inside a CPLD that can reduce the entire PCB size and it's much more flexible to reprogram it which is a very important point when working on designs.
If I had kept to TTL chips only, it would basically have worked out as a "build, test and be done with it" type of project and not anything like the project has now been able to become. Counting the CPLD revisions, that is hundreds or thousands of designs tested literally. Impossible with TTL.

Basically logic timing is fluid and uncertain, and using registers to time on the clock transitions is taking the system into more precise operation. Clocks are much more exact. For example the state machine is able to follow and predict the exact cycle in process inside the 286 and the outputs of the state machine are able to drive logic areas in the system controller. The state machine always transitions exactly on the 286 period clock, with one exception, the 286 initiating the new cycle is applied asynchronously because this does not occur exactly on the clock transition. We can actually say that the 286 status outputs are somewhat asynchronous, though they do appear in the same region within the period clock, just not following the transitions within that. For example the 82284 internally is using another period clock which is shifted into a delay for driving the logic which applies READY.

IBM created a really brilliant design in the 5170, after doing a lot of work on the 286 in the CPLD projects, and then going back to the old schematics, you really can say that they did really a lot with limited resources. Basically the design is a lot more advanced than you can make out from looking at the published schematic. When redrawing the diagrams in a more structured way the operation does become more clear. Like how they drew the shift registers it was really difficult to read the structure of the design with all the looped lines. Anyway I retain much respect for the 5170 design how they basically complimented the Intel 286 principles into a most practical and advanced computer system. And the whole industry basically started to develop from that initial concept so that was kind of a legendary start of professional productivity systems that could be mass introduced and integrated into our society. So the 5170 was really legendary and elemental. The initial circuits using TTL chips did run at a much lower speed in order to be able to function. When wanting to speed up that system it would become necessary to change logic types here and there to adjust for the faster timing. That could be a neat exercise to achieve this in such a way to go up to 16MHz or so.

Right, in the REV1 design I started out to replicate the 5170 concept first and get this operational. Just rebuilding and proving the 5170 design itself. So many system control circuits were integrated into the CPLD to reduce board space, initially still driving the 82284 and 82288 chips. Later I started more ambitious work to completely remove the 82284 and 82288 chips and recreate these inside the system controller. Thankfully the CPLD in the REV1 system was fully capable to support this work. Basically I recreated each system control signal one by one after first designing the state machine to predict the exact 286 operation so the system control can follow this.
So the REV1 got heavily rewired signal by signal to take each signal no longer as inputs to the CPLD from the 82284 and 82288 but instead the CPLD driving these signals as outputs instead.
So with each new signal recreated, the exciting moment followed to disconnect the 82284/82288 pin and drive that signal with the CPLD instead. Finally it all worked out and there was no longer the 82284 and 82288 needed on the mainboard. So I replaced the 82284 socket with a clock oscillator to drive the FCLOCK/286_CLK signal.

Simply put, the system control starts in decoding the scenarios to determine the wait state moments, then the wait states and IOCH_RDY are combined in a single point which also registers the cycle start moment, to generate timing and control using shifters driving the mechanisms, then the wait state timed READY time base is fed into a final stage to apply ready. So that final stage replaces parts of the 82284, and the initial combination stages were based on TTL chips and the U87 PAL logic in the 5170.

So we have these areas:

Primary ARDY logic:
- cycle start detection / driving the ARDY_n signal high
- wait state timing shifter driven by ARDY_n
- cycle type decoder creating END_CYC_n
- ARDY mechanism which combines IOCH_RDY and END_CYC, activating ARDY_n according to END_CYC wait states, or later if IOCH_RDY is lowered
The ARDYEN related process:
- conversion scenario decoder
- conversion timing shifter and decoding mechanism driving the ARDYEN_n signal
So these are the parts driving the "82284" or equivalent in the system.

ARDY_n and ARDYEN_n are then combined in a replacement for parts of the 82284 which take ARDY_n and ARDYEN_n to apply READY to the 286 at exactly the right moment in the final T_COMMAND cycle.
ARDY and ARDYEN are asynchronous to the CPU cycle so these inputs are taken together with other signals to decode the start of READY and apply READY in a synchronous timing to the 286.

So the READY application circuit consists of two parts:
- decoding and timing to initiate the qualified READY, delivering the READY conditions in a synchronized point of the cycle. (first half of final T_COMMAND, just before falling edge of 286_CLK.
- READY output shifter to hold READY for exactly two 286_CLK cycles, starting mid final T_COMMAND, exactly on the falling edge of 286_CLK.

Remember, when ARDY and ARDYEN are being decoded and applied, the command is already activated on the bus, which then also drives END_CYC wait state decoder.
END_CYC consists of several situation decoders and a final "terminate all cycles" input from Q4, which activates END_CYC at the latest after 4 wait states.
So in the chipsets when they extend the wait states from 4 to 5, they are basically also shifting the END_CYC equivalent operation one period clock further.
 
Last edited:
I was looking at the diagrams and it seems ARDY/ARDYEN and such are essentially contained entirely in the chipset, or CPLD in your case, and are not literal pins on the 80286 or ISA bus, so I wondered if a completely different design might be possible, since this logic is all self contained in the CPLD and does not need to necessarily match the same design anymore. It sounds like you talked about this as well though and have been making improvements.

Basically the principle of what needs to happen is always the same with the ISA slot VGA cards. The wait state timing needs to be established and applied, IOCH_RDY needs to be monitored, the conversion mechanism needs to take place, the READY pre-conditions need to be decoded and stored when they occur, and READY needs to be applied to the 286. In addition, the ARDY timing is very critical as well. With CPLDs there are not many alternatives to get these things done possible, I have tested many circuits and ideas and this is not really reliable enough because the logic is too slow.

I was successful to replace the conversion mechanisms with alternative circuits but then the logic ran out in the CPLD.
So I could not take this idea to another level yet.

The interaction between IOCH_RDY and END_CYC to create the starting point of applying READY will always be necessary.
You are absolutely right, how to handle this can 100% surely be done in other ways however this needs some really fast logic.

Definitely I can tell from experience, when the timing of READY is off or IOCH_RDY is not handled, this will result in a non POST situation or POSTing until various levels and if booting, then lots of glitching on the screen may occur and also freezing.

Using CPLDs is definitely not a good idea to try to establish more advanced system control, they are just too slow and especially limited in capacity.
If there were enough logic cells, something could be invented to compensate for other shortcomings of the CPLD but this combination of speed and limited logic just kills the ideas really.

In the FPGA stage I will revisit everything and create more structured and solid mechanisms which only an FPGA can support.
And I will create custom clock bitstreams for each cycle type that will be fed to the 286 clock input.
So then we do away with the whole wait state Q1-Q4 and similar shifter idea entirely and just create custom clock signals for all scenarios.
Just for example. If the clock phase is taking longer time, the 286 will wait longer which allows slow IO and memory to keep up.
The 286 does everything based on the clock transitions, and not based on time, which makes the 286 very flexible to adapt a system around it.

Quartus can do a good job as long as enough logic cells are available to build what you designed.
Definitely the wait state, conversion, IOCH_RDY and READY handling is really elemental on how fast a 286 will be able to be clocked.
Also the command generation, ALE, data bus speed and direction switching will be important to need to be able to handle the speeds.
Finally the memory needs to be fast but that also greatly depends on how well the memory is driven with exact timing when the data is solid for the transfers to and from the 286.
SRAM is definitely the best because it's a more simple process to setup the address states and do the transfer at some time after the address is able to be registered by the SRAM.
This time could be experimented with to reduce it and thus shorten the cycles.
Advanced work which we can do in the FPGA stage could involve tweaking of the cycle lengths, shortening it in places where we can, and extending where necessary.
That way with a tweaked cycle we can gain the maximum efficiency. Like for example using 100MHz clocks or higher as a basis and just creating a clock shape from those.
Each 100MHz bit you can take out will increase the effective processing speeds of the whole system.
And maybe if certain cycles are internal to the 286 only, if you can detect this and speed them up, maybe that can also yield more efficiency for register based operations.
Anyway that will border on crazy, but still cool to think of these ideas!

The key to getting the fastest but still solid 286 system is to be able to tweak each area in the cycles with high precision.
Then you can determine the optimal timings simply by testing.
An FPGA should be able to provide this, so I will experiment with this a lot as soon as I have a full operational system created.
Like at first just replicate the REV3D system controller to allow the system to function and test, and then I will just completely rewrite the system control logic into the most ideal concept.
I have a lot of ideas for this and I will share them in every detail here as soon as I can work on this in the future.

I am also thinking of other weird "impossible" experiments like interfacing a PCI VGA card with the 286.
This should theoretically be possible using a kind of "reverse conversion" similar to an XT PC controlling a 16 bit IDE drive with the XT-IDE principle.
Basically that is very similar to exchange data between different bit widths.
Though it may require some BIOS code rewriting and such to get the BIOS to work on a 286 CPU for starters.
Besides this the PCI bus would need to be handled in a minimal way so the VGA controller could be able to receive screen and control data and send status and data back.
This could maybe happen by doing some kind of modifications to drive signals on the PCI slot just to get the VGA controller operational.
Anyway just crazy ideas for now, it would take a lot of research.
I have not taken any time yet to look at the PCI slot in detail.

Kind regards,

Rodney
 
Last edited:
I will refer back to the manual once in a while as I'd like to have a better understanding of some of the aspects of the 286 system design - especially asynchronous bus operation and wait states. However there's also a lot of extra stuff in there I don't need to worry about like multibus and multiprocessor stuff.
Maybe some day I will find the time to create a complete and structured schematic of the equivalent of the 5170 or the REV1 which would include the system control logic and everything in a single PDF diagram.
When structuring the logic together it can make much more sense and it's more easy to go back and forth between circuit areas to see their relation.
When you can look over everything several times, the operation becomes more clear.
Especially the "multi purpose" circuits are a little confusing.
And when reading the circuits, you also have to remember the timing and sequence of each signal, what signal becomes active at which part of the cycle.

For an FPGA version of the design, would you be using modern FPGAs or something earlier? You mentioned BGA, which leads me to believe its not something too old. I don't know if there are design considerations (voltages, etc) that make modern FPGAs less desirable. I know you said you want to work on a 486 design, I would hope the AT/286 design provides a good starting point.
A very good question Patrick. I was writing my FPGA related post while you also posted your thoughts.
I have given this a lot of thought and did a few test compiles of the initial first "complete" PC/AT logic to see if the chips would be capable.
Newer FPGAs cannot do it easily because they are more focused on differential IO pins which take two pins per signal to increase the speed.
So I went for the "Cyclone 2" generation chips which quartus supports and are still available to buy from Chinese sellers.
These chips are really starting to offer FPGA level logic sizes and pin numbers, but still with single ended IO being possible on 450 pins, for example.
Just ideal for a PC/AT except the logic voltage which needs to be converted to interface with the 5V 286 and slots etc.

Certainly the 286 will offer the perfect FPGA entry point to get started. The FPGA in return should be able provide the most advanced system control possible.
Using a large and fast FPGA, it seems doubtful that another new stage would become necessary after that to get to the ultimate speeds possible.
I will look at the board space involved to create a 286 system with that level of integration, which should be able to become smaller.

So definitely I will start off with the earlier Cyclone 2 line of FPGAs and not the latest ones to determine if these will be sufficient for the development efforts.

Oh yes, do let me know at which point you do need an EMS driver for our EMS design. I had somewhat forgotten about it amongst everything else going on, but I can probably prepare one in just a an hour or so of work, however the testing process might involve some back and forth so it doesn't make sense to get it ready until you are ready for it. I also understand if you aren't looking to work on it at the moment.

Thanks Patrick, I do want to take the EMS on at some point and basically the bulk of other work on the REV3D is somewhat completed.
So I would appreciate it when possible to start testing your EMS driver that you have in mind.
But I don't want to disturb your time you want to spend on RealDOOM, I realize it's still a lot of work.
Though needless to say, running RealDOOM on the REV3D will be a huge cheer here when this is finally able to happen!

Basically I only need to restore the logic into the EMS controller, add the SRAM modules and then we could start testing.
A INIT stage programming sequence may be needed to set the default values in the page registers for not mapping initially as EMS.
I also could use a jumper initially to prevent the EMS to interfere with the normal SRAMs until the driver is able to initialize.
Or we could use some IO register bit to enable the EMS system when the driver loads. That would be more safe in any scenario and requires less work to accommodate.
Like you could write to a certain IO port and that can switch on the EMS system after the page register is fully programmed with the right values to get started.

Kind regards,

Rodney
 
First pass of the ems driver is SQEMM12.sys which can be found here:

As is usual with sqemm, this is not a full fledged EMS driver yet but should run RealDOOM. (There are actually a couple conscious decisions I made while writing the driver that are counter to the 4.0 spec but have better backwards compatibility. I will write about this some day)

Since I don't have this hardware I can't really test it of course. I might in the coming days try to modify the fantasy EMS device I created in martypc to more closely try and emulate the described behavior of this EMS chipset, then test against that.
 
I am also thinking of other weird "impossible" experiments like interfacing a PCI VGA card with the 286.
This should theoretically be possible using a kind of "reverse conversion" similar to an XT PC controlling a 16 bit IDE drive with the XT-IDE principle.
Basically that is very similar to exchange data between different bit widths.
Though it may require some BIOS code rewriting and such to get the BIOS to work on a 286 CPU for starters.
Besides this the PCI bus would need to be handled in a minimal way so the VGA controller could be able to receive screen and control data and send status and data back.
This could maybe happen by doing some kind of modifications to drive signals on the PCI slot just to get the VGA controller operational.
Anyway just crazy ideas for now, it would take a lot of research.
I have not taken any time yet to look at the PCI slot in detail.

Crazy! Well, there is this ISA card I have - I think it was only released in Japan, called the GA-DR2/ISA. It contains the Trident TGUI9660/9680 which are PCI only VGA chipsets. My understanding is it contains some ISA/PCI bridge chip. So anyway, in theory this kind of bridging logic ought to be possible. However they are probably filled with 386 instructions in the VGA bios too, so that part would have to be solved - I'm hesitant to believe any PCI VGA card is going to be 286 compatible out of the box (but we can dream). But it ought to be possible. I did want to port that Cirrus 5434 bios to work on 286, and that is a VGA chipset that also exists in PCI. Furthermore there are some other chipsets like Mach 32 which exist in PCI and ISA as well. I wonder if the 'bridge chips' were common in some other more boring type of application like dialup modems or high speed serial cards.
 
As is usual with sqemm, this is not a full fledged EMS driver yet but should run RealDOOM. (There are actually a couple conscious decisions I made while writing the driver that are counter to the 4.0 spec but have better backwards compatibility. I will write about this some day)
Right, I totally understand Patrick. Standards are one thing but the actual application in use is of course the most important reason for writing software.
I created the EMS function specifically for supporting RealDOOM of course so that's my primary reason to create that part of the design.
It's just cool if we can say that it runs RealDOOM!
I just hope that we have everything covered in the design but I checked everything several times.

I see the point about testing being a difficult procedure.
Let's hope that there will not be any complications either way.

So today I have started the work to update the CPLD programming logic to include the EMS functions.
The Address bus driver CPLD part is already updated and tested initially, and I am currently working on the EMS controller CPLD.

After that is all completed and I have tested that the system will not have any issues with all the EMS logic in place, I will solder the EMS modules in and it will be ready for testing.

If you have time, could you create a first simple test program?
Just for example:
- writing 00 to port EAh for all page index locations
- writing 00 to port EBh for all page index locations
- enabling the EMS system by IO writing any value to E9h which will switch the EMS system on. (my suggestion to use this way)

Writing 0 to bit 7 of EBh sets all the EMS locations to "default page" which maps them back to the XMS SRAM blocks.
So after running such a test write sequence, I will be able to verify if the EMS system is feeding back the "0=default page" information from the page register RAM for all memory blocks.

I can check whether the EMS enable register is activated by the write to E9h, which also would mean that the data read from bit 7 of page register RAM 2 is indeed feeding back into the conventional RAM decoding of the XMS memory chips. If the system then keeps running after enabling that register, it means that this part of the system is operational.

So after running this program, the system should keep operational and not freeze.
And I can use a CPLD pin to temporarily output the EMS enable bit from the "on switch" register so I can probe it with the scope and know the feedback signal to the XMS decoder is enabled and running for all memory blocks.

I could probe the EMS translated address lines coming out of the page register RAM 1 before and after clearing the page register RAM 1 data and this could theoretically change from noise to all zero outputs as the 286 continues to drive the address bits going into page register RAM 1 with different values so we can then probe the RAM 1 outputs.

It also depends on the noise theory after powering on an SRAM if that is indeed the case that the chip would contain random noise. For testing it would be cool if they do.

Like one test writing any value such as FF and then another test writing all 00 values.
This would allow to measure the page register RAM 1 output lines without yet enabling the EMS system.
So that would make three routines,
- writing all 00 values to EAh for all index positions
- writing a different value to EAh for all index positions for example 55 (the output lines will be always 01010101 during conventional memory access
- writing all 00 values to both EAh and EBh, and then also doing a single write to E9h to enable EMS
So the third test if the system remains stable afterwards that would be very cool!
These three tests seem really cool just to verify the SRAM translation if you could write some small routines for them.
If I could verify to see that happening it would already give me a lot of confirmation of things that work.

After a RESET, the EMS system is always disabled first so it doesn't influence booting the system and the MR BIOS counting up the RAM etc.
The two page register RAMs will retain their previous info after RESET since they are based on SRAM chips.

Kind regards,

Rodney
 
Crazy! Well, there is this ISA card I have - I think it was only released in Japan, called the GA-DR2/ISA. It contains the Trident TGUI9660/9680 which are PCI only VGA chipsets. My understanding is it contains some ISA/PCI bridge chip. So anyway, in theory this kind of bridging logic ought to be possible. However they are probably filled with 386 instructions in the VGA bios too, so that part would have to be solved - I'm hesitant to believe any PCI VGA card is going to be 286 compatible out of the box (but we can dream). But it ought to be possible. I did want to port that Cirrus 5434 bios to work on 286, and that is a VGA chipset that also exists in PCI. Furthermore there are some other chipsets like Mach 32 which exist in PCI and ISA as well. I wonder if the 'bridge chips' were common in some other more boring type of application like dialup modems or high speed serial cards.
Indeed, I will keep this idea in mind and go over the PCI slot operation.
If I have enough remaining pins to drive a PCI slot, I may include it on the mainboard purely for experimentation which would also be a great reason to do it.

Possibly we can view the VGA controller as a simple combination of mode programming and memory transfers, if we can facilitate interfacing those, it would go a long way if the actual BIOS that could do these operations could then be translated. It's some work involved, but the rewards in performance could be really cool!

I would really like to see some disassembly of how the VGA controller is initialized, and how the video mode is programmed, and how the screen RAM data is interpreted etc.
Basically this would also allow using VGA controllers for other types of systems.

Kind regards,

Rodney
 
I have written a summary of the EMS system operation, hopefully what I wrote is clear.

The Address bus driver CPLD does the EMS region decoding. At the moment it's basically all the 640KB conventional and UMB blocks D and E.
If a location is EMS capable, so within these areas, the EMS_RANGE_n output is activated and sent to the EMS controller.
So the EMS controller only responds to the EMS capable memory regions as setup in the Address bus driver.
And we need not concern if accidentally the page register RAM values are programmed in the BIOS segment etc. since these will be ignored.
In any region outside EMS blocks the decoders that cover these regions do not look at the "EMS default page" setting.

The EMS controller, if receiving a EMS_RANGE_n decode, directs the XMS/EMS selection.
If page register RAM 2 bit 7 is set high for any EMS capable memory block being addressed, the EMS controller disables the XMS decoder by raising the EMS_DEFAULT_n pin high, which signals that the block of memory should not be mapped to default XMS but will be handled in the EMS system.
register RAM 2 (EBh) bit 7 = 0 -> EMS_DEFAULT_n = 0 => XMS space used, default page condition.
register RAM 2 (EBh) bit 7 = 1 -> EMS_DEFAULT_n = 1 => EMS system used, non-default page condition.

There are 4 I/O-write only ports:
Port E8h - page index register (here we store the page number to be IO written to next via ports EAh and EBh)
Port E9h - EMS enable
Port EAh - IO write into page register RAM 1
Port EBh - IO write into page register RAM 2

Port E9h:
Any IO write to Port E9h turns on a register which enables the EMS system.
This enable is cleared upon system RESET.

Index register E8h:
Page memory blocks are completely sequential throughout the entire 1MB region.
So page index number 00h refers to the first 16KB in conventional RAM, 00000h - 03FFFh.
And index number 10h refers to the location 40000h-43FFFh in memory
Index 34h should refer to location D0000h to D3FFFh
And so on.
So then we cover all the segments in 6 bits of page index numbers, 64 page locations.
I think some shift right two bit operation could be used to convert the first 8 bits of any 20 bit memory location to the 6 bit index number that covers it.
But I may be wrong, anyway I think the page number can easily be found since all 16KB EMS memory location blocks are sequential.

EMS memory will not respond in ROM and VGA regions or above the 1MB boundary because these areas are not enabling the EMS_RANGE_n signal.
The page register index location for these regions can be programmed with values but this will have no effect since EMS is not enabled in those locations.
So this issue is protected from happening.

In the future we can test auto increments on IO writes to EAh or EBh by setting bit 7 of the index register high.
I have disabled the counter clock function for now until we are ready to test this after ensuring the basics are working.

So we have two page register RAMs available to IO write into using the indexing port.

Page register RAM 1(EAh) is used to program an 8 bit block number which selects one of the 256 pages from 4MB of EMS memory pool.
So this RAM, if EMS is enabled for a memory location below 1MB, translates the input page block address from the CPU into an output page block address within the EMS memory pool.
When the page register RAM chips are not being IO programmed into, they are constantly enabled and translating the address information.
There is no output enable involved.
When we IO write into the page register RAM chips, the write operation overrules the enabled outputs and the chip stores the values.
During IO write operations to the ports EAh and EBh, the page index register supplies the page number address selected to the page register RAMs.
The databus is directed to the page register RAM data lines when writing to EAh or EBh.
The two page register RAMs are written to in 8 bit IO writes.

Page register RAM 2(EBh) is available for storing configuration bits and expanding EMS memory pool capacity if needed.
And basically anything else we could think of.
EBh bit 7 is used to enable/disable the memory blocks from 0-1MB to be mapped into the EMS memory pool.
1 = the memory block is paged into the EMS memory pool according to the page number programmed into Page register RAM 1.
0 = the memory block uses its original power-on RAM location block in the XMS memory chips
So theoretically we have the original memory locations as default pages in addition to the 4MB of EMS memory pool.
For each 16KB memory location we have a separate "EMS DEFAULT" storage location in the XMS SRAMs
 
I have now programmed both the Address bus driver and EMS Controller CPLDs with everything necessary for EMS to theoretically be able to operate.
So today I took some time to sort this out more.

At first I decoded all IO operations to E9h to enable the EMS system however that got triggered by the BIOS I think when powering on the system.
Then as that happened this was actually useful to observe this, I could see the designated LED for EMS operation light up and I got a POST memory error, so that appears to be correctly interpreted as far as I could see from what happened. Also the XMS and EMS seemed to both get triggered which could mean random values in bit 7 of the page register RAM 2.

So I changed the logic to an actual IO write to E9h being needed to enable EMS and this was then no longer accidentally triggered.
If this is ever a problem we also can use more conditions such as a sequence of setting Index location 3F and then IO writing to E9h as the trigger, for example.
For now the IO write to E9h appears safe enough. The EMS system is inactive without the IO switch and the system is fully POSTing and booting without issues.
For now I am testing with 20MHz CPU clock which is all-round completely stable, even in Windows 3.1.
So if anything is affected I should be able to notice issues.

Tomorrow I will solder the EMS SRAMs to the board and then it should be theoretically possible to test the EMS system.

Patrick, if you feel you can just test the EMS with an actual driver, that would also be fine with me if this could save you some time.
We also can choose to test with some testing routines only in case there are any issues.

I really look forward to working on this, it's the last really major feature for the REV3D to support an SQEMM driver and run RealDOOM!
Thanks Patrick in advance for your efforts to help with this as soon as you can find the time, it's much appreciated!

Kind regards,

Rodney
 
Last edited:
Quick thoughts:

- One small issue, I need to add the E9h register EMS initialization step in the driver, its not hard though.
- I did not expect the default unmapped value would point to XMS chips instead of EMS chips. Actually, I don't think it is a problem because in my RealDOOM designs while I use the default unmapped memory space I treat it as 'unaliasable'.

I'll get you that test program soon, but meanwhile a helpful tool to get used to is the simple MS-DOS DEBUG program. Here's an example:

"O E9 FF" - Write FF to port E9 to enable EMS subsystem. (By the way is there a way to turn it off? Just on RESET?)
"D 4000:0000" - display/dump memory at location 4000:0000 (40000h)
"E 4000:0000 FF" - write FF to memory location 4000:0000 (40000h)
"O E8 10" Write 10h to port E8, select page for 040000h
"O EA 40" Select the page at the 1MB mark in the EMS memory
"O EB 80" Turn on the EMS page
"D 4000:0000" - display/dump memory at location 4000:0000 (40000h) - see if the page contents changed

etc
 
Here is a zip with "EMSSETUP.EXE" which is the specified test program above, writing 0 to all 64 page registers. And then there is an updated SQEMM12.SYS which basically does the same thing during initialization now.
 

Attachments

- One small issue, I need to add the E9h register EMS initialization step in the driver, its not hard though.
- I did not expect the default unmapped value would point to XMS chips instead of EMS chips. Actually, I don't think it is a problem because in my RealDOOM designs while I use the default unmapped memory space I treat it as 'unaliasable'.

Okay I see. Basically any type of operation after the init procedure writes would also be possible to detect.
Like for example writing an index value which is outside of the usable memory locations is also possible for me to detect this.
Just as an example. I just chose a write to E9h since it seems not to be used for anything else.
The EMS controller can monitor any IO port operation so if in the programming there would be a more convenient address to do a signature write to, that is also easy for me to change the logic to detect that and turn on the EMS system in the future. Also if it would be handy to turn the EMS off as well besides using a RESET, let me know and I can create that.
I just think we would not want this to accidentally happen while running RealDOOM that the EMS would go off.
Anyway, it definitely is possible to create that in the hardware to turn the EMS off.
Like for example when exiting the game. Just let me know if that would be good to have.

Right, unmapped means that XMS RAM is used in this area. For the CPU it won't make any difference if a block of memory comes from an EMS or XMS chip since this is also a usable block of memory space.

I'll get you that test program soon, but meanwhile a helpful tool to get used to is the simple MS-DOS DEBUG program. Here's an example:

"O E9 FF" - Write FF to port E9 to enable EMS subsystem. (By the way is there a way to turn it off? Just on RESET?)
"D 4000:0000" - display/dump memory at location 4000:0000 (40000h)
"E 4000:0000 FF" - write FF to memory location 4000:0000 (40000h)
"O E8 10" Write 10h to port E8, select page for 040000h
"O EA 40" Select the page at the 1MB mark in the EMS memory
"O EB 80" Turn on the EMS page
"D 4000:0000" - display/dump memory at location 4000:0000 (40000h) - see if the page contents changed
Very cool! I copied this into my EMS system notes and I can use this for testing new IO registers etc.

Here is a zip with "EMSSETUP.EXE" which is the specified test program above, writing 0 to all 64 page registers. And then there is an updated SQEMM12.SYS which basically does the same thing during initialization now.
Wow amazing, thanks Patrick!

I will get the modules soldered in and I look forward a lot to try this out!

Kind regards,

Rodney
 
Hi Patrick,

I have soldered two SRAM modules to the EMS memory connectors so we now have 4MB of SRAM connected to the EMS system as well.

I proceeded to test and found a few things that needed fixing:
The EMS_RANGE_n decoding needed to be added to the MEM_BUS_n decoder since this controls the memory data bus which also should enable when the EMS RAM is being accessed.
The page index register was non functional, I used some standard quartus counter/ register part, so I replaced that by creating a new page index register from D-flipflops.
Then I could indeed see the page index register output bit 0 pulsing when loading the EMS driver or EMSSETUP.EXE. So then the index register was fixed.

My next test was to initialize/clear the EMS page register RAMs and checking if this has happened.
I first measured EMS_A14 going to the EMS SRAMs from the page register RAM 1 output data bit 0 after a power cycle, initially this showed random activity coming from the CPU A14 line filtered though the random noise contents in page register RAM 1. After initializing the EMS system with EMSSETUP.EXE, indeed the output bit 0 from page register RAM 1 (EAh) going to EMS_A14 became low and remained quiet.
So far so good so we have confirmed that the EMS page register RAM 1 programming appears to be correct since that address line data coming out of page register RAM 1 becomes quiet since all contents of RAM 1 was cleared. So the output bit is always zero which is good.

However when loading the EMS driver, the system is freezing. I am not sure, after the EMS driver is loaded, should we then see activity on the EMS RAM since the pages are all disabled initially and no paging is activated by the driver yet? I believe I should not see the LED go on.

I am seeing that the EMS LED is lighted clearly on after loading the EMS driver so this means that the page register RAM 2 is apparently enabling the EMS_DEFAULT_n to be high which lights the EMS LED.
So this also means that EMS_DEFAULT is low(not default) and this disables the conventional memory SRAM decoder, and enables the EMS system to replace some location in memory with SRAM.
I am not sure on what memory area this is happening in however after loading the driver I cannot control DOS anymore with the keyboard.
I am seeing the DOS screen but it is not responding anymore.
My theory is that the page register RAM 2 is still containing some 1 values in bit 7 which is triggering an EMS page to be selected, however the page register RAM 1 contains all 00 values so the page 0 will be selected. So this page switch appears to freeze the system when some location(s) got swapped.

When I do a F5 boot to DOS prompt and run EMSSETUP.EXE this also lights the EMS LED dimly, however the system does not crash.
So some swap is happening but it's not affecting DOS directly in that case.
For some memory locations the EMS system still appears to be triggered by bit 7 of page register RAM 2 being on.

I am not sure what type of IO writes you programmed for clearing page register RAM 2 (EBh) however this should be at least an 8 bit IO write of value 00 to port EAh and also to port EBh as well for each index location before doing the E9h write to enable the EMS system.

So that's how far I have been able to progress with the testing.

I hope you can find something in the code where it's not clearing page register RAM 2?
I checked the logic in the EMS controller however this does not differ from the logic writing to page register RAM 1.

I will do more detailed probing on the page register RAM 2 outputs to see if there is any activity on bit 7, which I believe there is.

Kind regards,

Rodney
 
HMM ok. I am taking a look at the asm for initialization, I think its pretty straightforward. Maybe another pair of eyes can catch me having done something dumb.

Code:
RODNEY_PAGE_SELECT_REGISTER = 0E8h
RODNEY_EMS_ENABLE_REGISTER = 0E9h
RODNEY_PAGE_SET_REGISTER = 0EAh


  mov       cx, 00040h

  setdefaultpageloop:
  mov       ax, cx
  dec       ax  ; 040h to 1 loop translates to 03Fh to 0
  out       RODNEY_PAGE_SELECT_REGISTER, al ; page select
  xor       ax, ax
  out       RODNEY_PAGE_SET_REGISTER, ax    ; write word 0  to EA
  loop      setdefaultpageloop
 
  out       RODNEY_EMS_ENABLE_REGISTER, al  ; enable EMS subsystem after all pages set to 0

Of note we are writing backwards from 3F down to 0 in this loop to take advantage of the loop instruction and to use fewer registers.

I re-built the driver as SQEMM12a.sys (attached) just in case i mistakenly did not attach the correct version last time or something.
Then I made a second one named SQEMM12b.sys that doesn't initialize the registers, it just loads up the resident driver into memory. If EMSSETUP.EXE worked, then what you can try to run that manually after the driver has loaded and it should be equivalent.

I'll take a closer look at other parts of the driver to see if I might've caused this issue some other way.

EDIT: There is an implicit assumption here in my code that a WORD sized write of 0000h to port EA translates to also hitting EB with a byte 00h write. Is there a possibility this might not be actually happening?
 

Attachments

Can we write a module for 86Box which behaves exactly like your hardware does? That would make debugging the EMS driver a lot easier.

86box no,
MartyPC yes, more or less already exists. There's enough things just different in the implementation here that I haven't done it yet. If the application level (RealDOOM) has significant issues then it makes more sense to pursue.
 
Can we write a module for 86Box which behaves exactly like your hardware does? That would make debugging the EMS driver a lot easier.
86box no,
MartyPC yes, more or less already exists. There's enough things just different in the implementation here that I haven't done it yet. If the application level (RealDOOM) has significant issues then it makes more sense to pursue.

Thanks MennoJoshua for the suggestion and thinking along with us.

Thanks Patrick that is clear and makes sense of course since that would be more work.
Besides we are still working on the EMS system so the configuration may be changing resulting from the current work we are doing.

So I have taken more measurements of different internal signals in the EMS controller.
So the word IO write instructions in the code of EMSSETUP.EXE in your code example Patrick, that seems to be correctly handled by data byte conversion.
Since I have observed in a measurement that EBh is being cleared throughout the page register RAM 2 address range.
Regardless, after the clearing occurs, the bit 7 on EBh remains zero so the clearing is correctly happening as per your code.

Weirdly enough when I do a F5 boot to DOS and not loading any software, when I then press a key on the keyboard, I am seeing IO write pulses to port EBh.
So why does the CPU appear to be doing this? This is the big question here causing issues now.

I mean, I am doing a full decode of the IO write instruction, including IOW and SA9-SA0 port address, and I also included AEN_n which masks out any DMA cycles from the IO decoder gate.
Those pulses should of course not happen in our case because they will trigger a write from the data bus to EBh
And this in turn enables the EMS_DEFAULT_n to be raised high, which will enable EMS paging when that should not be happening.

I just confirmed the test by monitoring EMS_DEFAULT_n. So when I do a bare F5 boot and run EMSSETUP.EXE, this then clears the registers which seems to happen correctly.
So then I can measure EMS_DEFAULT_n being inactive right after running EMSSETUP.EXE which is correct, it's inactive.
However, as soon as I press a key, the system freezes when that write occurs to port EBh following the keypress which I was seeing, which then indeed starts activity on the EMS_DEFAULT_n signal that should not be happening. Subsequently, of course, the system freezes since some page of memory is being flipped to some EMS SRAM page which may contain random noise after power on.

So I am really wondering, why is the CPU doing IO writes to port EBh when I press a key on the keyboard?
Is MR BIOS doing this then?
I just did a test where I went into the MR BIOS menu, and using the arrow keys to go left and right through the menus of MR BIOS, and again I am seeing the IO writes to port EBh occurring.
Totally weird really.

I will do more testing while EMS_DEFAULT_n is temporarily disconnected from the XMS memory decoder so the memory function won't get disrupted while measuring IO port operations from the CPU.
I will also measure the IO writes to EAh just to see if that is also affected by the weird IO write pulses from pressing the keyboard.

So for now, we first need to track down why this is going on.
If it is an operation started by MR BIOS, which it seems to look like, we had better then change the port numbers to avoid the matter.
Rewriting the MR BIOS for example would be far more difficult than using a different port scheme.
I previously checked the PC port list and I did not see any listing for port EBh to be used.
I did see ports 00E0h-00E7h listed there as being used for Microchannel purposes.
The ports E8h, E9h, EAh and EBh are actually within the internal X-DATA bus IO range which is normally used for core AT controller IO, however since the SCAMP chip is also using these ports so we copied those port numbers. For the X-BUS when writing to this port it won't have any consequence since only during read operations the X-DATA bus transceiver would be reversed.
So as pure write only operations we would not need to be concerned if the writable data is placed on the X-BUS as well since nothing in the core AT controller chips is listening there to this port.
So both the X-DATA and S-DATA bus will carry the signals to be written and subsequently this is also working correctly inside the EMS controller.

However what the CPU should not be doing is those 200ns writes to port EBh of course.

I will try to find out more to see if anything to the other IO ports involved is written by MR BIOS.

Kind regards,

Rodney
 
Last edited:
Hmmm interesting. Do you have the link to which version of MR BIOS you are using? I can take a quick look at disassembling to see if i can find anything obvious.

Is it possible that there is some write to a higher numbered port like 1EB, 2EB, 3EB, or even 40EB, etc is having bits truncated off which is leading to it getting decoded this way? (I recall something about more than 10 bits to the port address often being truncated)

Changing ports is possible, its a little bit extra work in the driver to use a port that doesn't fit in one byte but I have done it with C&T SCAT and Intel Above Board and some other chipsets. If we have to change the ports then so be it, I can work on that over the next couple days when I find time.
 
Back
Top