I think if you build a dedicated board you can design it right, but for people already using the direct P2-EVAL breakout using Parallax supplied Digital Video Out board without resistors, perhaps this float/1.5k setting is okay, OR if it varies from cable/setup we can try the BITDAC approach.
I felt rather uneasy about having the direct 0V drive down and 3.3V drive up approach I'd been using myself in my driver (so I went and released it with the 1.5k drive coded in for high and low) but perhaps with the 50 ohm termination in the DVI/HDMI receiver it shouldn't ever be a dead short. This float up and 1.5k pull down seems safe(ish?) if it also works for other people. We sort of need people to try it out to see if it works.
Alternatively the BITDAC level version might be a more universal/well constrained solution to be used with the Digital Video Out board.
If the outputs are 3.3V/0V CMOS then an external 270 ohm series resistor at each output will emulate a CML transmitter, which is open-collector so floating high is not a problem. 1.5k seems a very large pull-down, compared to the 50 ohm pull-ups in the receiver. Is it possible to measure the voltage carefully across a differential pair somewhere in BITDAC mode when the receiver is switched on? This should eliminate the guesswork about internal and pin resistances.
A BITDAC mode may not need the resistor if the P2 is already internally using 123 ohms. I am assuming we can use the BITDAC to set the DC level output from 0-3.3V in 3.3V/15 increments. I would think this allows us the range to develop the 400mV to 600mV swing across the termination resistor in the receiver fairly accurately, however reflections might become an issue if the impedance doesn't match the transmission line when we switch between high and low. To get it to match you might have to have a parallel resistance too.
A raw GPIO mode (~20 ohms in the P2) could use a series resistor to help limit the current, because it appears that simply grounding it via 20 ohms is too high a current for the swing we want, and this extra resistor it could help absorb any reflections if it matches the impedance. You should still be able to use the float high case I think (it looks like CML is designed with that in mind) but driving it up to 3.3V as well is probably ok if the impedance matches.
I'm happy that float high and pull low via 1.5k works in my setup (it seems pretty safe) but this may only be because the LCD monitor's CML receiver is far more sensitive than the specs require.
On the face of things, BITDAC mode using 3.3V & 1.32V (steps 15 & 6) would give ~500mV at the receiver, with no external resistors, if that is safe to try.
On the face of things, BITDAC mode using 3.3V & 1.32V (steps 15 & 6) would give ~500mV at the receiver, with no external resistors, if that is safe to try.
Yes, I think that would be okay.
I just tried it with BITDAC HHHH_LLLL set to 1111_0110 it looks okay, no sparkling pixels.
Also tried with 1111_0111 and that was good too. They both should fall within the 400-600mV range I think (from a DC standpoint anyway).
I just found a bug in my current video driver code affecting interlacing with region wrap in graphics modes.
To fix it in your codebase just change this line in the "newregion" routine...
if_z incmod rowscan, rowheight wz
to this
if_z_and_nc incmod rowscan, rowheight wz
I will add the fix to the next release.
I am also seeing some weirdness with region wrapping in the text mode, as it is meant to start a new text row at the wrapped scan line in the region but instead seems to continue on from the same scan line row offset in the font it left off with. The row number is also not being incremented correctly in all cases and this can affect the cursor size at the wrapping point on the screen. I know I did still have some issues with some tricky line doubling, interlacing and wrapping combinations and some of it may require wrapping on even scan line boundaries. Hopefully any fixes I decide to add there will fit in the remaining longs left free for my bug fixes...
I think I found a fix for the remaining text region wrap issues, and I'm testing it out. It looks like the fix needs to use up 3 more longs and after my last PAL CQ colour flip changes I put into the code I think there were only 2 longs left in the COG. Thankfully today I found a way to free up 4 more longs in the code (2 very quickly which I already did in order to test this fix, and a further 2 more are possible with a bit more work in rearranging some lookup table data).
With any luck the solution I've found now solves the combinations of interlaced/line doubling with odd/even scan line wrap points in the text region, so there shouldn't be any restrictions. After the wrap point in the region the font starts at row offset 0 and the row number increments by one from the previous screen row, so the cursor looks good again. So far it seems okay in VGA but it's rather flickery in interlaced mode and I need to prove it out on a proper interlaced monitor to make sure it looks good there too.
However when testing this fix I did find that for some reason none of my SD/HD TV video output modes are working - this could be a simple software setup/timing issue in the test code or I might have introduced a regression somewhere in the driver. Now need to figure that out too.
Update: I posted too soon, there seems to still be an issue with line doubling enabled and wrapping on odd boundary offsets in text regions, which leaves a single pixel line before the end of the wrap point and at the start of the wrapped region if the wrap scan line count is an odd number. I can't easily fix this without breaking the mouse calculations or adding even more new code and state to adjust scan line counters. I think if we are line doubling we should just expect to have to set the wrap boundary on an even number of scanlines in a region for things to make sense visually. In most cases the wrap point in a text mode region would be setup at the end of a complete font row anyway, certainly if you are using wrapping to enable high speed vertical text scroll without block copying, which is probably one of its main benefits. Apart from split screen text region effects the only other purpose of supporting wrapping with text is to hide the last screen row if it doesn't fit the remaining scan lines on the screen because you can point that final excess portion to a different memory buffer just containing blanks.
Update2: l found the issue with my other TV output modes. I had left a line controlling custom timing commented out in the driver setup code during a recent test. I restored that init code and my analog TV modes are working again.
I've been working on the driver fixes and think it is close to another release. I'm just tidying it up a fraction more and also updating the documentation to try to get things in sync. Once that is done soon I'll try to post it, perhaps also with my HyperRAM arbiter that allow it to work with this external memory (though that is a slightly separate effort).
Here's the summary of the current driver changes for my next release.
New features:
- added proper PAL phase alternation for better SDTV PAL colour output
- activate two mono text mode(s) when p2:pixel clock ratio is low (i.e. mono text only when 2 <= ratio < 5, colour text if ratio >= 5)
Other changes:
- made COG driver code memory position independent - useful for MicroPython
- changed DVI mode pin output to use the P2 BIT DAC output
- reduced hub data transfers in text mode by making it screen width dependent
- optimized region init code to save more instructions
- set default to VGA timing not SVGA when no timing passed
- enabled optional extra front porch in interlaced TV modes
- handled more odd clock count cases in analog TV mode timing computations
- added external memory driver to the SPIN2 API
- optimized CQ/CI/CY parameter order for PAL and added CQ flip xor parameter
- added further comments to the code
Bug fixes:
- fixed pin group bug in setup code affecting pixel output
- fixed rowscan offset after region wrap in text mode
- fixed bug with interlacing after region wrap in gfx mode
- fixed bug with external memory use affecting scan line buffer alternation
- fixed bug with cursor1 and cursor2 register offsets in COGRAM
- fixed bug in SPIN2 API for cursor initialization
Any chance you could point me to the old code/docs so I can get a jump on learning these things? I’m working my way through a stack of posts in several threads but I’m not seeing a recent code bundle.
As an interim question: does your driver support some of the low-end modes such as 800x600x16 color analog VGA mode? Much of what I do needs analog VGA/Svga text-only output but not many colors for a basic textual HMI. I know this is sort of like driving a Ferrari in a crowded parking lot, but...
Hi JRoark. The first post in this thread contains a zip file containing the initial driver (beta) release and its documentation which is the last one I've posted.
Yes the driver certainly supports this 800x600x16 colour resolution with analog VGA outputs. For graphics only you can probably run it as low as 2x pixel clock (so 80MHz for SVGA), but for a 16 colour text mode the P2 would need to be clocked higher. Currently for text you'd need 4-5x for SVGA I think, so setup a 200MHz P2 to be safe. Soon you'll be able to use mono text with the P2 down as low as a 2x pixel clock.
If you wanted just transparent passthrough graphics frame buffer data read from HUB RAM (i.e. no mouse, text or pixel doubling features from the driver) you could probably get it to run with a P2 as low as 40MHz for typical SVGA timing.
Thanks JRoark. Yeah I think the first beta is pretty solid. Haven't seem any real crashes in all my own tests, it's just a few minor bug fixes so far really. The only thing that can affect things is if you push it too hard by shrinking sync timing too far or trying to do too many things like enable a mouse, borders or pixel doubling in 24bpp mode while the P2 clock speed is too low to support that particular processing workload in the scan line time. At that point the video output can obviously be corrupted and/or a monitor can fail to sync but the code will still run, nothing typically locks up. If you go past what can reliably be output in any cycle budget, just drive the P2 clock higher or reduce the resolution if you can. It's nice and scalable in its abilities.
If you like it so far you should see what is really possible with this driver and the external memory stuff coming next. That opens up some decent frame buffer sizes for the P2. Also this current driver architecture should enable sprite drivers tapping into it too - I plan to make something there at some point, but others could easily do so as well.
You’ll be repulsed, but I have a confession. I’m cannablizing it already, trying to make it a completely self-contained “engine” so I can use it from FlexBASIC. Right now it needs buffers, font files, and stuff like that declared externally and then passed to it so it can init and run. I want all of that stuff internal/local to the driver so the only interfaces to it are things like “print this string”, “put the cursor here”, etc.
So far I’ve managed to break it rather spectacularly... but admittedly that’s half the fun. I’ve managed a few simple methods (clear screen, locate cursor @ x/y, set fg/bg colors, etc) but I really just need to print your code out and get away from the machine for a bit so I’m not tempted to tweak before I have a better understanding of your code.
Yeah each P2 environment sort of needs its own appropriate way to bundle/package the driver COG appropriately with an API etc. Right now it is all controlled via HUB data structures so it is very generic and language agnostic.
I have only done a simple demo API so far for Fastspin's SPIN2, and tried some simple tests including it with MicroPython. It would be handy to put together something with a C interface at some point to enable that language and obviously something for official Parallax SPIN2 when that is available.
I know Peter Jakacki was interested in using this with his Forth too, and now you with FlexBASIC. It should be possible for any P2 environment to make use of this COG in the end. I certainly don't plan to try to mandate any API, people can just add whatever they want on top to suit their needs. It's just the hub data structures this video driver uses in the end that control it. I'm planning to keep these mostly static but they still could extended from release to release as additional output interfaces are added, for example LCD's or CGA or HDMI etc. So if you ever pickup a new release you may still need to re-validate your code or check for changes there. I'm trying to get the new release out soon with the bug fixes (probably only bugs 1 and 5 in the list of changes posted above are the main ones that may affect you).
One thing that is needed to make a standalone system, aside from a good video driver, is a FAT system for the 16MB flash chip. It would be really cool to be able to call routines to read and write files.
Yes a local FAT or other flash filesystem will be very handy. I think in some cases it might become extravagant to allocate a standalone COG to manage it like we need to with video, so longer term it could be coded in the language of choice and just called synchronously by the client, perhaps in a hub exec mode. That being said I'd be very happy to see and use a dedicated COG for hosting a filesystem from flash in the short term if someone developed one that was solid. The SD card is the other option for FAT but that comes with its own variabilities and is also removable which can be both good and bad.
Only the low level SD routines for Initialisation, plus Read and Write sector routines would need to change (and of course their lower level routines). The CSD/CID routine would need to be trapped as they are specific to SD IIRC.
All the top level FAT routines would remain the same.
IIRC there are a couple of locks that are read/written on the SD card. These could cause wear levelling problems.
I'm turning into a serious @rogloh fanboy. This is 1920x1200 mode (DVI) into a 24 inch ASUS monitor. This is 240 characters by 75 lines. Crystal clear. Perfectly stable. Prop2 dev board for scale. (With a dangling DS3231 RTC off the side. Oops. You didn't see that)
Just... WOW!
EDIT: I thought it was maxxed-out at 240x75 text. Wrong. It will do 240 x 150 chars using the EGA14 font at 1920x1200 resolution.
Looks great!
I've had 240x128 on 1920x1024 Acer 24" monitor on the RevA boards at 148.5MHz using VGA. Not a true terminal program, just the display of fixed characters using 8x8 font. Looed great after I got rid of the shimmering effect.
LOL. If you want the highest resolution text @JRoark , with the next release version you can do mono text with the P2 as low as a 2x pixel clock. This enables 240x200 with a 6 line font on 1920x1200 monitors at 60Hz. I posted these images earlier in my other discussion thread a little while ago if you've not seen it...
This is probably about the practical readable limit the driver can hit, though you could always try shrinking the font height more if you only wanted to output non-alphabetic characters or other tiny symbols.
Also with its HyperRAM external memory driver interface you'll eventually be able to do this sort of thing too if you've not seen this either...multiple COGs can access the same HyperRAM and draw graphics dynamically while the video COG uses it as a frame buffer.
I need to get back to work on that again. It already somewhat works nicely at some resolutions but I need to tidy it up a bit and attempt the 4us fragment transfers to avoid refresh corruption issues that creep in when the memory is starved of refresh at higher resolutions.
@JRoark , just noticed something in your post above, you are using the DVI breakout board. Do you know what vertical refresh you had in the picture above and what P2 clock rate worked with that hires text output resolution? If you use DVI the driver requires the P2 to operate at a 10x pixel clock. So for 1920x1200 output the vertical refresh would have had to be very much less than 60Hz to allow it to work. What can your monitor achieve? My Dell 2405 only likes its VSYNC frequency to be > 50 Hz (though works down to around ~48Hz or so I think in practice IIRC). Yours would appear to work at something around 10-15Hz or so at this resolution, depending on your P2 clock rate and reduced blanking etc. What timing did you apply?
@rogloh I have to admit I am not manually setting any clock speeds! Your driver does it all. In that picture I am using your simple demo program and feeding it my own text file with just a couple of params (VGA/DVI, linebuffer, screensize, etc) tweaked.
When I get back to my bench I’ll see what speed the Prop is running at. I’m curious too.
That monitor has aptly handled every oddball mode I have thrown at it. Its 4 years old now, but was kind of expensive when I bought it. It wouldnt surprise me to find that its working down that low.
@rogloh Ok! We have data... and I lied... and an oddity!
Data:
The P2 clock speed for what the driver calls "1920x1200" in DVI mode is 308 mhz.
I Lied:
Turns out the monitor is a 28 inch, not a 24 inch. My bad. It's an ASUS PB287Q (4K UHD (3840 x 2160) display with 1ms response time and 60Hz refresh rate. I'm still looking for a specific list of the various modes/refresh capabilities, but the spec says "24 ~99 KHz (H) / 30 ~75 Hz (V)".
The Oddity:
By my math, 1920x1200 using the "font6" font file should give us 240 cols by 200 rows of text. But see the picture. I can fit *210* rows on-screen. It isn't scrolling. It all fits.
The only parts of your DEMO.SPIN2 code that I'm manipulating are:
LINEBUFSIZE = 240*4 ' for VID#RES_1920x1200
SCREENSIZE = 240*200 ' for VID#RES_1920x1200
timing := vid.getTiming(VID#RES_1920x1200)
vid.initDisplay(@display, VID#DVI, VGA_BASE_PIN, VGA_VSYNC_PIN, VID#RGBHV, @lineBuffer1, LINEBUFSIZE, timing)
fontvga16 file "font6"
features file "240x200.txt"
Everything else is box-stock-Rogloh.
EDIT: I went ahead and added the CPU speeds to a table I had been developing. In the process of this I discovered there seem to be multiple cases where the expected character row counts do not match what the driver actually produces. This only happens on the higher resolutions. See the table below:
Man, that's like microfiche. If you can get 200 rows in landscape, you could get 320 rows in portrait mode. Seeing lots of code at once is like high-def for your programming mind.
Comments
If the outputs are 3.3V/0V CMOS then an external 270 ohm series resistor at each output will emulate a CML transmitter, which is open-collector so floating high is not a problem. 1.5k seems a very large pull-down, compared to the 50 ohm pull-ups in the receiver. Is it possible to measure the voltage carefully across a differential pair somewhere in BITDAC mode when the receiver is switched on? This should eliminate the guesswork about internal and pin resistances.
A raw GPIO mode (~20 ohms in the P2) could use a series resistor to help limit the current, because it appears that simply grounding it via 20 ohms is too high a current for the swing we want, and this extra resistor it could help absorb any reflections if it matches the impedance. You should still be able to use the float high case I think (it looks like CML is designed with that in mind) but driving it up to 3.3V as well is probably ok if the impedance matches.
I'm happy that float high and pull low via 1.5k works in my setup (it seems pretty safe) but this may only be because the LCD monitor's CML receiver is far more sensitive than the specs require.
Yes, I think that would be okay.
I just tried it with BITDAC HHHH_LLLL set to 1111_0110 it looks okay, no sparkling pixels.
Also tried with 1111_0111 and that was good too. They both should fall within the 400-600mV range I think (from a DC standpoint anyway).
Change this line in p2videodrv.spin2 to this for float high pull low with 1.5k or replace with this for BITDAC
To fix it in your codebase just change this line in the "newregion" routine... to this
I will add the fix to the next release.
I am also seeing some weirdness with region wrapping in the text mode, as it is meant to start a new text row at the wrapped scan line in the region but instead seems to continue on from the same scan line row offset in the font it left off with. The row number is also not being incremented correctly in all cases and this can affect the cursor size at the wrapping point on the screen. I know I did still have some issues with some tricky line doubling, interlacing and wrapping combinations and some of it may require wrapping on even scan line boundaries. Hopefully any fixes I decide to add there will fit in the remaining longs left free for my bug fixes...
With any luck the solution I've found now solves the combinations of interlaced/line doubling with odd/even scan line wrap points in the text region, so there shouldn't be any restrictions. After the wrap point in the region the font starts at row offset 0 and the row number increments by one from the previous screen row, so the cursor looks good again. So far it seems okay in VGA but it's rather flickery in interlaced mode and I need to prove it out on a proper interlaced monitor to make sure it looks good there too.
However when testing this fix I did find that for some reason none of my SD/HD TV video output modes are working - this could be a simple software setup/timing issue in the test code or I might have introduced a regression somewhere in the driver. Now need to figure that out too.
Update: I posted too soon, there seems to still be an issue with line doubling enabled and wrapping on odd boundary offsets in text regions, which leaves a single pixel line before the end of the wrap point and at the start of the wrapped region if the wrap scan line count is an odd number. I can't easily fix this without breaking the mouse calculations or adding even more new code and state to adjust scan line counters. I think if we are line doubling we should just expect to have to set the wrap boundary on an even number of scanlines in a region for things to make sense visually. In most cases the wrap point in a text mode region would be setup at the end of a complete font row anyway, certainly if you are using wrapping to enable high speed vertical text scroll without block copying, which is probably one of its main benefits. Apart from split screen text region effects the only other purpose of supporting wrapping with text is to hide the last screen row if it doesn't fit the remaining scan lines on the screen because you can point that final excess portion to a different memory buffer just containing blanks.
Update2: l found the issue with my other TV output modes. I had left a line controlling custom timing commented out in the driver setup code during a recent test. I restored that init code and my analog TV modes are working again.
Here's the summary of the current driver changes for my next release.
New features:
- added proper PAL phase alternation for better SDTV PAL colour output
- activate two mono text mode(s) when p2:pixel clock ratio is low (i.e. mono text only when 2 <= ratio < 5, colour text if ratio >= 5)
Other changes:
- made COG driver code memory position independent - useful for MicroPython
- changed DVI mode pin output to use the P2 BIT DAC output
- reduced hub data transfers in text mode by making it screen width dependent
- optimized region init code to save more instructions
- set default to VGA timing not SVGA when no timing passed
- enabled optional extra front porch in interlaced TV modes
- handled more odd clock count cases in analog TV mode timing computations
- added external memory driver to the SPIN2 API
- optimized CQ/CI/CY parameter order for PAL and added CQ flip xor parameter
- added further comments to the code
Bug fixes:
- fixed pin group bug in setup code affecting pixel output
- fixed rowscan offset after region wrap in text mode
- fixed bug with interlacing after region wrap in gfx mode
- fixed bug with external memory use affecting scan line buffer alternation
- fixed bug with cursor1 and cursor2 register offsets in COGRAM
- fixed bug in SPIN2 API for cursor initialization
As an interim question: does your driver support some of the low-end modes such as 800x600x16 color analog VGA mode? Much of what I do needs analog VGA/Svga text-only output but not many colors for a basic textual HMI. I know this is sort of like driving a Ferrari in a crowded parking lot, but...
Yes the driver certainly supports this 800x600x16 colour resolution with analog VGA outputs. For graphics only you can probably run it as low as 2x pixel clock (so 80MHz for SVGA), but for a 16 colour text mode the P2 would need to be clocked higher. Currently for text you'd need 4-5x for SVGA I think, so setup a 200MHz P2 to be safe. Soon you'll be able to use mono text with the P2 down as low as a 2x pixel clock.
If you wanted just transparent passthrough graphics frame buffer data read from HUB RAM (i.e. no mouse, text or pixel doubling features from the driver) you could probably get it to run with a P2 as low as 40MHz for typical SVGA timing.
If you like it so far you should see what is really possible with this driver and the external memory stuff coming next. That opens up some decent frame buffer sizes for the P2. Also this current driver architecture should enable sprite drivers tapping into it too - I plan to make something there at some point, but others could easily do so as well.
You’ll be repulsed, but I have a confession. I’m cannablizing it already, trying to make it a completely self-contained “engine” so I can use it from FlexBASIC. Right now it needs buffers, font files, and stuff like that declared externally and then passed to it so it can init and run. I want all of that stuff internal/local to the driver so the only interfaces to it are things like “print this string”, “put the cursor here”, etc.
So far I’ve managed to break it rather spectacularly... but admittedly that’s half the fun. I’ve managed a few simple methods (clear screen, locate cursor @ x/y, set fg/bg colors, etc) but I really just need to print your code out and get away from the machine for a bit so I’m not tempted to tweak before I have a better understanding of your code.
Well done, Rogloh!
I have only done a simple demo API so far for Fastspin's SPIN2, and tried some simple tests including it with MicroPython. It would be handy to put together something with a C interface at some point to enable that language and obviously something for official Parallax SPIN2 when that is available.
I know Peter Jakacki was interested in using this with his Forth too, and now you with FlexBASIC. It should be possible for any P2 environment to make use of this COG in the end. I certainly don't plan to try to mandate any API, people can just add whatever they want on top to suit their needs. It's just the hub data structures this video driver uses in the end that control it. I'm planning to keep these mostly static but they still could extended from release to release as additional output interfaces are added, for example LCD's or CGA or HDMI etc. So if you ever pickup a new release you may still need to re-validate your code or check for changes there. I'm trying to get the new release out soon with the bug fixes (probably only bugs 1 and 5 in the list of changes posted above are the main ones that may affect you).
Enjoy it.
Only the low level SD routines for Initialisation, plus Read and Write sector routines would need to change (and of course their lower level routines). The CSD/CID routine would need to be trapped as they are specific to SD IIRC.
All the top level FAT routines would remain the same.
IIRC there are a couple of locks that are read/written on the SD card. These could cause wear levelling problems.
Just... WOW!
EDIT: I thought it was maxxed-out at 240x75 text. Wrong. It will do 240 x 150 chars using the EGA14 font at 1920x1200 resolution.
I've had 240x128 on 1920x1024 Acer 24" monitor on the RevA boards at 148.5MHz using VGA. Not a true terminal program, just the display of fixed characters using 8x8 font. Looed great after I got rid of the shimmering effect.
https://forums.parallax.com/discussion/comment/1485247/#Comment_1485247
This is probably about the practical readable limit the driver can hit, though you could always try shrinking the font height more if you only wanted to output non-alphabetic characters or other tiny symbols.
Also with its HyperRAM external memory driver interface you'll eventually be able to do this sort of thing too if you've not seen this either...multiple COGs can access the same HyperRAM and draw graphics dynamically while the video COG uses it as a frame buffer.
https://forums.parallax.com/discussion/comment/1485242/#Comment_1485242
I need to get back to work on that again. It already somewhat works nicely at some resolutions but I need to tidy it up a bit and attempt the 4us fragment transfers to avoid refresh corruption issues that creep in when the memory is starved of refresh at higher resolutions.
When I get back to my bench I’ll see what speed the Prop is running at. I’m curious too.
That monitor has aptly handled every oddball mode I have thrown at it. Its 4 years old now, but was kind of expensive when I bought it. It wouldnt surprise me to find that its working down that low.
Data:
The P2 clock speed for what the driver calls "1920x1200" in DVI mode is 308 mhz.
I Lied:
Turns out the monitor is a 28 inch, not a 24 inch. My bad. It's an ASUS PB287Q (4K UHD (3840 x 2160) display with 1ms response time and 60Hz refresh rate. I'm still looking for a specific list of the various modes/refresh capabilities, but the spec says "24 ~99 KHz (H) / 30 ~75 Hz (V)".
The Oddity:
By my math, 1920x1200 using the "font6" font file should give us 240 cols by 200 rows of text. But see the picture. I can fit *210* rows on-screen. It isn't scrolling. It all fits.
The only parts of your DEMO.SPIN2 code that I'm manipulating are:
Everything else is box-stock-Rogloh.
EDIT: I went ahead and added the CPU speeds to a table I had been developing. In the process of this I discovered there seem to be multiple cases where the expected character row counts do not match what the driver actually produces. This only happens on the higher resolutions. See the table below:
See the 2 pictures attached. I included the pic of the left screen margin so you can see I'm not cheating on the numbering. Sharpie for scale.