VOGONS


First post, by Cloudschatze

User metadata
Rank Oldbie
Rank
Oldbie

Here's some research/testing I'd put together regarding MPU-401 UART-mode buffer sizes. Yes, my life is that exciting.

mpu_uarts.png

A couple of notes:

  • Transmit Buffer = Host to MPU
  • Receive Buffer = External MIDI Input to MPU
  • Populated fields represent information that is documented, mostly in datasheets and programming references, where the fields highlighted in green have been personally determined and/or verified.
  • Mega-Em employs software-based circular-buffering. I'm not sure what the impact on the transmit buffer is, if any, but it bumps the receive buffer from 16-bytes (hardware) to 255-bytes.
  • Windows' MMSYSTEM.DLL, while not represented in or by this data, also seems to employ circular-buffering.
  • Where a dedicated, non-MCU-based UART is used, 1-byte buffering is adequate (the Atari ST being another such example).

Reply 1 of 10, by Scali

User metadata
Rank l33t
Rank
l33t

That's interesting. So at the very least, some MPU401 implementations appear to get away with the minimal 1-byte buffer.

Cloudschatze wrote:

[*]Where a dedicated, non-MCU-based UART is used, 1-byte buffering is adequate (the Atari ST being another such example).[/list]

Yes, I suppose when you have a (slow) microcontroller on the board, the buffer can be used for asynchronous communication, so you won't deadlock the host waiting for the MCU to process the byte.
I guess that's the entire reason why you'd want a buffer for sending MIDI.
For receiving MIDI, a larger buffer makes more sense, because you basically can't lock on the MIDI data lines as far as I know. That is, you only have one data line, there's no additional handshaking. So you can't signal to a device that tries to send MIDI that it has to wait.
So a MIDI interface will have to store anything it receives in a buffer, so that it can wait there for the host to read it. Using a 1-byte buffer on that side is quite a risk on very slow computers I'd say.
On modern computers you'd get away with it, because you could put a host-side buffer on it:
When a byte is received, the device generates an interrupt. The interrupt handler copies the byte to an internal buffer ASAP, so that the device is ready to receive the next byte.
The MIDI applications will then read from the internal buffer, not the device buffer, so as not to deadlock the interface.
In the Windows-age MIDI devices always work that way anyway, because MIDI applications always talk to the MIDI mapper, not directly to the hardware.

I'd want to ask though: How exactly do you test for specific receive and transmit buffer sizes? As in, how can you verify the exact size of the buffers?

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 2 of 10, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
Scali wrote:

So a MIDI interface will have to store anything it receives in a buffer, so that it can wait there for the host to read it. Using a 1-byte buffer on that side is quite a risk on very slow computers I'd say.
On modern computers you'd get away with it, because you could put a host-side buffer on it:
When a byte is received, the device generates an interrupt. The interrupt handler copies the byte to an internal buffer ASAP, so that the device is ready to receive the next byte.

Yes, and also given the byte rate of 3125 bytes per second, when sending bytes back to back, and if there would be no HW buffering, you have only 320 microseconds time to read the first byte or the second will overrun it. A motherboard I have with dump MPU interface (no DOS drivers installed), it does not give me MIDI byte receive interrupts, so if there was no FIFO, I'd have to set a timer interrupt to be generated at a rate faster than 3125 Hz so I could poll received bytes in the timer interrupt. Fortunately, the chipset has 16-byte FIFO, so any timer rate over 200Hz would be enough to poll so no bytes are lost. Assuming nothing causes latency in the interrupt processing, like performing some longish operations in the timer interrupt like playing OPL music.

Scali wrote:

I'd want to ask though: How exactly do you test for specific receive and transmit buffer sizes? As in, how can you verify the exact size of the buffers?

For determining receive FIFO, you first flush the input so FIFO is empty, by reading buffered MIDI bytes until there's no more to read. Then you send a bunch of MIDI bytes like by pushing few keys on a MIDI keyboard, and stop sending. Now again, you check how many bytes you can read from the FIFO until there is no more to read. You can also connect MIDI OUT to MIDI IN and send bytes to yourself, one byte at a time.

It's kind of similar to determine the transmit FIFO size, I connected MIDI OUT to MIDI IN on the motherboard and again flushed the input FIFO. Then in a FOR loop wrote letters from 'A' to 'Z' to the MIDI output port, and since filling the output FIFO is faster than transferring bytes, I waited for bytes to start appearing at the input, and checked what letters I got back. I recall getting back 16 letters from 'A' onwards, and 17th letter was 'Z', so I determined the TX FIFO is 16 bytes. That's because 'A' starts to be transferred out so 16 letters from 'B' onwards go to TX FIFO, and when the FIFO is full, the last letter gets overwritten, so it's 'Z'.

Reply 3 of 10, by Cloudschatze

User metadata
Rank Oldbie
Rank
Oldbie
Jepael wrote:

For determining receive FIFO, you first flush the input so FIFO is empty, by reading buffered MIDI bytes until there's no more to read. Then you send a bunch of MIDI bytes like by pushing few keys on a MIDI keyboard, and stop sending. Now again, you check how many bytes you can read from the FIFO until there is no more to read.

This describes the process I'd used near-verbatim. To help facilitate things, I'd written a dumb little routine in QBasic to read the input and provide a count at the end.

It's kind of similar to determine the transmit FIFO size, I connected MIDI OUT to MIDI IN on the motherboard and again flushed the input FIFO. Then in a FOR loop wrote letters from 'A' to 'Z' to the MIDI output port, and since filling the output FIFO is faster than transferring bytes, I waited for bytes to start appearing at the input, and checked what letters I got back. I recall getting back 16 letters from 'A' onwards, and 17th letter was 'Z', so I determined the TX FIFO is 16 bytes. That's because 'A' starts to be transferred out so 16 letters from 'B' onwards go to TX FIFO, and when the FIFO is full, the last letter gets overwritten, so it's 'Z'.

I'd tried something similar, but was unable to send data to the MPU faster than it could transmit it, using either debug or QBasic routines. I am not a programmer. 😀

Validating the UART-mode transmit buffer of an actual MPU-401 or variant yet needs to occur, as it's more-or-less the reference standard, but remains mostly anecdotal at 256-bytes until it can be tested, or determined through ROM disassembly otherwise.

Testing the transmit buffer of the SB16 chipset proved easy enough though. Here's what I'd written about that in related correspondence with NewRisingSun:

Cloudschatze wrote:

The undocumented DSP command FAh is described exactly nowhere, but it's behavior is such that the DSP is put into a "busy" state, and in which mode it responds to nothing other than a Reset command. Consequently, the MPU behavior is also affected, whereby, after sending exactly one data byte to the MPU (which does not get output), the DRR flag is raised. Continuing to send data to the MPU at this point simply causes the one-byte buffer to be overwritten (LIFO behavior). Upon resetting the DSP, this buffered MPU byte is automatically output. I've tested this behavior with all of the cards in my little Excel spreadsheet, and they all behave similarly. In short, I've been able to confirm and verify that the MPU output buffer of the entire SB16 family is indeed only a single byte.

After further testing, it was determined that the FAh command would "hang" the DSP because it expected a further two bytes of data, and was therefore incomplete, but this behavior worked for the purposes described.

Reply 4 of 10, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie
Cloudschatze wrote:

Validating the UART-mode transmit buffer of an actual MPU-401 or variant yet needs to occur, as it's more-or-less the reference standard, but remains mostly anecdotal at 256-bytes until it can be tested, or determined through ROM disassembly otherwise.

From manual: UART mode 85 bytes for firmware versions below 1.3, approximately 1700 bytes for versions 1.3 and above.

I don't own one, I haven't tested it.

Reply 5 of 10, by Cloudschatze

User metadata
Rank Oldbie
Rank
Oldbie
Jepael wrote:

From manual: UART mode 85 bytes for firmware versions below 1.3, approximately 1700 bytes for versions 1.3 and above.

Right, that refers to the UART-mode receive buffer, and it's exactly 1744 bytes. 😀

The transmit buffer, on the other hand, isn't documented anywhere that I've seen. The sole reference I've found is a USENET post, wherein the 256-byte figure was supposedly provided by Roland. The problem with this information is that it may actually refer to the total buffering used in "smart" mode, rather than UART mode.

Reply 6 of 10, by Scali

User metadata
Rank l33t
Rank
l33t
Jepael wrote:

It's kind of similar to determine the transmit FIFO size, I connected MIDI OUT to MIDI IN on the motherboard and again flushed the input FIFO. Then in a FOR loop wrote letters from 'A' to 'Z' to the MIDI output port, and since filling the output FIFO is faster than transferring bytes, I waited for bytes to start appearing at the input, and checked what letters I got back. I recall getting back 16 letters from 'A' onwards, and 17th letter was 'Z', so I determined the TX FIFO is 16 bytes. That's because 'A' starts to be transferred out so 16 letters from 'B' onwards go to TX FIFO, and when the FIFO is full, the last letter gets overwritten, so it's 'Z'.

Yes, but that seems to imply that the state management does not take into account that a buffer can be full.
As in, I would expect a robust implementation to not signal the DRR-flag once the FIFO buffer is full, so you simply cannot overwrite values in the buffer.
But perhaps the implementation is simplified, and DRR is only intended as a synchronization mechanism from host to FIFO buffer, and does not extend to the FIFO buffer waiting to output its data.

Because if it was implemented in a robust way, the only way to measure it would be to measure the delay between writes, I suppose.
That is, we can assume that we can write faster than 3125 bytes per second to the FIFO buffer, and once it's full, it will be throttled to exactly 3125 bytes per second, because we will be in a busy-wait for DRR until a byte has been sent out of the FIFO buffer, and we have room to send a new byte.
It will be difficult to get an exact number this way, since bytes will be sent out of the buffer while you're trying to fill it up.
So if you see a delay after 20 bytes, the buffer may only be 16 bytes large, but it managed to send out 4 bytes while you were filling it.

The idea of the FIFO might be that it's merely a 'helper' to throttle writes a bit. That is, the application is expected to only write 3125 bytes per second to the interface nominally, but since MIDI commands are generally just 2 or 3 bytes, it can write these out in small bursts.
Which would mean that sending SysEx commands would still be a problem, because they're generally much larger than the FIFO size.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 7 of 10, by jxalex

User metadata
Rank Member
Rank
Member

Waking up a old thread since it is very good reference.

I like to add that the FIFO buffers measurements may be also affected by the bus speed itself . Does all of those cards had the same 8bit IO? (the SB has 8bit io, while 16bit IO takes much less bus)

THe AMD interwave datasheet says that chip has 16bytes fifo for receive and 16bytes fifo for sending a MIDI.

Scali wrote:

Which would mean that sending SysEx commands would still be a problem, because they're generally much larger than the FIFO size.

Well, in this case I need help. How big FIFO buffers would be generous enough and how big ones are overkill? The design can be with hardware 512 byte buffer for separate send and extra 512bytes for receive, but how much should be enough actually?
SO in a thought as making a new soundcard with MIDI and to have all generous options what man can imagine.

Recommendations, caveats to avoid based on old other cards and experiences, which were some cards design flaws with midi ports?
the MIDI FIFO size. how much then would be enough and how much would be overkill? 16/64/512 bytes? (or more? 😁 😁 )
Also I consider the bus interface will be ISA 16bit instead of 8bit I/O which can help the bus load reducing and if the software can use the 16bit transfer to soundcard with midi data.
Should there also be in hardware some configurable options about when it is time to generate interrupt?
also, should there be also possibility to use DMA ?
(so to use that specification fully and with details which were considered very expensive on the time back then but now no problem to exceed that)

The focus should be that it should be stable timing, low CPU and bus load even with a modest CPUs like 386 while using the pitch bend, sysex and program changes and all 16 channels are in use.
The card will be a dedicated separate FIFOs and IRQ handler and CPU for midi channels. So that the card should not hog the more modest CPUs like 386 processors, could handle the pitch bend and midi sysex code too plus program changes (FT2 with MIDI mapped on instruments).

The focus is still about having the compatibility with those old trackers which can map the MIDI to instruments.
With Fasttracker 2. So far with SB AWE64 and Gravis Ultrasound MAX on a Pentium II runs okay with MIDI but so far I have not used the compositions with all 16 channels.

The extreme would be trackers to have a support for a multi port MIDI interfaces and multi wave outs, but... just if there would be also dos trackers which support that all hardware.

Last edited by jxalex on 2018-09-26, 16:47. Edited 1 time in total.

Current project: DOS ISA soundcard with 24bit/96Khz digital I/O, SB16 compatible switchable.
newly made SB-clone ...with 24bit and AES/EBU... join in development!

Reply 8 of 10, by Cloudschatze

User metadata
Rank Oldbie
Rank
Oldbie
jxalex wrote:

THe AMD interwave datasheet says that chip has 16bytes fifo for receive and 16bytes fifo for sending a MIDI.

The MC6850-based UART in the Am78C201 is described as having a 16-byte receive FIFO, but a single-byte transmit buffer. Regarding the latter:

InterWave IC Am78C201 Programmer's Guide v2 wrote:

GMTDR--MIDI Transmit Data
Address: P3XR+1 write

Writing to this register causes the 8-bit value written to be transmitted serially through the UART to the MIDITX pin in MIDI data format. There is a buffer between the register data bus and the UART that can store one byte; therefore, it is possible to send a second byte to this register shortly after an initial byte is sent.

As mentioned in the "Notes" section of my original post, the 16-byte receive FIFO is functionally software-increased to 255-bytes through use of Mega-Em. It's possible that the transmit buffer is similarly increased in this manner.

Regarding new designs, I think a reasonable suggestion would be to have transmit and receive buffers of at least 16-bytes each, while an "ideal" design might match the MPU-401 UART-mode sizes as closely as possible, in which case you're looking at a 256-byte transmit buffer, and a (lesser, but probably adequate) 512-byte receive buffer, per the limitation you'd mentioned.

Reply 9 of 10, by jxalex

User metadata
Rank Member
Rank
Member

No problem, there are no such limitations as the different size FIFOs are pin compatible in the CYpress C7Cxxxx series. The biggest one is 4096 bytes, PLUS those FIFOs can be also cascaded to get 8192bytes FIFO or more
Or in a case if just the 512byte fifos are available by cascading them the 1024...1536 bytes FIFO will be as a result.
So I add some extra socket places for socket-happy people (or those who will combine the buffer in any length).

Just now from feebay I got a hold on the discontinued 512 x9 organization fifos (which in cascade provide already 1024 byte buffers) . Those who can afford bigger FIFOs to order from their nearest detail shop (as they are pin compatible) can upgrade later when needed for some serious composition.

Any other tips?

Current project: DOS ISA soundcard with 24bit/96Khz digital I/O, SB16 compatible switchable.
newly made SB-clone ...with 24bit and AES/EBU... join in development!

Reply 10 of 10, by jxalex

User metadata
Rank Member
Rank
Member

have someone also tried the MIDI TIME STAMPING ability of these devices in the list? ALso, which programs and soundtrackers can use this capability of MIDI port? How far in the future the messages should be possible to adjust with that MPU401
?

Current project: DOS ISA soundcard with 24bit/96Khz digital I/O, SB16 compatible switchable.
newly made SB-clone ...with 24bit and AES/EBU... join in development!