Let us posit that one has a need to obtain an image of the instrument ROM of an Ensoniq Soundscape S-2000, Elite, or OPUS sound card. There are two basic approaches: A) Desolder or cut off the ROM chip, plug into a PROM reader, extract the data; or B) Design and write software to read the ROM contents and leave the hardware intact. Method A) is crude but effective—very simple but potentially destroys the card. So let’s see how method B) might be done.
First it is necessary to understand the architecture of the Ensoniq Soundscape. This text will focus on the original S-2000 and Elite, with a brief note on the newer Opus and VIVO cards.
The S-2000 is a 16-bit sound card with an onboard synthesizer and instrument ROM. The card is compatible with Sound Blaster and AdLib (Yamaha OPL2/OPL3) standards, as well as MPU-401 and General MIDI, but the compatibility is implemented purely in software (firmware in fact). The S-2000 has four major chips, clearly seen in the above photo: Ensoniq ODIE (ES 5706), the system interface and control gate array; Ensoniq OTTO (ES 5506), the wavetable synthesizer chip; Analog Devices AD1848, the audio codec; and Motorola 68EC000, the OBP (On-Board Processor). There is also 128KB of DRAM for use by the OBP, and an instrument ROM with 1 or 2 MB of data (our target).
Much like it was the case with E-mu/Creative, Ensoniq’s sound cards were essentially the respective company’s cut-down synthesizers on an ISA card; in Ensoniq’s case it was the TS-10/TS-12. The Soundscape was clearly not intended for musicians (it was a consumer/gaming card) and therefore had no sampler functionality (no sample RAM), even though the OTTO synthesizer could have handled it without trouble.
Note: For reasons which are not clear, certain people think that just because a chip has ‘(C) SEQUOIA DEV GRP’ etched on it, it must be called “Sequoia”. Sequoia Development Group was in fact a company specialized in developing MIDI equipment and is known to have provided the firmware for the Logitech Soundman Wave card (Yamaha OPL4 synthesizer) or Samsung KS0164 and KS0165 synthesizer chips. The Ensoniq chip in question is clearly called ODIE.
Besides the instrument ROM, there is no other ROM on the Soundscape card. The OBP obviously needs some code to run; the firmware is uploaded into the RAM on the card by the host. There does not appear to be any way to read the ROM directly from the host (there’s no way to map it such that it would be accessible through memory or I/O space, and it does not appear to be accessible via DMA either). But the OBP firmware can and must access the instrument ROM, because the synthesizer chip has no direct understanding of the ROM; the OBP firmware reads the ROM to find out where and how the waveforms corresponding to specific instruments are stored, and directs the OTTO synthesizer chip to access the waveform data. In fact there are several OBP firmware versions corresponding to different instrument ROMs, and a miniature firmware module (SCOPE.COD) is used to read the ROM and report back to the host which actual firmware variant (SOUNDSCAPE.COx) it should upload.
The OBP firmware handles Sound Blaster emulation, AdLib emulation, as well as General MIDI. Thanks to this design, from the host side the S-2000 looks like a pure hardware implementation and doesn’t require any special TSRs or other software running on the host (unlike the later VIVO cards).
So all we need to do is write special firmware for the OBP, upload it to the card, and then communicate with it to obtain the ROM data. Should be easy, right? Well, perhaps not easy, but doable once we have the ODIE datasheet and some OSS/ALSA driver code which can upload the OBP firmware.
Custom OBP Firmware
As it turned out, writing the custom firmware was the easier part, even for someone with approximately zero knowledge of 68000 assembler. SCOPE.COD (part of the Soundscape driver package) proved to be an excellent example because it already accesses the ROM. There is one tiny wrinkle—for reasons that are not obvious, the OBP firmware files are byte-swapped. That means they must be un-swapped before any attempt to disassemble them, and the custom-built firmware image needs to be byte-swapped again before uploading to the OBP.
A brief attempt was made to extract the ROM contents via DMA. In theory it might be possible to have the OBP program ODIE to point at the instrument ROM and use DMA to transfer it to the host, but that didn’t work. Either some additional steps were needed or the ROM is actually not accessible to ODIE (entirely plausible, since ODIE doesn’t need it).
The working implementation uses a very simple approach: Read the ROM byte by byte and write it to ODIE’s host data communication register where the host can read it from. On both the OBP and host side there are status bits indicating whether the host data register is empty or full; that way we can implement simple and reliable transfer, with the OBP writing another byte once the data register becomes empty (i.e. host read it), and the host reading another byte once the data register becomes full (i.e. OBP wrote it). This is not blazingly fast, but dumping 2 MB of ROM this way still takes well under a minute on a 486 system.
For whatever reason, only every other byte contains ROM data, which means that odd bytes need to be skipped. And it is also worth mentioning that some higher-order address bits are ignored, which means the ROM is mapped multiple times into the OBP’s address space.
The EASy64K Editor/Assembler was used to assemble the custom firmware, SRecord version 1.64 was then used to convert it to binary and byte swap. Zero experience with Motorola 68000 assembly language proved to be of next to no consequence.
Host-Side ROM Extractor
Now for the host part. As mentioned above, the host side is far more complex, with several hundred lines of C code (compared to a handful of assembly instructions for the firmware).
The host tool runs under DOS for the sake of simplicity, and is written in 16-bit C. Using a 32-bit environment would be entirely possible but wouldn’t buy much. Using a “better” OS was rejected because it would only complicate the code and make much higher demands on the host system. The actual hardware used was an Alaris Cougar VLB board with a 66 MHz Intel 486 OverDrive processor and a CF to IDE adapter. The compiler used was Watcom C, primarily because it’s very easy to cross-compile from a Windows machine and do the bulk of development on a modern system (with the inevitable debugging and tweaks on the 486).
The host tool needs to detect an ODIE-based Soundscape card, perform basic initialization, set up host DMA controller, upload the firmware via DMA (potentially in multiple blocks), start the OBP, and communicate with the firmware using the host communication register.
There is a fair amount of code which needs to be in place before anything at all starts happening (never a good situation to be in). Fortunately it only took a few iterations to get to a point where the OBP firmware was successfully initialized—after crashing the host a few times due to incorrect programming of the host DMA controller.
The actual ROM dumping was quite easy and only needed proper observation of the empty/full status bits to reliably read a megabyte or two of data.
The completed ROM dumper is available here. It’s not particularly polished and has not been widely tested, but works on at least one system with several cards.
The Soundscape Opus (3000-series) is a lower cost OEM-only product. It has no provision for CD-ROM support but it does support PnP. The functionality of OTTO and ODIE appears to be integrated in a new chip called OPUS (likely ES 5530). Programming the OPUS chip is not significantly different from programming ODIE/OTTO. Instead of a separate DAC for the wavetable synth, everything is handled by an AD1845 codec. There is still a separate 68EC000 OBP and similar OBP firmware.
Adapting the ROM dumping tool for OPUS turned out to be trivial—all it took was adjusting the detection logic to accept the OPUS (the original detection failed because OPUS has more registers). The existing OBP firmware DMA upload logic worked just fine, and the firmware itself didn’t need any changes either.
The VIVO is a rather different beast. The 4000-series Soundscape VIVO uses a standalone OTTO synth again, but completely drops the OBP. What that means is that everything is run on the host CPU, using a rather clever patented technique which places a “TSR” into protected memory.
For the purpose of this project, the VIVO is a completely unrelated design because there’s no OBP, hence no OBP firmware. And also no documentation. On the other hand the VIVO uses the exact same instrument ROM as Opus, so there has been no real incentive to deal with the VIVO either.
It is worth noting that the VIVO is a clear evolutionary step between the original S-2000 and the 5000-series AudioPCI (one of the first PCI-based sound cards). The AudioPCI goes further and also drops the synthesizer chip, doing everything in software. But in principle the AudioPCI builds on the techniques pioneered by VIVO.
What does all this signify? Probably not much. Perhaps that a little bit of information can go a long way.
The byte swapping is probably done in hardware to make it easier to transfer 16 bit data between the x86 architecture in a PC and the 68k architecture on the sound card. One is big endian and the other is little endian.
Also Motorola 68000 (and 68010, and also 68040 and 68060) has no buildt in hardware to handle different bus sizes so it’s common procedure to connect 8-bit peripherials to just one half of the 16 bit data bus and just ignore every other byte. (In fact if you mix which half of the 16 bit data bus each 8 bit peripherial sits on you can reduce the load on the data bus. Commodore Amiga resused the “CIA” 8520 from the C64/C128 computers, and since those are 8-bit one sits on the upper and the other on the lower half of the 68000 data bus). Motorla 68020 and 68030 do have hardware to handle 8/16/32 bit bus width and also handle misaligned data.
You’re almost certainly right about the byte swapping. The DMA engine is designed to transfer 16-bit samples between the host (little-endian) and the OBP (big-endian), so automatic swapping makes sense.
I don’t really know if the ROM is attached as an 8-bit device, but it’s possible. If it’s 8-bit then that would make sense together with the 68000 behavior.
The rom seems to have a lot of pins, 44 if I count correctly, and judging by your photo atleast four of the pins are redundant (i.e. tied together with some other pin(s)).
With 2MB and an 8 bit bus 22+8=30 pins would be needed for adress, while with a 16 bit bus 21+15=37 pins would be needed, plus power supply, ground and probably atleast one select signal. So both would fit, atleast with a shoe horn. With an 8-bit rom there is room for expansion, while with a 16-bit rom it cannot be extended, unless those redundant pins would be brought into use.
The ROM could be a Macronix MX23C8100. That’s a switchable 1Mx8/512Kx16 mask ROM available in 44-pin SOP. It looks to me like pins 32 and 33 are tied, that’s BYTE# and VSS, meaning the ROM is hardwired to byte mode.
The Dumping works with my Elite and 1 MB ROM.
SSDUMP.EXE SSDUMPROM.BIN X dumps the ROM to the X file. The Dumper also checks at which address the ROM content repeats to determine the actual ROM size.
What does the OPD response mean? The response is always different when I restart the dump. e.g. 0F, 01.
Success on my end, with what I am fairly sure is a SoundScape S-2000 (same FCC ID).
A 2 MB ROM results, with a mystery ‘SDGI’ header, and what looks like 8-bit samples. It doesn’t sound like PCM or µ-law when I try to play it back straight. Maybe https://github.com/vgmrips/vgmplay/blob/master/VGMPlay/chips/es5506.c can decode it?
I found one other file with the same SDGI header named SSMT32.PDF that comes with the SoundScape drivers. It’s much smaller, @ 60 KB.
I see no links to the extracted ROM file up above. I assume that that’s because the file is copyrighted, so I guess I won’t post any links of my own. Though some searching around shows a file named “ensoniq.2m” embedded into certain MAME ROMs with a checksum of 9FDC4825, same as mine.
ssromdmp.bin is fine, but ssromdmp.asm is out of sync with it, and needs this:
— ssromdmp.asm 2018-02-07 15:55:52.000000000 -0500
+++ ssromdmp.asm 2018-09-02 14:05:51.437467053 -0400
@@ -95,7 +95,7 @@
move.b (a1)+,d0 ; Read byte from ROM
– beq.s wait_dma
+ beq.s wait_byte
move.b d0,3(a0) ; Write host interface data
Also, wild guess: ‘SDGI’ is “Sequoia Development Group, Inc.”
That’s a pretty good guess. I could not confirm if SDGI really stands for Sequoia but it would make sense.
You’re absolutely right about the firmware, somehow I managed to upload source code that doesn’t match the binary. The link should now be updated and point to an archive with the source file fixed. Thanks.
Here’s a quick and dirty script to convert from the ROM format here to a SoundFont: https://gitlab.com/dmo2118/read_sdgi
It’s pretty crummy at this point. Volume and filtering are probably the biggest issues for now. Hopefully I’ll have a chance to fix that…relatively soon.
Very cool. Thanks for posting that!
I had an Ensoniq clone in the Nineties and I’ve always wished to get the same instrument sounds when replaying my youth’s games in DosBox. With the instructions in this article and the script in the comments one can indeed create a soundfont that emulates the sound of the original hardware very well. Thanks for making this information available!
Glad to hear that my hacking was helpful! I personally find that the Ensoniq cards had really good sound banks, even with a relatively small ROM they were able to get very good results.