📜 ⬆️ ⬇️

Emulator in the emulator for playing chip-tunes on YM2149F


Who remembers Tetris 2 on the Spectrum? There were a lot of levels, the ability to play together and great music.

Recently, we made an 8-bit computer for simple games , but we didn’t foresee any sound capabilities in it. And I wanted to add some 8-bit music there. I remembered exactly the melody from Tetris 2 (a lot of hours were spent behind it), so I started poking around with it.

The ATmega328P processor in our computer is busy most of the time drawing the image, so there is no time to synthesize normal music at all. So we need a sound processor YM2149F (aka AY-3-8910), the same as in the ZX Spectrum and other computers.

Connect YM2149F to Arduino


I started with connecting the sound synthesizer to the Arduino board and outputting simple notes to it. YM is controlled by writing values ​​to one of 15 (in fact, we use 13) registers. The registers record the frequencies of the sound in each of the three channels, the frequency of the noise, the volume level, the frequency and the shape of the envelope. For addressing and data transmission uses 8 signals. A couple more are needed to control the bus mode — selecting a register or loading a value.
')

Found on the Internet connection diagram

For YM clocking, the processor's integrated timer with frequency divider is used. As a result, 2 MHz comes to the sound chip input, which is wrong in terms of compliance with the original, but for the time being it will come down for our tests. We are programmers, not zhelezyachniki.

Code to initialize the clock generator
// Sets a 4MHz clock OC2A (PORTB3) void set_ym_clock(void) { // PB3 - output DDRB |= 0x01 << PORTB3; // Set Timer 2 CTC mode with no prescaling. OC2A toggles on compare match // // WGM22:0 = 010: CTC Mode, toggle OC // WGM2 bits 1 and 0 are in TCCR2A, // WGM2 bit 2 is in TCCR2B // COM2A0 sets OC2A (arduino pin 11 on Uno or Duemilanove) to toggle on compare match // TCCR2A = ((1 << WGM21) | (1 << COM2A0)); // Set Timer 2 No prescaling (ie prescale division = 1) // // CS22:0 = 001: Use CPU clock with no prescaling // CS2 bits 2:0 are all in TCCR2B TCCR2B = (1 << CS20); // Make sure Compare-match register A interrupt for timer2 is disabled TIMSK2 = 0; // Divide the 16MHz clock by 8 -> 2MHz OCR2A = 3; } 



Test notes were lost successfully and it was necessary to move on.

I had not been very interested in Spectrum music separately from the Spectrum itself, but still heard about the format AY. Even in one of the articles I saw the mention of the PSG format. It is similar to any WAV to MP3 in the sense that it contains a linear sequence of actions with the registers of the music coprocessor. Therefore, the files are large and do not fit in the memory of ATmega.

AY files are much smaller. What is the secret there? And the fact that these are pieces of code from games or demos for playing a melody, as well as some data arrays for this code. Usually, players simply emulate the Spectrum CPU to run this program and so play the melody.

Why not emulate a Z80 on an AVR?


... I thought and looked for some library simulator processor Z80 in the language C. Such a simulator was found . He needed to slip only the functions of reading / writing memory and I / O ports.

A small difficulty arose with memory - after all, the ZX Spectrum has 48 kilobytes of RAM, and the ATmega328P has only 2 - it will not be possible to directly create an array of memory for the read / write functions. I had to make an array of addresses and cells, and in it look for values ​​when accessing from the processor.



It turned out (who would have thought!) That emulating one 8-bit computer on another 8-bit is not a good idea. Some sound is output, but everything happens so slowly that it is difficult to call it a melody. Then I decided to figure out the player code and rewrite it to C.

Manual decompilation or sunset


The code was a bit confusing. It was the interpreter of some byte-code that controls the music co-processor. The bytecode even has support for loops and subroutines. Each YM channel is controlled by a separate program with a separate stack. It turned out that initially I emulated a computer that emulates another three-processor computer. And even though the program was small (and started only 50 times per second), it was still very slow.

After I almost got to see the format of this bytecode, I accidentally stumbled upon its description. It was Fuxoft AY Language. It was developed by Frantisek Fuka (Fuxoft), who wrote Tetris himself, and music for him. This language is used in dozens of compositions. And their code is even extracted from games as FXM files. The code that I have already analyzed had to be thrown out to start all over again (but you can still see it in the history of changes to the repository ).



FXM Player


I got a brief description of the format and its decoder in the sources of the Bulbovsky player . Comparing it with the disassembled code, I found only a couple of small differences, but the semantics of the data structures became much clearer.

Now the player works fast enough. Music is played, you can combine the computer and the programmer. Each composition takes only a couple of kilobytes, so if you take the Arduino Mega (on an ATmega2560 processor), you can fit all existing tunes in the FXM format into its memory.

What's next?


It remains to add the correct crystal oscillator, so that the frequency of the microcircuit was like on the Spectrum. You can also write decoders of other tracker formats, add an SD card and you get a hardware player of Spectrum music. And when we connect it to our game box - you get a real slot machine.

True, for some reason, it does not work out that the speaker volume is normal, now everything is very quiet. Can anyone know how to make such a speaker from a toy phone sound? The Chinese phone copes with this, but for some reason the outputs of the YM2149F are not very good. Therefore, the video of the player, I still do not post.



UPD : Soldered the amplifier and recorded the video as it all plays:


Links


  1. Player Code Repository
  2. How we connected a 64x64 LED display to an Arduino
  3. Chip Control YM2149F with Arduino
  4. Z80 processor emulator in the form of a library in C
  5. AY Music Player
  6. Music archives

Source: https://habr.com/ru/post/335508/


All Articles