Skip to content

Instantly share code, notes, and snippets.

@Frank-Buss
Created September 26, 2019 05:16
Show Gist options
  • Save Frank-Buss/4a6fd7f7357a400e84e6ffd9478d9d05 to your computer and use it in GitHub Desktop.
Save Frank-Buss/4a6fd7f7357a400e84e6ffd9478d9d05 to your computer and use it in GitHub Desktop.
Commander X16 YM2151 player
// ym2151 basic player by Barry Yost - sep 25, 2019
// original original tune "Stardust" from C64 game "Lazy Jones"
// ported to C by Frank Buss
#include <stdint.h>
#include <6502.h>
struct YM2151_t {
uint8_t reg;
uint8_t data;
};
static uint8_t ofs;
static uint8_t b;
static uint8_t bp;
static uint8_t delay;
static uint8_t patch[] = {
0x20, 0xe4,
0x38, 0x00,
// patches for operator 0
0x40, 0x31,
0x60, 0x07,
0x80, 0x1f,
0xa0, 0x09,
0xc0, 0x00,
0xe0, 0xff,
// patches for operator 1
0x48, 0x31,
0x68, 0x11,
0x88, 0x1f,
0xa8, 0x09,
0xc8, 0x00,
0xe8, 0xff,
// patches for operator 2
0x50, 0x31,
0x70, 0x08,
0x90, 0x1f,
0xb0, 0x09,
0xd0, 0x00,
0xf0, 0xff,
// patches for operator 3
0x58, 0x30,
0x78, 0x24,
0x98, 0x1f,
0xb8, 0x09,
0xd8, 0x00,
0xf8 ,0xff,
0
};
uint8_t notes[] = {
0xff, 0xff, 0xff, 0xff, 0xff,
0x2d, 0x31, 0x34, 0x36, 0x2d, 0xff, 0xff, 0xff,
0x2d, 0x31, 0x34, 0x36, 0x38, 0x36, 0x31, 0x34, 0xff, 0xff, 0xff,
0x31, 0xff, 0x36, 0x2d,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0
};
#define YM2151 (*(volatile struct YM2151_t*) 0x9fe0)
static void setReg(uint8_t adr, uint8_t value)
{
YM2151.reg = adr;
YM2151.data = value;
}
static void loadPatch(uint8_t ch)
{
uint8_t i = 0;
while (1) {
if (patch[i] == 0) break;
setReg(patch[i] + ch, patch[i + 1]);
i += 2;
}
}
static unsigned char irq()
{
uint8_t n;
if (delay++ < 9) return IRQ_HANDLED;
delay = 0;
// play a note
n = notes[ofs++];
if (n == 0) {
ofs = 0;
bp = 1;
} else {
if (n < 0xfe) setReg(0x28, n);
if (n != 0xff) {
setReg(8, 0);
if (n != 0xfe) setReg(8, 0x78);
}
b = (b + 1) & 1;
if ((ofs == 21) || (ofs == 25)) bp += 2;
if (ofs == 29) bp = 1;
setReg(8, b + bp);
setReg(8, 0x78 + b + bp);
}
// return from interrupt
return IRQ_HANDLED;
}
static void main2()
{
int i;
uint8_t l, r;
uint8_t ch;
uint8_t n;
// init ym2151
for (i = 0; i <= 256; i++) setReg(i, 0);
// load the patch into all voices
for (i = 0; i <= 7; i++) loadPatch(i);
// set up bass notes on channels 1-6
l = 0xe4 - 0xc0 + 0x40;
r = 0xe4 - 0xc0 + 0x80;
// settings for left/right audio only
for (ch = 1; ch <= 5; ch += 2) {
if (ch == 1) n = 0x0d;
if (ch == 3) n = 0x14;
if (ch == 5) n = 0x16;
setReg(0x20 + ch, l);
setReg(0x20 + ch + 1, r);
setReg(0x28 + ch, n);
setReg(0x28 + ch + 1, n + 0x10);
}
ofs = 0;
bp = 1;
b = 1;
delay = 0;
// set new interrupt function
// needs different local stack from 0xa000 to 0xa7ff, because the stack functions are not reentrant
set_irq(irq, (void*) 0xa800, 0x0800);
while (1);
}
int main(void)
{
// switch back to uppercase character set
__asm__("lda #$8e");
__asm__("jsr BSOUT");
// bad hack: redefine CC65 stack to 0x0xa800-0xafff, should be a proper x16 custom target
*((uint16_t*) 0x02) = 0xb000;
// call new main function, because local variables are not valid anymore after the stack change
main2();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment