The problem is that it's dependant on a whole lot of other C++ classes, which I can't use with the PSP build of x86EMU. I'm also not that good with C++(Those vectors etc.), if it's at all possible to convert it to plain C. Looks like I have no choice to convert from Dosbox-X, which barely uses C++ in the code...
No need to use the whole thing - the bits you need are just the methods/members of CGASimulator and NTSCDecoder. Their only dependencies are Complex and Colour/Vector3 and it should be pretty straightforward and obvious what the equivalent C code would be for those. But if you do that you should end up with something similar to the DOSBox patch. For what it's worth, I grant UNLICENSE rights over the DOSBox patch insofar as whatever copyright I have over it (but if it's a derived work of DOSBox then I don't know who else might claim copyright on it).
No debugger needed: it's open source. Looking at it reveals that it will use mono CGA with PPI port 62 bits 4-5 reporting 01=Monochrome CGA (sets up mode 7h), 11=MDA adapter. 00h starts autodetecting CGA vs MDA. It first verifies the display RAM, then proceed to set the default mode&adapter: If the equipment word(which contains bits 4-5 of PPI62) has bits 4-5=11 then MDA(Mode 7), if it's 01h(different source at detection) then color 40x25(Mode 01h). Finally, in this case, it'll default to 80x25(Mode 3h). Finally it initializes video and should be detected as color CGA instead of Mono/Hercules card.
Hum, this sounds somewhat confusing to me...
There is no 'mono CGA'. CGA is always the 'colour adapter', even in a 'mono' setup such as in the IBM 5155, and its CRTC is always hardwired to the 3Dxh IO-range (CGA is not MDA-compatible at the hardware-level, only via BIOS/DOS routines).
EGA and VGA can be configured as 'mono' as well, using the 3Bxh IO-range, so they can be used together with a CGA card.
Note also that it is perfectly legal and common for a system to have both an MDA (or Hercules) and a CGA (or EGA/VGA colour) card side-by-side. On a real IBM PC and many clones, there would be a dipswitch or jumper to select which card to boot up with. Using the 'mode mono' or 'mode co40/co80' commands would switch the display on-the-fly at runtime (DOS can only output to one screen at a time).
Using custom software, it is possible to drive both displays at the same time.
Well, I've adjusted the bits in PPI port 62 bits 0-1(The ioports.lst of Bochs has the nibbles of that port reversed if I look at what the Turbo XT BIOS does(reverse the nibbles before processing) and Bochs' ioports.lst reports the data in AX after the BIOS has swapped the low and high nibbles.
The Turbo BIOS processes it like this:
Bits 0-1: Video adapter
Bits 2-3: Number of floppy drives (minus 1).
Bits 4-7: Memory installed
The ioports.lst documents the following:
Bits 0-3: Memory installed
Bits 4-5: Video adapter
Bits 6-7: Number of floppy drives (minus 1).
).
Is this an error in ioports.lst or simply an error in the Turbo XT BIOS (doubt that though, since it works on real IBM PCs)? I currently have it implemented so that the Turbo XT BIOS reads the first set of values (essentially ioports.lst nibbles swapped in those values. Any values written to it will overwrite that value though).
The "Mono/Hercules graphics" adapter it detected was because the format was still reversed back then (So it was reading the floppy drives and VGA as value 0xF and memory as 0x1, so it took the floppy disks as the correct value, but since the adapter bits were placed (after processing it, reversing the nibbles) at the wrong nibble, it used value 3(bits 0-1 of the original register, which were both set by default(it was setting bits 4-5 to the Adapter emulated), which resolves into a Monochrome Display Adapter(MDA) being detected. This causes the reads from port 0x3BA(MDA) instead of 0x3DA(CGA)). If the hardware isn't emulating it at that address, the BIOS will hang (It will wait forever for bit 0 of port 3BA to clear, but since it doesn't exist(no MDA adapter emulated with those settings) it will loop forever). The same would happen when emulating a CGA (but with port 3DA).
The MDA and CGA emulation (except for the CRT emulation shared by all adapters emulated and the CGA timing registers shared by the MDA and CGA emulation(same structure and location in memory, they're based on each other after all(as far as I know the MDA is based on the CGA(or at least the CRT chip used is the same), since it was made at a later point in time, as a cheap version of the CGA?))).
The CRT timing processing is handled in the VGA core module (It just handles basic stuff required for display like horizontal and vertical timings and basic output capability (Text vs Graphics modes, although the CGA only uses two of three VGA Graphics modes(The modes for serial pixels(monochrome graphics mode 6h) and Interleaved Shift(modes 4h/5h) are used. 8-bit color mode is essentially unused.) Further the text mode of the VGA is used in CGA mode as well to provide 8x8 character display, although instead of retrieving it's pixels from the plane 2 lookup table(which is reversed and padded to 32 lines) it uses a lookup table generated when the VGA is initialized, which essentially is a simpler plane 2(No attribute bit 3 character set handling) handler which always retrieves it's data from the 8-line CGA or 14-line MDA(depending on the emulated adapter) lookup table)).
I've implemented the Dosbox-X "update_cga16_color(void)" function in my emulator(pretty simple to implement: just remove the <> to int typecasts(replace with (int) typecasts) and replace the registers accessed at the start of the function with the actual VGA registers. Then only some handlers to handle RGB vs NTSC generation and a function to be called to call the update_cga16_color function when the attribute colors have been updated(or the RGB vs NTSC and/or New CGA option is changed to reflect the change in rendering)). This will now generate graphics like a CGA should, but I notice that the display is still a bit strange, even the overscan itself has vertical lines passing through it?
The attachment Snap 2016-03-31 at 14.12.52.png is no longer available
Also I notice that the screen resolution is aparently constantly changing now(with that screen active): Even when minimized Windows 10 keeps screaming with it's blinking orange icon, that it's changed the window (SDL_setVideoMode being called too much).
Also, for some reason, since implementing the new CGA/MDA displays, it started becoming unresponsive(or immediately exiting the Direct Input mode upon access) to the Direct Input mode mouse buttons (Both middle mouse button and Both mouse buttons combination), maybe because of the constant display changing? When I do set the video mode to 4:3(800x600) or enter the BIOS Settings menu, the middle mouse button works without problems.
Could this be because I've made an error in my handling of CGA pixels? It currently performs the following steps:
1. Render individual pixels to a one-line display buffer (current line).
2. Upon horizontal total(end-of-line has been rendered), it calls the convertion procedure to convert the CGA pixels(which have attributes ranging from 0x0 to 0xF(4-bits values) buffered in the one-line buffer instead of normal display memory(memory used by the GPU of the emulator to resize to the window according to the BIOS Settings)) to NTSC/RGB output.
3. The conversion function checks the current conversion method(Set in the BIOS Settings menu). If it's RGB it calls the RGB conversion function. If it's NTSC it calls the NTSC conversion function.
3.1. The RGB conversion function simply takes the pixels, converts the 4-bit attributes to normal RGB values and plots them on the output buffer.
3.2. The NTSC conversion function also takes the pixels and converts them into RGB values like the RGB function, but uses the lookup table (8-bit index) createn by update_cga16_color() to translate it into RGB values instead.
4. Finally, the VGA rendering plots the outputted converted line(which contains either the RGB or NTSC output, depending on the function called in the previous step) to the GPU's display buffer.
The RGB method just uses a simple conversion to RGB by a 16-color lookup table(which is also used by the GPU text surfaces for displaying stuff like the BIOS menu in the right colors, as well as the OSK and other informational text on the screen, like the framerate, CPU speed and debugger. The 16-color lookup table itself is just a direct map to all 16 CGA RGB colors(taken from wikipedia)).
The NTSC method also converts by using a table, but it uses the table generated by the update_cga16_color() function. The index into the table for a given pixel is currently "(x<<4)|attribute". Although I didn't find it used anywhere in the Dosbox-X's video emulation source code, I did find it's used in the code for recording using ffmpeg? I've created the lookup table index by simply looking at how the table was generated. Anyone can confirm this formula or knows the correct formula?
Is this an error in ioports.lst or simply an error in the Turbo XT BIOS
This isn't standardized - different motherboards have different ways of reading the switches (it's a contract between the BIOS and the motherboard, so software compatibility is not affected). PC 5150 is different from XT 5160 here. From the name, presumably Turbo XT BIOS needs the switches to work like the ones on the 5160 motherboard.
superfury wrote:
a function to be called to call the update_cga16_color function when the attribute colors have been update
This isn't needed with the latest CGA composite simulation (required to get accurate colours in 8088 MPH). Does DOSBox-X have this code yet? (DOSBox SVN does). You can tell because the latest version has a 256 element table called chroma_multiplexer and the older one doesn't.
superfury wrote:
Also I notice that the screen resolution is aparently constantly changing now(with that screen active): Even when minimized Windows 10 keeps screaming with it's blinking orange icon, that it's changed the window (SDL_setVideoMode being called too much).
Doing that on real hardware would be quite the trick (write a port, change the physical size of your monitor) 😀
Well, other emulators change the size depending on it's input (In my emulator the Windows Forced mode). It simply makes the size of the window the size of the emulated display(which can change depending on retrace signals). The keep aspect ratio option adds the function to keep the aspect ratio the same (instead of converting to 1:1 aspect ratio of CRT output). The 4:3 aspect ratio converts to 800x600(4:3) aspect ratio. It's currently the only mode that specifies a window size (besides the Automatic&Disabled modes specifying a window size of 480x272(PSP screen resolution)). When Forced is used with the Fullscreen rendering on the PSP it will use a simple direct plot of displayed output 1:1 on the PSP screen, but anything past 480 pixels wide or 272 pixels high is cut off(essentially it's not rendered to the PSP screen at all, as it's out of range of the display viewable by the user of the application).
superfury wrote:The ioports.lst documents the following:
Bits 0-3: Memory installed
Bits 4-5: Video adapter
Bits 6-7: Number of floppy drives (m […] Show full quote
The ioports.lst documents the following:
Bits 0-3: Memory installed
Bits 4-5: Video adapter
Bits 6-7: Number of floppy drives (minus 1).
).
This seems to correspond mostly with the 5150/5160 switches: http://www.rci.rutgers.edu/~preid/pcxtsw.htm
How the switchblock is actually wired to the hardware, I do not know. Chances are, they map the bits 1:1 to a byte on a single I/O port.
That would mean that only bits 2-3 are for memory installed, and the first two are for FPU and boot options (funny how the XT doesn't seem to boot to BASIC on the first switch).
superfury wrote:
(doubt that though, since it works on real IBM PCs)
This may be an area where each clone does things slightly differently, and uses a slightly modified BIOS. At any rate, it seems the Turbo XT BIOS is very common with emulators, so if you make your emulator work with that BIOS, it should be fine.
superfury wrote:
The MDA and CGA emulation (except for the CRT emulation shared by all adapters emulated and the CGA timing registers shared by the MDA and CGA emulation(same structure and location in memory, they're based on each other after all(as far as I know the MDA is based on the CGA(or at least the CRT chip used is the same), since it was made at a later point in time, as a cheap version of the CGA?))).
CGA and MDA were both available since the launch of the IBM PC 5150. They use the same MC6845 chip (or a clone), but take note: MDA runs with completely different timings.
CGA takes its clock signal from the ISA bus, and is therefore in sync with the CPU and PIT.
MDA has its own 16 MHz crystal on the card and runs asynchronously from the rest of the system. MDA also runs at 50 Hz refresh rate rather than the 59.92 Hz of CGA (progressive scan NTSC). And MDA uses 9x14 (instead of 8x8) characters, for an effective resolution of 720x350, rather than 620x200.
Last edited by Scali on 2016-03-31, 16:05. Edited 1 time in total.
Well, other emulators change the size depending on it's input (In my emulator the Windows Forced mode). It simply makes the size of the window the size of the emulated display(which can change depending on retrace signals).
So what happens if I generate a signal that doesn't have a vsync pulse at all? I do actually have an effect that does that (deliberately). It didn't make it into 8088 MPH, but may be part of a future demo. On a real CRT, there is a natural retrace frequency (a little slower than 60Hz) which is what you get without vsync pulses. Also on a real CRT, you can skip every other hsync pulse with no ill effects - that is something else that I might use in a future demo. On your emulator it sounds like this would make the window twice as wide as it should be.
Anyway, I guess the symptom you're seeing means that your logic for translating from sync pulses to window sizes is faulty - all the effects in 8088 MPH have 15.7kHz hsync and 60Hz vsync like normal CGA. This might be interrupted briefly during a transition from one effect to another, but that's something your emulator should handle since it will happen with any mode change anyway.
Look at the CGA composite thread to see when it was committed, but you can definitely find the code just by looking at the DOSBox SVN repository as of now.
I'm currently implementing the PCEm-X version at https://github.com/OBattler/PCem-X/blob/maste … /vid_cga_comp.c . It seems to have those chroma variables you spoke of. I do need to remove and convert those *cga pointers and replace with my VGA compatibility variables though.
Also, is this a good time to shout: BORDERS!? 😀
I am pretty appalled by the fact that no PC emulator seems to emulate a border around the screen.
People who've only used LCD screens may not be familiar with the concept, but CGA/EGA/VGA, like most other computers of the era, are designed to include an overscan area next to the 'display area' (where your pixels are). The background colour in the palette includes this overscan area.
The border is there for two reasons:
1) The display area is rectangular, and CRTs have a somewhat oval shape. Without overscan, some pixels would fall off the side of the visible area (CRTs don't actually display the full NTSC/PAL signal, there's always something lost at the edges).
2) Because of various limitations on memory addressing and timing the video signal to the NTSC/PAL clock, there needs to be some 'slack space' to the left and right of each scanline, to sync up the pixels properly and center them on screen.
Anyway, this border is real, and is actually used by various games. For example, if you're hit in Wolfenstein 3D, the border will change to red colour to indicate this.
I don't know why I've never seen an emulator that has bothered to emulate this stuff. It should be obvious (emulators for other platforms do it, eg C64 and Amiga), but apparently it is not.
So what happens if I generate a signal that doesn't have a vsync pulse at all? I do actually have an effect that does that (deliberately). It didn't make it into 8088 MPH, but may be part of a future demo. On a real CRT, there is a natural retrace frequency (a little slower than 60Hz) which is what you get without vsync pulses. Also on a real CRT, you can skip every other hsync pulse with no ill effects - that is something else that I might use in a future demo.
To what extent would this be hardware-specific though? As in, would 'natural retrace' frequency vary depending on the monitor/TV used?
And when skipping hsync pulses, would some devices be more tolerant than others?
I guess devices that digitize the signal (LCD monitors/TVs, capture devices etc) would probably not be as tolerant as CRTs, and may not work.
To what extent would this be hardware-specific though? As in, would 'natural retrace' frequency vary depending on the monitor/TV used?
Yes, it will (and may vary with things like temperature as well). So you can only use it for effects where there does not need to be vertical coherence between frames.
Scali wrote:
And when skipping hsync pulses, would some devices be more tolerant than others?
I guess devices that digitize the signal (LCD monitors/TVs, capture devices etc) would probably not be as tolerant as CRTs, and may not work.
Yes, that's true. In my democoding I generally target a particular hardware configuration - I'm only interested in compatibility if I can get it without compromising performance of the demo on the target hardware.
Yes, that's true. In my democoding I generally target a particular hardware configuration - I'm only interested in compatibility if I can get it without compromising performance of the demo on the target hardware.
True, but you have to be able to capture it in some way to enter your demo in a compo 😀
As far as computers go, I agree that targeting a certain set of specifications that was reasonably common at a time, is plausible. Eg, a 5150/5160 with CGA and composite display. That's no different from 'a NES', 'a C64', 'an Amiga' etc.
But when it comes to '...and this specific TV connected to it', well, I think that's a bridge too far 😀
You could argue that if you make an effect on an IBM 5153, it's still sorta plausible, as most people will have had the 5153, if they had a CGA monitor at all.
But when it comes to '...and this specific TV connected to it', well, I think that's a bridge too far 😀
Agreed. I'm not targeting any specific TVs, though - in the case of these sync effects, any NTSC CRT should work. I'll try it on a bunch of different ones to make sure, but the nature of the oscillators in these beats is such that they can't turn on a dime - there's a narrow range of frequencies that they will sync to and if you miss too many pulses or the phase changes too much they'll just drift until they can lock on to the sync signal again.
Your question about overscan: that's already implemented since I built the VGA CRT emulation. Of course it's also present on the CGA(At the calibration screen it can be changed using space, It's also visible at the Intel logo screen if I remember correctly.
I've implemented the NTSC converter. It's configurable through the emulator BIOS Settings menu. Currently you can choose any of the four CGA combinations:
Old-style RGB
Old-style NTSC
New-style RGB
New-style NTSC
Old vs new style has effect on NTSC when used. Also some palettes differ in RGB Mode. Output CGA 16 colors are currently the same in both RGB Modes(Although mapped differently according to the pallette).
So far the NTSC conversion works. Still need to verify with 8088 MPH though, but normal text mode seems to work(Although the BIOS disables active display by setting the CGA Mode Control register bit 3 to zero, causing all output to be black(Although strange enough there's the gray blocks of the XT-IDE BIOS on top of the screen(I believe attribute 0x77). Normally it's in color, but it IS the CGA that's used, so why not 15 colors? The rest of the display is always black and the ms-dos CLS command doesn't do anything on the outputted screen, only in VRAM?
I don't think that's correct. In RGBI mode, old style and new style CGA should be exactly the same. The only difference is in the DAC ladder used for the composite output.
superfury wrote:
Normally it's in color, but it IS the CGA that's used, so why not 15 colors?
Artifacts would make text very unreadable in 80-column mode.
Aside from that, because of a design flaw, the colorburst signal is timed incorrectly in 80-column mode, making most displays lose sync (that's why we need a calibration screen in 8088 MPH, to find some settings that are 'close enough' for your display to accept the colorburst. These settings are different for every display, hence the need to calibrate at runtime, instead of using presets).
For these reasons, colorburst is disabled by default in 80-column mode, and effectively you're looking at a B/W videomode on composite (RGBI does not bother with the colorburst signal, so it is still in colour).
What I meant wasn't that RGB modes differs between old and new CGA. What I meant is that the palette itself is different in RGB mode vs NTSC mode. RGB mode has palette #3. NTSC mode doesn't have that palette.
What I meant wasn't that RGB modes differs between old and new CGA. What I meant is that the palette itself is different in RGB mode vs NTSC mode. RGB mode has palette #3. NTSC mode doesn't have that palette.
Okay, I thought you did, since you also listed old style RGB and new style RGB separately. There is no such thing.
I also wasn't sure what you meant with "Output CGA 16 colors are currently the same in both RGB Modes(Although mapped differently according to the pallette)."
The four options simply translate to a simple bitmap:
Bit0=NTSC(1) or RGB(0)
Bit1=New style CGA(1) or Old style CGA(0)
The NTSC vs RGB has effect on the palette (Palette 3 is enabled and used when set when in RGB mode only. Furthermore, NTSC and RGB select the translation used for translating pixels (0-F) to colours on screen(RGB) values using a simple 15-color lookup table(when selecting RGB) or the Composite translation that's now implemented(when selecting NTSC).
The New style vs Old style CGA currently only has an effect on the NTSC translation(according to new CGA changes).
I've modified the CRT emulation to render the frame to display (including screen captures when rendering to display) and to only render to display on vertical retrace (instead of the old vertical total), but the display during the Kefrens Bars keeps showing black frames. The part with the cube etc. 4 times (first quarter of the screen being correct, but only 1/4 height it's supposed to be).
The faces now show two times vertically, with the second time being displaced. The first row of heads shows correctly, but is cut off about a 1/4 to 1/2 the final head(I think it's the final head, the fifth head if I remember correctly). The same happens to the calibration screen as far as I can see.
Any screen capture made during the demo (using the emulator itself to create the BMP files) is filled with nothing but black pixels(RGB(0,0,0))? Captures with normal VGA are fine (exactly as displayed).
Also concerning old style and new style RGB, I just added those for future implementations. I don't know if there's any difference between Old Style CGA and New Style CGA when connected to a RGB monitor? I could make it a simple RGB mode if there's no difference between the monitors?
Also the flower girl displays twice horizontally and only half vertically (although the colors aren't correct since the pixels aren't in the right place)? You would get the same if you've taken the image, copied it twice horizontally (double the image), then cut off the bottom half of the image. That's what my CGA emulation(well, technically it's still the VGA rendering code, but modified for CGA) is displaying.
Also, the credits mess up big: It first renders the first frame correctly(displays correctly when the emulator is paused and resumed by opening and closing the BIOS Settings menu), but after that it keeps rendering the top line only until the credits end(Dos prompt should be displayed), after which the screen is again updated one final time. Then anything done at the Dos prompt (which isn't visible on the screen) doesn't change the displayed output.
The intel logo looks like it's skipping every 4 lines(lines divided by four). The 1K image does the same as the flower girl (double height, half width).
The 16/256 colors is half the vertical display height, with the bottom half showing duplicates of memory overflow? (Part of the end of the image(color circles)'s top right(about 1/4 part) at the bottom and the rest is the top left of the top 1/4 of the display)
The code used for configuring the CGA-on-VGA(Mode control register and Palette register) and MDA compatiblity(MDA Mode Control register):
1//Foreground colors: Red green yellow(not set), Magenta cyan white(set), Black red cyan white on a color monitor(RGB)! 2byte CGA_lowcolors[3][4] = {{0,0x4,0x2,0xE},{0,0x5,0x3,0xF},{0,0x4,0x3,0xF}}; 3extern byte CGA_RGB; //Are we a RGB monitor(1) or Composite monitor(0)? 4 5//Compatibility handling on both writes and reads to compatibility registers! 6void applyCGAPaletteRegisters() 7{ 8 byte i,color; 9 if (getActiveVGA()->registers->specialMDAflags&1) //MDA enabled? 10 { 11 //Apply the MDA palette registers! 12 for (i=0;i<0x10;i++) //Process all colours! 13 { 14 color = 0; //Default to black! 15 if (i&0x8) //Bright(8-F)? 16 { 17 color |= 2; //Set bright attribute! 18 } 19 if (i&0x7) //On (1-7 and 9-15)? 20 { 21 color |= 1; //Set on attribute! 22 } 23 switch (color) //What color to map? 24 { 25 default: 26 case 0: //Black=Black! 27 case 3: //Bright foreground=Bright foreground! 28 break; 29 case 1: //Normal on? 30 color = 2; //Bright! 31 break; 32 case 2: //Bright background! 33 color = 1; //Lighter! 34 break; 35 } 36 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.PALETTEREGISTERS[i].DATA = color; //Make us equal! 37 } 38 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.OVERSCANCOLORREGISTER = 0; //This forces black overscan! We don't have overscan! 39 } 40 //Apply the new CGA palette register? 41 else if (!(getActiveVGA()->registers->Compatibility_CGAModeControl&0x2)) //Text mode? 42 { 43 for (i=0;i<0x10;i++) //Process all colours! 44 { 45 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.PALETTEREGISTERS[i].DATA = i; //Make us equal! 46 } 47 if (getActiveVGA()->registers->Compatibility_CGAModeControl&0x10) //High resolution graphics mode(640 pixels)? 48 { 49 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.OVERSCANCOLORREGISTER = 0; //This forces black overscan! 50 } 51 else //Use overscan! 52 { 53 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.OVERSCANCOLORREGISTER = (getActiveVGA()->registers->Compatibility_CGAPaletteRegister&0x1F); 54 } 55 } 56 else //Graphics mode? 57 { 58 if (getActiveVGA()->registers->Compatibility_CGAModeControl&0x10) //High resolution graphics mode(640 pixels)? 59 { 60 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.OVERSCANCOLORREGISTER = 0; //Black overscan!
…Show last 167 lines
61 } 62 else //Low resolution graphics mode (320 pixels)? 63 { 64 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.OVERSCANCOLORREGISTER = (getActiveVGA()->registers->Compatibility_CGAPaletteRegister&0x1F); //Use the specified color for border! 65 } 66 67 for (i=0;i<0x10;i++) //Process all colours! 68 { 69 color = i; //Default to the normal color! 70 if (((getActiveVGA()->registers->Compatibility_CGAModeControl&0x14)==0x14) && (!CGA_RGB)) //Monochrome mode on NTSC only? 71 { 72 if (i) //We're on? 73 { 74 color = (getActiveVGA()->registers->Compatibility_CGAPaletteRegister&0x1F); //Use the specified ON color! 75 } 76 } 77 else //Color mode? 78 { 79 if (!i) //Background color? 80 { 81 if (!(getActiveVGA()->registers->Compatibility_CGAModeControl&0x10)) //320x200 graphics mode? 82 { 83 color = (getActiveVGA()->registers->Compatibility_CGAPaletteRegister&0x1F); //Use the specified background color! 84 } 85 else 86 { 87 color = 0; //Use black background! 88 } 89 } 90 else //Three foreground colors? 91 { 92 if (i&3) //Foreground color? 93 { 94 if ((getActiveVGA()->registers->Compatibility_CGAModeControl&0x4) && CGA_RGB) //B/W set applies 3rd palette on RGB monitor? 95 { 96 color = CGA_lowcolors[2][color&3]; //Use the RGB-specific 3rd palette! 97 } 98 else //Normal palettes? 99 { 100 color = CGA_lowcolors[(getActiveVGA()->registers->Compatibility_CGAModeControl&0x20)>>5][color&3]; //Don't use the RGB palette! 101 } 102 } 103 else //Background? 104 { 105 color = (getActiveVGA()->registers->Compatibility_CGAPaletteRegister&0x1F); //Background color! 106 } 107 } 108 } 109 if (!(getActiveVGA()->registers->Compatibility_CGAModeControl&0x10)) //320x200 mode has intensity switches? 110 { 111 color |= 8; //Default: display in high intensity! 112 if (!(getActiveVGA()->registers->Compatibility_CGAPaletteRegister&0x10)) //Display in low intensity? 113 { 114 color &= 7; //Apply low intensity! 115 } 116 } 117 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.PALETTEREGISTERS[i].DATA = color; //Make us the specified value! 118 } 119 } 120 VGA_calcprecalcs(getActiveVGA(),WHEREUPDATED_ALL_SECTION|WHEREUPDATED_ATTRIBUTECONTROLLER); //We have been updated(whole attribute controller mode)! 121 RENDER_updateCGAColors(); //Update the NTSC color translation if required! 122} 123 124void applyCGAPaletteRegister() //Update the CGA colors! 125{ 126 applyCGAPaletteRegisters(); //Apply the palette registers! 127} 128 129//useGraphics: 0 for text mode, 1 for graphics mode! GraphicsMode: 0=Text mode, 1=4 color graphics, 2=B/W graphics 130void setCGAMDAMode(byte useGraphics, byte GraphicsMode) 131{ 132 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.DATAROTATEREGISTER.RotateCount = 0; //No special operation! 133 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.DATAROTATEREGISTER.LogicalOperation = 0; //No special operation! 134 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.ENABLESETRESETREGISTER.EnableSetReset = 0; //No set/reset used! 135 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.WriteMode = 0; 136 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.ReadMode = 0; 137 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.OddEvenMode = 1; 138 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.ShiftRegisterInterleaveMode = (GraphicsMode==2)?1:0; 139 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.Color256ShiftMode = 0; 140 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.AlphaNumericModeDisable = useGraphics; 141 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.EnableOddEvenMode = 1; 142 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.MemoryMapSelect = ((useGraphics&&(GraphicsMode==2)) || (!useGraphics && (GraphicsMode==1)))?2:3; //Use map B000 or B800, depending on the graphics mode! 143 getActiveVGA()->registers->GraphicsRegisters.REGISTERS.BITMASKREGISTER = 0xFF; //Use all bits supplied by the CPU! 144 getActiveVGA()->registers->SequencerRegisters.REGISTERS.MAPMASKREGISTER.MemoryPlaneWriteEnable = 3; //Write to planes 0/1 only, since we're emulating CGA! 145 getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.S4 = 0; //CGA display! 146 getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.DCR = 0; //CGA display! Single pixels only! 147 getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.SLR = 0; //CGA display! Single load rate! 148 getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.DotMode8 = 1; //CGA display! 8 dots/character! 149 getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.OEDisabled = 0; //Write to planes 0/1 only, since we're emulating CGA! 150 getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.Chain4Enable = 0; //Write to planes 0/1 only, since we're emulating CGA! 151 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.AttributeControllerGraphicsEnable = useGraphics; //Text mode! 152 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.MonochromeEmulation = ((!useGraphics) && (GraphicsMode==1)); //CGA attributes! 153 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.LineGraphicsEnable = 1; //CGA line graphics! 154 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.PixelPanningMode = 0; //CGA pixel panning mode! 155 VGA_3C0_PAL = 1; //Enable the palette! 156 getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.COLORPLANEENABLEREGISTER.DATA = 0xF; //CGA: enable all color planes! 157 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.DIV4 = 0; //CGA normal mode! 158 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.DW = 0; //CGA normal mode! 159 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.SLDIV = 0; //CGA no scanline division! 160 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.DIV2 = 0; //CGA no scanline division! 161 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.UseByteMode = 0; //CGA word mode! 162 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.SE = 1; //CGA enable CRT rendering HSYNC/VSYNC! 163 //Memory mapping special: always map like a CGA! 164 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP13 = 1; //CGA mapping! 165 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP14 = 1; //CGA mapping! 166 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW = 1; //CGA mapping! 167 getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.RAM_Enable = 1; //CGA! 168 getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.OE_HighPage = 0; //CGA! 169 getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.HSyncP = 0; //CGA has positive polarity! 170 getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.VSyncP = 0; //CGA has positive polarity! 171 getActiveVGA()->registers->ExternalRegisters.FEATURECONTROLREGISTER.FC0 = 0; //CGA! 172 getActiveVGA()->registers->ExternalRegisters.FEATURECONTROLREGISTER.FC1 = 1; //CGA! 173} 174 175void applyCGAModeControl() 176{ 177 //Apply the new CGA mode control register? 178 if (getActiveVGA()->registers->Compatibility_CGAModeControl&8) //Video enabled on the CGA? 179 { 180 if (getActiveVGA()->registers->Compatibility_MDAModeControl&8) //MDA also enabled? 181 { 182 getActiveVGA()->registers->Compatibility_MDAModeControl &= ~8; //Disable the MDA! 183 } 184 } 185 if (!(getActiveVGA()->registers->Compatibility_CGAModeControl&0x2)) //Text mode? 186 { 187 if (getActiveVGA()->registers->Compatibility_CGAModeControl&0x1) //80 column text mode? 188 { 189 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.OFFSETREGISTER = 80; //We're 80 column text! 190 } 191 else //40 column text mode? 192 { 193 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.OFFSETREGISTER = 40; //We're 40 column text! 194 } 195 setCGAMDAMode(0,0); //Text mode! 196 } 197 else //Graphics mode? 198 { 199 if (getActiveVGA()->registers->Compatibility_CGAModeControl&0x4) //2 colour? 200 { 201 setCGAMDAMode(1,2); //Set up basic 2-color graphics! 202 } 203 else //4 colour? 204 { 205 setCGAMDAMode(1,1); //Set up basic 4-color graphics! 206 } 207 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.OFFSETREGISTER = 80; //We're 80 bytes per row(divide by 2)! 208 } 209 applyCGAPaletteRegisters(); //Apply the palette registers according to our settings! 210 VGA_calcprecalcs(getActiveVGA(),WHEREUPDATED_ALL); //We have been updated! 211} 212 213void applyMDAModeControl() 214{ 215 //Apply the new MDA mode control register? 216 if (getActiveVGA()->registers->Compatibility_MDAModeControl&8) //Video enabled on the MDA? 217 { 218 if (getActiveVGA()->registers->Compatibility_CGAModeControl&8) //CGA also enabled? 219 { 220 getActiveVGA()->registers->Compatibility_CGAModeControl &= ~8; //Disable the CGA! 221 } 222 getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.OFFSETREGISTER = 80; //We're 80 column text! 223 setCGAMDAMode(0,1); //Set special CGA/VGA MDA compatible text mode! 224 } 225 applyCGAPaletteRegisters(); //Apply the palette registers according to our settings! 226 VGA_calcprecalcs(getActiveVGA(),WHEREUPDATED_ALL); //We have been updated! 227}
Also, the credits looks like it's redrawing the first line only.
Edit: Fixed some scrolling issues (moving text top to bottom) by fixing the CGA Start Address being applied: It wasn't applied at all(VGA Line compare register was 0, thus it was forcing the Start Address to 0). I've applied the maximum line compare (0x3FF). Now the text is moving up and down(although still reduced to two-liners).
The 16/256-color part is now heavily shaking vertically. The text before the 3d objects(as well as the 3d objects part itself) is displayed 4 times vertically, with each part being shifted further to the left(and the next scanline following it). Is the offset register set in all modes correct(assuming the VGA is in Word mode with all other registers set to CGA text-mode compatible values)?
Running Microsoft Diagnostics shows the card is a CGA card. it also only has an active display of 36 characters(The bottom text line reads: "Press ALT for menu, or press highlig, with the final pixel(s) of "g" not seen. It looks like it's blanking or going into overscan at that point. The CGA Mode Control register's value is 8(So display enabled, 40x25 text mode).
Moving the mouse up and down makes it jump some lines up and down, jumping left and right at seemingly random spots. The upper-left corner seems to be around character 20,4 or 20,5? It's still in 40x25 text mode.
Finally(still the same running session) running edit.com(MS-DOS 5.0) reports a "DOS memory-arena error".
I seem to notice that most graphics/text modes keep inserting black scanlines in the active display?
Last edited by superfury on 2016-04-01, 18:44. Edited 1 time in total.