MCUME/MCUME_teensy/teensy5200/pokey.c

711 wiersze
20 KiB
C

/*
* pokey.c - POKEY sound chip emulation
*
* Copyright (C) 1995-1998 David Firth
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "cpu.h"
#include "pokey.h"
#include "gtia.h"
#ifdef SOUND
#include "pokeysnd.h"
#endif
#include "antic.h"
#ifdef VOICEBOX
#include "voicebox.h"
#include "votraxsnd.h"
#endif
#ifdef POKEY_UPDATE
void pokey_update(void);
#endif
UBYTE POKEY_KBCODE;
UBYTE POKEY_SERIN;
UBYTE POKEY_IRQST;
UBYTE POKEY_IRQEN;
UBYTE POKEY_SKSTAT;
UBYTE POKEY_SKCTL;
int POKEY_DELAYED_SERIN_IRQ;
int POKEY_DELAYED_SEROUT_IRQ;
int POKEY_DELAYED_XMTDONE_IRQ;
/* structures to hold the 9 pokey control bytes */
UBYTE POKEY_AUDF[4 * POKEY_MAXPOKEYS]; /* AUDFx (D200, D202, D204, D206) */
UBYTE POKEY_AUDC[4 * POKEY_MAXPOKEYS]; /* AUDCx (D201, D203, D205, D207) */
UBYTE POKEY_AUDCTL[POKEY_MAXPOKEYS]; /* AUDCTL (D208) */
int POKEY_DivNIRQ[4], POKEY_DivNMax[4];
int POKEY_Base_mult[POKEY_MAXPOKEYS]; /* selects either 64Khz or 15Khz clock mult */
UBYTE POKEY_POT_input[8] = {228, 228, 228, 228, 228, 228, 228, 228};
static int pot_scanline;
#include "noise.h"
//UBYTE POKEY_poly9_lookup[POKEY_POLY9_SIZE];
//UBYTE POKEY_poly17_lookup[POKEY_POLY17_SIZE];
static ULONG random_scanline_counter;
ULONG POKEY_GetRandomCounter(void)
{
return random_scanline_counter;
}
void POKEY_SetRandomCounter(ULONG value)
{
random_scanline_counter = value;
}
UBYTE POKEY_GetByte(UWORD addr, int no_side_effects)
{
UBYTE byte = 0xff;
#ifdef STEREO_SOUND
if (addr & 0x0010 && POKEYSND_stereo_enabled)
return 0;
#endif
addr &= 0x0f;
if (addr < 8) {
return (INPUT_handle_trigger(addr));
//byte = POKEY_POT_input[addr];
//if (byte <= pot_scanline)
// return byte;
//return pot_scanline;
}
switch (addr) {
case POKEY_OFFSET_ALLPOT:
{
int i;
for (i = 0; i < 8; i++)
if (POKEY_POT_input[i] <= pot_scanline)
byte &= ~(1 << i); /* reset bit if pot value known */
}
break;
case POKEY_OFFSET_KBCODE:
byte = POKEY_KBCODE;
break;
case POKEY_OFFSET_RANDOM:
if ((POKEY_SKCTL & 0x03) != 0) {
int i = random_scanline_counter + ANTIC_XPOS;
if (POKEY_AUDCTL[0] & POKEY_POLY9)
byte = POKEY_poly9_lookup[i % POKEY_POLY9_SIZE];
else {
const UBYTE *ptr;
i %= POKEY_POLY17_SIZE;
ptr = POKEY_poly17_lookup + (i >> 3);
i &= 7;
byte = (UBYTE) ((ptr[0] >> i) + (ptr[1] << (8 - i)));
}
}
break;
case POKEY_OFFSET_SERIN:
byte = POKEY_SERIN;
#ifdef DEBUG3
printf("SERIO: SERIN read, bytevalue %02x\n", POKEY_SERIN);
#endif
#ifdef SERIO_SOUND
POKEYSND_UpdateSerio(0,byte);
#endif
break;
case POKEY_OFFSET_IRQST:
byte = POKEY_IRQST;
break;
case POKEY_OFFSET_SKSTAT:
#if SKIP
byte = POKEY_SKSTAT + (CASSETTE_IOLineStatus() << 4);
#else
byte = INPUT_handle_skstat(addr);
// byte = POKEY_SKSTAT;
#endif
#ifdef VOICEBOX
if (VOICEBOX_enabled) {
byte = POKEY_SKSTAT + (VOTRAXSND_busy << 4);
}
#endif
break;
}
return byte;
}
static void Update_Counter(int chan_mask);
static int POKEY_siocheck(void)
{
return (((POKEY_AUDF[POKEY_CHAN3] == 0x28 || POKEY_AUDF[POKEY_CHAN3] == 0x10
|| POKEY_AUDF[POKEY_CHAN3] == 0x08 || POKEY_AUDF[POKEY_CHAN3] == 0x0a)
&& POKEY_AUDF[POKEY_CHAN4] == 0x00) /* intelligent peripherals speeds */
|| (POKEY_SKCTL & 0x78) == 0x28) /* cassette save mode */
&& (POKEY_AUDCTL[0] & 0x28) == 0x28;
}
#ifndef SOUND_GAIN /* sound gain can be pre-defined in the configure/Makefile */
#define SOUND_GAIN 4
#endif
#ifndef SOUND
#define POKEYSND_Update(addr, val, chip, gain)
#else
//#define POKEYSND_Update(addr, val, chip, gain) if (chip == 0) emu_sndPlaySound((chip*4)+addr, gain*16, val*16)
#endif
void POKEY_PutByte(UWORD addr, UBYTE byte)
{
#ifdef STEREO_SOUND
addr &= POKEYSND_stereo_enabled ? 0x1f : 0x0f;
#else
addr &= 0x0f;
#endif
switch (addr) {
case POKEY_OFFSET_AUDC1:
POKEY_AUDC[POKEY_CHAN1] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC1, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDC2:
POKEY_AUDC[POKEY_CHAN2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC2, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDC3:
POKEY_AUDC[POKEY_CHAN3] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC3, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDC4:
POKEY_AUDC[POKEY_CHAN4] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC4, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDCTL:
POKEY_AUDCTL[0] = byte;
/* determine the base multiplier for the 'div by n' calculations */
if (byte & POKEY_CLOCK_15)
POKEY_Base_mult[0] = POKEY_DIV_15;
else
POKEY_Base_mult[0] = POKEY_DIV_64;
Update_Counter((1 << POKEY_CHAN1) | (1 << POKEY_CHAN2) | (1 << POKEY_CHAN3) | (1 << POKEY_CHAN4));
POKEYSND_Update(POKEY_OFFSET_AUDCTL, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF1:
POKEY_AUDF[POKEY_CHAN1] = byte;
Update_Counter((POKEY_AUDCTL[0] & POKEY_CH1_CH2) ? ((1 << POKEY_CHAN2) | (1 << POKEY_CHAN1)) : (1 << POKEY_CHAN1));
POKEYSND_Update(POKEY_OFFSET_AUDF1, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF2:
POKEY_AUDF[POKEY_CHAN2] = byte;
Update_Counter(1 << POKEY_CHAN2);
POKEYSND_Update(POKEY_OFFSET_AUDF2, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF3:
POKEY_AUDF[POKEY_CHAN3] = byte;
Update_Counter((POKEY_AUDCTL[0] & POKEY_CH3_CH4) ? ((1 << POKEY_CHAN4) | (1 << POKEY_CHAN3)) : (1 << POKEY_CHAN3));
POKEYSND_Update(POKEY_OFFSET_AUDF3, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF4:
POKEY_AUDF[POKEY_CHAN4] = byte;
Update_Counter(1 << POKEY_CHAN4);
POKEYSND_Update(POKEY_OFFSET_AUDF4, byte, 0, SOUND_GAIN);
break;
case POKEY_OFFSET_IRQEN:
POKEY_IRQEN = byte;
#ifdef DEBUG1
printf("WR: IRQEN = %x, PC = %x\n", POKEY_IRQEN, PC);
#endif
POKEY_IRQST |= ~byte & 0xf7; /* Reset disabled IRQs except XMTDONE */
#if SKIP
if ((~POKEY_IRQST & POKEY_IRQEN) == 0 && PBI_IRQ == 0 && PIA_IRQ == 0)
#else
if ((~POKEY_IRQST & POKEY_IRQEN) == 0)
#endif
{
CPU_IRQ = 0;
}
else {
CPU_GenerateIRQ();
}
break;
case POKEY_OFFSET_SKRES:
POKEY_SKSTAT |= 0xe0;
break;
case POKEY_OFFSET_POTGO:
if (!(POKEY_SKCTL & 4))
pot_scanline = 0; /* slow pot mode */
break;
case POKEY_OFFSET_SEROUT:
#ifdef VOICEBOX
VOICEBOX_SEROUTPutByte(byte);
#endif
#if SKIP
if ((POKEY_SKCTL & 0x70) == 0x20 && POKEY_siocheck())
SIO_PutByte(byte);
#endif
/* check if cassette 2-tone mode has been enabled */
if ((POKEY_SKCTL & 0x08) == 0x00) {
/* intelligent device */
#if SKIP
POKEY_DELAYED_SEROUT_IRQ = SIO_SEROUT_INTERVAL;
#endif
POKEY_IRQST |= 0x08;
#if SKIP
POKEY_DELAYED_XMTDONE_IRQ = SIO_XMTDONE_INTERVAL;
#endif
}
else {
/* cassette */
/* some savers patch the cassette baud rate, so we evaluate it here */
/* scanlines per second*10 bit*audiofrequency/(1.79 MHz/2) */
POKEY_DELAYED_SEROUT_IRQ = 312*50*10*(POKEY_AUDF[POKEY_CHAN3] + POKEY_AUDF[POKEY_CHAN4]*0x100)/895000;
/* safety check */
if (POKEY_DELAYED_SEROUT_IRQ >= 3) {
POKEY_IRQST |= 0x08;
POKEY_DELAYED_XMTDONE_IRQ = 2*POKEY_DELAYED_SEROUT_IRQ - 2;
}
else {
POKEY_DELAYED_SEROUT_IRQ = 0;
POKEY_DELAYED_XMTDONE_IRQ = 0;
}
};
#ifdef SERIO_SOUND
POKEYSND_UpdateSerio(1, byte);
#endif
break;
case POKEY_OFFSET_STIMER:
POKEY_DivNIRQ[POKEY_CHAN1] = POKEY_DivNMax[POKEY_CHAN1];
POKEY_DivNIRQ[POKEY_CHAN2] = POKEY_DivNMax[POKEY_CHAN2];
POKEY_DivNIRQ[POKEY_CHAN4] = POKEY_DivNMax[POKEY_CHAN4];
POKEYSND_Update(POKEY_OFFSET_STIMER, byte, 0, SOUND_GAIN);
#ifdef DEBUG1
printf("WR: STIMER = %x\n", byte);
#endif
break;
case POKEY_OFFSET_SKCTL:
#ifdef VOICEBOX
VOICEBOX_SKCTLPutByte(byte);
#endif
POKEY_SKCTL = byte;
POKEYSND_Update(POKEY_OFFSET_SKCTL, byte, 0, SOUND_GAIN);
if (byte & 4)
pot_scanline = 228; /* fast pot mode - return results immediately */
if ((byte & 0x03) == 0) {
/* POKEY reset. */
/* Stop serial IO. */
POKEY_DELAYED_SERIN_IRQ = 0;
POKEY_DELAYED_SEROUT_IRQ = 0;
POKEY_DELAYED_XMTDONE_IRQ = 0;
#if SKIP
CASSETTE_ResetPOKEY();
#endif
/* TODO other registers should also be reset. */
}
break;
#ifdef STEREO_SOUND
case POKEY_OFFSET_AUDC1 + POKEY_OFFSET_POKEY2:
POKEY_AUDC[POKEY_CHAN1 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC1, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDC2 + POKEY_OFFSET_POKEY2:
POKEY_AUDC[POKEY_CHAN2 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC2, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDC3 + POKEY_OFFSET_POKEY2:
POKEY_AUDC[POKEY_CHAN3 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC3, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDC4 + POKEY_OFFSET_POKEY2:
POKEY_AUDC[POKEY_CHAN4 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDC4, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDCTL + POKEY_OFFSET_POKEY2:
POKEY_AUDCTL[1] = byte;
/* determine the base multiplier for the 'div by n' calculations */
if (byte & POKEY_CLOCK_15)
POKEY_Base_mult[1] = POKEY_DIV_15;
else
POKEY_Base_mult[1] = POKEY_DIV_64;
POKEYSND_Update(POKEY_OFFSET_AUDCTL, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF1 + POKEY_OFFSET_POKEY2:
POKEY_AUDF[POKEY_CHAN1 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDF1, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF2 + POKEY_OFFSET_POKEY2:
POKEY_AUDF[POKEY_CHAN2 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDF2, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF3 + POKEY_OFFSET_POKEY2:
POKEY_AUDF[POKEY_CHAN3 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDF3, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_AUDF4 + POKEY_OFFSET_POKEY2:
POKEY_AUDF[POKEY_CHAN4 + POKEY_CHIP2] = byte;
POKEYSND_Update(POKEY_OFFSET_AUDF4, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_STIMER + POKEY_OFFSET_POKEY2:
POKEYSND_Update(POKEY_OFFSET_STIMER, byte, 1, SOUND_GAIN);
break;
case POKEY_OFFSET_SKCTL + POKEY_OFFSET_POKEY2:
POKEYSND_Update(POKEY_OFFSET_SKCTL, byte, 1, SOUND_GAIN);
break;
#endif
}
}
int POKEY_Initialise(void)
{
int i;
ULONG reg;
/* Initialise Serial Port Interrupts */
POKEY_DELAYED_SERIN_IRQ = 0;
POKEY_DELAYED_SEROUT_IRQ = 0;
POKEY_DELAYED_XMTDONE_IRQ = 0;
POKEY_KBCODE = 0xff;
POKEY_SERIN = 0x00; /* or 0xff ? */
POKEY_IRQST = 0xff;
POKEY_IRQEN = 0x00;
POKEY_SKSTAT = 0xef;
POKEY_SKCTL = 0x00;
for (i = 0; i < (POKEY_MAXPOKEYS * 4); i++) {
POKEY_AUDC[i] = 0;
POKEY_AUDF[i] = 0;
}
for (i = 0; i < POKEY_MAXPOKEYS; i++) {
POKEY_AUDCTL[i] = 0;
POKEY_Base_mult[i] = POKEY_DIV_64;
}
for (i = 0; i < 4; i++)
POKEY_DivNIRQ[i] = POKEY_DivNMax[i] = 0;
pot_scanline = 0;
#if SKIP
/* initialise poly9_lookup */
reg = 0x1ff;
for (i = 0; i < POKEY_POLY9_SIZE; i++) {
reg = ((((reg >> 5) ^ reg) & 1) << 8) + (reg >> 1);
POKEY_poly9_lookup[i] = (UBYTE) reg;
}
/* initialise poly17_lookup */
reg = 0x1ffff;
for (i = 0; i < POKEY_POLY17_SIZE; i++) {
reg = ((((reg >> 5) ^ reg) & 0xff) << 9) + (reg >> 8);
POKEY_poly17_lookup[i] = (UBYTE) (reg >> 1);
}
#endif
#ifndef BASIC
#if SKIP
if (INPUT_Playingback()) {
random_scanline_counter = INPUT_PlaybackInt();
}
else
#endif
#endif
{
random_scanline_counter =
#ifdef HAVE_WINDOWS_H
GetTickCount() % POKEY_POLY17_SIZE;
#elif defined(HAVE_TIME)
time(NULL) % POKEY_POLY17_SIZE;
#else
0;
#endif
}
#ifndef BASIC
#if SKIP
if (INPUT_Recording()) {
INPUT_RecordInt(random_scanline_counter);
}
#endif
#endif
return TRUE;
}
void POKEY_Frame(void)
{
random_scanline_counter %= (POKEY_AUDCTL[0] & POKEY_POLY9) ? POKEY_POLY9_SIZE : POKEY_POLY17_SIZE;
}
/***************************************************************************
** Generate POKEY Timer IRQs if required **
** called on a per-scanline basis, not very precise, but good enough **
** for most applications **
***************************************************************************/
void POKEY_Scanline(void)
{
#ifdef POKEY_UPDATE
pokey_update();
#endif
#ifdef VOL_ONLY_SOUND
POKEYSND_UpdateVolOnly();
#endif
#ifndef BASIC
INPUT_Scanline(); /* Handle Amiga and ST mice. */
/* It's not a part of POKEY emulation, */
/* but it looks to be the best place to put it. */
#endif
/* on nonpatched i/o-operation, enable the cassette timing */
#if SKIP
if (!ESC_enable_sio_patch) {
if (CASSETTE_AddScanLine())
POKEY_DELAYED_SERIN_IRQ = 1;
}
#endif
if ((POKEY_SKCTL & 0x03) == 0)
/* Don't process timers when POKEY is in reset mode. */
return;
if (pot_scanline < 228)
pot_scanline++;
random_scanline_counter += ANTIC_LINE_C;
if (POKEY_DELAYED_SERIN_IRQ > 0) {
if (--POKEY_DELAYED_SERIN_IRQ == 0) {
/* Load a byte to SERIN - even when the IRQ is disabled. */
#if SKIP
POKEY_SERIN = SIO_GetByte();
#else
// POKEY_SERIN = 0;
#endif
if (POKEY_IRQEN & 0x20) {
if (POKEY_IRQST & 0x20) {
POKEY_IRQST &= 0xdf;
#ifdef DEBUG2
printf("SERIO: SERIN Interrupt triggered, bytevalue %02x\n", POKEY_SERIN);
#endif
}
else {
POKEY_SKSTAT &= 0xdf;
#ifdef DEBUG2
printf("SERIO: SERIN Interrupt triggered, bytevalue %02x\n", POKEY_SERIN);
#endif
}
CPU_GenerateIRQ();
}
#ifdef DEBUG2
else {
printf("SERIO: SERIN Interrupt missed, bytevalue %02x\n", POKEY_SERIN);
}
#endif
}
}
if (POKEY_DELAYED_SEROUT_IRQ > 0) {
if (--POKEY_DELAYED_SEROUT_IRQ == 0) {
if (POKEY_IRQEN & 0x10) {
#ifdef DEBUG2
printf("SERIO: SEROUT Interrupt triggered\n");
#endif
POKEY_IRQST &= 0xef;
CPU_GenerateIRQ();
}
#ifdef DEBUG2
else {
printf("SERIO: SEROUT Interrupt missed\n");
}
#endif
}
}
if (POKEY_DELAYED_XMTDONE_IRQ > 0)
if (--POKEY_DELAYED_XMTDONE_IRQ == 0) {
POKEY_IRQST &= 0xf7;
if (POKEY_IRQEN & 0x08) {
#ifdef DEBUG2
printf("SERIO: XMTDONE Interrupt triggered\n");
#endif
CPU_GenerateIRQ();
}
#ifdef DEBUG2
else
printf("SERIO: XMTDONE Interrupt missed\n");
#endif
}
if ((POKEY_DivNIRQ[POKEY_CHAN1] -= ANTIC_LINE_C) < 0 ) {
POKEY_DivNIRQ[POKEY_CHAN1] += POKEY_DivNMax[POKEY_CHAN1];
if (POKEY_IRQEN & 0x01) {
POKEY_IRQST &= 0xfe;
CPU_GenerateIRQ();
}
}
if ((POKEY_DivNIRQ[POKEY_CHAN2] -= ANTIC_LINE_C) < 0 ) {
POKEY_DivNIRQ[POKEY_CHAN2] += POKEY_DivNMax[POKEY_CHAN2];
if (POKEY_IRQEN & 0x02) {
POKEY_IRQST &= 0xfd;
CPU_GenerateIRQ();
}
}
if ((POKEY_DivNIRQ[POKEY_CHAN4] -= ANTIC_LINE_C) < 0 ) {
POKEY_DivNIRQ[POKEY_CHAN4] += POKEY_DivNMax[POKEY_CHAN4];
if (POKEY_IRQEN & 0x04) {
POKEY_IRQST &= 0xfb;
CPU_GenerateIRQ();
}
}
}
/*****************************************************************************/
/* Module: Update_Counter() */
/* Purpose: To process the latest control values stored in the AUDF, AUDC, */
/* and AUDCTL registers. It pre-calculates as much information as */
/* possible for better performance. This routine has been added */
/* here again as I need the precise frequency for the pokey timers */
/* again. The pokey emulation is therefore somewhat sub-optimal */
/* since the actual pokey emulation should grab the frequency values */
/* directly from here instead of calculating them again. */
/* */
/* Author: Ron Fries,Thomas Richter */
/* Date: March 27, 1998 */
/* */
/* Inputs: chan_mask: Channel mask, one bit per channel. */
/* The channels that need to be updated */
/* */
/* Outputs: Adjusts local globals - no return value */
/* */
/*****************************************************************************/
static void Update_Counter(int chan_mask)
{
/************************************************************/
/* As defined in the manual, the exact Div_n_cnt values are */
/* different depending on the frequency and resolution: */
/* 64 kHz or 15 kHz - AUDF + 1 */
/* 1 MHz, 8-bit - AUDF + 4 */
/* 1 MHz, 16-bit - AUDF[CHAN1]+256*AUDF[CHAN2] + 7 */
/************************************************************/
/* only reset the channels that have changed */
if (chan_mask & (1 << POKEY_CHAN1)) {
/* process channel 1 frequency */
if (POKEY_AUDCTL[0] & POKEY_CH1_179)
POKEY_DivNMax[POKEY_CHAN1] = POKEY_AUDF[POKEY_CHAN1] + 4;
else
POKEY_DivNMax[POKEY_CHAN1] = (POKEY_AUDF[POKEY_CHAN1] + 1) * POKEY_Base_mult[0];
if (POKEY_DivNMax[POKEY_CHAN1] < ANTIC_LINE_C)
POKEY_DivNMax[POKEY_CHAN1] = ANTIC_LINE_C;
}
if (chan_mask & (1 << POKEY_CHAN2)) {
/* process channel 2 frequency */
if (POKEY_AUDCTL[0] & POKEY_CH1_CH2) {
if (POKEY_AUDCTL[0] & POKEY_CH1_179)
POKEY_DivNMax[POKEY_CHAN2] = POKEY_AUDF[POKEY_CHAN2] * 256 + POKEY_AUDF[POKEY_CHAN1] + 7;
else
POKEY_DivNMax[POKEY_CHAN2] = (POKEY_AUDF[POKEY_CHAN2] * 256 + POKEY_AUDF[POKEY_CHAN1] + 1) * POKEY_Base_mult[0];
}
else
POKEY_DivNMax[POKEY_CHAN2] = (POKEY_AUDF[POKEY_CHAN2] + 1) * POKEY_Base_mult[0];
if (POKEY_DivNMax[POKEY_CHAN2] < ANTIC_LINE_C)
POKEY_DivNMax[POKEY_CHAN2] = ANTIC_LINE_C;
}
if (chan_mask & (1 << POKEY_CHAN4)) {
/* process channel 4 frequency */
if (POKEY_AUDCTL[0] & POKEY_CH3_CH4) {
if (POKEY_AUDCTL[0] & POKEY_CH3_179)
POKEY_DivNMax[POKEY_CHAN4] = POKEY_AUDF[POKEY_CHAN4] * 256 + POKEY_AUDF[POKEY_CHAN3] + 7;
else
POKEY_DivNMax[POKEY_CHAN4] = (POKEY_AUDF[POKEY_CHAN4] * 256 + POKEY_AUDF[POKEY_CHAN3] + 1) * POKEY_Base_mult[0];
}
else
POKEY_DivNMax[POKEY_CHAN4] = (POKEY_AUDF[POKEY_CHAN4] + 1) * POKEY_Base_mult[0];
if (POKEY_DivNMax[POKEY_CHAN4] < ANTIC_LINE_C)
POKEY_DivNMax[POKEY_CHAN4] = ANTIC_LINE_C;
}
}
#ifndef BASIC
void POKEY_StateSave(void)
{
int shift_key = 0;
int keypressed = 0;
StateSav_SaveUBYTE(&POKEY_KBCODE, 1);
StateSav_SaveUBYTE(&POKEY_IRQST, 1);
StateSav_SaveUBYTE(&POKEY_IRQEN, 1);
StateSav_SaveUBYTE(&POKEY_SKCTL, 1);
StateSav_SaveINT(&shift_key, 1);
StateSav_SaveINT(&keypressed, 1);
StateSav_SaveINT(&POKEY_DELAYED_SERIN_IRQ, 1);
StateSav_SaveINT(&POKEY_DELAYED_SEROUT_IRQ, 1);
StateSav_SaveINT(&POKEY_DELAYED_XMTDONE_IRQ, 1);
StateSav_SaveUBYTE(&POKEY_AUDF[0], 4);
StateSav_SaveUBYTE(&POKEY_AUDC[0], 4);
StateSav_SaveUBYTE(&POKEY_AUDCTL[0], 1);
StateSav_SaveINT(&POKEY_DivNIRQ[0], 4);
StateSav_SaveINT(&POKEY_DivNMax[0], 4);
StateSav_SaveINT(&POKEY_Base_mult[0], 1);
}
void POKEY_StateRead(void)
{
int i;
int shift_key;
int keypressed;
StateSav_ReadUBYTE(&POKEY_KBCODE, 1);
StateSav_ReadUBYTE(&POKEY_IRQST, 1);
StateSav_ReadUBYTE(&POKEY_IRQEN, 1);
StateSav_ReadUBYTE(&POKEY_SKCTL, 1);
StateSav_ReadINT(&shift_key, 1);
StateSav_ReadINT(&keypressed, 1);
StateSav_ReadINT(&POKEY_DELAYED_SERIN_IRQ, 1);
StateSav_ReadINT(&POKEY_DELAYED_SEROUT_IRQ, 1);
StateSav_ReadINT(&POKEY_DELAYED_XMTDONE_IRQ, 1);
StateSav_ReadUBYTE(&POKEY_AUDF[0], 4);
StateSav_ReadUBYTE(&POKEY_AUDC[0], 4);
StateSav_ReadUBYTE(&POKEY_AUDCTL[0], 1);
for (i = 0; i < 4; i++) {
POKEY_PutByte((UWORD) (POKEY_OFFSET_AUDF1 + i * 2), POKEY_AUDF[i]);
POKEY_PutByte((UWORD) (POKEY_OFFSET_AUDC1 + i * 2), POKEY_AUDC[i]);
}
POKEY_PutByte(POKEY_OFFSET_AUDCTL, POKEY_AUDCTL[0]);
StateSav_ReadINT(&POKEY_DivNIRQ[0], 4);
StateSav_ReadINT(&POKEY_DivNMax[0], 4);
StateSav_ReadINT(&POKEY_Base_mult[0], 1);
}
#endif