Optimizing VGA rendering speed for emulator?

Pages: 12
I've made a VGA rendering system, which renders from the VRAM to a scanline on-screen (a PSP in this case). For some reason, it still runs pretty slow (about 1-2 frames a second max). The scanline rendering function is called 60 times the number of scanlines for rendering per second (depends on the system, with maximum of 768 visible scanlines on-screen (allowing for a maximum of a 1024x768 resolution)).

Can someone tell me how to make this faster? (I've based it on the freeVGA documents)

Btw the VGA_generateScreenLine function in vga_screen.c renders every line (called by a frequency generator I made myself, at 60*lines calls a second).

Next posts contain the files:
Last edited on
VGA.h: part 1: Contains all typedefs and constants for the VGA itself. Split in multiple parts, because of the huge size (3 parts).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#ifndef VGA_H
#define VGA_H

#include "headers/types.h"

//Emulate VGA?
#define EMU_VGA 1

//Plane 0 text mode: Contains character codes
#define VGA_PLANE0 0
//Plane 1 text mode: Contains text attributes
#define VGA_PLANE1 0x10000
//Plane 2 text mode: Contains font data
#define VGA_PLANE2 0x20000
//Plane 3 text mode: unused in text mode!
#define VGA_PLANE3 0x30000

//We're an VGA Architecture!
#define IS_VGA_ARCH 1

//4 planes of 64k totaling 256k (0x40000) of VRAM is a Minimum! Currently: 0x300000=1024x768x32;0x3C0000=1280x1024x24
#define VGA_VRAM_VGA 0x40000
#define VGA_VRAM_SVGA_1024_32 0x300000
#define VGA_VRAM_SVGA_1280_24 0x3C0000
//What size to use for a minimum: Should always be set to standard VGA.
#define VRAM_SIZE VGA_VRAM_VGA

//SRC for registers: http://www.osdever.net/FreeVGA/vga/vga.htm
//- Input/Output Register Information, before Indices.


//First, the registers:

typedef union
{
	byte DATA[8]; //8 registers present!
	struct //Contains the registers itself!
	{
		//Set/Reset Register (index 00h)
		union
		{
			struct
			{
				byte SetReset : 4; //Set/reset!
				byte notused1 : 4; //Not used
			};
			byte SetResetFull; //Full Set/Reset register!
		} SETRESETREGISTER;

		//Enable Set/Reset register (index 01h)
		union
		{
			struct
			{
				byte EnableSetReset : 4; //Set/reset!
				byte notused2 : 4; //Not used
			};
			byte EnableSetResetFull; //Full Set/Reset register!
		} ENABLESETRESETREGISTER;

		//Color Compare register (index 02h)
		union
		{
			struct
			{
				byte ColorCompare : 4; //Set/reset!
				byte notused3 : 4; //Not used
			};
			byte ColorCompareFull; //Full Set/Reset register!
		} COLORCOMPAREREGISTER;

		//Data Rotate Register register (index 03h)
		union
		{
			struct
			{
				byte RotateCount : 3; //Rotate count!
				byte LogicalOperation : 2; //Logical operation!
				byte notused4 : 3; //Not used
			};
			byte DataRotateFull; //Full Set/Reset register!
		} DATAROTATEREGISTER;

		//Read Map Select Register (index 04h)

		union
		{
			struct
			{
				byte ReadMapSelect : 2; //Active memory plane for CPU (at location for VRAM)!
				byte notused5 : 6;
			};
			byte ReadMapSelectRegisterFull; //Full register!
		}  READMAPSELECTREGISTER;


		//Graphics Mode Register (Index 05h)

		union
		{
			struct
			{
				byte WriteMode : 2;
				byte notused6 : 1;
				byte ReadMode : 1;
				byte HostOddEvenMemory : 1;
				byte ShiftRegisterInterleaveMode : 1; //Shift Register interleave mode (4 colors), else 4-bits (16 colors).
				byte Color256ShiftMode : 1; //1=support for 256-color, 0=Use Above bit.
			};
			byte GraphicsModeRegisterFull; //Full register!
		} GRAPHICSMODEREGISTER;

		union
		{
			struct
			{
				byte AlphaNumericModeDisable : 1; //1 for graphics, 0 for text-mode.
				byte ChainOddEvenEnable : 1; //1 for enabled, 0 for disabled.
				byte MemoryMapSelect : 2; //Where display memory resides in MMU:
				/*
				00b = A0000-BFFFFh (128k region)
				01b = A0000-AFFFFh (64k region)
				02b = B0000-B7FFFh (32k region)
				03b = B8000-BFFFFh (32k region)
				*/
			};
			byte MiscellaneousGraphicsRegister;
		} MISCGRAPHICSREGISTER;

		union
		{
			byte ColorDontCare0 : 1; //Plane 0 CDC
			byte ColorDontCare1 : 1; //Plane 1 CDC
			byte ColorDontCare2 : 1; //Plane 2 CDC
			byte ColorDontCare3 : 1; //Plane 3 CDC

			byte notused7 : 4;
		} COLORDONTCAREREGISTER;

		byte BITMASKREGISTER; //Bit Mask Register (index 08h)

	} REGISTERS; //The registers itself!
} GRAPHREGS; //Graphics registers!





//Sequencer Registers

typedef union
{
	byte DATA[5]; //5 registers present!

	struct //Contains the registers itself!
	{

		struct
		{
			byte AR : 1; //Asynchronous reset?
			byte SR : 1; //Synchronous reset?
			byte unused[6]; //Unused!
		} RESETREGISTER; //Reset Register (index 00h)

		struct
		{
			byte DotMode8 : 1; //8 Dots/Char? Else 9 Dots/Char!
			byte unused1 : 1; //Unused!
			byte SLR : 1; //Shift/Load Rate
			byte DCR : 1; //Dot Clock Rate
			byte S4 : 1; //Shift Fout Enable?
			byte ScreenDisable : 1; //Turn off display (Screen Disable)?
			byte unused2 : 2; //Unused!
		} CLOCKINGMODEREGISTER; //Clocking Mode Register (index 01h)

		struct
		{
			byte ModifyPlane0 : 1; //Modify plane 0?
			byte ModifyPlane1 : 1; //Modify plane 1?
			byte ModifyPlane2 : 1; //Modify plane 2?
			byte ModifyPlane3 : 1; //Modify plane 3?
			byte unused : 4; //Unused
		} MAPMASKREGISTER; //Map Mask Register (index 02h)

		struct
		{
			byte CharacterSetBSelect_low : 2; //Low 2 bits of select
			byte CharacterSetASelect_low : 2; //Low 2 bits of select
			byte CharacterSetBSelect_high : 1; //High bit of select
			byte CharacterSetASelect_high : 1; //High bit of select
			byte unused : 2; //Unused!
			/*
			Values for Character set A&B: (A is used when bit 3 of the attribute byte for a character is set, else B)
			000b: 0000h-1FFFh
			001b: 4000h-4FFFh
			010b: 8000h-9FFFh
			011b: C000h-DFFFh
			100b: 2000h-3FFFh
			101b: 6000h-7FFFh
			110b: A000h-BFFFh
			111b: E000h-FFFFh
			*/
		} CHARACTERMAPSELECTREGISTER; //Character Map Select Register (index 03h)

		struct
		{
			byte unused1 : 1; //Unused!
			byte ExtendedMemory : 1; //Ext. Mem
			byte OddEvenHostMemoryWriteAddressingDisable : 1; //Odd/Even Host Memory Write Adressing Disable
			byte Chain4Enable : 1; //Chain 4 Enable?
			byte unused : 4; //Unused!
		} SEQUENCERMEMORYMODEREGISTER; //Sequencer Memory Mode Register (index 04h)

	} REGISTERS;
} SEQUENCERREGS;


typedef union
{
	byte DATA[0x15]; //10h color registers + 5 registers present!

	struct //Contains the registers itself!
	{

		union
		{
			byte DATA;
			struct
			{
				byte InternalPaletteIndex : 6;
				byte unused : 2;
			};
		} PALETTEREGISTERS[0x10];

		struct
		{
			byte AttributeControllerGraphicsEnable : 1;
			byte MonochromeEmulation : 1;
			byte LineGraphicsEnable : 1;
			byte BlinkEnable : 1;
			byte unused : 1;
			byte PixelPanningMode : 1;
			byte ColorEnable8Bit : 1;
			byte PaletteBits54Select : 1;
		} ATTRIBUTEMODECONTROLREGISTER;

		byte OVERSCANCOLORREGISTER;

		union
		{
			byte DATA; //The Data!
			struct
			{
				byte ColorPlaneEnable1 : 1;
				byte ColorPlaneEnable2 : 1;
				byte ColorPlaneEnable3 : 1;
				byte ColorPlaneEnable4 : 1;
				byte unused : 4;
			};
		} COLORPLANEENABLEREGISTER;

		struct
		{
			byte PixelShiftCount : 4;
			byte unused : 4;
		} HORIZONTALPIXELPANNINGREGISTER;

		struct
		{
			byte ColorSelect54 : 2;
			byte ColorSelect76 : 2;
			byte unused : 4;
		} COLORSELECTREGISTER;

	} REGISTERS;
} ATTRIBUTECONTROLLERREGS;
Last edited on
VGA.h: part 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
typedef union
{
	byte DATA[0x25]; //25h registers present!

	struct //Contains the registers itself!
	{

		byte HORIZONTALTOTALREGISTER; //# of char. clocks per scan line
		byte ENDHORIZONTALDISPLAYREGISTER; //When to stop outputting pixels from display memory.
		byte STARTHORIZONTALBLANKINGREGISTER; //At which character clock does the horizontal blanking period begin?
		struct
		{
			byte EndHorizontalBlanking : 5; //Bits 4-0 of the End Horizontal Blanking field which specifies the end of the Horizontal Blanking Period.
			byte DisplayEnableSkew : 2; //???
			byte EVRA : 1; //Enable Vertical Retrace Access; When set to 0 (forced 1 on VGA), index 10h&11h are read-only
		} ENDHORIZONTALBLANKINGREGISTER;

		byte STARTHORIONTALRETRACEREGISTER; //When to move to the left side of the screen.
		struct
		{
			byte EndHorizontalRetrace : 5; //End of the Horizontal Retrace Period, which begins at the char. clock specified in the Start Horizontal Retrace field.
			byte HorizontalRetraceSkew : 2;  //Delays the start of the Horizontal Retrace period by the number of char. clocks equal to the value of this field. (Always 0. 40 column text mode have 1).
			byte EHB5 : 1; //Bit 5 of End Horizontal Blanking.
		} ENDHORIZONTALRETRACEREGISTER;

		byte VERTICALTOTALREGISTER; //Lower 8 bits of the Vertical Total field. Bits 9-8 are located in the Overflow Register.

		struct
		{
			byte VerticalTotal8 : 1; //Vertical Total (bit 8)
			byte VerticalDisplayEnd8 : 1; //Vertical Display End (bit 8)
			byte VerticalRetraceStart8 : 1; //Vertical Retrace Start (bit 8)
			byte StartVerticalBlanking8 : 1; //Start Vertical Blanking (bit 8)
			byte LineCompare8 : 1; //Line Compare (bit 8)
			byte VerticalTotal9 : 1; //Vertical total (bit 9)
			byte VerticalDisplayEnd9 : 1; //Vertical Display End (bit 9)
			byte VerticalRetraceStart9 : 1; //Vertical Retrace Start (bit 9)
		} OVERFLOWREGISTER;

		struct
		{
			byte PresetRowScan : 5; //Used when using text mode or mode with non-0 Maximum Scan Line to provide more precise scrolling than the Start Address Register provides. How many scan lines to scroll the display upwards. Values:0-Maximum Scan Line field.
			byte BytePanning : 2; //Added to Start Address Register when calculating the display mmory address for the upper-left hand pixel or character of the screen.
		} PRESETROWSCANREGISTER;

		struct
		{
			byte MaximumScanLine : 5; //In text mode =Character Height-1 (0-based). In graphics mode, non-0 value causes each scan line to be repeated by the value+1.
			byte StartVerticalBlanking9 : 1; //Vertical Blanking field (bit 9)
			byte LineCompare9 : 1; //Line compare field (bit 9)
			byte ScanDoubling : 1; //When set to 1, 200-scan-line video data is converted to 400-scan line output. (Doubling every scan line).
		} MAXIMUMSCANLINEREGISTER;

		struct
		{
			byte CursorScanLineStart : 5; //Start scan line of the cursor.
			byte CursorDisable : 1; //When set, the cursor is disabled.
			byte Unused : 1;
		} CURSORSTARTREGISTER;

		struct
		{
			byte CursorScanLineEnd : 5; //End scan line of the cursor.
			byte CursorSkew : 2; //Added to the Scan line start and end.
			byte unused : 1;
		} CURSORENDREGISTER;

		byte STARTADDRESSHIGHREGISTER; //Bits 15-8 of the Start Address field.
		byte STARTADDRESSLOWREGISTER; //Bits 7-0 of the Start Address field. Specifies 0,0 location of the display memory.

		byte CURSORLOCATIONHIGHREGISTER; //Bits 15-8 of the Cursor Location field.
		byte CURSORLOCATIONLOWREGISTER; //Bits 7-0 of the Cursor Location field. When displaying text-mode and the cursor is enabled, compare current display address with the sum of this field and the Cursor Skew field. If it equals then display cursor depending on scan lines.

		byte VERTICALRETRACESTARTREGISTER; //Bits 7-0 of Vertical Retrace Start field. Bits 9-8 are in the Overflow Register. When to move up to the beginning of display memory. Contains the value of the vertical scanline counter at the beginning of the 1st scanline where the signal is asserted.
		struct
		{
			byte VerticalRetraceEnd : 4; //Determines the end of the vertical retrace pulse, and this it's length. Lower 4 bits of Vertical Retrace End register.
			byte unused : 2;
			byte Bandwidth : 1; //Memory Refresh Bandwidth: Unused by VGA.
			byte Protect : 1; //Protect CRTC Registers? 1=Ignore writes to indexes 00h-07h, except bit 4 of the Overflow Register.
		} VERTICALRETRACEENDREGISTER;

		byte VERTICALDISPLAYENDREGISTER; //Bits 7-0 of the Vertical Display End field. Bits 9-8 are located in the Overflow Register.

		byte OFFSETREGISTER; //Specifies the address difference between two scan lines (graphics) or character (text).
		/*
		Text modes: Width/(MemoryAddressSize*2).
				MemoryAddressSize =1:byte,2:word,4:dword.
		Graphics modes: Width/(PixelsPerAddress*MemoryAddressSize*2)
				Width=Width in pixels of the screen
				PixelsPerAddress=Number of pixels stored in one display memory address.
				MemoryAddressSize is the current memory addressing size.
		*/

		struct
		{
			byte UnderlineLocation : 5; //Horizontal Scan line of a character row on which an underline occurs. =Scanline-1.
			byte DivideMemoryAddressClockBy4 : 1; //Divide Memory Address Clock by 4 (when dword addresses are used)
			byte DW : 1; //Double-Word Addressing: When set to 1, memory addresses are dword addresses. See bit 6 of the Mode Control Register.
			byte unused : 1;
		} UNDERLINELOCATIONREGISTER;

		byte STARTVERTICALBLANKINGREGISTER; //Bits 7-0 of the Start Vertical Blanking field. Bit 8 is located in the Overflow Register, and bit 9 is located in the Maximum Scan Line register. Determines when the vblanking period begins, and contains the value of the vertical scanline counter at the beginning of the first vertical scanline of blanking.

		struct
		{
			byte EndVerticalBlanking : 7; //Determines when the vblanking period ends and contins the value of the vertical scanline counter at the beginning of the vertical scanline immediately after the last scanline of blanking.
			byte unused : 1;
		} ENDVERTICALBLANKINGREGISTER;

		struct
		{
			byte MAP13 : 1; //Map Display Address 13: Source of bit 13 of the output multiplexer. When set to 0, bit 0 of the row scan counter is the source. When set to 1, bit 13 of the address counter is the source.
//For 640x200 graphics, CRTC is programmed for 100 horizontal scan lines with 2 scan-line addresses per char. row. Row san address bit 0 becomes the most-significant address bit to the display buffer. Successive scan lines are placed in 8KB of memory.
			byte MAP14 : 1; //Map Display Address 14: When set to 0, bit 1 of the Row Scan Counter is the source. When set to 1, the bit 14 of the address counter is the source.
			byte SLDIV : 1; //Divide Scan Line clock by 2.
			byte DIV2 : 1; //Divide Memory Address clock by 2: When set to 0, the address counter uses the character clock. When set to 1, the address counter uses the character clock input divided by 2. Used to create either byte or word refresh address for display memory.
			byte AW : 1; //Address Wrap Select: Selects the memory-address bit, bit MA 13 or MA 15, that appears on output pin MA 0, in the words address mode. ...
			byte UseByteMode : 1; //1=Use byte mode, 0=Use word mode.
			byte SE : 1; //1=Enable horizontal and vertical retrace signals. Doesn't reset any other registers or signal outputs.
		} CRTCMODECONTROLREGISTER;
Last edited on
vga.h: part 3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
		byte LINECOMPAREREGISTER; //Bits 7-0 of the Line Compare field. Bit 9 is located in the Maximum Scan Line Register and bit 8 is located in the Overflow Register. Specifies the scan line at which a horizontal division can occur, providing for split-screen operation. If no horizontal division is required, this field sohuld be set to 3FFh. When the scan line counter reaches the value of the Line Compare field, the current scan line address is reset to 0 and the Preset Row Scan is presumed to be 0. If the Pixel Panning Mode field is set to 1 then the Pixel Shift Count and the Byte Panning fields are reset to 0 for the remainder of the display cycle.
		byte notused[9]; //Unused registers
//Now for some undocumented registers (index 22,24,3X)
		struct
		{
			byte bit7 : 1; //Data latch n, bit 7
			byte bit6 : 1;
			byte bit5 : 1;
			byte bit4 : 1;
			byte bit3 : 1;
			byte bit2 : 1;
			byte bit1 : 1;
			byte bit0 : 1; //Data latch n, bit 0
		} GraphicsControllerDataLatches; //Index 22 data latch 'n', controlled by Graphics Register 4 bits 0-1; range 0-3; READ ONLY!
		byte unused2; //Unused: index 23!
		struct
		{
			byte CurrentIndex : 5; //Current palette index!
			byte PAL : 1; //Palette Address Source!
			byte reserved : 1; //Reserved!
			byte DataState : 1; //DATA Mode (1); Index mode (0)
		} ATTRIBUTECONTROLLERTOGGLEREGISTER; //Index 24 Attribute Controller Toggle Register (CR24). READ ONLY at 3B5/3D5 index 24h!
	} REGISTERS;
} CRTCONTROLLERREGS;





typedef struct
{
	byte DAC_ADDRESS_WRITE_MODE_REGISTER; //Port 3C8
	byte DAC_ADDRESS_READ_MODE_REGISTER; //Port 3C7 Write only
	byte DAC_ADDRESS_DATA_REGISTER; //Port 3C9 immediately processed if state is OK (on R/W).

	union
	{
		byte DATA;
		struct
		{
			byte DACState : 2; //0:Prepared for reads, 3:Prepared for writes.
			byte unused : 6;
		};
	} DAC_STATE_REGISTER; //Port 3C7 Read only

} COLORREGS;

typedef struct
{
	union
	{
		byte DATA;
		struct
		{
			byte IO_AS : 1; //Input/Output Address Select (Select CRT Addresses. 0=03Bx; Input Status Register 1=3BA. 1=03Dx; Input Status Register=3DA)
			byte RAM_Enable : 1; //1=Enable VRAM System Access (see MISC Graphics Register); 0=Disabled.
			byte ClockSelect : 2; //0=25MHz;1=28MHz;2-3=Undefined (possible ext. clock)
			byte unused : 1;
			byte OE_HighPage : 1; //Select upper/lower 64K page when system in odd/even mode. 0=Low;1=High.
			byte HSyncP : 1; //Horizontal Sync Polarity of Horizontal Sync Pulse. 0=Select Positive Horizontal Retrace Sync Pulse
			byte VSyncP : 1; //See HSyncP, but Vertical.
		};
	} MISCOUTPUTREGISTER; //Read at 3CCh, Write at 3C2h

	union
	{
		byte DATA;
		struct
		{
			byte FC0; //Unknown!
			byte LightpenTriggered : 1; //Light pen triggered?
		};
	} FEATURECONTROLREGISTER; //Read at 3CAh, write at 3BAh(mono)/3DAh(color) Bit 1 is lightpen triggered when on!

	union
	{
		byte DATA;
		struct
		{
			byte notimplemented;
		};
	} INPUTSTATUS0REGISTER; //Input status #0 register (Read-only at 3C2h)

	union
	{
		byte DATA;
		struct
		{
			byte notimplemented;
		};
	} INPUTSTATUS1REGISTER; //Read at 3BAh(mono), Read at 3DAh(color)
} EXTERNALREGS;

typedef struct
{
	byte r;
	byte g;
	byte b;
} DACEntry; //A DAC Entry!

typedef struct
{
	byte videoMode; //Real video mode!
	word VRAMmode; //16, 256, 0(text) or 4 color mode?
	byte textmode; //Text mode?
//Basic screen resolution:
	word text_rows; //Ammount of text rows!
	word text_columns; //Ammount of text columns!
	word graphics_rows; //Graphics rows!
	word graphics_columns; //Graphics columns!
//Data within active map:
	word minx; //Minimum X (window 0,0)!
	word miny; //Minimum Y (window 0,0)!
	word maxx; //Maximum X (window max,max)!
	word maxy; //Maximum Y (window max,max)!
	word startMap; //Start of the active VRAM map!
	word curScanline; //Current scan line!

//Text-mode cursor
	byte CursorStartLine; //Start line of cursor!
	byte CursorEndLine; //End line of cursor!
	uint_32 CursorLocation; //Start of the character where the cursor is located.
//Cursor on/off state changes every 16 Vertical Frames.
} VGAInfo; //Info for rendering the screen pixels etc.! 
Last edited on
vga.h: part 4(final):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
typedef struct
{
	byte VideoMode; //Active video mode!

//Next, our registers:

//First, the indexed registers:
	GRAPHREGS GraphicsRegisters; //Graphics registers!
	byte GraphicsRegisters_Index; //Current index!

	SEQUENCERREGS SequencerRegisters; //Sequencer registers!
	byte SequencerRegisters_Index; //Current index!

	ATTRIBUTECONTROLLERREGS AttributeControllerRegisters; //Attribute controller registers!
	byte AttributeControllerRegisters_Index; //Current index!

	CRTCONTROLLERREGS CRTControllerRegisters; //CRT Controller registers!
	byte CRTControllerRegisters_Index; //Current index!

//Now the normal registers, by group:

	COLORREGS ColorRegisters; //Color registers!
	EXTERNALREGS ExternalRegisters; //External registers!

	byte DACMaskRegister; //DAC Mask Register (port 0x3C6 for read/write; default is 0xFF)
	byte DAC[3*256]; //All DAC values!

//For colors:
	byte colorIndex; //Written to port 0x3C8; 3 bytes to 3C9 in order R, G, B
	byte current_3C9; //Current by out of 3 from writing to 3C9.

//Index registers:
//Set by writing to 0x3C0, set address or data depending on 3C0_Current. See CRTController Register 24!

	byte ModeStep; //Current mode step (used for mode 0&1)!
	byte DataLatch; //Latch for mode step 0!
	word Scanline; //Current scan line updating!

	byte VerticalDisplayTotalReached; //Set when Scanline>max. Setting this causes Scanline to reset!
	byte lightpen_high; //Lightpen high register!
	byte lightpen_low; //Lightpen low register!
} VGA_REGISTERS;

typedef struct
{
//First, VRAM and registers:
	byte *VRAM; //The VRAM!
	uint_32 VRAM_size; //The size of the VRAM!
//Active video mode:

	VGA_REGISTERS *registers; //The registers itself!

	uint_32 ExpandTable[256]; //Expand Table (originally 32-bit) for VRAM read and write by CPU!

	byte CursorOn; //Cursor on?
	byte TextBlinkOn; //Text blink on? (Every 2 CursorOn changed)

	byte Keyboard[15][15]; //The keyboard to be display
	byte Keyboard_Enabled; //Keyboard enabled?

	int initialised; //Are we initialised (row timer active? After initVGA is called, this is 1, row timer sets this to 0!)

//For rendering:
	VGAInfo info; //VGA's info for us to use!
	int frameDone; //We have a frame ready for rendering? (for GPU refresh)

//For the extra functions of the VGA:
	int wait_for_vblank; //Waiting for VBlank?
	int VGA_vblank; //VBlank occurred?
} VGA_type; //VGA dataset!

/*

Read and write ports:

Info:						Type:
3B4h: CRTC Controller Address Register		ADDRESS
3B5h: CRTC Controller Data Register		DATA

3BAh Read: Input Status #1 Register (mono)	DATA
3BAh Write: Feature Control Register		DATA

3C0h: Attribute Address/Data register		ADDRESS/DATA
3C1h: Attribute Data Read Register		DATA

3C2h Read: Input Status #0 Register		DATA
3C2h Write: Miscellaneous Output Register	DATA

3C4h: Sequencer Address Register		ADDRESS
3C5h: Sequencer Data Register			DATA

3C7h Read: DAC State Register			DATA
3C7h Write: DAC Address Read Mode Register	ADDRESS

3C8h: DAC Address Write Mode Register		ADDRESS
3C9h: DAC Data Register				DATA

3CAh Read: Feature Control Register (mono Read)	DATA

3CCh Read: Miscellaneous Output Register	DATA

3CEh: Graphics Controller Address Register	ADDRESS
3CFh: Graphics Controller Data Register		DATA

3D4h: CRTC Controller Address Register		ADDRESS
3D5h: CRTC Controller Data Register		DATA

3DAh Read: Input Status #1 Register (color)	DATA
3DAh Write: Feature Control Register (color)	DATA

*/

/*

All functions!

*/









void initVGA(); //Initialises VGA Chipset!
void doneVGA(); //Cleans up after the VGA operations are done.

inline byte VRAM_readdirect(uint_32 offset);
inline void VRAM_writedirect(uint_32 offset, byte value); //Direct read/write!

//CPU offset from 0xA000:0000 (contained in BDA)
inline byte VRAM_readcpu(uint_32 offset);
inline void VRAM_writecpu(uint_32 offset, byte value);

byte PORT_readVGA(unsigned int port); //Read from a port/register!
void PORT_writeVGA(unsigned int port, unsigned char value); //Write to a port/register!

inline void VGALoadCharTable(int rows, word startaddr); //Load a character table from ROM to VRAM!
inline int getcharxy(byte attribute, unsigned char character, int x, int y); //Retrieve a characters x,y pixel on/off from table!

//DAC (for rendering)
inline void readDAC(byte entrynumber,DACEntry *entry); //Read a DAC entry
inline void writeDAC(byte entrynumber,DACEntry *entry); //Write a DAC entry

//VGA Information for int10 etc.:
inline void readVGAInfo(VGAInfo *info); //Info for drawing a line!
inline byte readVRAMplane(uint_32 start, byte plane, word offset); //Read from a VRAM plane!
inline void writeVRAMplane(uint_32 start, byte plane, word offset, byte value); //Write to a VRAM plane!

inline byte getcharacterwidth(); //Character width active!
inline byte getcharacterheight(); //Character height active!

inline float VGA_VerticalRefreshRate(); //Vertical refresh rate of one scanline (see below function)
inline void VGA_generateScreenLine(); //Generate the screen line based on VGA register calls!

//CRTC Controller renderer&int10:
inline byte getVRAMMemAddrSize(); //Current memory address size?
inline void VGA_LoadVideoMode(byte mode); //Loads a preset video mode to be active!
inline void VGA_VBlankHandler(); //VBlank handler for VGA!

void VGA_waitforVBlank(); //Wait for a VBlank to happen?
#endif 
Last edited on
vga_screen.c: Main renderer functions (called by timing function):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "headers/types.h" //Basic types!
#include "headers/emu/gpu.h" //GPU support!
#include "headers/cpu/interrupts.h" //Interrupt support!
#include "headers/hardware/vga.h" //VGA support!
#include "headers/mmu/mmu.h" //BDA support!
#include "headers/mmu/bda.h" //BDA support!
#include "headers/hardware/vga_rest/colorconversion.h" //Color conversion support!

//Finally all subparts, in order of occurence:
#include "headers/hardware/vga_screen/vga_sequencer.h" //Sequencer!
#include "headers/hardware/vga_screen/vga_sequencer_textmode.h" //Text-mode!
#include "headers/hardware/vga_screen/vga_sequencer_textmode_cursor.h" //Text-mode cursor!
#include "headers/hardware/vga_screen/vga_attributecontroller.h" //Attribute controller!
#include "headers/hardware/vga_screen/vga_dac.h" //DAC operations!
#include "headers/hardware/vga_screen/vga_displaygeneration_crtcontroller.h" //CRT Controller

extern GPU_type GPU; //GPU contents!
extern BDA_type *BDA; //BIOS Data Area!
extern VGA_type VGA; //VGA!

uint_32 CurrentScanLine[1024]; //A scan line's data!

//Video padding functions:

//Display row info:
//Start Vertical Retrace=X width
//Vertical Total - Vertical Blank End = Y height

//Display type functions:


inline void dumpVGARegisters() //Dump all used VGA display registers?
{
	return; //Not used for now!
	int i;
	int valid;
	valid = 0; //Default: invalid!
	for (i=0; i<NUMITEMS(VGA.registers->SequencerRegisters.DATA); i++) //Check if any value is non-0!
	{
		if (VGA.registers->SequencerRegisters.DATA[i]!=0) //Filled?
		{
			valid = 1; //Valid!
		}
	}

	fontcolor(RGB(0xFF,0xFF,0xFF)); //White text!
	if (!valid) //Not filled?
	{
		gotoxy(0,4);
		printf("VGA Invalid!");
		return; //Stop info!
	}
	gotoxy(0,4); //Start of info!
	printf("Characters: %ix%i",getcharacterwidth(),getcharacterheight());
	gotoxy(0,5);
	printf("(Active area) Horiz start-end: %i-%i",getHorizontalStart(),getHorizontalEnd());
	gotoxy(0,6);
	printf("(Active area end, border start) Vertical display end: %i",getVerticalDisplayEnd());
	gotoxy(0,7);
	printf("(Border area) Vertical: >Vertical display end || < Vertical blank start");
	gotoxy(0,8);
	printf("(Border area) Horizontal: <Horizontal Start || (>Horizontal End & <Horizontal Blank Start)");
	gotoxy(0,9);
	printf("(Inactive area) Vertical blank start: %i+",getVerticalBlankingStart());
	gotoxy(0,10);
	printf("(Inactive area) Horizontal blank start: %i+",getHorizontalBlankingStart());
	gotoxy(0,11);
	printf("Screen split @%i",getTopWindowStart()); //Where to split?
	gotoxy(0,12);
	printf("Offset between two rows: %i",getrowsize()); //Row size!
}

inline int isvalidscanline(word ScanLine) //Are we GPU-renderable?
{
	return ((NUMITEMS(GPU.emu_screenbuffer)/1024)>=(ScanLine+1)); //Enough scanlines to render?
}

inline void int10_renderScanLine(word ScanLine, byte currentscreenbottom) //Render a scanline for a top or bottom screen!
{
	bzero(CurrentScanLine,sizeof(CurrentScanLine)); //No data to show by default!

	if (!isvalidscanline(ScanLine) && (ScanLine<getTopWindowStart())) //Bottom and invalid?
	{
		return; //Disable when invalid scanline!
	}
	else if (!isvalidscanline(ScanLine-getTopWindowStart()) && (ScanLine>=getTopWindowStart())) //Top and invalid?
	{
		return; //Disable when invalid scanline!
	}

	dumpVGARegisters(); //Dump it if enabled!

	readVGAInfo(&VGA.info); //Get the info!

	if (VGA.registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.ScreenDisable) //No drawing (empty lines)?
	{
//Do nothing to fill: screen is disabled, so empty buffer to show!
	}
	else //Fill the scan line!
	{
		VGA_Sequencer(ScanLine); //First, sequencer, attribute controller and special effects!
		VGA_DAC(ScanLine,&VGA.info); //DAC final processing!
	}

//Now copy to real video (if active screen)!
	if ((ScanLine<getTopWindowStart()) && (currentscreenbottom)) //To do the bottom window?
	{
		memcpy(&GPU.emu_screenbuffer[ScanLine*1024],&CurrentScanLine,sizeof(CurrentScanLine)); //Copy the scan line to the screen buffer!
	}
	else if ((ScanLine>=getTopWindowStart()) && (!currentscreenbottom)) //To do the top window?
	{
		memcpy(&GPU.emu_screenbuffer[(ScanLine-getTopWindowStart())*1024],&CurrentScanLine,sizeof(CurrentScanLine)); //Copy the scan line to the screen buffer!
	}
}

//To generate the screen, we use the CRTC registers!
extern int active_screen; //Active screen?

int cursorCounter = 0; //For cursor on/off!

inline void VGA_generateScreenLine() //Generate a screen line!
{
	if (!GPU.video_on) //Not rendering?
	{
		return; //Don't do rendering!
	}

	if (BDA==NULL) //No BIOS Data Area set yet?
	{
		raiseError("vga_screen::int10_generatescreen","No BDA set!");
		return; //Stop: No BDA!
	}

	GPU.GPU_screenxsize = getxresfull(); //X resolution we need!
	GPU.GPU_screenysize = getyresfull(); //Y resolution we need!

//We work by changing one scan line at a time!
	readVGAInfo(&VGA.info); //Prepare our VGA info!

	int10_renderScanLine(VGA.registers->Scanline++,!active_screen); //Process the scan line (we're running the top window)!

	if (VGA.registers->Scanline>VGA.info.graphics_rows) //Over the limit?
	{
		VGA.registers->VerticalDisplayTotalReached = 1; //Reset!
	}

	if (VGA.registers->VerticalDisplayTotalReached) //Total reached (to reset?)
	{
		VGA.registers->Scanline = 0; //Reset scan line to the top of the screen!
		VGA.frameDone = 1; //We have a frame ready, so we can refresh now, GPU!
		VGA.registers->VerticalDisplayTotalReached = 0; //Reset!
		VGA_VBlankHandler(); //Handle all VBlank stuff!
	}
//Now a scanline has been rendered!
}
Last edited on
vga_sequencer.c: Basic sequencer operations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "headers/emu/gpu.h" //GPU!
#include "headers/hardware/vga.h" //VGA!
#include "headers/hardware/vga_screen/vga_attributecontroller.h" //Attribute controller!
#include "headers/hardware/vga_screen/vga_sequencer_graphicsmode.h" //Text mode!
#include "headers/hardware/vga_screen/vga_sequencer_textmode.h" //Text mode!
#include "headers/hardware/vga_screen/vga_sequencer_textmode_cursor.h" //Text mode cursor!
#include "headers/hardware/vga_screen/vga_displaygeneration_crtcontroller.h" //CRT Controller for finishing up!
#include "headers/cpu/interrupts.h" //For get/putpixel variant!

extern uint_32 CurrentScanLine[1024];
extern GPU_type GPU; //GPU!

inline void VGA_Sequencer(word Scanline)
{
	word tempx, tempy;
	word x; //X counter!
	tempy = Scanline; //Save!
	if (VGA_ScanDoubling()) //Double scan line?
	{
		tempy /= 2; //Double all scan lines!
	}

	tempy -= VGA.registers->CRTControllerRegisters.REGISTERS.PRESETROWSCANREGISTER.PresetRowScan; //Shift up some!

	word topwindowstart;
	topwindowstart = getTopWindowStart(); //When to start rendering the top window!

	int allow_pixelshiftcount;
	allow_pixelshiftcount = 1; //Default: allow!

	byte bytepanning; //Byte panning for Start Address Register for characters or 0,0 pixel!
	bytepanning = VGA.registers->CRTControllerRegisters.REGISTERS.PRESETROWSCANREGISTER.BytePanning;

	VGAInfo info; //Contains info after next line!
	readVGAInfo(&info);

	allow_pixelshiftcount = 1; //Allow by default!
	if (Scanline>=topwindowstart) //Top window?
	{
		info.startMap = 0; //Enforce start of map to 0 for the top window!
		if (VGA.registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.PixelPanningMode)
		{
			bytepanning = 0; //Act like no byte panning is enabled!
			allow_pixelshiftcount = 0; //Don't allow it anymore!
		}
	}

//First, Process scanline to buffer!
	for (x=0; x<GPU.GPU_screenxsize; x++)
	{
		if (is_activedisplay(Scanline,x)) //Active display?
		{
			tempx = x; //Use this for panning!
			if (allow_pixelshiftcount) //Allow Pixel Shift Count?
			{
				tempx += getHorizontalPixelPanning(); //Extra pixel shift to the left (start further at the right for 0,Y)!
			}

			tempx -= getHorizontalStart(); //Take off the pixels we have too much (left border) to get the start of the pixels to show!

			if (!VGA.registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.AlphaNumericModeDisable) //Text mode?
			{
				VGA_AttributeInfo *characterinfo; //Info about the current character!
				characterinfo = VGA_Sequencer_TextMode(Scanline,x,tempx,tempy,&info,bytepanning); //Process to font or back color!
				VGA_AttributeController(Scanline,x,characterinfo); //Apply attribute to generate DAC Index!
			}
			else //Graphics Mode?
			{
				VGA_Sequencer_GraphicsMode(Scanline,x,tempx,tempy,&info,bytepanning);
			}
		}
		else if (is_overscan(Scanline,x)) //Overscan?
		{
			CurrentScanLine[x] = getOverscanColor(); //Overscan! Already DAC Index!
		}
	}

}
Last edited on
vga_sequencer_graphicsmode.c: Graphics mode sequencer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "headers/emu/gpu.h" //GPU!
#include "headers/hardware/vga.h" //VGA!
#include "headers/hardware/vga_screen/vga_attributecontroller.h" //Attribute controller!
#include "headers/hardware/vga_screen/vga_sequencer_graphicsmode.h" //Text mode!
#include "headers/hardware/vga_screen/vga_sequencer_textmode.h" //Text mode!
#include "headers/hardware/vga_screen/vga_sequencer_textmode_cursor.h" //Text mode cursor!
#include "headers/hardware/vga_screen/vga_displaygeneration_crtcontroller.h" //CRT Controller for finishing up!
#include "headers/cpu/interrupts.h" //For get/putpixel variant!

extern uint_32 CurrentScanLine[1024]; //Current scan line!
extern VGA_type VGA; //VGA!

inline void VGA_Sequencer_GraphicsMode(word Scanline, word x, word tempx, word tempy, VGAInfo *info, byte bytepanning)
{
	switch (info->VRAMmode) //What color depth?
	{
	case 1: //Black/white?
		CurrentScanLine[x] = MEMGRAPHICS_get2colors(info->startMap+bytepanning,tempx,tempy,getxres(),getyres()); //Plot 2 bits!
		break;
	case 4: //4 colors?
		CurrentScanLine[x] = MEMGRAPHICS_get4colors(info->startMap+bytepanning,tempx,tempy,getxres(),getyres()); //Plot 4 colors!

		VGA_AttributeInfo tempattribute;

		switch (CurrentScanLine[x]) //What color to attribute?
		{
		default:
		case 0:
			tempattribute.attribute = 0; //Attribute!
			break;
		case 1:
			tempattribute.attribute = 1; //Attribute!
			break;
		case 2:
			tempattribute.attribute = 4; //Attribute!
			break;
		case 3:
			tempattribute.attribute = 5; //Attribute!
			break;
		}
		tempattribute.charinner_y = 0; //No inner Y!
		CurrentScanLine[x] = 1; //The pixel is always foreground color!

		VGA_AttributeController(Scanline, x, &tempattribute); //Process attribute to DAC index!
		break;
	case 16: //16 colors?
		CurrentScanLine[x] = MEMGRAPHICS_get16colors(info->startMap+bytepanning,tempx,tempy,getxres(),getyres()); //Plot 16 colors!
		VGA_AttributeInfo temp;
		bzero((char *)&temp,sizeof(temp)); //Init!

		temp.attribute = CurrentScanLine[x]; //Attribute!
		temp.charinner_y = 0; //No inner Y!

		CurrentScanLine[x] = 1; //The scanline is always on!

		VGA_AttributeController(Scanline, x, &temp); //Process attribute to DAC index!
		break;
	case 256: //256 colors?
		CurrentScanLine[x] = MEMGRAPHICS_get256colors(info->startMap+bytepanning,tempx,tempy,getxres(),getyres()); //Plot 256 colors!
		break;
	}
}
Last edited on
vga_sequencer_textmode.c: Sequencer for text mode operations:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "headers/hardware/vga.h" //Our typedefs etc!
#include "headers/hardware/vga_screen/vga_attributecontroller.h" //Attribute controller for typedef of attribute info!
#include "headers/hardware/vga_screen/vga_sequencer_textmode_cursor.h" //Cursor!
#include "headers/hardware/vga_screen/vga_displaygeneration_crtcontroller.h" //CRT controller!

extern VGA_type VGA; //VGA!

extern uint_32 CurrentScanLine[1024];

//Character sizes in pixels!
inline byte getcharacterwidth()
{
	return VGA.registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.DotMode8?8:9; //8 or 9 dots per line?
}

inline byte getcharacterheight()
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.MAXIMUMSCANLINEREGISTER.MaximumScanLine+1; //The character height!
}

VGA_AttributeInfo attributeinfo; //Our active attribute info!

inline VGA_AttributeInfo *VGA_Sequencer_TextMode(word Scanline, word x, word tempx, word tempy, VGAInfo *info, byte bytepanning)
{
//First: character info!

//This is correct:
	attributeinfo.chary = (tempy / getcharacterheight()); //Y of current character!
	attributeinfo.charinner_y = tempy % getcharacterheight(); //Current ScanLine within the character!

//x position is incorrect!
	attributeinfo.charx = (tempx / getcharacterwidth()); //X of current character!
	attributeinfo.charinner_x = tempx % getcharacterwidth(); //Current pixel within the ScanLine!

//Get character and attribute!
	byte character; //Character!
	word charindex;
//Data loading:
//Index of character/attribute:
	charindex = (attributeinfo.chary*getrowsize()*2*getVRAMMemAddrSize()); //Character row!
	charindex += (attributeinfo.charx); //Add x coordinate!

	word reloffset;
	reloffset = charindex+bytepanning; //Relative offset in VRAM plane from start of map!
	character = VGA.VRAM[VGA_PLANE0+info->startMap+reloffset]; //Attribute!
	attributeinfo.attribute = VGA.VRAM[VGA_PLANE1+info->startMap+reloffset]; //Attribute!

	/*
	character = 97; //A!
	attributeinfo.attribute = 0xF; //White
	*/

//Determine cursor!
	byte is_cursor;
	is_cursor = is_cursorscanline(attributeinfo.charinner_y,reloffset); //Cursor location?

	int pixelon;
	pixelon = getcharxy(attributeinfo.attribute, character,attributeinfo.charinner_x,attributeinfo.charinner_y)|is_cursor; //Get if we're to plot font? (Else back)

	CurrentScanLine[x] = pixelon; //Font(1) or back color(0)!
	return &attributeinfo; //We give the attribute info!
}
Last edited on
vga_sequencer_textmode_cursor.c: Everything hardware text-mode cursor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "headers/hardware/vga.h" //VGA!
extern VGA_type VGA; //VGA!

inline uint_32 getcursorlocation() //Location of the cursor!
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.CURSORLOCATIONLOWREGISTER+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.CURSORLOCATIONHIGHREGISTER*0x100)+
	       VGA.registers->CRTControllerRegisters.REGISTERS.CURSORENDREGISTER.CursorSkew; //Cursor location!
}

inline int is_cursorscanline(byte ScanLine,uint_32 characterlocation) //Cursor scanline within character is cursor?
{
	byte startLine; //Start line of cursor!
	byte endLine; //End line of cursor!
	byte cursorEnabled; //Cursor is enabled?
//Calculated:
	byte char_is_cursor; //Current character is cursor character?
	byte scanline_is_cursor; //Current scanline is cursor scanline?
//Now set them!
	char_is_cursor = (characterlocation==getcursorlocation()); //We're the cursor location?

	startLine = VGA.registers->CRTControllerRegisters.REGISTERS.CURSORSTARTREGISTER.CursorScanLineStart;
	endLine = VGA.registers->CRTControllerRegisters.REGISTERS.CURSORENDREGISTER.CursorScanLineEnd;

	scanline_is_cursor = ((ScanLine>=startLine) && (ScanLine<=endLine)); //Is cursor scanline?

	cursorEnabled = !VGA.registers->CRTControllerRegisters.REGISTERS.CURSORSTARTREGISTER.CursorDisable; //Not to disable the cursor?

	byte showcursor; //Allowed to show the cursor now?
	showcursor = (cursorEnabled && VGA.CursorOn); //Allowed to show the cursor?

	return (char_is_cursor && scanline_is_cursor && showcursor); //To show the cursor on this scanline?
}
Last edited on
vga_attributecontroller.c: The attribute controller operations:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "headers/hardware/vga.h"
#include "headers/hardware/vga_screen/vga_attributecontroller.h" //Our own typedefs!
#include "headers/hardware/vga_screen/vga_dac.h" //DAC support!
extern VGA_type VGA; //VGA!
extern uint_32 CurrentScanLine[1024]; //Current scanline to process!

inline byte getHorizontalPixelPanning() //Active horizontal pixel panning when enabled?
{
	byte pixelboost; //Actual pixel boost!
	byte possibleboost; //Possible value!
	pixelboost = 0; //Default: no pixel boost!
	possibleboost = VGA.registers->AttributeControllerRegisters.REGISTERS.HORIZONTALPIXELPANNINGREGISTER.PixelShiftCount; //Possible value, to be determined!
	if (VGA.registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.ColorEnable8Bit) //8-bit colors?
	{
		if ((possibleboost%2)==0) //Enabled?
		{
			possibleboost /= 2; //Bit 2 only!
			if (possibleboost<4) //Valid?
			{
				pixelboost = possibleboost; //Use this boost!
			}
		}
	}
	else //Determine by character width!
	{
		if (getcharacterwidth()==9) //9 dot mode?
		{
			if (possibleboost<8) //1-8?
			{
				pixelboost = possibleboost+1; //Enable with +1!
			} //Else 0!
		}
		else //8 dot mode?
		{
			if (possibleboost<8) //Enable?
			{
				pixelboost = possibleboost; //Enable!
			} //Else 0!
		}
	}
	return pixelboost; //Give the boost!
}

inline byte getOverscanColor() //Get the active overscan color (256 color byte!)
{
	return VGA.registers->AttributeControllerRegisters.REGISTERS.OVERSCANCOLORREGISTER; //Take the overscan color!
}

inline byte getattributefont(byte attr)
{
	return (attr&0xF); //Font color!
}

inline byte getattributeback(byte attr,byte filter)
{
	return (((attr&0xF0)/0x10)&filter); //Need attribute registers below used!
}

word currentrow; //For debugging only!

//Translate 4-bit or 8-bit color to 256 color DAC Index through palette!
inline byte getcol16(byte pixel, VGA_AttributeInfo *info) //Convert color to RGB!
{
	byte DACIndex; //DAC index generated!
	DACIndex = info->attribute; //Current DAC Index from 256-color by default!

	if (!VGA.registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.ColorEnable8Bit) //Disable in 8-bit mode (we use 4-bit or 2-bit colors, maybe 1-bit colors)?
	{
//First, process attribute!

		if (VGA.registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.BlinkEnable) //Enable blink?
		{
			if ((info->attribute&0x80)==0x80) //Blink enabled?
			{
				pixel = (pixel && VGA.TextBlinkOn); //Need text blink on to show!
			}

			if (pixel) //Says font color?
			{
				DACIndex = getattributefont(info->attribute); //Use font color!
			}
			else //Background color?
			{
				DACIndex = getattributeback(info->attribute,0x7); //Get back color (Exclude Blink bit)!
			}

			if (info->charinner_y==VGA.registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.UnderlineLocation) //Underline?
			{
				if (((info->attribute&0x3)==1) && (((info->attribute&0x70)>>4)==0) && pixel) //Underline?
				{
					DACIndex = getattributefont(info->attribute); //Force font color for underline!
				}
			}
		}

		else //Without blink?
		{
			if (pixel) //Says font color?
			{
				DACIndex = getattributefont(info->attribute); //Use font color!
			}
			else //Background color?
			{
				DACIndex = getattributeback(info->attribute,0xF); //Get back color!
			}
			if (info->charinner_y==VGA.registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.UnderlineLocation) //Underline?
			{
				if (((info->attribute&0x3)==1) && (((info->attribute&0x70)>>4)==0)) //Underline?
				{
					DACIndex = getattributefont(info->attribute); //Force font color for underline!
				}
			}
		}

//int i;
//for (i=0;i<0x10;i++) VGA.AttributeControllerRegisters.REGISTERS.PALETTEREGISTERS[i].InternalPaletteIndex = i; //Manual solid palette! WE DONT GET LOADED!

		if (VGA.registers->CRTControllerRegisters.REGISTERS.ATTRIBUTECONTROLLERTOGGLEREGISTER.PAL) //Internal palette enable?
		{
//Use original 16 color palette!
			DACIndex &= (VGA.registers->AttributeControllerRegisters.REGISTERS.COLORPLANEENABLEREGISTER.DATA&0xF); //Mask color planes off if needed!

			byte PALIndex;
			PALIndex = DACIndex; //Currently the palette's index!

			DACIndex = VGA.registers->AttributeControllerRegisters.REGISTERS.PALETTEREGISTERS[DACIndex].InternalPaletteIndex; //Get base index into DAC!

//First, bit 4&5 processing if needed!
			if (VGA.registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.PaletteBits54Select) //Bit 4&5 map to the C45 field of the Color Select Register, determined by bit 7?
			{
				DACIndex &= 0xF; //Only 4 lower bits are used!
				DACIndex |= (VGA.registers->AttributeControllerRegisters.REGISTERS.COLORSELECTREGISTER.ColorSelect54<<4); //Use them as 4th&5th bit!
			}

//Else: already 6 bits wide fully!

//Finally, bit 6&7 always processing!
			DACIndex |= (VGA.registers->AttributeControllerRegisters.REGISTERS.COLORSELECTREGISTER.ColorSelect76<<6); //Apply bits 6&7!
		}
		else
		{
			DACIndex = 0; //Screen output is disabled!
		}
	}

	return DACIndex; //Give the DAC index!
}

//Handler itself:

inline void VGA_AttributeController(word Scanline, word x, VGA_AttributeInfo *info) //Process attribute to DAC index!
{
	currentrow = Scanline; //Current row!
	CurrentScanLine[x] = getcol16(CurrentScanLine[x],info); //Set DAC Index!
//Done: DAC Index loaded!
}
Last edited on
vga_dac.c: DAC conversion operations:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "headers/emu/gpu.h" //Relative conversion!
#include "headers/hardware/vga.h" //VGA support!
#include "headers/hardware/vga_rest/colorconversion.h" //Color conversion!

extern GPU_type GPU; //GPU!
extern VGA_type VGA; //VGA!

//Works!
inline uint_32 getcol256(byte color) //Convert color to RGB!
{
	DACEntry colorEntry;
	readDAC((color&VGA.registers->DACMaskRegister),&colorEntry); //Read the DAC entry, masked on/off by the DAC Mask Register!
	return RGB(convertrel(colorEntry.r,63,255),convertrel(colorEntry.g,63,255),convertrel(colorEntry.b,63,255)); //Convert using DAC!
}

extern uint_32 CurrentScanLine[1024]; //Current scan line!

//Works!
inline void VGA_DAC(uint_32 ScanLine, VGAInfo *info)
{
	word x;
	for (x=0; x<GPU.GPU_screenxsize; x++) //Process all pixels!
	{
		CurrentScanLine[x] = getcol256(CurrentScanLine[x]); //Convert through DAC!
	}
//We're ready for display!
}
Last edited on
vga_displaygeneration_crtcontroller.c:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "headers/hardware/vga.h"
extern VGA_type VGA; //VGA!

extern uint_32 CurrentScanLine[1024];

inline word getHorizontalStart() //How many pixels to take off the active display x to get the start x!
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.ENDHORIZONTALBLANKINGREGISTER.DisplayEnableSkew*getcharacterwidth(); //Horizontal start
}

inline word getHorizontalEnd() //What is the last character start x of the current line? (max character-1)
{
	return (VGA.registers->CRTControllerRegisters.REGISTERS.ENDHORIZONTALDISPLAYREGISTER*getcharacterwidth()); //Horizontal End of display area!
}

inline word getHorizontalBlankingStart()
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.STARTHORIZONTALBLANKINGREGISTER*getcharacterwidth(); //When to start blanking horizontally!
}

inline word getHorizontalTotal()
{
	return (VGA.registers->CRTControllerRegisters.REGISTERS.HORIZONTALTOTALREGISTER+5)*getcharacterwidth(); //Horizontal total!
}

inline word getVerticalDisplayEnd()
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.VERTICALDISPLAYENDREGISTER+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.VerticalDisplayEnd8*0x100)+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.VerticalDisplayEnd9*0x200); //Vertical Display End Register value!
}

inline word getVerticalBlankingStart()
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.STARTVERTICALBLANKINGREGISTER+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.StartVerticalBlanking8*0x100)+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.MAXIMUMSCANLINEREGISTER.StartVerticalBlanking9*0x200); //Vertical Blanking Start value!
}

inline word getVerticalRetraceStart() //When to start retracing (vblank)
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.VERTICALRETRACESTARTREGISTER+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.VerticalRetraceStart8*0x100)+
	       (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.VerticalRetraceStart9*0x200); //When to start vertical retrace (full resolution in fact)!
}

inline word getVerticalTotal()
{
	return ((VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.VerticalTotal9*0x200)+
	        (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.VerticalTotal8*0x100)+
	        VGA.registers->CRTControllerRegisters.REGISTERS.VERTICALTOTALREGISTER);
}

//Active display info:
//Horizontal Start@Display Enable Skew
//Horizontal End@End Horizontal Display
//Vertical Start @ 0
//Vertical End @ Vertical Display End
inline int is_activedisplay(word ScanLine, word x)
{
	if (ScanLine>=getVerticalDisplayEnd()) //Not active display?
	{
		return 0; //Not Active Display!
	}
//Might be active display, check horizontals!
	if (x>=getHorizontalStart()) //Higher than start?
	{
		if (x<(getHorizontalEnd()+getcharacterwidth())) //Lower than end?
		{
			return 1; //Active Display!
		}
	}
	return 0; //Not Active Display!
}

//Overscan display info:
//Horizontal 0 to Display Enable Skew
//Horizontal End Horizontal Display to Start Horizontal Blanking
//Vertical Vertical Display End to Vertical Blank Start

inline int is_overscan(word ScanLine, word x)
{
	if ((ScanLine>=getVerticalDisplayEnd()) && (ScanLine<getVerticalBlankingStart())) //Overscan full line?
	{
		return (x<getHorizontalBlankingStart()); //Overscan when not blanking!
	}
	else if (ScanLine<=getVerticalDisplayEnd()) //Now check for horizontal borders!
	{
		if (x<getHorizontalStart()) //Left border?
		{
			return 1; //Overscan?
		}
		else if (x>=(getHorizontalEnd()+getcharacterwidth())) //Right border possible?
		{
			return (x<getHorizontalBlankingStart()); //Not over the blanking horizontal?
		}
	}
	return 0; //No Overscan!
}

inline word getxres()
{
	return (getHorizontalEnd()-getHorizontalStart())+1; //X Resolution!
}

inline word getyres()
{
	return getVerticalDisplayEnd()+1; //Y resolution!
}

inline word getxresfull() //Full resolution (border+active display area) width
{
	return getHorizontalBlankingStart(); //Full x resolution incl. border
}

inline word getyresfull() //Full resolution (border+active display area) height
{
	return getVerticalBlankingStart(); //Full y resolution incl. border
}

inline word getrowsize() //Give the size of a row in VRAM!
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.OFFSETREGISTER; //Size of a text OR graphics row!
}

inline word getTopWindowStart()
{
	return (VGA.registers->CRTControllerRegisters.REGISTERS.LINECOMPAREREGISTER+
	        (VGA.registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.LineCompare8*0x100)+
	        (VGA.registers->CRTControllerRegisters.REGISTERS.MAXIMUMSCANLINEREGISTER.LineCompare9*0x200)); //Give top window start scanline!
}

inline byte getVRAMMemAddrSize() //Current memory address size?
{
	if (VGA.registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.DW) //Double-word addressing?
	{
		return 4; //Double-word!
	}
	else if (VGA.registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.UseByteMode) //Byte mode?
	{
		return 1; //Byte!
	}
	return 2; //Default: Word Mode!
}

inline int VGA_ScanDoubling()
{
	return VGA.registers->CRTControllerRegisters.REGISTERS.MAXIMUMSCANLINEREGISTER.ScanDoubling;
}
Last edited on
End of files. You can post now.
Can someone tell me how to make this faster? (I've based it on the freeVGA documents)


Profile your code. Optimized code based on the profiling results.
One of the points with the code-tag is that it preserves the indentation, but you failed to include the indentation which makes the code unnecessary hard to read.

I don't know enough about VGA to know how to optimize this.

Have you turned on compiler optimizations? Have you tried running your program with a profiler to see where your program is spending the most time?

┬┐Shouldn't inline functions definitions be in headers?
Last edited on
could you revise your coding style a bit so that there are tabs, its a lot of stuff to process without clear levels. What emulator is this for?
@ne555 No inline only works if the code is visible, and hences inline. If the code was private to the .obj it would not work properly and there would be no speed up, defeating the purpose of inline functions. If his stuff is in the main file or in header (visible program statements) then he is doing it correctly.
Last edited on
@DeXecipher: It's for a x86 emulator (atm 8086/80186 implemented, still has little bugs unfortunately) i'm building from the ground up.

@Peter87: I've indented the code within the files.
Isn't code automatically optimized? Do I really need to set it in the Makefile?

Makefile: (It's for the PSP)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
TARGET = eboot
#Init for below:
OBJS = 
CFLAGS = 
CXXFLAGS = 
LIBS = 

#SDL for GPU!

#LIBS = -lstdc++ -lc -lSDLmain -lSDL  -lSDL_image -lSDL_ttf -lSDL_mixer -lfreetype -lpng -lz -lm -ljpeg -lpspaudio -lpsphprm -lpspgu -lpspwlan -lpsppower -lpsprtc 

#CFLAGS += $(shell sdl-config --cflags) 
#CXXFLAGS += $(shell sdl-config --cflags) 
#LIBS += $(shell $(PSPBIN)/sdl-config --libs) 

#Dosbox takeover!
# OBJS += gpu\dosbox_vga\int10_char.o gpu\dosbox_vga\int10_memory.o gpu\dosbox_vga\int10_misc.o gpu\dosbox_vga\int10_modes.o gpu\dosbox_vga\int10_pal.o gpu\dosbox_vga\int10_put_pixel.o gpu\dosbox_vga\int10_vesa.o gpu\dosbox_vga\int10_video_state.o gpu\dosbox_vga\int10_vptable.o

#Basic key input!
OBJS += support\input.o

#Timers&Threads!
OBJS += support\threads.o support\timers.o

#Basic Callback manager in-memory!
OBJS += cpu\cb_manager.o
#first, interrupts
OBJS += interrupts\interrupt13.o interrupts\interrupt10.o interrupts\interrupt18.o interrupts\interrupt19.o interrupts\interrupt16.o interrupts\interrupt5.o interrupts\interrupt11.o interrupts\unkint.o
OBJS += cpu\cpu_interrupts.o
#VGA Modes help:
OBJS += interrupts\modelist_vga.o interrupts\switchvideomode.o
#next, support
OBJS += basicio\dynamicimage.o support\isoreader.o support\varbuffer.o support\modrm.o support\lba.o support\crc32.o support\cpusupport.o support\state.o
#all main stuff we need
OBJS += basicio\io.o basicio\ports.o
#external chips
OBJS += hardware\82C54.o hardware\8042.o hardware\8237A.o hardware\8259A.o hardware\82093.o hardware\CMOS.o hardware\DP8390D.o hardware\soundblaster.o
#external chip caller:
OBJS += hardware\ports.o
#GPU:
OBJS += gpu\gpu.o
#VGA Adapter for CPU and EMU (non-view):
OBJS += hardware\vga\vga_textmodedata.o hardware\vga\vga_colorconversion.o hardware\vga\vga_vram.o hardware\vga\vga_dac.o hardware\vga\vga.o hardware\vga\vga_info.o hardware\vga\vga_modes.o
#VGA view:
# *1*: Sequencer Operation
OBJS += hardware\vga\vga_screen\vga_sequencer.o hardware\vga\vga_screen\vga_sequencer_graphicsmode.o hardware\vga\vga_screen\vga_sequencer_textmode.o hardware\vga\vga_screen\vga_sequencer_textmode_cursor.o
# *2*: Attribute Controller Operation
OBJS += hardware\vga\vga_screen\vga_attributecontroller.o
# *3*: DAC Operation
OBJS += hardware\vga\vga_screen\vga_dac.o
# *4*: Display Generation
OBJS += hardware\vga\vga_screen\vga_displaygeneration_crtcontroller.o
# *F* Finally, everything comes together
OBJS += hardware\vga\vga_screen\vga_screen.o
#BIOS:
OBJS += bios\bios.o bios\biosmenu.o bios\initmem.o
#MMU:
OBJS += mmu\memory_adressing.o mmu\paging.o mmu\mmuhandler.o mmu\mmu.o
#CPU:
#Interrupts used.
OBJS += cpu\hardware_interrupts.o
#Runromverify: Verifies ROM by execution.
OBJS += debugger\runromverify.o
#8086,80186 GRP Opcodes:
OBJS += cpu\8086_grpOPs.o
#Opcodes for CPU 8086,Debugger,Flags
OBJS += cpu\opcodes_8086.o debugger\8086_debugger.o cpu\flags.o
#Opcodes for CPU 80186,Debugger
OBJS += cpu\opcodes_80186.o debugger\80186_debugger.o
#Opcodes for CPU 80386&JMPTbl
#OBJS += cpu\opcodes0F_386.o cpu\opcodes_386.o
#Opcodes: unknown opcodes and rest handler functions (386 0x0F, unknown opcode handler for 386&8086)
OBJS += cpu\unkop.o
#Now the jumptables for all CPUs!
OBJS += cpu\cpu_jmptbls.o
#finally CPU module itself
OBJS += cpu\cpu.o
#Debugger
OBJS += debugger\debugger.o
#Basic timer handlers for timing etc.
OBJS += cpu\timers.o

#Rest and main script
OBJS += basicio\boot.o main.o

CFLAGS += -O2 -G0 -Wall
CXXFLAGS += $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

LIBS = -lpspgu -lpsppower -lpng -lz -lm -lstdc++ -lpspdebugkb

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = x86 emulator

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
Pages: 12