mist-devel / c64

C64 core
12 stars 13 forks source link

feature request: MIDI for C64 #1

Closed hippi-viking closed 2 years ago

hippi-viking commented 2 years ago

Hey guys (szia @gyurco)! :)

I was thinking Mist with the C64 core would make a fantastic synth - especially with the dual-SID capability! - if the ports on the MIDI add-on card could be utilised. I am just starting out with the FPGA-adventure, though it looks like a perfect candidate for a first more serious project i imagine it's beyond my current skills. Would you be so kind as to guide me to a direction to start or if your time allows help out with this project?

I know the C64 doesn't have built in MIDI support (unlike the Atari ST), but there are a few custom solutions around for which the source code and schematic are available:

At the moment something does get through the MIDI ports of the add-on card to the C64 core (i guess it might be the UART implemented on the user port), but it does not resemble the data being sent.

Could you help out with this? What should be the first step to take? Maybe implement a small CPU core to process and forward MIDI data to the synth software running on the C64 core in the format it can process?

Thank you in advance! :)

gyurco commented 2 years ago

As I see, some of them are using an ACIA6850 chip (same as on ST), some are using a CPLD with custom logic. The ACIA ones could be easy, just get the 6850 code from MiSTery and connect to the appropriate CPU signals. The output should end at UART_TX (add an OSD option to switch from user port based UART to the ACIA output).

hippi-viking commented 2 years ago

Thank you for the help! I have found the ACIA file in MiSTery's repo and will try to do my homework and implement the feature.

djhardrich commented 2 years ago

This may be useful, it’s a 6850-based MIDI cart (precursor to Kerberos) with schematics and source code (source is at bottom of page): https://frank-buss.de/c64/midi/index.html . Most of the source appears to be flash-cart related, but midi.asm is helpful I’m sure ;)

I also have a couple Datel MIDI Carts for the c64, would be happy to pop one open/dump roms, anything that helps the effort; just let me know!

gyurco commented 2 years ago

The ACIA-based MIDI is not hard to implement, but is it really useful? I guess there won't be too much software support.

djhardrich commented 2 years ago

It’s actually really useful/the preferred way to implement because it should also work with legacy software like Pro16. Both Station64 (http://djindikator.net/) and “Cynthcart” (https://github.com/PaulSlocum/cynthcart) support it as well, turning the c64 core into an incredible Dual-SID MIDI synth :)

Note: Even though it’s called “Cynthcart,” it’s available as a PRG and doesn’t need to take a cart slot

hippi-viking commented 2 years ago

Hey guys, thanks for the feedback!

@djhardrich: thanks! I think the device on the page you linked is pretty much the same as the Datel cart - or the Kerberos without the flash part. I don't think there is much (any?) rom to dump there, it's mostly just the ACIA chip which handles the serial line way faster than the 6526 CIA in the C64 so it is suitable for MIDI. As @gyurco said the ACIA implementation is readily available in the MiSTery core source, that should be enough. I had a brief look into it, it looks good, but didn't have the time yet to try to wire it to the C64 core.

@gyurco: as @djhardrich just said it would actually be pretty useful, most of the C64 music software would support it straight off.

gyurco commented 2 years ago

Here I found some info about various MIDI interfaces: https://codebase64.org/doku.php?id=base:c64_midi_interfaces Now there's a problem: looks like these (except the Passport & Sentech) are not using the CPU's RW line to differentiate reads from writes, but one of the address line used for this purpose. And here lies the issue: the 6502 usually does a dummy read before the write, thus a dummy write before the real one will happen to the ACIA if I connect it according to this table, which is not really good. Is there any schematics available for one of these interfaces to check?

djhardrich commented 2 years ago

I’m pretty sure this is a Datel clone, still digging for other schematics to verify, but I hope this helps: https://github.com/barzamin/midiskirt

hippi-viking commented 2 years ago

I was using Frank Buss's Kerberos schematic, page 8 (the ACIA part without the flash). It looks fairly simple.

djhardrich commented 2 years ago

@gyurco as requested, a schematic (in ASCII!) for a triple-mode c64 cart (covers DATEL, Sequential, and Passport support)! http://www.zimmers.net/anonftp/pub/cbm/documents/projects/other/C64MIDI-INTERFACE.TXT

gyurco commented 2 years ago

Good! But they didn't surprise me, A(1) is used as R/W on most interfaces (expect Kerberos and Passport). I must think about how they work.

gyurco commented 2 years ago

Here's a Visual6502 simulation of a STA instruction (similar is executed during a POKE): image

As you see, the address bus already has "6938" in Step 4-5, but the data bus is 0. If it is the write address of the MIDI interface, then first a 0 will be written to the ACIA. Then at step 5-6, the correct value ($aa) will be used.

hippi-viking commented 2 years ago

Thanks for the visualisation! :) I think I understand now why most designs do not connect the RW straight away (I didn't understand that before). Would it be possible to only pass every second rw opearation from the CPU to the ACIA and discard the others (of course the problem then is to know which one to keep and which one to discard). If I understood the design correctly from the spec. sheet the ACIA might be doing something similar internally. (By clock rate division or not setting the E[nable] line for the first operation.)

gyurco commented 2 years ago

Enable line is the phi2 from the CPU, it has two phases in every machine cycle (that's why you have 2 same numbered mcycles - one is phi2 low, the next is phi2 high). When phi2 goes high, the data bus will read/write by the CPU (that's why VIC-II can use the bus when it's low). So the ACIA won't skip every 2nd bus cycle :) I can assure the R/W line is low when the write address is selected (thus using only cycle 5), but I just want to understand why does it work in the original design.

hippi-viking commented 2 years ago

Sorry for the confusion. :) Hmm... what if we assume that it isn't working correctly in the original design? On a MIDI In interface the dummy writes from the CPU won't be seen (because the TX line is not connected) so as on the MIDI Out where the RX line is not connected dummy reads won't make a difference. (As far as I know these carts aren't used in a full-duplex way.) But of course this is just a hypothesis, it might still change the state of the ACIA.

gyurco commented 2 years ago

If you want to use MIDI Out, then it'll make a difference - writing two bytes to the Transmit Data Register will send two bytes via MIDI (and the first will be totally bogus).

harbaum commented 2 years ago

I have only briefly looked over this, so i may be totally wrong. But:

Looking at the 6850 datasheet it seems to latch incoming data at the end of its bus cycle. So it wouldn't hurt if there's wrong data at first. This trick would allow them to extend the access time. Maybe the 6502 cycle is too short for the 6850 otherwise.

I'll have a closer look tomorrow.

gyurco commented 2 years ago

If ACIA latches at the rising edge of nCS, then it would be OK (but it says the E clock is used). Or the latched data is not used until CS is de-asserted.

gyurco commented 2 years ago

I think about one rational behind of not using the RW line: the dummy read won't clear the 'midi in available' bit (as it is translated to a write), thus sending out new data on MIDI OUT won't discard existing MIDI IN byte sitting in the ACIA.

gyurco commented 2 years ago

BTW, it's perfectly possible that the transmitter won't send out the written byte until CS is de-asserted, thus avoiding glitches during asserted CS (like this). I wonder if the 6800 also has these dummy cycles.

gyurco commented 2 years ago

I found a a real signal capture of the control lines: https://www.lemon64.com/forum/viewtopic.php?t=42396&start=15 IO1 is asserted only when PHI2 (E clock for ACIA) is high (actually that's how the current core behaves, too). And you can see the dummy read there. I cannot imagine how POKEing without using the R/W line will not do 2 writes into ACIA. Maybe because IO1 lags a bit after PHI2 rising edge in the dummy read cycle, but they're changing together in the write one, thus the dummy read is ignored? Crazy if the real HW depends on this.

gyurco commented 2 years ago

...or the ACIA might be a slow device internally, and doing 2 writes in two consecutive cycles will discard the first one. The second write simply overwrites the first before it's "executed".

hippi-viking commented 2 years ago

Sorry I am not familiar with the 6850 nor the 6502 on a timing-level. :( Would the chip datasheets help? 6850, 6502 [MIDI baud rate is 31250, so I believe the /16 mode should be used on the 6850.]

gyurco commented 2 years ago

One can be absolutely sure only if die shots are reverse engineered. But I committed a possible implementation (midi branch). Please try it, as I don't have MIDI hardware.

hippi-viking commented 2 years ago

Thank you very much @gyurco! I will try to compile the bitstream (this will be the first time for me, it might take some time to get it right), test it and report back how it worked out.

djhardrich commented 2 years ago

Sorry for the delay, I tested all modes and there’s some flooding of messages/malformed messages happening, tested in all cart modes with Station64/Cynthcart (hangs in Datel mode on both MiST and VICE; will have parts for SD2IEC for my real c64 to test with a real Datel cart in 2 days). This MIDI Monitor program (http://data.uni64.com/Midi_Monitor_PRG.prg.zip , Datel-only) should help troubleshoot a little; currently on MiST (with no MIDI hardware connected) the second two values flicker/receive tons of message changes, on VICE the values are FF FF FF and don’t change until a MIDI packet is received. I can keep rebuilding/testing the MiST core with MIDI hardware, my c64c will be set up to compare against real hardware and a Datel cart in 2 days (I normally use a MSSIAH cart with my c64c, and didn’t have a way to load PRG’s/d64’s on it before)!

gyurco commented 2 years ago

I fixed the reads, but I don't know what happens if MIDI data arrives. It displays 0, as it constantly checks if RX data is available, and if not, then it doesn't even try to read the data register. Maybe VICE sent a dummy FF to the MIDI first? I wonder what happens on real hardware. But it should work in practice. MIDI Out wasn't affected at all.

djhardrich commented 2 years ago

Can confirm that MIDI in is fixed! I’ve tested with all of the cartridge types in Station64 and they’re all working properly! As soon as the other parts for my sd2iec come in, I’ll confirm how real hardware behaves for you. Thank you so much, this is -excellent-!!

gyurco commented 2 years ago

Cool! Now I wonder if MIDI Out also works.

djhardrich commented 2 years ago

Tested MIDI Out with Steinberg Pro16 (uses Datel standard) and an external synth, can confirm that MIDI Out/Thru is working properly without ghost notes/anomalies! Will try to find/run sequencers that support the other cart types to test, but Datel works fine!

gyurco commented 2 years ago

Excellent! I hope I wired the others correctly, as the only difference is the cart port - ACIA connections.

djhardrich commented 2 years ago

It looks like sending a string of MIDI CC messages (like turning a knob) floods the AICA and it stops passing messages.. I’ve tested with MIDI Monitor and Station64 (Datel) and while the behavior is different (MIDI Monitor locks up where Station64 semi-slowly degrades), VICE doesn’t exhibit this and I’m pretty sure real hardware wouldn’t either, will be testing MIDI Monitor, a Datel cart, and c64c in about 12 hours :) Thanks again for all of this, it’s super close to perfect!

gyurco commented 2 years ago

Is it with MIDI In or Out? Do you have some instructions how to reproduce it in Station64? (Sorry, I'm a musician anti-talent.)

djhardrich commented 2 years ago

It happens with MIDI in, the easiest way to reproduce is with the MIDI Monitor prg, start the program and turn a knob left and right, it’ll lock up at some point (sometimes instantly, sometimes it takes 5-30 seconds). I can keep rebuilding changes and testing with my midi controllers/sequencers here, I’m up all night :)

Edit: this happens with pretty much every controller with knobs that I have; doesn’t happen with pitch bend/note data, probably due to the density of the messages. When MIDI Monitor locks up, the c64 cursor continues to flash, so it really feels like it’s the AICA misbehaving/not being reset(?)

gyurco commented 2 years ago

Uhh, I'm afraid I couldn't debug this without actual external equipment.

gyurco commented 2 years ago

Can you read the status register when the ACIA is stuck with MIDI Monitor? E.g. PRINT PEEK(56838)

gyurco commented 2 years ago

Is it possible to try the same equipment with the MiSTery core? Probably there's a MIDI Monitor like prg there, too. As the ACIA implementation is the same, I wonder if it stucks the same way.

djhardrich commented 2 years ago

PRINT PEEK(56838) returns “2” when AICA input stops, can confirm that this doesn’t happen on MiSTery core, just tested Cubase with the same controller/even heavier message load with multiple knobs turning, couldn’t get it to miss a message :)

Sending an email about getting you some midi gear!

gyurco commented 2 years ago

"2" means a clear ACIA status, no data in the RDR, TDR is empty. Maybe the problem is the baud rate generator clock using the C64's PLL, which is not exactly 32 MHz, but has some differences depending on PAL/NTSC is selected. Can you try it with the other video standard setting than you're currently using?

djhardrich commented 2 years ago

Tested with both PAL/NTSC and the same thing happens (unfortunately?)… If you happen to have a spare 32u4 board or pi pico, we can build you a midi test rig out of a board + resistor + din connector like so: https://github.com/rsta2/pico/tree/main/midi_adapter

gyurco commented 2 years ago

Yeah, I can connect a PC or an RPi to the MiST and then it'll be possible to experiment (unfortunately my USB-serial converter doesn't speak that weird MIDI bitrate...)

Meanwhile I made the ACIA to use the exact 32 MHz clock as the baudrate generator clock base, it works with the keyboard ACIA in MiSTery. Can you try this one with you MIDI stuff (pushed to the repo)?

djhardrich commented 2 years ago

Building and testing now, will report back in 15 minutes :)

djhardrich commented 2 years ago

Same behavior (both NTSC and PAL), with one change: a pulsing change in midi data is introduced in NTSC mode (pulse of a few messages every second), doesn’t happen in PAL, doesn’t happen in NTSC or PAL in previous commit. Just trying to get you as much information as possible :)

djhardrich commented 2 years ago

Another note that may be useful: on these c64 carts, the AICA is clocked by an external crystal on-cartridge; Datel carts use a 2mhz oscillator, all others use a 1mhz oscillator….

gyurco commented 2 years ago

Yeah, I know this, Datel users must program the ACIA to /64 divider, all others are using /16 (because the ACIA gets 500 kHz clock, like in ST). I think I'll get a cheap FT232 based USB-TTL adapter (it's capable of 31250 bps, not like my PL2303 based one), or an USB-MIDI cable, so I can flood the MIDI Monitor from my PC. I accept donations for one of these gadgets :)

hippi-viking commented 2 years ago

@gyurco, is my hunch right that you are located in Hungary? If that is so I might be able to visit you with any of those things (FT232 USB-TTL adapter, USB-MIDI cable, MIDI controller) anytime soon. :) In the meanwhile I am still trying to get Quartus II to work... its dependency on old libraries under linux gives me a real hard time... :(

gyurco commented 2 years ago

Yeah, I'm in Hun :) I already ordered a cheap USB-MIDI cable, but thanks anyway.

BTW, I didn't notice that "pulsing change" in MIDI Monitor, it's constant 0 in NTSC mode (nothing is connected to the MIDI port).

djhardrich commented 2 years ago

@hippi-viking Use the free version of Quartus 13.1, it’ll install in a modern linux and work ;)

hippi-viking commented 2 years ago

@djhardrich Do you mean Quartus web 13.1(.0.162 + 13.1.4.182 update) for linux? I am trying to get that to work. Install went without a problem, but it requires versions of libraries to run that have been removed from most distros years ago (libpng12 for example, it has been superseded by libpng16 as of now). :( I found a solution for ubuntu, but I have kali on my tinker laptop which is also debian based, but can't use ppas... tried the debian version of libpng12 as well, but that requires more debian base stuff... I probably should use a windows (vm) as most others do.

gyurco commented 2 years ago

I've hacked a Dockerfile to make it work on newer Fedoras, and it's using Ubuntu as a base. There's even a libpng12 deb package there: https://github.com/mist-devel/mist-board/tree/master/tools/docker-quartus Maybe you can go with the libpng only (and it's possible that you should remove the installed libQt* to go with the distro-shipped ones).