30Video: New video board for SE/30 / IIsi / more?

zigzagjoe

Well-known member
Hello! Here is a project I have been working on for the past couple months: the imaginatively named 30Video board. Using a newer (but still obsolete) controller from Epson, it targets SE/30, and is expected to work in IIsi too. Hopefully, the LC PDS later.... I've got some plans. here's the prototype in action.

20240613_115005.jpg

Currently, this is my featureset:

Two resolutions: VGA 640x480@60hz, SVGA 800x600@75hz
Supports B&W, 4-color, 16-color, 256-color modes (4096 color palette)
Supports System 6 - 8.1, and A/UX (3.0, maybe others)
Works with Carrera, Interware Booster, DiimoCache.
Compatible with IIsi and SE/30 ROMs in either 24 bit or 32 bit mode.
Correctly supports gamma profiles and defaults to linear gamma suitable for modern LCDs (CRT also available).

I expect it will work with PowerCache cards, and in IIsi, but will need to find a beta tester to confirm this.

Massive thanks go to @t-shinb for his backups of the Pickles source code, this was my touchpoint for much of the process. The Micron Color 30 source, SuperMario Mac OS leak, and @Melkhior's nubusfpga also provided valuable info on how others approached the same problem. I discovered lots of fun tidbits along the way.

"fun" tidbits for those writing DeclROMs
  • csBaseAddr is always harmful; do not ever return anything but 0 from any Control or Status call that supports it. Mostly it is ignored, but in some cases (Macsbug and some others) it willbreak things if nonzero.
    • The base address of your video buffer is calculated by the dCtlDevBase + offset in video mode entry, it must be consistent across all depths and modes your hardware supports (exception: if you reboot for a resolution change, then it can be different)
  • Hardware video pages are obsolete unused functionality that will never be used. Quickdraw cannot deal with its base address changing.
    • There is literally no point in implementing them (written after implementing them and trying to figure out how to test).
  • Despite apple saying 24 bit addressed devices can be used when the new slot manager loads, this does not seem to be true.
    • So you must kill the 24 bit resource and load 32 bit resource in SecondaryInit when new slot manager loads.
    • Also, you have to hack the GDevice's base address to the new 32 bit base if you were the boot device. Both are mandatory.
  • SE/30 ROM is dumb and will never load anything but the default TFB gamma table to a card that supports gamma.
    • For vintage cards already produced, if the card exposes custom gamma, you must manually select the appropriate card gamma entry in Monitors. (Workaround in the DeclROM is to identify this case and ignore it)
  • setEntries and getEntries use 16 bit color values. You must use the upper byte if you are less than 16bit, and in getEntries you can duplicate the same 8 bit entry into upper and lower bytes. (Why, apple? 48 bits of color info when 8 bits of color was a novel concept?)
  • Most of the status methods are obsolete and not ever used.
  • MODE32 closes all Drvr loaded by the ROM prior to switching into 32 bit mode, at which point it re-runs primaryinits but still with old slot manager! so you need 24 bit srsrc.
  • Despite A/UX 3.0 toolbox documentation stating otherwise, SDeleteSRTRec is at least partially supported in A/UX. Makes sense, as video cards with more than one mode would not work without it.
 

cheesestraws

Well-known member
Despite A/UX 3.0 toolbox documentation stating otherwise, SDeleteSRTRec is at least partially supported in A/UX. Makes sense, as video cards with more than one mode would not work without it.

I suspect what's going on here is that the Term "A/UX Toolbox" in the documentation usually means the toolbox as available to Mac applications or things in the Mac environment. Display drivers run in their own different context with a separate A-trap dispatch table, where different rules apply - and I'm fairly sure it's available there. And yes, SDeleteSRTRec would be necessary from the driver side...
 

zigzagjoe

Well-known member
I suspect what's going on here is that the Term "A/UX Toolbox" in the documentation usually means the toolbox as available to Mac applications or things in the Mac environment. Display drivers run in their own different context with a separate A-trap dispatch table, where different rules apply - and I'm fairly sure it's available there. And yes, SDeleteSRTRec would be necessary from the driver side...
Yeah, now that I actually looked at that document - it's absolutely intended for application developers. I guess that means the Micron Color 30 ROM I was tinkering with has another problem with A/UX then...
 

robin-fo

Well-known member
20240613_115005.jpg
It took me some time to recognize this as a SE/30 logic board. 😂 So many upgrades!

I really appreciate your work! Well done! 😃
 

zigzagjoe

Well-known member
Combined with an Ethernet controller, this card would be the ideal expansion for a IIsi!
I have something like that in mind, combined with @halkyardo's excellent work on the SEthernet design. I also like the idea of making a "trifecta" card that combines my booster design with both ethernet and video for a one-stop-shop. We'll see what happens...
 

Reasons.

Well-known member
This looks great! External video has always seemed like a great addition to the SE/30. Internal grayscale's cool, but I find myself limited by the resolution of the internal display much more than the color depth.
 

Melkhior

Well-known member
  • setEntries and getEntries use 16 bit color values
First, great job! What controller did you end up using that you could make compatible with the '030 bus?

About cscSetEntries - how many entries do you end up writing in the CLUT? In the *FPGA, I'm writing one more than I think I should (csCount + 1 instead of csCount), but if I don't one color is missing... It puzzled me when I wrote it, and it puzzled me when I had to fix the indirect fills (csStart >=0) for the "Fate of Atlantis" game, and I've still no idea what I'm doing/reading wrong.
 

zigzagjoe

Well-known member
First, great job! What controller did you end up using that you could make compatible with the '030 bus?

About cscSetEntries - how many entries do you end up writing in the CLUT? In the *FPGA, I'm writing one more than I think I should (csCount + 1 instead of csCount), but if I don't one color is missing... It puzzled me when I wrote it, and it puzzled me when I had to fix the indirect fills (csStart >=0) for the "Fate of Atlantis" game, and I've still no idea what I'm doing/reading wrong.

It's from Epson's S1D1 line. They still make entries in this line that are rather interesting, but it looks like CLUT support was removed at some point as it transitioned to become a purely LCD controller. The one I used is designed for late 90s stuff and will natively speak a multitude of bus interfaces including 68K. Looks to me like it was designed for PDAs as it was used in at least two that I found. It's been rather agreeable so far except for 15/16bit mode not respecting the endianness setting. If I can figure out how radius powerview monitors screen region updates, I may implement a VRAM shadowing mode where I quietly byteswap into the actual display buffer.

Next on my to-do list is implementing mode switching, of which the technical piece is done, but the UI is left. I'm in a bit of an unpleasant place since 6 and 7.1 need an extension iirc but 7.5 doesn't support that, instead need to use video families AFAIK...

SetEntries: No, that's correct behavior. Per DC&D: "Both csStart and csCount are zero based; their values are 1 less than the desired amount. "

While DC&D isn't always perfect (especially regarding obsolete stuff) it gave me a good touchpoint on the actual purpose of these calls. Though, many of them are obsolete... most of the original set of status routines don't seem to be used, Only GetGamma and GetMode I know of specific cases that use them. Other tidbits that seem to have been commonly accepted at the time were only demonstrated (such as the gdevice fixup) and never documented.

Do you know of anything that uses GetEntries?
 

Melkhior

Well-known member
It's from Epson's S1D1 line
I didn't even know Epson made graphics devices... I'll have to look them up for my own education, thanks for the reference.

Next on my to-do list is implementing mode switching, of which the technical piece is done, but the UI is left. I'm in a bit of an unpleasant place since 6 and 7.1 need an extension iirc but 7.5 doesn't support that, instead need to use video families AFAIK...
I didn't try any 6.x (the *FPGA require 32-bits mode with their 8 Mib framebuffer), but 7.1 worked in Qemu using the Monitor control panel, through 'options'. In there you do see the resolution name set in the DeclRom, though in later version the name seems synthesized by the OS (which isn't convenient when you want the same resolution twice, in my case for hardware vs. windowboxed).

SetEntries: No, that's correct behavior. Per DC&D: "Both csStart and csCount are zero based; their values are 1 less than the desired amount. "
I've read that line, but somehow my brain won't accept it... every time I look at that loop something in my head screams "there's an off-by-one error!!" and refuses to remember why it's OK. Weird.

Do you know of anything that uses GetEntries?
Don't remember, but I don't think so. The only 'weird' behavior I've seen was in cscSetEntries from "Fate of Atlantis" - it reloads the entire CLUT but using the index table. As in your experience, a lot of stuff is unused. The 'asm volatile(".word 0xfe16\n");' that appear in some calls in my DeclRom is to cause an illegal instruction and make it obvious they have been called... any still there means that was never called in any OS I've tried! The reverse is not true, I might have implemented some of the seemingly useful ones blindly and if they were never called I didn't notice (which may include cscGetEntries).
 

zigzagjoe

Well-known member
I didn't even know Epson made graphics devices... I'll have to look them up for my own education, thanks for the reference.


I didn't try any 6.x (the *FPGA require 32-bits mode with their 8 Mib framebuffer), but 7.1 worked in Qemu using the Monitor control panel, through 'options'. In there you do see the resolution name set in the DeclRom, though in later version the name seems synthesized by the OS (which isn't convenient when you want the same resolution twice, in my case for hardware vs. windowboxed).


I've read that line, but somehow my brain won't accept it... every time I look at that loop something in my head screams "there's an off-by-one error!!" and refuses to remember why it's OK. Weird.


Don't remember, but I don't think so. The only 'weird' behavior I've seen was in cscSetEntries from "Fate of Atlantis" - it reloads the entire CLUT but using the index table. As in your experience, a lot of stuff is unused. The 'asm volatile(".word 0xfe16\n");' that appear in some calls in my DeclRom is to cause an illegal instruction and make it obvious they have been called... any still there means that was never called in any OS I've tried! The reverse is not true, I might have implemented some of the seemingly useful ones blindly and if they were never called I didn't notice (which may include cscGetEntries).
Me either. Epson has some interesting framebuffer chips with embedded SRAM too (though this is not one of them). I've got 2MB of DRAM, though currently the most that will ever be used is about 480kb since I 16 bit currently is not on the table and hardware pages are literally pointless :(

Apple has a lot of weird choices. The interrupt one is the one that always gets me where 0 = enabled for some reason. And let's not even mention the 24->32bit slot manager stuff, that drove me up and down the wall.

I didn't realize Apple had mode switching implemented that in 7.1 also. Good call out. I may just go with that then, I'm less fussed about the 6 use case (though I want it to boot and work of course). I REALLY don't want to write software for mac os, the driver stuff has been enough of a trip as it is.

I thought that is what was going on with those FE16s - I do something similar for debugging purposes + my code is also full of debugging statements. I'd not have finished this without a strong debug facility. Using my ISP-SIMM, I can write a temporary flasher program to write a new DeclROM to the card and be back booting the Mac ROM in about 8 seconds... 1221 builds flashed to hardware and counting.

At first, I was using my PDSPico card as a janky FIFO that I could just jam bytes at but I've changed to serial for now. In case it helps someone, here's the rude way to steal the modem SCC and stick bytes up it.

C:
 // SCC registers SE/30
  #define aData ((volatile uint8_t*)(6 + 0x50F04000))        // offset for A channel data
  #define aCtl  ((volatile uint8_t*)(2 + 0x50F04000))         //offset for A channel control

inline void dbg_init() {
      *aCtl = 0x09; *aCtl = 0xC0;            //reg  9; *aCtl =  reset hardware
      *aCtl = 0x0F; *aCtl = 0x00;            //reg 15; *aCtl =  disable interrupts
      *aCtl = 0x04; *aCtl = 0x44;            //reg  4; *aCtl =  X16clk; *aCtl = 8 bit; *aCtl = 1 stop (original 2 stop 0x4C)
      *aCtl = 0x0B; *aCtl = 0x50;            //reg 11; *aCtl =  rClk = tClk = BR gen
      *aCtl = 0x0E; *aCtl = 0x00;            //reg 14; *aCtl =  disable BR gen
      *aCtl = 0x0D; *aCtl = 0x00;            //reg 13; *aCtl =  high byte 9600 baud   
      *aCtl = 0x0C; *aCtl = 0x0A;            //reg 12; *aCtl =  low  byte 9600 baud   
      *aCtl = 0x0E; *aCtl = 0x01;            //reg 14; *aCtl =  enable BR gen
      *aCtl = 0x0A; *aCtl = 0x00;            //reg 10; *aCtl =  NRZ
      *aCtl = 0x03; *aCtl = 0xC1;            //reg  3; *aCtl =  Rx 8 bits; *aCtl =  enabled
      *aCtl = 0x05; *aCtl = 0xEA;            //reg  5; *aCtl =  Tx 8 bits; *aCtl =  DTR/RTS   
      *aCtl = 0x01; *aCtl = 0x00;            //reg  1; *aCtl =  Ext Sts interrupts disabled
  }

  inline void dbg_printch (char c){
    *aCtl = 0x30;
    *aData = c;

    uint8_t i = 0; // timeout in case something takes back the serial port
    do {
      *aCtl=1;
    } while (! (*aCtl & 1) && ++i);
  }
 

zigzagjoe

Well-known member
This looks great! External video has always seemed like a great addition to the SE/30. Internal grayscale's cool, but I find myself limited by the resolution of the internal display much more than the color depth.
I agree - a larger color monitor considerably broadens what you can do with the machine.

@Melkhior, fun fact, switching res also works back in 6.0.8 as well.... which is interesting, because I assume they must have backported the new slot manager? Haven't looked into things too much, but I only prepare resources for video mode families if new slot manager is present and secondary init is run.... so if it worked, that had to have occurred.
 

zigzagjoe

Well-known member
Thanks to a helpful fellow at VCF who, I think, is reading this thread - we popped it into an IIsi and it worked perfectly there.

Here's a tidbit of something interesting...

1718825848909.jpeg
 
Last edited:

zigzagjoe

Well-known member
Another tease! Just a little bit of spaghetti going on.

The objective here is to implement the switchable video of the original Micron design: you either can run the internal screen at 512*342 and grayscale, or you can use an external monitor at VGA / SVGA resolution while the internal display will run in B&W.

1719000860701.jpeg
 

zigzagjoe

Well-known member
Take my money! Nice work

I hope to have these available soon, but soon is a relative thing when parts involve overseas shipping and time to build cards/harness/neckboard.

Here's a WIP. The passthrough connector can also be a straight connector for use in the IIsi.

1719267873480.png
 
Top