2024-03-27 23:56:55 +01:00
/*
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
*
* This file is part of the 86 Box distribution .
*
* Pro Audio Spectrum Plus and 16 emulation .
*
* Original PAS uses :
* - 2 x OPL2 ;
* - PIT - sample rate / count ;
* - LMC835N / LMC1982 - mixer ;
* - YM3802 - MIDI Control System .
*
* 9 A01 - I / O base :
* - base > > 2.
*
* All below + I / O base .
*
* B89 - Interrupt status / clear :
* - Bit 2 - sample rate ;
* - Bit 3 - PCM ;
* - Bit 4 - MIDI .
*
* B88 - Audio mixer control register .
*
* B8A - Audio filter control :
* - Bit 5 - mute ? .
*
* B8B - Interrupt mask / board ID :
* - Bits 5 - 7 - board ID ( read only on PAS16 ) .
*
* F88 - PCM data ( low ) .
*
* F89 - PCM data ( high ) .
*
* F8A - PCM control ? :
* - Bit 4 - input / output select ( 1 = output ) ;
* - Bit 5 - mono / stereo select ;
* - Bit 6 - PCM enable .
*
* 1388 - 138 B - PIT clocked at 1193180 Hz :
* - 1388 - Sample rate ;
* - 1389 - Sample count .
*
* 178 B - ? ? ? ? .
* 2789 - Board revision .
*
* 8389 :
* - Bit 2 - 8 / 16 bit .
*
* BF88 - Wait states .
*
* EF8B :
* - Bit 3 - 16 bits okay ? .
*
* F388 :
* - Bit 6 - joystick enable .
*
* F389 :
* - Bits 0 - 2 - DMA .
*
* F38A :
* - Bits 0 - 3 - IRQ .
*
* F788 :
* - Bit 1 - SB emulation ;
* - Bit 0 - MPU401 emulation .
*
* F789 - SB base address :
* - Bits 0 - 3 - Address bits 4 - 7.
*
* FB8A - SB IRQ / DMA :
* - Bits 3 - 5 - IRQ ;
* - Bits 6 - 7 - DMA .
*
* FF88 - board model :
* - 3 = PAS16 .
*
* Authors : Sarah Walker , < https : //pcem-emulator.co.uk/>
* Miran Grca , < mgrca8 @ gmail . com >
* TheCollector1995 , < mariogplayer @ gmail . com >
*
* Copyright 2008 - 2024 Sarah Walker .
* Copyright 2024 Miran Grca .
*/
# include <math.h>
2018-05-21 19:04:05 +02:00
# include <stdarg.h>
2017-09-25 04:31:20 -04:00
# include <stdint.h>
2018-05-21 19:04:05 +02:00
# include <stdio.h>
2016-06-26 00:34:39 +02:00
# include <stdlib.h>
2022-02-22 20:28:56 -05:00
# include <string.h>
2018-05-21 19:04:05 +02:00
# define HAVE_STDARG_H
2022-02-22 20:28:56 -05:00
2020-02-29 19:12:23 +01:00
# include "cpu.h"
2022-02-22 20:28:56 -05:00
# include <86box/86box.h>
# include <86box/device.h>
# include <86box/dma.h>
# include <86box/filters.h>
2024-05-03 17:02:13 +02:00
# include <86box/plat_unused.h>
2020-03-29 14:24:42 +02:00
# include <86box/io.h>
2024-05-03 17:02:13 +02:00
# include <86box/mem.h>
2024-03-18 17:10:36 +01:00
# include <86box/midi.h>
2020-03-29 14:24:42 +02:00
# include <86box/pic.h>
# include <86box/timer.h>
# include <86box/pit.h>
2024-03-27 23:56:55 +01:00
# include <86box/pit_fast.h>
2024-05-03 17:02:13 +02:00
# include <86box/rom.h>
2024-05-06 13:09:08 +02:00
# include <86box/scsi_device.h>
2024-05-03 17:02:13 +02:00
# include <86box/scsi_ncr5380.h>
2024-05-06 13:09:08 +02:00
# include <86box/scsi_t128.h>
2020-03-29 14:24:42 +02:00
# include <86box/snd_mpu401.h>
2022-02-22 20:28:56 -05:00
# include <86box/sound.h>
2020-03-29 14:24:42 +02:00
# include <86box/snd_opl.h>
2022-01-26 01:59:50 -05:00
# include <86box/snd_sb.h>
2020-03-29 14:24:42 +02:00
# include <86box/snd_sb_dsp.h>
2024-05-03 17:02:13 +02:00
typedef struct nsc_mixer_t {
double master_l ;
double master_r ;
int bass ;
int treble ;
double fm_l ;
double fm_r ;
double imixer_l ;
double imixer_r ;
double line_l ;
double line_r ;
double cd_l ;
double cd_r ;
double mic_l ;
double mic_r ;
double pcm_l ;
double pcm_r ;
double speaker_l ;
double speaker_r ;
uint8_t lmc1982_regs [ 8 ] ;
uint8_t lmc835_regs [ 32 ] ;
uint8_t im_state ;
uint16_t im_data [ 4 ] ;
} nsc_mixer_t ;
typedef struct mv508_mixer_t {
double master_l ;
double master_r ;
int bass ;
int treble ;
double fm_l ;
double fm_r ;
double imixer_l ;
double imixer_r ;
double line_l ;
double line_r ;
double cd_l ;
double cd_r ;
double mic_l ;
double mic_r ;
double pcm_l ;
double pcm_r ;
double speaker_l ;
double speaker_r ;
double sb_l ;
double sb_r ;
uint8_t index ;
uint8_t regs [ 3 ] [ 128 ] ;
} mv508_mixer_t ;
2017-05-06 17:48:33 +02:00
2022-02-22 20:28:56 -05:00
typedef struct pas16_t {
2024-03-27 23:56:55 +01:00
uint8_t this_id ;
uint8_t board_id ;
uint8_t master_ff ;
2024-05-03 17:02:13 +02:00
uint8_t has_scsi ;
2024-03-27 23:56:55 +01:00
uint8_t dma ;
uint8_t sb_irqdma ;
uint8_t type ;
uint8_t filter ;
uint8_t audiofilt ;
uint8_t audio_mixer ;
uint8_t compat ;
uint8_t compat_base ;
uint8_t io_conf_1 ;
uint8_t io_conf_2 ;
uint8_t io_conf_3 ;
uint8_t io_conf_4 ;
uint8_t irq_stat ;
uint8_t irq_ena ;
2022-02-22 20:28:56 -05:00
uint8_t pcm_ctrl ;
2024-03-27 23:56:55 +01:00
uint8_t prescale_div ;
uint8_t stereo_lr ;
uint8_t dma8_ff ;
uint8_t waitstates ;
uint8_t enhancedscsi ;
uint8_t sys_conf_1 ;
uint8_t sys_conf_2 ;
uint8_t sys_conf_3 ;
uint8_t sys_conf_4 ;
uint8_t midi_ctrl ;
uint8_t midi_stat ;
uint8_t midi_data ;
uint8_t fifo_stat ;
2024-05-03 17:02:13 +02:00
uint8_t timeout_count ;
uint8_t timeout_status ;
uint8_t pad_array [ 6 ] ;
2024-03-27 23:56:55 +01:00
uint8_t midi_queue [ 256 ] ;
2016-06-26 00:34:39 +02:00
2024-03-27 23:56:55 +01:00
uint16_t base ;
uint16_t new_base ;
2024-04-04 03:09:35 +02:00
uint16_t sb_compat_base ;
uint16_t mpu401_base ;
uint16_t dma8_dat ;
uint16_t ticks ;
2023-06-09 23:46:54 -04:00
uint16_t pcm_dat_l ;
uint16_t pcm_dat_r ;
2022-02-20 02:26:27 -05:00
2024-04-04 03:09:35 +02:00
int32_t pcm_buffer [ 2 ] [ SOUNDBUFLEN * 2 ] ;
2024-03-27 23:56:55 +01:00
int pos ;
int midi_r ;
int midi_w ;
int midi_uart_out ;
int midi_uart_in ;
int sysex ;
2016-06-26 00:34:39 +02:00
2024-05-03 17:02:13 +02:00
int irq ;
int scsi_irq ;
nsc_mixer_t nsc_mixer ;
mv508_mixer_t mv508_mixer ;
2022-07-25 20:24:31 +02:00
fm_drv_t opl ;
2022-02-22 20:28:56 -05:00
sb_dsp_t dsp ;
2016-06-26 00:34:39 +02:00
2024-03-27 23:56:55 +01:00
mpu_t * mpu ;
2024-03-18 17:10:36 +01:00
2024-03-27 23:56:55 +01:00
pitf_t * pit ;
2024-05-03 17:02:13 +02:00
2024-05-06 13:09:08 +02:00
t128_t * scsi ;
2024-05-03 17:02:13 +02:00
pc_timer_t scsi_timer ;
2016-06-26 00:34:39 +02:00
} pas16_t ;
2024-03-27 23:56:55 +01:00
static uint8_t pas16_next = 0 ;
2022-02-22 20:28:56 -05:00
static void pas16_update ( pas16_t * pas16 ) ;
2016-06-26 00:34:39 +02:00
2022-02-22 20:28:56 -05:00
static int pas16_dmas [ 8 ] = { 4 , 1 , 2 , 3 , 0 , 5 , 6 , 7 } ;
static int pas16_sb_irqs [ 8 ] = { 0 , 2 , 3 , 5 , 7 , 10 , 11 , 12 } ;
static int pas16_sb_dmas [ 8 ] = { 0 , 1 , 2 , 3 } ;
2016-06-26 00:34:39 +02:00
2022-02-22 20:28:56 -05:00
enum {
PAS16_INT_SAMP = 0x04 ,
2024-03-18 17:10:36 +01:00
PAS16_INT_PCM = 0x08 ,
2024-03-27 23:56:55 +01:00
PAS16_INT_MIDI = 0x10
2016-06-26 00:34:39 +02:00
} ;
2022-02-22 20:28:56 -05:00
enum {
PAS16_PCM_MONO = 0x20 ,
2024-03-21 22:00:48 +01:00
PAS16_PCM_ENA = 0x40 ,
PAS16_PCM_DMA_ENA = 0x80
2016-06-26 00:34:39 +02:00
} ;
2022-02-22 20:28:56 -05:00
enum {
PAS16_SC2_16BIT = 0x04 ,
PAS16_SC2_MSBINV = 0x10
2016-06-26 00:34:39 +02:00
} ;
2022-02-22 20:28:56 -05:00
enum {
PAS16_FILT_MUTE = 0x20
2016-06-26 00:34:39 +02:00
} ;
2024-05-03 17:02:13 +02:00
enum {
STATE_SM_IDLE = 0x00 ,
STATE_LMC1982_ADDR = 0x10 ,
STATE_LMC1982_ADDR_0 = 0x10 ,
STATE_LMC1982_ADDR_1 ,
STATE_LMC1982_ADDR_2 ,
STATE_LMC1982_ADDR_3 ,
STATE_LMC1982_ADDR_4 ,
STATE_LMC1982_ADDR_5 ,
STATE_LMC1982_ADDR_6 ,
STATE_LMC1982_ADDR_7 ,
STATE_LMC1982_ADDR_OVER ,
STATE_LMC1982_DATA = 0x10 ,
STATE_LMC1982_DATA_0 = 0x20 ,
STATE_LMC1982_DATA_1 ,
STATE_LMC1982_DATA_2 ,
STATE_LMC1982_DATA_3 ,
STATE_LMC1982_DATA_4 ,
STATE_LMC1982_DATA_5 ,
STATE_LMC1982_DATA_6 ,
STATE_LMC1982_DATA_7 ,
STATE_LMC1982_DATA_8 ,
STATE_LMC1982_DATA_9 ,
STATE_LMC1982_DATA_A ,
STATE_LMC1982_DATA_B ,
STATE_LMC1982_DATA_C ,
STATE_LMC1982_DATA_D ,
STATE_LMC1982_DATA_E ,
STATE_LMC1982_DATA_F ,
STATE_LMC1982_DATA_OVER ,
STATE_LMC835_DATA = 0x40 ,
STATE_LMC835_DATA_0 = 0x40 ,
STATE_LMC835_DATA_1 ,
STATE_LMC835_DATA_2 ,
STATE_LMC835_DATA_3 ,
STATE_LMC835_DATA_4 ,
STATE_LMC835_DATA_5 ,
STATE_LMC835_DATA_6 ,
STATE_LMC835_DATA_7 ,
STATE_LMC835_DATA_OVER ,
} ;
# define STATE_DATA_MASK 0x07
# define STATE_DATA_MASK_W 0x0f
# define LMC1982_ADDR 0x00
# define LMC1982_DATA 0x01
# define LMC835_ADDR 0x02
# define LMC835_DATA 0x03
# define LMC835_FLAG_ADDR 0x80
# define SERIAL_MIXER_IDENT 0x10
# define SERIAL_MIXER_STROBE 0x04
# define SERIAL_MIXER_CLOCK 0x02
# define SERIAL_MIXER_DATA 0x01
# define SERIAL_MIXER_RESET_PCM 0x01
2024-03-27 23:56:55 +01:00
# define PAS16_PCM_AND_DMA_ENA (PAS16_PCM_ENA | PAS16_PCM_DMA_ENA)
2024-05-03 17:02:13 +02:00
/*
LMC1982CIN registers ( data bits 7 and 6 are always don ' t care ) :
- 40 = Mode ( 0x01 = INPUT2 ) ;
- 41 = 0 = Loudness ( 1 = on , 0 = off ) , 1 = Stereo Enhance ( 1 = on , 0 = off )
( 0x00 ) ;
- 42 = Bass , 00 - 0 c ( 0x06 ) ;
- 43 = Treble , 00 - 0 c ( 0x06 ) ;
- 45 [ L ] / 44 [ R ] = Master , 28 - 00 , counting down ( 0x28 , later 0xa8 ) ;
- 46 = ? ? ? ? ( 0x05 = Stereo ) .
*/
# define LMC1982_REG_MASK 0xf8 /* LMC1982CIN: Register Mask */
# define LMC1982_REG_VALID 0x40 /* LMC1982CIN: Register Valid Value */
# define LMC1982_REG_ISELECT 0x00 /* LMC1982CIN: Input Select + Mute */
# define LMC1982_REG_LES 0x01 /* LMC1982CIN: Loudness, Enhanced Stereo */
# define LMC1982_REG_BASS 0x02 /* LMC1982CIN: Bass */
# define LMC1982_REG_TREBLE 0x03 /* LMC1982CIN: Treble */
/* The Windows 95 driver indicates left and right are swapped in the wiring. */
# define LMC1982_REG_VOL_L 0x04 /* LMC1982CIN: Left Volume */
# define LMC1982_REG_VOL_R 0x05 /* LMC1982CIN: Right Volume */
# define LMC1982_REG_MODE 0x06 /* LMC1982CIN: Mode */
# define LMC1982_REG_DINPUT 0x07 /* LMC1982CIN: Digital Input 1 and 2 */
/* Bits 7-2: Don't care. */
# define LMC1982_ISELECT_MASK 0x03 /* LMC1982CIN: Input Select: Mask */
# define LMC1982_ISELECT_I1 0x00 /* LMC1982CIN: Input Select: INPUT1 */
# define LMC1982_ISELECT_I2 0x01 /* LMC1982CIN: Input Select: INPUT2 */
# define LMC1982_ISELECT_NA 0x02 /* LMC1982CIN: Input Select: N/A */
# define LMC1982_ISELECT_MUTE 0x03 /* LMC1982CIN: Input Select: MUTE */
/* Bits 7-2: Don't care. */
# define LMC1982_LES_MASK 0x03 /* LMC1982CIN: Loudness, Enhanced Stereo: Mask */
# define LMC1982_LES_BOTH_OFF 0x00 /* LMC1982CIN: Loudness OFF, Enhanced Stereo OFF */
# define LMC1982_L_ON_ES_OFF 0x01 /* LMC1982CIN: Loudness ON, Enhanced Stereo OFF */
# define LMC1982_L_OFF_ES_ON 0x02 /* LMC1982CIN: Loudness OFF, Enhanced Stereo ON */
# define LMC1982_LES_BOTH_ON 0x03 /* LMC1982CIN: Loudness OFF, Enhanced Stereo ON */
/* Bits 7-3: Don't care. */
# define LMC1982_MODE_MASK 0x07 /* LMC1982CIN: Mode: Mask */
# define LMC1982_MODE_MONO_L 0x04 /* LMC1982CIN: Mode: Left Mono */
# define LMC1982_MODE_STEREO 0x05 /* LMC1982CIN: Mode: Stereo */
# define LMC1982_MODE_MONO_R 0x06 /* LMC1982CIN: Mode: Right Mono */
# define LMC1982_MODE_MONO_R_2 0x07 /* LMC1982CIN: Mode: Right Mono (Alternate value) */
/* Bits 7-2: Don't care. */
# define LMC1982_DINPUT_MASK 0x03 /* LMC1982CIN: Digital Input 1 and 2: Mask */
# define LMC1982_DINPUT_DI1 0x01 /* LMC1982CIN: Digital Input 1 */
# define LMC1982_DINPUT_DI2 0x02 /* LMC1982CIN: Digital Input 2 */
/*
LMC835N registers :
- 01 [ L ] / 08 [ R ] = FM , 00 - 2f , bit 6 = clear , but the DOS driver sets
the bit , indicating a volume boost ( 0x69 ) ;
- 02 [ L ] / 09 [ R ] = Rec . monitor , 00 - 2f , bit 6 = clear ( 0x29 ) ;
- 03 [ L ] / 0 A [ R ] = Line in , 00 - 2f , bit 6 = clear , except for the DOS
driver ( 0x69 ) ;
- 04 [ L ] / 0 B [ R ] = CD , 00 - 2f , bit 6 = clear , except for the DOS driver
( 0x69 ) ;
- 05 [ L ] / 0 C [ R ] = Microphone , 00 - 2f , bit 6 = clear , except for the DOS
driver ( 0x44 ) ;
- 06 [ L ] / 0 D [ R ] = Wave out , 00 - 2f , bit 6 = set , except for DOS driver ,
which clears the bit ( 0x29 ) ;
- 07 [ L ] / 0 E [ R ] = PC speaker , 00 - 2f , bit 6 = clear , except for the DOS
drive ( 0x06 ) .
The registers for which the DOS driver sets the boost , also have bit 6
set in the address , despite the fact it should be a don ' t care - why ?
Apparently , no Sound Blaster control .
*/
# define LMC835_REG_MODE 0x00 / * LMC835N: Mode, not an actual register, but our internal register
to store the mode for Channels A ( 1 - 7 ) and B ( 8 - e ) . */
# define LMC835_REG_FM_L 0x01 /* LMC835N: FM Left */
# define LMC835_REG_IMIXER_L 0x02 /* LMC835N: Record Monitor Left */
# define LMC835_REG_LINE_L 0x03 /* LMC835N: Line in Left */
# define LMC835_REG_CDROM_L 0x04 /* LMC835N: CD Left */
# define LMC835_REG_MIC_L 0x05 /* LMC835N: Microphone Left */
# define LMC835_REG_PCM_L 0x06 /* LMC835N: Wave out Left */
# define LMC835_REG_SPEAKER_L 0x07 /* LMC83N5: PC speaker Left */
# define LMC835_REG_FM_R 0x08 /* LMC835N: FM Right */
# define LMC835_REG_IMIXER_R 0x09 /* LMC835N: Record Monitor Right */
# define LMC835_REG_LINE_R 0x0a /* LMC835N: Line in Right */
# define LMC835_REG_CDROM_R 0x0b /* LMC835N: CD Right */
# define LMC835_REG_MIC_R 0x0c /* LMC835N: Microphone Right */
# define LMC835_REG_PCM_R 0x0d /* LMC835N: Wave out Right */
# define LMC835_REG_SPEAKER_R 0x0e /* LMC83N5: PC speaker Right */
# define MV508_ADDRESS 0x80 /* Flag indicating it is the address */
/*
I think this may actually operate as such :
- Bit 6 : Mask left channel ;
- Bit 5 : Mask right channel .
*/
# define MV508_CHANNEL 0x60
# define MV508_LEFT 0x20
# define MV508_RIGHT 0x40
# define MV508_BOTH 0x00
# define MV508_MIXER 0x10 /* Flag indicating it is a mixer rather than a volume */
# define MV508_INPUT_MIX 0x20 /* Flag indicating the selected mixer is input */
# define MV508_MASTER_A 0x01 /* Volume: Output */
# define MV508_MASTER_B 0x02 /* Volume: DSP input */
# define MV508_BASS 0x03 /* Volume: Bass */
# define MV508_TREBLE 0x04 /* Volume: Treble */
# define MV508_MODE 0x05 /* Volume: Mode */
# define MV508_LOUDNESS 0x04 /* Mode: Loudness */
# define MV508_ENH_MASK 0x03 /* Mode: Stereo enhancement bit mask */
# define MV508_ENH_NONE 0x00 /* Mode: No stereo enhancement */
# define MV508_ENH_40 0x01 /* Mode: 40% stereo enhancement */
# define MV508_ENH_60 0x02 /* Mode: 60% stereo enhancement */
# define MV508_ENH_80 0x03 /* Mode: 80% stereo enhancement */
# define MV508_FM 0x00 /* Mixer: FM */
# define MV508_IMIXER 0x01 /* Mixer: Input mixer (recording monitor) */
# define MV508_LINE 0x02 /* Mixer: Line in */
# define MV508_CDROM 0x03 /* Mixer: CD-ROM */
# define MV508_MIC 0x04 /* Mixer: Microphone */
# define MV508_PCM 0x05 /* Mixer: PCM */
# define MV508_SPEAKER 0x06 /* Mixer: PC Speaker */
# define MV508_SB 0x07 /* Mixer: Sound Blaster DSP */
# define MV508_REG_MASTER_A_L (MV508_MASTER_A | MV508_LEFT)
# define MV508_REG_MASTER_A_R (MV508_MASTER_A | MV508_RIGHT)
# define MV508_REG_MASTER_B_L (MV508_MASTER_B | MV508_LEFT)
# define MV508_REG_MASTER_B_R (MV508_MASTER_B | MV508_RIGHT)
# define MV508_REG_BASS (MV508_BASS | MV508_LEFT)
# define MV508_REG_TREBLE (MV508_TREBLE | MV508_LEFT)
# define MV508_REG_FM_L (MV508_MIXER | MV508_FM | MV508_LEFT)
# define MV508_REG_FM_R (MV508_MIXER | MV508_FM | MV508_RIGHT)
# define MV508_REG_IMIXER_L (MV508_MIXER | MV508_IMIXER | MV508_LEFT)
# define MV508_REG_IMIXER_R (MV508_MIXER | MV508_IMIXER | MV508_RIGHT)
# define MV508_REG_LINE_L (MV508_MIXER | MV508_LINE | MV508_LEFT)
# define MV508_REG_LINE_R (MV508_MIXER | MV508_LINE | MV508_RIGHT)
# define MV508_REG_CDROM_L (MV508_MIXER | MV508_CDROM | MV508_LEFT)
# define MV508_REG_CDROM_R (MV508_MIXER | MV508_CDROM | MV508_RIGHT)
# define MV508_REG_MIC_L (MV508_MIXER | MV508_MIC | MV508_LEFT)
# define MV508_REG_MIC_R (MV508_MIXER | MV508_MIC | MV508_RIGHT)
# define MV508_REG_PCM_L (MV508_MIXER | MV508_PCM | MV508_LEFT)
# define MV508_REG_PCM_R (MV508_MIXER | MV508_PCM | MV508_RIGHT)
# define MV508_REG_SPEAKER_L (MV508_MIXER | MV508_SPEAKER | MV508_LEFT)
# define MV508_REG_SPEAKER_R (MV508_MIXER | MV508_SPEAKER | MV508_RIGHT)
# define MV508_REG_SB_L (MV508_MIXER | MV508_SB | MV508_LEFT)
# define MV508_REG_SB_R (MV508_MIXER | MV508_SB | MV508_RIGHT)
double low_fir_pas16_coef [ SB16_NCoef ] ;
/*
Also used for the MVA508 .
*/
static double lmc1982_bass_treble_4bits [ 16 ] ;
/*
Copied from the Sound Blaster code : - 62 dB to 0 dB in 2 dB steps .
Note that these are voltage dB ' s , so it corresonds in power dB
( formula for conversion to percentage : 10 ^ ( dB / 10 ) ) to - 31 dB
to 0 dB in 1 dB steps .
This is used for the MVA508 Volumes .
*/
static const double mva508_att_2dbstep_5bits [ ] = {
25.0 , 32.0 , 41.0 , 51.0 , 65.0 , 82.0 , 103.0 , 130.0 ,
164.0 , 206.0 , 260.0 , 327.0 , 412.0 , 519.0 , 653.0 , 822.0 ,
1036.0 , 1304.0 , 1641.0 , 2067.0 , 2602.0 , 3276.0 , 4125.0 , 5192.0 ,
6537.0 , 8230.0 , 10362.0 , 13044.0 , 16422.0 , 20674.0 , 26027.0 , 32767.0
} ;
/*
The same but in 1 dB steps , used for the MVA508 Master Volume .
*/
static const double mva508_att_1dbstep_6bits [ ] = {
18.0 , 25.0 , 29.0 , 32.0 , 36.0 , 41.0 , 46.0 , 51.0 ,
58.0 , 65.0 , 73.0 , 82.0 , 92.0 , 103.0 , 116.0 , 130.0 ,
146.0 , 164.0 , 184.0 , 206.0 , 231.0 , 260.0 , 292.0 , 327.0 ,
367.0 , 412.0 , 462.0 , 519.0 , 582.0 , 653.0 , 733.0 , 822.0 ,
923.0 , 1036.0 , 1162.0 , 1304.0 , 1463.0 , 1641.0 , 1842.0 , 2067.0 ,
2319.0 , 2602.0 , 2920.0 , 3276.0 , 3676.0 , 4125.0 , 4628.0 , 5192.0 ,
5826.0 , 6537.0 , 7335.0 , 8230.0 , 9234.0 , 10362.0 , 11626.0 , 13044.0 ,
14636.0 , 16422.0 , 18426.0 , 20674.0 , 23197.0 , 26027.0 , 29204.0 , 32767.0
} ;
/*
In 2 dB steps again , but to - 80 dB and counting down ( 0 = Flat ) , used
for the LMC1982CIN Master Volume .
*/
static const double lmc1982_att_2dbstep_6bits [ ] = {
32767.0 , 26027.0 , 20674.0 , 16422.0 , 13044.0 , 10362.0 , 8230.0 , 6537.0 ,
5192.0 , 4125.0 , 3276.0 , 2602.0 , 2067.0 , 1641.0 , 1304.0 , 1036.0 ,
822.0 , 653.0 , 519.0 , 412.0 , 327.0 , 260.0 , 206.0 , 164.0 ,
130.0 , 103.0 , 82.0 , 65.0 , 51.0 , 41.0 , 32.0 , 25.0 ,
20.0 , 16.0 , 13.0 , 10.0 , 8.0 , 6.0 , 5.0 , 4.0 ,
3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 ,
3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 ,
3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0
} ;
/*
LMC385N attenuation , both + / - 12 dB and + / - 6 dB .
Since the DOS and Windows 95 driver diverge on boost vs . cut for
the various inputs , I think it is best to just do a 12 dB cut on
the input , and then apply cut or boost as needed . I have factored
in said cut in the below values .
*/
static const double lmc835_att_1dbstep_7bits [ 128 ] = {
/* Flat */
[ 0x40 ] = 8230.0 , /* Flat */
/* Boost */
[ 0x60 ] = 9234.0 , /* 1 dB Boost */
[ 0x50 ] = 10362.0 , /* 2 dB Boost */
[ 0x48 ] = 11626.0 , /* 3 dB Boost */
[ 0x44 ] = 13044.0 , /* 4 dB Boost */
[ 0x42 ] = 14636.0 , /* 5 dB Boost */
[ 0x52 ] = 16422.0 , /* 6 dB Boost */
[ 0x6a ] = 18426.0 , /* 7 dB Boost */
[ 0x56 ] = 20674.0 , /* 8 dB Boost */
[ 0x41 ] = 23197.0 , /* 9 dB Boost */
[ 0x69 ] = 26027.0 , /* 10 dB Boost */
[ 0x6d ] = 29204.0 , /* 11 dB Boost */
/* The Win95 drivers use D5-D0 = 1D instead of 2D, datasheet erratum? */
[ 0x5d ] = 29204.0 , /* 11 dB Boost */
[ 0x6f ] = 32767.0 , /* 12 dB Boost */
/* Flat */
/* The datasheet says this should be Flat (1.0) but the
Windows 95 drivers use this as basically mute ( 12 dB Cut ) . */
[ 0x00 ] = 2067.0 , /* 12 dB Cut */
/* Cut - D5-D0 = 2F is minimum cut (0 dB) according to Windows 95 */
[ 0x20 ] = 2319.0 , /* 11 dB Cut */
[ 0x10 ] = 2602.0 , /* 10 dB Cut */
[ 0x08 ] = 2920.0 , /* 9 dB Cut */
[ 0x04 ] = 3276.0 , /* 8 dB Cut */
[ 0x02 ] = 3676.0 , /* 7 dB Cut */
[ 0x12 ] = 4125.0 , /* 6 dB Cut */
[ 0x2a ] = 4628.0 , /* 5 dB Cut */
[ 0x16 ] = 5192.0 , /* 4 dB Cut */
[ 0x01 ] = 5826.0 , /* 3 dB Cut */
[ 0x29 ] = 6537.0 , /* 2 dB Cut */
[ 0x2d ] = 7335.0 , /* 1 dB Cut */
/* The Win95 drivers use D5-D0 = 1D instead of 2D, datasheet erratum? */
[ 0x1d ] = 7335.0 , /* 1 dB Cut */
[ 0x2f ] = 8230.0 , /* Flat */
2024-05-04 11:40:07 +02:00
0.0
2024-05-03 17:02:13 +02:00
} ;
static const double lmc835_att_05dbstep_7bits [ 128 ] = {
/* Flat */
[ 0x40 ] = 8230.0 , /* Flat */
/* Boost */
[ 0x60 ] = 8718.0 , /* 0.5 dB Boost */
[ 0x50 ] = 9234.0 , /* 1.0 dB Boost */
[ 0x48 ] = 9782.0 , /* 1.5 dB Boost */
[ 0x44 ] = 10362.0 , /* 2.0 dB Boost */
[ 0x42 ] = 10975.0 , /* 2.5 dB Boost */
[ 0x52 ] = 11626.0 , /* 3.0 dB Boost */
[ 0x6a ] = 12315.0 , /* 3.5 dB Boost */
[ 0x56 ] = 13044.0 , /* 4.0 dB Boost */
[ 0x41 ] = 13817.0 , /* 4.5 dB Boost */
[ 0x69 ] = 14636.0 , /* 5.0 dB Boost */
[ 0x6d ] = 15503.0 , /* 5.5 dB Boost */
/* The Win95 drivers use D5-D0 = 1D instead of 2D, datasheet erratum? */
[ 0x5d ] = 15503.0 , /* 5.5 dB Boost */
[ 0x6f ] = 16422.0 , /* 6.0 dB Boost */
/* Flat */
/* The datasheet says this should be Flat (1.0) but the
Windows 95 drivers use this as basically mute ( 12 dB Cut ) . */
[ 0x00 ] = 4125.0 , /* 6.0 dB Cut */
/* Cut - D5-D0 = 2F is minimum cut (0 dB) according to Windows 95 */
[ 0x20 ] = 4369.0 , /* 5.5 dB Cut */
[ 0x10 ] = 4628.0 , /* 5.0 dB Cut */
[ 0x08 ] = 4920.0 , /* 4.5 dB Cut */
[ 0x04 ] = 5192.0 , /* 4.0 dB Cut */
[ 0x02 ] = 5500.0 , /* 3.5 dB Cut */
[ 0x12 ] = 5826.0 , /* 3.0 dB Cut */
[ 0x2a ] = 6172.0 , /* 2.5 dB Cut */
[ 0x16 ] = 6537.0 , /* 2.0 dB Cut */
[ 0x01 ] = 6925.0 , /* 1.5 dB Cut */
[ 0x29 ] = 7335.0 , /* 1.0 dB Cut */
[ 0x2d ] = 7770.0 , /* 0.5 dB Cut */
/* The Win95 drivers use D5-D0 = 1D instead of 2D, datasheet erratum? */
[ 0x1d ] = 7770.0 , /* 0.5 dB Cut */
[ 0x2f ] = 8230.0 , /* Flat */
2024-05-04 11:40:07 +02:00
0.0
2024-05-03 17:02:13 +02:00
} ;
2024-03-27 23:56:55 +01:00
static __inline double
2024-05-03 17:02:13 +02:00
sinc ( const double x )
2024-03-27 23:56:55 +01:00
{
return sin ( M_PI * x ) / ( M_PI * x ) ;
}
static void
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( const int playback_freq )
2024-03-27 23:56:55 +01:00
{
/* Cutoff frequency = playback / 2 */
2024-05-03 17:02:13 +02:00
int n ;
const double fC = ( ( double ) playback_freq ) / ( double ) FREQ_96000 ;
double gain = 0.0 ;
2024-03-27 23:56:55 +01:00
for ( n = 0 ; n < SB16_NCoef ; n + + ) {
/* Blackman window */
2024-05-03 17:02:13 +02:00
const double w = 0.42 - ( 0.5 * cos ( ( 2.0 * n * M_PI ) / ( double ) ( SB16_NCoef - 1 ) ) ) +
( 0.08 * cos ( ( 4.0 * n * M_PI ) / ( double ) ( SB16_NCoef - 1 ) ) ) ;
2024-03-27 23:56:55 +01:00
/* Sinc filter */
2024-05-03 17:02:13 +02:00
const double h = sinc ( 2.0 * fC * ( ( double ) n - ( ( double ) ( SB16_NCoef - 1 ) / 2.0 ) ) ) ;
2024-03-27 23:56:55 +01:00
/* Create windowed-sinc filter */
2024-05-03 17:02:13 +02:00
low_fir_pas16_coef [ n ] = w * h ;
2024-03-27 23:56:55 +01:00
}
2024-05-03 17:02:13 +02:00
low_fir_pas16_coef [ ( SB16_NCoef - 1 ) / 2 ] = 1.0 ;
2024-03-27 23:56:55 +01:00
for ( n = 0 ; n < SB16_NCoef ; n + + )
2024-05-03 17:02:13 +02:00
gain + = low_fir_pas16_coef [ n ] ;
2024-03-27 23:56:55 +01:00
/* Normalise filter, to produce unity gain */
for ( n = 0 ; n < SB16_NCoef ; n + + )
2024-05-03 17:02:13 +02:00
low_fir_pas16_coef [ n ] / = gain ;
2024-03-27 23:56:55 +01:00
}
2018-05-21 19:04:05 +02:00
# ifdef ENABLE_PAS16_LOG
int pas16_do_log = ENABLE_PAS16_LOG ;
static void
pas16_log ( const char * fmt , . . . )
{
va_list ap ;
if ( pas16_do_log ) {
2022-02-22 20:28:56 -05:00
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
2018-05-21 19:04:05 +02:00
}
}
2018-10-19 00:39:32 +02:00
# else
2022-02-22 20:28:56 -05:00
# define pas16_log(fmt, ...)
2018-10-19 00:39:32 +02:00
# endif
2018-05-21 19:04:05 +02:00
2024-03-21 22:00:48 +01:00
static uint8_t
pas16_in ( uint16_t port , void * priv ) ;
2024-03-18 17:10:36 +01:00
static void
2024-03-21 22:00:48 +01:00
pas16_out ( uint16_t port , uint8_t val , void * priv ) ;
2024-03-18 17:10:36 +01:00
static void
2024-03-21 22:00:48 +01:00
pas16_update_irq ( pas16_t * pas16 )
2024-03-18 17:10:36 +01:00
{
2024-03-21 22:00:48 +01:00
if ( pas16 - > midi_uart_out & & ( pas16 - > midi_stat & 0x18 ) ) {
pas16 - > irq_stat | = PAS16_INT_MIDI ;
2024-05-03 17:02:13 +02:00
if ( ( pas16 - > irq ! = - 1 ) & & ( pas16 - > irq_ena & PAS16_INT_MIDI ) )
2024-03-21 22:00:48 +01:00
picint ( 1 < < pas16 - > irq ) ;
}
if ( pas16 - > midi_uart_in & & ( pas16 - > midi_stat & 0x04 ) ) {
pas16 - > irq_stat | = PAS16_INT_MIDI ;
2024-05-03 17:02:13 +02:00
if ( ( pas16 - > irq ! = - 1 ) & & ( pas16 - > irq_ena & PAS16_INT_MIDI ) )
2024-03-21 22:00:48 +01:00
picint ( 1 < < pas16 - > irq ) ;
2024-03-18 17:10:36 +01:00
}
}
2022-02-22 20:28:56 -05:00
static uint8_t
2023-06-09 23:46:54 -04:00
pas16_in ( uint16_t port , void * priv )
2016-06-26 00:34:39 +02:00
{
2023-06-09 23:46:54 -04:00
pas16_t * pas16 = ( pas16_t * ) priv ;
2024-03-27 23:56:55 +01:00
uint8_t ret = 0xff ;
port - = pas16 - > base ;
2024-03-21 22:00:48 +01:00
switch ( port ) {
2024-03-27 23:56:55 +01:00
case 0x0000 . . . 0x0003 :
ret = pas16 - > opl . read ( port + 0x0388 , pas16 - > opl . priv ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0800 :
2024-05-03 17:02:13 +02:00
ret = pas16 - > type ? pas16 - > audio_mixer : 0xff ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0801 :
ret = pas16 - > irq_stat & 0xdf ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0802 :
ret = pas16 - > audiofilt ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0803 :
2024-04-06 02:44:50 +02:00
ret = pas16 - > irq_ena | 0x20 ;
2024-03-27 23:56:55 +01:00
pas16_log ( " IRQ Mask read=%02x. \n " , ret ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0c02 :
ret = pas16 - > pcm_ctrl ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1401 :
case 0x1403 :
ret = pas16 - > midi_ctrl ;
2024-03-18 17:10:36 +01:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1402 :
case 0x1802 :
ret = 0 ;
2024-03-21 22:00:48 +01:00
if ( pas16 - > midi_uart_in ) {
if ( ( pas16 - > midi_data = = 0xaa ) & & ( pas16 - > midi_ctrl & 0x04 ) )
2024-03-27 23:56:55 +01:00
ret = pas16 - > midi_data ;
2024-03-21 22:00:48 +01:00
else {
2024-03-27 23:56:55 +01:00
ret = pas16 - > midi_queue [ pas16 - > midi_r ] ;
2024-03-21 22:00:48 +01:00
if ( pas16 - > midi_r ! = pas16 - > midi_w ) {
pas16 - > midi_r + + ;
pas16 - > midi_r & = 0xff ;
}
}
pas16 - > midi_stat & = ~ 0x04 ;
pas16_update_irq ( pas16 ) ;
}
2024-03-18 17:10:36 +01:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1800 :
ret = pas16 - > midi_stat ;
2024-03-21 22:00:48 +01:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1801 :
ret = pas16 - > fifo_stat ;
2022-02-22 20:28:56 -05:00
break ;
2024-05-03 17:02:13 +02:00
case 0x1c00 . . . 0x1c03 : /* NCR5380 ports 0 to 3. */
case 0x3c00 . . . 0x3c03 : /* NCR5380 ports 4 to 7. */
2024-05-06 13:09:08 +02:00
if ( pas16 - > has_scsi )
ret = ncr5380_read ( ( port & 0x0003 ) | ( ( port & 0x2000 ) > > 11 ) , & pas16 - > scsi - > ncr ) ;
2024-05-03 17:02:13 +02:00
break ;
2024-03-27 23:56:55 +01:00
case 0x2401 : /* Board revision */
ret = 0x00 ;
2022-02-22 20:28:56 -05:00
break ;
2024-05-03 17:02:13 +02:00
case 0x4000 :
ret = pas16 - > timeout_count ;
break ;
case 0x4001 :
ret = pas16 - > timeout_status ;
break ;
case 0x5c00 :
if ( pas16 - > has_scsi )
2024-05-06 13:09:08 +02:00
ret = t128_read ( 0x1e00 , pas16 - > scsi ) ;
2024-05-03 17:02:13 +02:00
break ;
case 0x5c01 :
2024-05-06 13:09:08 +02:00
if ( pas16 - > has_scsi )
/* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */
ret = ( ( ( pas16 - > scsi - > ncr . dma_mode ! = DMA_IDLE ) & & ( pas16 - > scsi - > status & 0x04 ) ) < < 7 ) | 0x7f ;
2024-05-03 17:02:13 +02:00
break ;
case 0x5c03 :
if ( pas16 - > has_scsi )
ret = pas16 - > scsi - > ncr . irq_state < < 7 ;
break ;
2024-03-27 23:56:55 +01:00
case 0x7c01 :
ret = pas16 - > enhancedscsi & ~ 0x01 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8000 :
ret = pas16 - > sys_conf_1 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8001 :
ret = pas16 - > sys_conf_2 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8002 :
ret = pas16 - > sys_conf_3 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8003 :
ret = pas16 - > sys_conf_4 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xbc00 :
ret = pas16 - > waitstates ;
2024-03-18 17:10:36 +01:00
break ;
2024-03-27 23:56:55 +01:00
case 0xbc02 :
ret = pas16 - > prescale_div ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xec03 :
2024-05-03 17:02:13 +02:00
/*
Operation mode 1 :
- 1 , 0 = CD - ROM ( 1 , 1 = SCSI , 1 , 0 = Sony , 0 , 0 = N / A ) ;
- 2 = FM ( 1 = stereo , 0 = mono ) ;
- 3 = Code ( 1 = 16 - bit , 0 = 8 - bit ) .
*/
2024-05-29 23:18:43 +02:00
ret = pas16 - > type ? pas16 - > type : 0x07 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf000 :
ret = pas16 - > io_conf_1 ;
break ;
case 0xf001 :
ret = pas16 - > io_conf_2 ;
2024-03-21 22:00:48 +01:00
pas16_log ( " pas16_in : set PAS DMA %i \n " , pas16 - > dma ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf002 :
ret = pas16 - > io_conf_3 ;
2024-03-21 22:00:48 +01:00
pas16_log ( " pas16_in : set PAS IRQ %i \n " , pas16 - > irq ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf003 :
ret = pas16 - > io_conf_4 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf400 :
2024-04-04 03:09:35 +02:00
ret = ( pas16 - > compat & 0xf3 ) ;
if ( pas16 - > dsp . sb_irqm8 | | pas16 - > dsp . sb_irqm16 | | pas16 - > dsp . sb_irqm401 )
ret | = 0x04 ;
if ( pas16 - > mpu - > mode = = M_UART )
ret | = 0x08 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf401 :
ret = pas16 - > compat_base ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf802 :
ret = pas16 - > sb_irqdma ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xfc00 : /* Board model */
/* PAS16 or PASPlus */
2024-04-04 03:09:35 +02:00
ret = pas16 - > type ? 0x0c : 0x01 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xfc03 : /* Master mode read */
/* AT bus, XT/AT timing */
2024-04-04 03:09:35 +02:00
ret = 0x11 ;
if ( pas16 - > type )
ret | = 0x20 ;
2022-02-22 20:28:56 -05:00
break ;
2023-06-09 23:46:54 -04:00
default :
break ;
2022-02-22 20:28:56 -05:00
}
2024-03-27 23:56:55 +01:00
pas16_log ( " [%04X:%08X] PAS16: [R] %04X (%04X) = %02X \n " ,
CS , cpu_state . pc , port + pas16 - > base , port , ret ) ;
return ret ;
}
static void
pas16_change_pit_clock_speed ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
pitf_t * pit = ( pitf_t * ) pas16 - > pit ;
if ( pas16 - > type & & ( pas16 - > sys_conf_1 & 0x02 ) & & pas16 - > prescale_div ) {
pit_change_pas16_consts ( ( double ) pas16 - > prescale_div ) ;
if ( pas16 - > sys_conf_3 & 0x02 )
pitf_set_pit_const ( pit , PAS16CONST2 ) ;
else
pitf_set_pit_const ( pit , PAS16CONST ) ;
} else
pitf_set_pit_const ( pit , PITCONST ) ;
}
static void
pas16_io_handler ( pas16_t * pas16 , int set )
{
if ( pas16 - > base ! = 0x0000 ) {
for ( uint32_t addr = 0x0000 ; addr < = 0xffff ; addr + = 0x0400 ) {
pas16_log ( " %04X-%04X: %i \n " , pas16 - > base + addr , pas16 - > base + addr + 3 , set ) ;
if ( addr ! = 0x1000 )
io_handler ( set , pas16 - > base + addr , 0x0004 ,
pas16_in , NULL , NULL , pas16_out , NULL , NULL , pas16 ) ;
}
pitf_handler ( set , pas16 - > base + 0x1000 , 0x0004 , pas16 - > pit ) ;
}
}
static void
pas16_reset_pcm ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
pas16 - > pcm_ctrl = 0x00 ;
pas16 - > stereo_lr = 0 ;
pas16 - > irq_stat & = 0xd7 ;
2024-05-03 17:02:13 +02:00
if ( ( pas16 - > irq ! = - 1 ) & & ! pas16 - > irq_stat )
2024-03-27 23:56:55 +01:00
picintc ( 1 < < pas16 - > irq ) ;
}
2024-05-03 17:02:13 +02:00
static void
lmc1982_recalc ( nsc_mixer_t * mixer )
{
/* LMC1982CIN */
/* According to the Windows 95 driver, the two volumes are swapped. */
if ( ( mixer - > lmc1982_regs [ LMC1982_REG_ISELECT ] & LMC1982_ISELECT_MASK ) = = LMC1982_ISELECT_I2 ) {
switch ( mixer - > lmc1982_regs [ LMC1982_REG_MODE ] & LMC1982_MODE_MASK ) {
case LMC1982_MODE_MONO_L :
mixer - > master_l = mixer - > master_r = lmc1982_att_2dbstep_6bits [ mixer - > lmc1982_regs [ LMC1982_REG_VOL_R ] ] / 32767.0 ;
break ;
case LMC1982_MODE_STEREO :
mixer - > master_l = lmc1982_att_2dbstep_6bits [ mixer - > lmc1982_regs [ LMC1982_REG_VOL_R ] ] / 32767.0 ;
mixer - > master_r = lmc1982_att_2dbstep_6bits [ mixer - > lmc1982_regs [ LMC1982_REG_VOL_L ] ] / 32767.0 ;
break ;
case LMC1982_MODE_MONO_R :
case LMC1982_MODE_MONO_R_2 :
mixer - > master_l = mixer - > master_r = lmc1982_att_2dbstep_6bits [ mixer - > lmc1982_regs [ LMC1982_REG_VOL_L ] ] / 32767.0 ;
break ;
default :
mixer - > master_l = mixer - > master_r = 0.0 ;
break ;
}
mixer - > bass = mixer - > lmc1982_regs [ LMC1982_REG_BASS ] & 0x0f ;
mixer - > treble = mixer - > lmc1982_regs [ LMC1982_REG_TREBLE ] & 0x0f ;
} else {
mixer - > master_l = mixer - > master_r = 0.0 ;
mixer - > bass = 0x06 ;
mixer - > treble = 0x06 ;
}
}
static void
lmc835_recalc ( nsc_mixer_t * mixer )
{
/* LMC835N */
/* Channel A (1-7) */
const double * lmc835_att = ( const double * ) ( ( mixer - > lmc835_regs [ LMC835_REG_MODE ] & 0x20 ) ?
lmc835_att_05dbstep_7bits : lmc835_att_1dbstep_7bits ) ;
mixer - > fm_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_FM_L ] & 0x7f ] / 32767.0 ;
mixer - > imixer_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_IMIXER_L ] & 0x7f ] / 32767.0 ;
mixer - > line_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_LINE_L ] & 0x7f ] / 32767.0 ;
mixer - > cd_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_CDROM_L ] & 0x7f ] / 32767.0 ;
mixer - > mic_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_MIC_L ] & 0x7f ] / 32767.0 ;
mixer - > pcm_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_PCM_L ] & 0x7f ] / 32767.0 ;
mixer - > speaker_l = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_SPEAKER_L ] & 0x7f ] / 32767.0 ;
/* Channel B (8-e) */
lmc835_att = ( const double * ) ( ( mixer - > lmc835_regs [ LMC835_REG_MODE ] & 0x08 ) ?
lmc835_att_05dbstep_7bits : lmc835_att_1dbstep_7bits ) ;
mixer - > fm_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_FM_R ] & 0x7f ] / 32767.0 ;
mixer - > imixer_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_IMIXER_R ] & 0x7f ] / 32767.0 ;
mixer - > line_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_LINE_R ] & 0x7f ] / 32767.0 ;
mixer - > cd_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_CDROM_R ] & 0x7f ] / 32767.0 ;
mixer - > mic_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_MIC_R ] & 0x7f ] / 32767.0 ;
mixer - > pcm_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_PCM_R ] & 0x7f ] / 32767.0 ;
mixer - > speaker_r = lmc835_att [ mixer - > lmc835_regs [ LMC835_REG_SPEAKER_R ] & 0x7f ] / 32767.0 ;
}
static void
mv508_mixer_recalc ( mv508_mixer_t * mixer )
{
mixer - > fm_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_FM_L ] ] / 32767.0 ;
mixer - > fm_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_FM_R ] ] / 32767.0 ;
mixer - > imixer_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_IMIXER_L ] ] / 32767.0 ;
mixer - > imixer_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_IMIXER_R ] ] / 32767.0 ;
mixer - > line_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_LINE_L ] ] / 32767.0 ;
mixer - > line_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_LINE_R ] ] / 32767.0 ;
mixer - > cd_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_CDROM_L ] ] / 32767.0 ;
mixer - > cd_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_CDROM_R ] ] / 32767.0 ;
mixer - > mic_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_MIC_L ] ] / 32767.0 ;
mixer - > mic_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_MIC_R ] ] / 32767.0 ;
mixer - > pcm_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_PCM_L ] ] / 32767.0 ;
mixer - > pcm_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_PCM_R ] ] / 32767.0 ;
mixer - > speaker_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_SPEAKER_L ] ] / 32767.0 ;
mixer - > speaker_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_SPEAKER_R ] ] / 32767.0 ;
mixer - > sb_l = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_SB_L ] ] / 32767.0 ;
mixer - > sb_r = mva508_att_2dbstep_5bits [ mixer - > regs [ 0 ] [ MV508_REG_SB_R ] ] / 32767.0 ;
mixer - > master_l = mva508_att_1dbstep_6bits [ mixer - > regs [ 2 ] [ MV508_REG_MASTER_A_L ] ] / 32767.0 ;
mixer - > master_r = mva508_att_1dbstep_6bits [ mixer - > regs [ 2 ] [ MV508_REG_MASTER_A_R ] ] / 32767.0 ;
mixer - > bass = mixer - > regs [ 2 ] [ MV508_REG_BASS ] & 0x0f ;
mixer - > treble = mixer - > regs [ 2 ] [ MV508_REG_TREBLE ] & 0x0f ;
}
static void
pas16_nsc_mixer_reset ( nsc_mixer_t * mixer )
{
mixer - > lmc1982_regs [ LMC1982_REG_ISELECT ] = 0x01 ;
mixer - > lmc1982_regs [ LMC1982_REG_LES ] = 0x00 ;
mixer - > lmc1982_regs [ LMC1982_REG_BASS ] = mixer - > lmc1982_regs [ LMC1982_REG_TREBLE ] = 0x06 ;
2024-09-22 21:29:00 +02:00
mixer - > lmc1982_regs [ LMC1982_REG_VOL_L ] = mixer - > lmc1982_regs [ LMC1982_REG_VOL_R ] = 0x00 ; /*0x28*/ /*Note by TC1995: otherwise the volume gets lowered too much*/
2024-05-03 17:02:13 +02:00
mixer - > lmc1982_regs [ LMC1982_REG_MODE ] = 0x05 ;
lmc1982_recalc ( mixer ) ;
mixer - > lmc835_regs [ LMC835_REG_MODE ] = 0x00 ;
mixer - > lmc835_regs [ LMC835_REG_FM_L ] = mixer - > lmc835_regs [ LMC835_REG_FM_R ] = 0x69 ;
mixer - > lmc835_regs [ LMC835_REG_IMIXER_L ] = mixer - > lmc835_regs [ LMC835_REG_IMIXER_R ] = 0x29 ;
mixer - > lmc835_regs [ LMC835_REG_LINE_L ] = mixer - > lmc835_regs [ LMC835_REG_LINE_R ] = 0x69 ;
mixer - > lmc835_regs [ LMC835_REG_CDROM_L ] = mixer - > lmc835_regs [ LMC835_REG_CDROM_R ] = 0x69 ;
mixer - > lmc835_regs [ LMC835_REG_MIC_L ] = mixer - > lmc835_regs [ LMC835_REG_MIC_R ] = 0x44 ;
mixer - > lmc835_regs [ LMC835_REG_PCM_L ] = mixer - > lmc835_regs [ LMC835_REG_PCM_R ] = 0x29 ;
mixer - > lmc835_regs [ LMC835_REG_SPEAKER_L ] = mixer - > lmc835_regs [ LMC835_REG_SPEAKER_R ] = 0x06 ;
lmc835_recalc ( mixer ) ;
}
static void
pas16_mv508_mixer_reset ( mv508_mixer_t * mixer )
{
/* Based on the Linux driver - TODO: The actual card's defaults. */
mixer - > regs [ 0 ] [ MV508_REG_FM_L ] = mixer - > regs [ 0 ] [ MV508_REG_FM_R ] = 0x18 ;
mixer - > regs [ 0 ] [ MV508_REG_IMIXER_L ] = mixer - > regs [ 0 ] [ MV508_REG_IMIXER_R ] = 0x1f ;
mixer - > regs [ 0 ] [ MV508_REG_LINE_L ] = mixer - > regs [ 0 ] [ MV508_REG_LINE_R ] = 0x17 ;
mixer - > regs [ 0 ] [ MV508_REG_CDROM_L ] = mixer - > regs [ 0 ] [ MV508_REG_CDROM_R ] = 0x17 ;
mixer - > regs [ 0 ] [ MV508_REG_MIC_L ] = mixer - > regs [ 0 ] [ MV508_REG_MIC_R ] = 0x17 ;
mixer - > regs [ 0 ] [ MV508_REG_PCM_L ] = mixer - > regs [ 0 ] [ MV508_REG_PCM_R ] = 0x17 ;
mixer - > regs [ 0 ] [ MV508_REG_SPEAKER_L ] = mixer - > regs [ 0 ] [ MV508_REG_SPEAKER_R ] = 0x0f ;
mixer - > regs [ 0 ] [ MV508_REG_SB_L ] = mixer - > regs [ 0 ] [ MV508_REG_SB_R ] = 0x17 ;
mixer - > regs [ 2 ] [ MV508_REG_MASTER_A_L ] = mixer - > regs [ 2 ] [ MV508_REG_MASTER_A_R ] = 0x1f ;
mixer - > regs [ 2 ] [ MV508_REG_BASS ] = 0x06 ;
mixer - > regs [ 2 ] [ MV508_REG_TREBLE ] = 0x06 ;
mv508_mixer_recalc ( mixer ) ;
}
2024-03-27 23:56:55 +01:00
static void
pas16_reset_regs ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
2024-05-03 17:02:13 +02:00
nsc_mixer_t * nsc_mixer = & pas16 - > nsc_mixer ;
mv508_mixer_t * mv508_mixer = & pas16 - > mv508_mixer ;
2024-03-27 23:56:55 +01:00
pitf_t * pit = ( pitf_t * ) pas16 - > pit ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > irq ! = - 1 )
picintc ( 1 < < pas16 - > irq ) ;
2024-03-27 23:56:55 +01:00
pas16 - > sys_conf_1 & = 0xfd ;
pas16 - > sys_conf_2 = 0x00 ;
pas16 - > sys_conf_3 = 0x00 ;
pas16 - > prescale_div = 0x00 ;
pitf_set_pit_const ( pit , PITCONST ) ;
pas16 - > audiofilt = 0x00 ;
pas16 - > filter = 0 ;
pitf_ctr_set_gate ( pit , 0 , 0 ) ;
pitf_ctr_set_gate ( pit , 1 , 0 ) ;
pas16_reset_pcm ( pas16 ) ;
2024-04-04 03:09:35 +02:00
pas16 - > dma8_ff = 0 ;
2024-03-27 23:56:55 +01:00
pas16 - > irq_ena = 0x00 ;
pas16 - > irq_stat = 0x00 ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > type )
pas16_mv508_mixer_reset ( mv508_mixer ) ;
else
pas16_nsc_mixer_reset ( nsc_mixer ) ;
2024-03-27 23:56:55 +01:00
}
static void
pas16_reset_common ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
pas16_reset_regs ( pas16 ) ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > irq ! = - 1 )
picintc ( 1 < < pas16 - > irq ) ;
2024-03-27 23:56:55 +01:00
pas16_io_handler ( pas16 , 0 ) ;
pas16 - > base = 0x0000 ;
}
static void
pas16_reset ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
pas16_reset_common ( priv ) ;
pas16 - > board_id = 0 ;
pas16 - > master_ff = 0 ;
pas16 - > base = 0x0388 ;
pas16_io_handler ( pas16 , 1 ) ;
pas16 - > new_base = 0x0388 ;
2024-04-04 03:09:35 +02:00
pas16 - > sb_compat_base = 0x0220 ;
pas16 - > compat = 0x02 ;
pas16 - > compat_base = 0x02 ;
sb_dsp_setaddr ( & pas16 - > dsp , pas16 - > sb_compat_base ) ;
2016-06-26 00:34:39 +02:00
}
2024-05-03 17:02:13 +02:00
static int
pas16_irq_convert ( uint8_t val )
{
int ret = val ;
if ( ret = = 0 )
ret = - 1 ;
else if ( ret < = 6 )
ret + + ;
else if ( ret < 0x0b )
ret + = 3 ;
else
ret + = 4 ;
return ret ;
}
static void
lmc1982_update_reg ( nsc_mixer_t * mixer )
{
pas16_log ( " LMC1982CIN register %02X = %04X \n " ,
mixer - > im_data [ LMC1982_ADDR ] , mixer - > im_data [ LMC1982_DATA ] ) ;
if ( ( mixer - > im_data [ LMC1982_ADDR ] & LMC1982_REG_MASK ) = = LMC1982_REG_VALID ) {
mixer - > im_data [ LMC1982_ADDR ] & = ~ LMC1982_REG_MASK ;
mixer - > lmc1982_regs [ mixer - > im_data [ LMC1982_ADDR ] ] = mixer - > im_data [ LMC1982_DATA ] & 0xff ;
lmc1982_recalc ( mixer ) ;
}
mixer - > im_state = STATE_SM_IDLE ;
}
static void
lmc835_update_reg ( nsc_mixer_t * mixer )
{
pas16_log ( " LMC835N register %02X = %02X \n " ,
mixer - > im_data [ LMC835_ADDR ] , mixer - > im_data [ LMC835_DATA ] ) ;
mixer - > lmc835_regs [ LMC835_REG_MODE ] = mixer - > im_data [ LMC835_ADDR ] & 0xf0 ;
mixer - > im_data [ LMC835_ADDR ] & = 0x0f ;
if ( ( mixer - > im_data [ LMC835_ADDR ] > = 0x01 ) & & ( mixer - > im_data [ LMC835_ADDR ] < = 0x0e ) )
mixer - > lmc835_regs [ mixer - > im_data [ LMC835_ADDR ] & 0x0f ] = mixer - > im_data [ LMC835_DATA ] ;
lmc835_recalc ( mixer ) ;
}
2024-05-06 13:09:08 +02:00
static void
pas16_scsi_callback ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
t128_t * dev = pas16 - > scsi ;
t128_callback ( pas16 - > scsi ) ;
if ( ( dev - > ncr . dma_mode ! = DMA_IDLE ) & & ( dev - > status & 0x04 ) ) {
timer_stop ( & pas16 - > scsi_timer ) ;
pas16 - > timeout_status & = 0x7f ;
}
}
2024-05-03 17:02:13 +02:00
static void
pas16_timeout_callback ( void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
pas16 - > timeout_status | = 0x80 ;
if ( ( pas16 - > timeout_status & 0x08 ) & & ( pas16 - > irq ! = - 1 ) )
picint ( 1 < < pas16 - > irq ) ;
timer_advance_u64 ( & pas16 - > scsi_timer , ( pas16 - > timeout_count & 0x3f ) * PASSCSICONST ) ;
}
2022-02-22 20:28:56 -05:00
static void
2023-06-09 23:46:54 -04:00
pas16_out ( uint16_t port , uint8_t val , void * priv )
2016-06-26 00:34:39 +02:00
{
2024-05-03 17:02:13 +02:00
pas16_t * pas16 = ( pas16_t * ) priv ;
nsc_mixer_t * nsc_mixer = & pas16 - > nsc_mixer ;
mv508_mixer_t * mv508_mixer = & pas16 - > mv508_mixer ;
2024-03-27 23:56:55 +01:00
pas16_log ( " [%04X:%08X] PAS16: [W] %04X (%04X) = %02X \n " ,
CS , cpu_state . pc , port , port - pas16 - > base , val ) ;
port - = pas16 - > base ;
2024-03-21 22:00:48 +01:00
switch ( port ) {
2024-03-27 23:56:55 +01:00
case 0x0000 . . . 0x0003 :
pas16 - > opl . write ( port + 0x0388 , val , pas16 - > opl . priv ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-05-03 17:02:13 +02:00
case 0x0400 . . . 0x0402 :
break ;
case 0x0403 :
if ( val & MV508_ADDRESS )
mv508_mixer - > index = val & ~ MV508_ADDRESS ;
else {
uint8_t bank ;
uint8_t mask ;
pas16_log ( " MVA508 register %02X = %02X \n " ,
mv508_mixer - > index , val ) ;
if ( mv508_mixer - > index & MV508_MIXER ) {
bank = ! ! ( val & MV508_INPUT_MIX ) ;
mask = 0x1f ;
} else {
bank = 2 ;
mask = 0x3f ;
}
if ( mv508_mixer - > index & MV508_CHANNEL )
mv508_mixer - > regs [ bank ] [ mv508_mixer - > index ] = val & mask ;
else {
mv508_mixer - > regs [ bank ] [ mv508_mixer - > index | MV508_LEFT ] = val & mask ;
mv508_mixer - > regs [ bank ] [ mv508_mixer - > index | MV508_RIGHT ] = val & mask ;
}
mv508_mixer_recalc ( mv508_mixer ) ;
}
break ;
2024-03-27 23:56:55 +01:00
case 0x0800 :
2024-05-03 17:02:13 +02:00
if ( pas16 - > type & & ! ( val & SERIAL_MIXER_RESET_PCM ) ) {
pas16 - > audio_mixer = val ;
2024-03-27 23:56:55 +01:00
pas16_reset_pcm ( pas16 ) ;
2024-05-03 17:02:13 +02:00
} else if ( ! pas16 - > type ) {
switch ( nsc_mixer - > im_state ) {
default :
break ;
case STATE_SM_IDLE :
/* Transmission initiated. */
if ( val & SERIAL_MIXER_IDENT ) {
if ( ! ( val & SERIAL_MIXER_CLOCK ) & & ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
/* Prepare for receiving LMC835N data. */
nsc_mixer - > im_data [ LMC835_DATA ] = 0x0000 ;
nsc_mixer - > im_state | = STATE_LMC835_DATA ;
}
} else {
if ( ( pas16 - > audio_mixer & SERIAL_MIXER_IDENT ) ) {
/*
Prepare for receiving the LMC1982CIN address .
*/
nsc_mixer - > im_data [ LMC1982_ADDR ] = 0x0000 ;
nsc_mixer - > im_state | = STATE_LMC1982_ADDR ;
}
if ( ( val & SERIAL_MIXER_CLOCK ) & & ! ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
/*
Clock the least siginificant bit of the LMC1982CIN address .
*/
nsc_mixer - > im_data [ LMC1982_ADDR ] | =
( ( val & SERIAL_MIXER_DATA ) < < ( nsc_mixer - > im_state & STATE_DATA_MASK ) ) ;
nsc_mixer - > im_state + + ;
}
}
break ;
case STATE_LMC1982_ADDR_0 :
if ( val & SERIAL_MIXER_IDENT ) {
/*
IDENT went high in LM1982CIN address state 0 ,
behave as if we were in the idle state .
*/
if ( ! ( val & SERIAL_MIXER_CLOCK ) & & ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
nsc_mixer - > im_data [ LMC835_DATA ] = 0x0000 ;
nsc_mixer - > im_state = STATE_LMC835_DATA_0 ;
}
} else if ( ( val & SERIAL_MIXER_CLOCK ) & &
! ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
/*
Clock the least siginificant bit of the LMC1982CIN address .
*/
nsc_mixer - > im_data [ LMC1982_ADDR ] | =
( ( val & SERIAL_MIXER_DATA ) < < ( nsc_mixer - > im_state & STATE_DATA_MASK ) ) ;
nsc_mixer - > im_state + + ;
}
break ;
case STATE_LMC1982_ADDR_1 . . . STATE_LMC1982_ADDR_7 :
if ( ( val & 0x02 ) & & ! ( pas16 - > audio_mixer & 0x02 ) ) {
/*
Clock the next bit of the LMC1982CIN address .
*/
nsc_mixer - > im_data [ LMC1982_ADDR ] | =
( ( val & SERIAL_MIXER_DATA ) < < ( nsc_mixer - > im_state & STATE_DATA_MASK ) ) ;
nsc_mixer - > im_state + + ;
}
break ;
case STATE_LMC1982_ADDR_OVER :
/*
Prepare for receiving the LMC1982CIN data .
*/
nsc_mixer - > im_data [ LMC1982_DATA ] = 0x0000 ;
nsc_mixer - > im_state = STATE_LMC1982_DATA_0 ;
break ;
case STATE_LMC1982_DATA_0 . . . STATE_LMC1982_DATA_7 :
case STATE_LMC1982_DATA_9 . . . STATE_LMC1982_DATA_F :
if ( ( val & SERIAL_MIXER_CLOCK ) & & ! ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
/*
Clock the next bit of the LMC1982CIN data .
*/
nsc_mixer - > im_data [ LMC1982_DATA ] | =
( ( val & SERIAL_MIXER_DATA ) < < ( nsc_mixer - > im_state & STATE_DATA_MASK_W ) ) ;
nsc_mixer - > im_state + + ;
}
break ;
case STATE_LMC1982_DATA_8 :
if ( val & SERIAL_MIXER_IDENT ) {
if ( ! ( pas16 - > audio_mixer & SERIAL_MIXER_IDENT ) )
/*
LMC1982CIN data transfer ended after 8 bits , process the data and
reset the state back to idle .
*/
lmc1982_update_reg ( nsc_mixer ) ;
else if ( ( val & SERIAL_MIXER_CLOCK ) & &
! ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
/*
Clock the next bit of the LMC1982CIN data .
*/
nsc_mixer - > im_data [ LMC1982_DATA ] | =
( ( val & SERIAL_MIXER_DATA ) < < ( nsc_mixer - > im_state & STATE_DATA_MASK_W ) ) ;
nsc_mixer - > im_state + + ;
}
}
break ;
case STATE_LMC1982_DATA_OVER :
if ( ( val & SERIAL_MIXER_IDENT ) & & ! ( pas16 - > audio_mixer & SERIAL_MIXER_IDENT ) )
/*
LMC1982CIN data transfer ended , process the data and reset the state
back to idle .
*/
lmc1982_update_reg ( nsc_mixer ) ;
break ;
case STATE_LMC835_DATA_0 . . . STATE_LMC835_DATA_7 :
if ( ( val & SERIAL_MIXER_CLOCK ) & & ! ( pas16 - > audio_mixer & SERIAL_MIXER_CLOCK ) ) {
/*
Clock the next bit of the LMC835N data .
*/
nsc_mixer - > im_data [ LMC835_DATA ] | =
( ( val & SERIAL_MIXER_DATA ) < < ( nsc_mixer - > im_state & STATE_DATA_MASK ) ) ;
nsc_mixer - > im_state + + ;
}
break ;
case STATE_LMC835_DATA_OVER :
if ( ( val & SERIAL_MIXER_STROBE ) & & ! ( pas16 - > audio_mixer & SERIAL_MIXER_STROBE ) ) {
if ( nsc_mixer - > im_data [ LMC835_DATA ] & LMC835_FLAG_ADDR )
/*
The LMC835N data is an address , copy it into its own space for usage
when processing it at the end and strip bits 7 ( it ' s the address / data
indicator ) and 6 ( it ' s a " don't care " bit ) .
*/
nsc_mixer - > im_data [ LMC835_ADDR ] = nsc_mixer - > im_data [ LMC835_DATA ] & 0x7f ;
else
lmc835_update_reg ( nsc_mixer ) ;
nsc_mixer - > im_state = STATE_SM_IDLE ;
}
break ;
}
pas16 - > audio_mixer = val ;
}
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0801 :
2022-02-22 20:28:56 -05:00
pas16 - > irq_stat & = ~ val ;
2024-05-03 17:02:13 +02:00
if ( ( pas16 - > irq ! = - 1 ) & & ! ( pas16 - > irq_stat & 0x1f ) )
2024-04-04 03:09:35 +02:00
picintc ( 1 < < pas16 - > irq ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0802 :
2024-04-04 03:09:35 +02:00
pas16_update ( pas16 ) ;
pitf_ctr_set_gate ( pas16 - > pit , 1 , ! ! ( val & 0x80 ) ) ;
pitf_ctr_set_gate ( pas16 - > pit , 0 , ! ! ( val & 0x40 ) ) ;
pas16 - > stereo_lr = 0 ;
pas16 - > dma8_ff = 0 ;
2024-03-27 23:56:55 +01:00
if ( ( val & 0x20 ) & & ! ( pas16 - > audiofilt & 0x20 ) ) {
pas16_log ( " Reset. \n " ) ;
pas16_reset_regs ( pas16 ) ;
}
2022-02-22 20:28:56 -05:00
pas16 - > audiofilt = val ;
2024-04-04 03:09:35 +02:00
2024-03-27 23:56:55 +01:00
if ( val & 0x1f ) {
pas16 - > filter = 1 ;
switch ( val & 0x1f ) {
default :
pas16 - > filter = 0 ;
break ;
case 0x01 :
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( 17897 ) ;
2024-03-27 23:56:55 +01:00
break ;
case 0x02 :
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( 15909 ) ;
2024-03-27 23:56:55 +01:00
break ;
case 0x04 :
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( 2982 ) ;
2024-03-27 23:56:55 +01:00
break ;
case 0x09 :
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( 11931 ) ;
2024-03-27 23:56:55 +01:00
break ;
case 0x11 :
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( 8948 ) ;
2024-03-27 23:56:55 +01:00
break ;
case 0x19 :
2024-05-03 17:02:13 +02:00
recalc_pas16_filter ( 5965 ) ;
2024-03-27 23:56:55 +01:00
break ;
}
} else
pas16 - > filter = 0 ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0803 :
2024-03-21 22:00:48 +01:00
pas16 - > irq_ena = val & 0x1f ;
2024-04-04 03:09:35 +02:00
pas16 - > irq_stat & = ( ( val & 0x1f ) | 0xe0 ) ;
2024-05-03 17:02:13 +02:00
if ( ( pas16 - > irq ! = - 1 ) & & ! ( pas16 - > irq_stat & 0x1f ) )
2024-04-04 03:09:35 +02:00
picintc ( 1 < < pas16 - > irq ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x0c00 :
case 0x0c01 :
2022-02-22 20:28:56 -05:00
pas16_update ( pas16 ) ;
break ;
2024-03-27 23:56:55 +01:00
case 0x0c02 :
if ( ( val & PAS16_PCM_ENA ) & & ! ( pas16 - > pcm_ctrl & PAS16_PCM_ENA ) ) {
/* Guess */
2022-02-22 20:28:56 -05:00
pas16 - > stereo_lr = 0 ;
2024-04-04 03:09:35 +02:00
pas16 - > irq_stat & = 0xd7 ;
2024-03-27 23:56:55 +01:00
/* Needed for 8-bit DMA to work correctly on a 16-bit DMA channel. */
pas16 - > dma8_ff = 0 ;
}
2024-03-18 17:10:36 +01:00
2022-02-22 20:28:56 -05:00
pas16 - > pcm_ctrl = val ;
2024-03-27 23:56:55 +01:00
pas16_log ( " Now in: %s (%02X) \n " , ( pas16 - > pcm_ctrl & PAS16_PCM_MONO ) ? " Mono " : " Stereo " , val ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1401 :
case 0x1403 :
2024-03-21 22:00:48 +01:00
pas16 - > midi_ctrl = val ;
2024-03-18 17:10:36 +01:00
if ( ( val & 0x60 ) = = 0x60 ) {
2024-03-21 22:00:48 +01:00
pas16 - > midi_uart_out = 0 ;
pas16 - > midi_uart_in = 0 ;
2024-05-03 17:02:13 +02:00
} else if ( ( val & 0x1c ) = = 0x04 )
2024-03-21 22:00:48 +01:00
pas16 - > midi_uart_in = 1 ;
else
pas16 - > midi_uart_out = 1 ;
2024-03-18 17:10:36 +01:00
2024-03-21 22:00:48 +01:00
pas16_update_irq ( pas16 ) ;
2024-03-18 17:10:36 +01:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1402 :
case 0x1802 :
2024-03-21 22:00:48 +01:00
pas16 - > midi_data = val ;
pas16_log ( " UART OUT=%d. \n " , pas16 - > midi_uart_out ) ;
if ( pas16 - > midi_uart_out )
midi_raw_out_byte ( val ) ;
2024-03-18 17:10:36 +01:00
break ;
2024-03-27 23:56:55 +01:00
case 0x1800 :
2024-03-21 22:00:48 +01:00
pas16 - > midi_stat = val ;
pas16_update_irq ( pas16 ) ;
break ;
2024-03-27 23:56:55 +01:00
case 0x1801 :
2024-03-21 22:00:48 +01:00
pas16 - > fifo_stat = val ;
2022-02-22 20:28:56 -05:00
break ;
2024-05-03 17:02:13 +02:00
case 0x1c00 . . . 0x1c03 : /* NCR5380 ports 0 to 3. */
case 0x3c00 . . . 0x3c03 : /* NCR5380 ports 4 to 7. */
2024-05-06 13:09:08 +02:00
if ( pas16 - > has_scsi )
ncr5380_write ( ( port & 0x0003 ) | ( ( port & 0x2000 ) > > 11 ) , val , & pas16 - > scsi - > ncr ) ;
2024-05-03 17:02:13 +02:00
break ;
case 0x4000 :
if ( pas16 - > has_scsi ) {
pas16 - > timeout_count = val ;
if ( timer_is_enabled ( & pas16 - > scsi_timer ) )
timer_disable ( & pas16 - > scsi_timer ) ;
2024-07-29 19:10:43 +02:00
if ( ( val & 0x3f ) > 0x00 )
timer_set_delay_u64 ( & pas16 - > scsi_timer , ( val & 0x3f ) * PASSCSICONST ) ;
2024-05-03 17:02:13 +02:00
}
break ;
case 0x4001 :
if ( pas16 - > has_scsi ) {
pas16 - > timeout_status = val & 0x7f ;
if ( pas16 - > scsi_irq ! = - 1 )
picintc ( 1 < < pas16 - > scsi_irq ) ;
}
break ;
case 0x5c00 :
if ( pas16 - > has_scsi )
2024-05-06 13:09:08 +02:00
t128_write ( 0x1e00 , val , pas16 - > scsi ) ;
2024-05-03 17:02:13 +02:00
break ;
case 0x5c03 :
if ( pas16 - > has_scsi ) {
if ( val & 0x80 ) {
pas16 - > scsi - > ncr . irq_state = 0 ;
if ( pas16 - > scsi_irq ! = - 1 )
picintc ( 1 < < pas16 - > scsi_irq ) ;
}
}
break ;
2024-03-27 23:56:55 +01:00
case 0x7c01 :
2022-02-22 20:28:56 -05:00
pas16 - > enhancedscsi = val ;
break ;
2024-03-27 23:56:55 +01:00
case 0x8000 :
2024-03-21 22:00:48 +01:00
if ( ( val & 0xc0 ) & & ! ( pas16 - > sys_conf_1 & 0xc0 ) ) {
pas16_log ( " Reset. \n " ) ;
val = 0x00 ;
2024-03-27 23:56:55 +01:00
pas16_reset_common ( pas16 ) ;
pas16 - > base = pas16 - > new_base ;
pas16_io_handler ( pas16 , 1 ) ;
2024-03-18 17:10:36 +01:00
}
2024-03-27 23:56:55 +01:00
2022-02-22 20:28:56 -05:00
pas16 - > sys_conf_1 = val ;
2024-03-27 23:56:55 +01:00
pas16_change_pit_clock_speed ( pas16 ) ;
pas16_log ( " Now in: %s mode \n " , ( pas16 - > sys_conf_1 & 0x02 ) ? " native " : " compatibility " ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8001 :
2022-02-22 20:28:56 -05:00
pas16 - > sys_conf_2 = val ;
2024-03-27 23:56:55 +01:00
pas16_log ( " Now in: %i bits (%02X) \n " ,
( pas16 - > sys_conf_2 & 0x04 ) ? ( ( pas16 - > sys_conf_2 & 0x08 ) ? 12 : 16 ) : 8 , val ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8002 :
2022-02-22 20:28:56 -05:00
pas16 - > sys_conf_3 = val ;
2024-03-27 23:56:55 +01:00
pas16_change_pit_clock_speed ( pas16 ) ;
pas16_log ( " Use 1.008 MHz clok for PCM: %c \n " , ( val & 0x02 ) ? ' Y ' : ' N ' ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0x8003 :
2022-02-22 20:28:56 -05:00
pas16 - > sys_conf_4 = val ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > has_scsi & & ( pas16 - > scsi_irq ! = - 1 ) & & ! ( val & 0x20 ) )
picintc ( 1 < < pas16 - > scsi_irq ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xbc00 :
2024-03-18 17:10:36 +01:00
pas16 - > waitstates = val ;
break ;
2024-03-27 23:56:55 +01:00
case 0xbc02 :
pas16 - > prescale_div = val ;
pas16_change_pit_clock_speed ( pas16 ) ;
pas16_log ( " Prescale divider now: %i \n " , val ) ;
break ;
2024-03-18 17:10:36 +01:00
2024-03-27 23:56:55 +01:00
case 0xf000 :
2022-02-22 20:28:56 -05:00
pas16 - > io_conf_1 = val ;
break ;
2024-03-27 23:56:55 +01:00
case 0xf001 :
2022-02-22 20:28:56 -05:00
pas16 - > io_conf_2 = val ;
pas16 - > dma = pas16_dmas [ val & 0x7 ] ;
2024-03-27 23:56:55 +01:00
pas16_change_pit_clock_speed ( pas16 ) ;
2024-03-21 22:00:48 +01:00
pas16_log ( " pas16_out : set PAS DMA %i \n " , pas16 - > dma ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf002 :
2022-02-22 20:28:56 -05:00
pas16 - > io_conf_3 = val ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > irq ! = - 1 )
picintc ( 1 < < pas16 - > irq ) ;
pas16 - > irq = pas16_irq_convert ( val & 0x0f ) ;
if ( pas16 - > has_scsi ) {
if ( pas16 - > scsi_irq ! = - 1 )
picintc ( 1 < < pas16 - > scsi_irq ) ;
pas16 - > scsi_irq = pas16_irq_convert ( val > > 4 ) ;
ncr5380_set_irq ( & pas16 - > scsi - > ncr , pas16 - > scsi_irq ) ;
}
2024-03-21 22:00:48 +01:00
pas16_log ( " pas16_out : set PAS IRQ %i, val=%02x \n " , pas16 - > irq , val & 0x0f ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf003 :
2022-02-22 20:28:56 -05:00
pas16 - > io_conf_4 = val ;
break ;
2024-03-27 23:56:55 +01:00
case 0xf400 :
2024-04-04 03:09:35 +02:00
pas16 - > compat = val & 0xf3 ;
2024-03-27 23:56:55 +01:00
pas16_log ( " PCM compression is now %sabled \n " , ( val & 0x10 ) ? " en " : " dis " ) ;
2022-02-22 20:28:56 -05:00
if ( pas16 - > compat & 0x02 )
2024-04-04 03:09:35 +02:00
sb_dsp_setaddr ( & pas16 - > dsp , pas16 - > sb_compat_base ) ;
2022-02-22 20:28:56 -05:00
else
sb_dsp_setaddr ( & pas16 - > dsp , 0 ) ;
2024-03-18 17:10:36 +01:00
if ( pas16 - > compat & 0x01 )
mpu401_change_addr ( pas16 - > mpu , ( ( pas16 - > compat_base & 0xf0 ) | 0x300 ) ) ;
else
mpu401_change_addr ( pas16 - > mpu , 0 ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf401 :
2022-02-22 20:28:56 -05:00
pas16 - > compat_base = val ;
2024-04-04 03:09:35 +02:00
pas16 - > sb_compat_base = ( ( pas16 - > compat_base & 0xf ) < < 4 ) | 0x200 ;
pas16_log ( " SB Compatibility base: %04X \n " , pas16 - > sb_compat_base ) ;
2022-02-22 20:28:56 -05:00
if ( pas16 - > compat & 0x02 )
2024-04-04 03:09:35 +02:00
sb_dsp_setaddr ( & pas16 - > dsp , pas16 - > sb_compat_base ) ;
2024-03-18 17:10:36 +01:00
if ( pas16 - > compat & 0x01 )
mpu401_change_addr ( pas16 - > mpu , ( ( pas16 - > compat_base & 0xf0 ) | 0x300 ) ) ;
2022-02-22 20:28:56 -05:00
break ;
2024-03-27 23:56:55 +01:00
case 0xf802 :
2022-02-22 20:28:56 -05:00
pas16 - > sb_irqdma = val ;
2024-04-04 03:09:35 +02:00
mpu401_setirq ( pas16 - > mpu , pas16_sb_irqs [ val & 7 ] ) ;
2022-02-22 20:28:56 -05:00
sb_dsp_setirq ( & pas16 - > dsp , pas16_sb_irqs [ ( val > > 3 ) & 7 ] ) ;
sb_dsp_setdma8 ( & pas16 - > dsp , pas16_sb_dmas [ ( val > > 6 ) & 3 ] ) ;
2024-03-27 23:56:55 +01:00
pas16_log ( " pas16_out : set SB IRQ %i DMA %i. \n " , pas16_sb_irqs [ ( val > > 3 ) & 7 ] ,
pas16_sb_dmas [ ( val > > 6 ) & 3 ] ) ;
2022-02-22 20:28:56 -05:00
break ;
default :
2024-03-21 22:00:48 +01:00
pas16_log ( " pas16_out : unknown %04X \n " , port ) ;
2022-02-22 20:28:56 -05:00
}
2016-06-26 00:34:39 +02:00
}
2024-03-27 23:56:55 +01:00
/*
8 - bit mono :
- 8 - bit DMA : On every timer 0 over , read the 8 - bit sample and ctr_clock ( ) ;
( One ctr_clock ( ) per timer 0 over )
- 16 - bit DMA : On every even timer 0 over , read two 8 - bit samples at once and ctr_clock ( ) ;
On every odd timer 0 over , read the MSB of the previously read sample word .
( One ctr_clock ( ) per two timer 0 overs )
8 - bit stereo :
- 8 - bit DMA : On every timer 0 , read two 8 - bit samples and ctr_clock ( ) twice ;
( Two ctr_clock ( ) ' s per timer 0 over )
- 16 - bit DMA : On every timer 0 , read two 8 - bit samples and ctr_clock ( ) once .
( One ctr_clock ( ) per timer 0 over )
16 - bit mono ( to be verified ) :
- 8 - bit DMA : On every timer 0 , read one 16 - bit sample and ctr_clock ( ) twice ;
( Two ctr_clock ( ) ' s per timer 0 over )
- 16 - bit DMA : On every timer 0 , read one 16 - bit sample and ctr_clock ( ) once .
( One ctr_clock ( ) per timer 0 over )
16 - bit stereo :
- 8 - bit DMA : On every timer 0 , read one 16 - bit sample and ctr_clock ( ) twice ;
( Two ctr_clock ( ) ' s per timer 0 over )
- 16 - bit DMA : On every timer 0 , read one 16 - bit sample and ctr_clock ( ) twice .
( Two ctr_clock ( ) ' s per timer 0 over )
What we can conclude from this is :
- Maximum 16 bits per timer 0 over ;
- A 8 - bit sample always takes one ctr_clock ( ) tick , unless it has been read
alongside the previous sample ;
- A 16 - bit sample always takes two ctr_clock ( ) ticks .
*/
static uint16_t
2024-04-04 03:09:35 +02:00
pas16_dma_channel_read ( pas16_t * pas16 , int channel )
2016-06-26 00:34:39 +02:00
{
2024-04-04 03:09:35 +02:00
int status ;
2024-03-27 23:56:55 +01:00
uint16_t ret ;
2024-04-04 03:09:35 +02:00
if ( pas16 - > pcm_ctrl & PAS16_PCM_DMA_ENA ) {
if ( pas16 - > dma > = 5 ) {
dma_channel_advance ( pas16 - > dma ) ;
status = dma_channel_read_only ( pas16 - > dma ) ;
} else
status = dma_channel_read ( pas16 - > dma ) ;
ret = ( status = = DMA_NODATA ) ? 0x0000 : ( status & 0xffff ) ;
} else
2024-03-27 23:56:55 +01:00
ret = 0x0000 ;
2024-04-04 03:09:35 +02:00
return ret ;
}
static uint16_t
2024-05-03 17:02:13 +02:00
pas16_dma_readb ( pas16_t * pas16 )
2024-04-04 03:09:35 +02:00
{
2024-05-03 17:02:13 +02:00
const uint16_t ret = pas16_dma_channel_read ( pas16 , pas16 - > dma ) ;
2024-04-04 03:09:35 +02:00
2024-05-03 17:02:13 +02:00
pas16 - > ticks + + ;
2024-03-27 23:56:55 +01:00
return ret ;
}
static uint16_t
2024-05-03 17:02:13 +02:00
pas16_dma_readw ( pas16_t * pas16 , const uint8_t timer1_ticks )
2024-03-27 23:56:55 +01:00
{
uint16_t ret ;
2024-04-04 03:09:35 +02:00
if ( pas16 - > dma > = 5 )
ret = pas16_dma_channel_read ( pas16 , pas16 - > dma ) ;
else {
ret = pas16_dma_channel_read ( pas16 , pas16 - > dma ) ;
ret | = ( pas16_dma_channel_read ( pas16 , pas16 - > dma ) < < 8 ) ;
}
2024-03-27 23:56:55 +01:00
2024-04-04 03:09:35 +02:00
pas16 - > ticks + = timer1_ticks ;
2024-03-27 23:56:55 +01:00
return ret ;
}
static uint16_t
pas16_readdmab ( pas16_t * pas16 )
{
if ( pas16 - > dma > = 5 ) {
if ( pas16 - > dma8_ff )
2024-04-04 03:09:35 +02:00
pas16 - > dma8_dat > > = 8 ;
2024-03-27 23:56:55 +01:00
else
2024-05-03 17:02:13 +02:00
pas16 - > dma8_dat = pas16_dma_readb ( pas16 ) ;
2024-03-27 23:56:55 +01:00
pas16 - > dma8_ff = ! pas16 - > dma8_ff ;
} else
2024-05-03 17:02:13 +02:00
pas16 - > dma8_dat = pas16_dma_readb ( pas16 ) ;
2024-03-27 23:56:55 +01:00
2024-05-03 17:02:13 +02:00
return ( ( pas16 - > dma8_dat & 0xff ) ^ 0x80 ) < < 8 ;
2024-03-27 23:56:55 +01:00
}
static uint16_t
pas16_readdmaw_mono ( pas16_t * pas16 )
{
2024-05-03 17:02:13 +02:00
const uint16_t ret = pas16_dma_readw ( pas16 , 1 + ( pas16 - > dma < 5 ) ) ;
2024-03-27 23:56:55 +01:00
return ret ;
}
static uint16_t
pas16_readdmaw_stereo ( pas16_t * pas16 )
{
uint16_t ret ;
2024-04-04 03:09:35 +02:00
uint16_t ticks = ( pas16 - > sys_conf_1 & 0x02 ) ? ( 1 + ( pas16 - > dma < 5 ) ) : 2 ;
2024-03-27 23:56:55 +01:00
2024-04-04 03:09:35 +02:00
ret = pas16_dma_readw ( pas16 , ticks ) ;
2024-03-27 23:56:55 +01:00
return ret ;
}
static uint16_t
pas16_readdma_mono ( pas16_t * pas16 )
{
uint16_t ret ;
if ( pas16 - > sys_conf_2 & 0x04 ) {
ret = pas16_readdmaw_mono ( pas16 ) ;
if ( pas16 - > sys_conf_2 & 0x08 )
ret & = 0xfff0 ;
} else
ret = pas16_readdmab ( pas16 ) ;
if ( pas16 - > sys_conf_2 & PAS16_SC2_MSBINV )
ret ^ = 0x8000 ;
return ret ;
}
static uint16_t
pas16_readdma_stereo ( pas16_t * pas16 )
{
uint16_t ret ;
if ( pas16 - > sys_conf_2 & 0x04 ) {
ret = pas16_readdmaw_stereo ( pas16 ) ;
if ( pas16 - > sys_conf_2 & 0x08 )
ret & = 0xfff0 ;
} else
ret = pas16_readdmab ( pas16 ) ;
if ( pas16 - > sys_conf_2 & PAS16_SC2_MSBINV )
ret ^ = 0x8000 ;
return ret ;
2016-06-26 00:34:39 +02:00
}
2022-02-22 20:28:56 -05:00
static void
2024-05-03 17:02:13 +02:00
pas16_pit_timer0 ( const int new_out , UNUSED ( int old_out ) , void * priv )
2016-06-26 00:34:39 +02:00
{
2024-05-03 17:02:13 +02:00
const pitf_t * pit = ( const pitf_t * ) priv ;
pas16_t * pas16 = ( pas16_t * ) pit - > dev_priv ;
2024-03-18 17:10:36 +01:00
2024-04-04 03:09:35 +02:00
if ( ! pas16 - > pit - > counters [ 0 ] . gate )
return ;
if ( ! dma_channel_readable ( pas16 - > dma ) )
return ;
2024-03-21 22:00:48 +01:00
pas16_update_irq ( pas16 ) ;
2024-04-04 03:09:35 +02:00
if ( ( ( pas16 - > pcm_ctrl & PAS16_PCM_ENA ) = = PAS16_PCM_ENA ) & & ( pit - > counters [ 1 ] . m & 2 ) & & new_out ) {
2024-05-03 17:02:13 +02:00
uint16_t temp ;
2024-04-04 03:09:35 +02:00
pas16 - > ticks = 0 ;
2022-02-22 20:28:56 -05:00
2024-03-27 23:56:55 +01:00
if ( pas16 - > pcm_ctrl & PAS16_PCM_MONO ) {
temp = pas16_readdma_mono ( pas16 ) ;
pas16 - > pcm_dat_l = pas16 - > pcm_dat_r = temp ;
} else {
temp = pas16_readdma_stereo ( pas16 ) ;
2022-02-22 20:28:56 -05:00
2024-03-27 23:56:55 +01:00
if ( pas16 - > sys_conf_1 & 0x02 ) {
pas16 - > pcm_dat_l = temp ;
temp = pas16_readdma_stereo ( pas16 ) ;
pas16 - > pcm_dat_r = temp ;
} else {
2022-02-22 20:28:56 -05:00
if ( pas16 - > stereo_lr )
pas16 - > pcm_dat_r = temp ;
else
pas16 - > pcm_dat_l = temp ;
2022-02-20 02:26:27 -05:00
2022-02-22 20:28:56 -05:00
pas16 - > stereo_lr = ! pas16 - > stereo_lr ;
2024-03-27 23:56:55 +01:00
pas16 - > irq_stat = ( pas16 - > irq_stat & 0xdf ) | ( pas16 - > stereo_lr < < 5 ) ;
2022-02-22 20:28:56 -05:00
}
}
2024-04-04 03:09:35 +02:00
if ( pas16 - > ticks ) {
2024-05-04 11:40:07 +02:00
for ( uint16_t i = 0 ; i < pas16 - > ticks ; i + + )
2024-04-04 03:09:35 +02:00
pitf_ctr_clock ( pas16 - > pit , 1 ) ;
pas16 - > ticks = 0 ;
}
pas16 - > irq_stat | = PAS16_INT_SAMP ;
if ( pas16 - > irq_ena & PAS16_INT_SAMP ) {
pas16_log ( " INT SAMP. \n " ) ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > irq ! = - 1 )
picint ( 1 < < pas16 - > irq ) ;
2024-04-04 03:09:35 +02:00
}
pas16_update ( pas16 ) ;
}
2016-06-26 00:34:39 +02:00
}
2024-03-18 17:10:36 +01:00
static void
2024-05-03 17:02:13 +02:00
pas16_pit_timer1 ( const int new_out , UNUSED ( int old_out ) , void * priv )
2024-03-18 17:10:36 +01:00
{
2024-05-03 17:02:13 +02:00
const pitf_t * pit = ( pitf_t * ) priv ;
pas16_t * pas16 = ( pas16_t * ) pit - > dev_priv ;
2024-03-27 23:56:55 +01:00
2024-04-04 03:09:35 +02:00
if ( ! pas16 - > pit - > counters [ 1 ] . gate )
return ;
2024-03-27 23:56:55 +01:00
/* At new_out = 0, it's in the counter reload phase. */
if ( ( pas16 - > pcm_ctrl & PAS16_PCM_ENA ) & & ( pit - > counters [ 1 ] . m & 2 ) & & new_out ) {
if ( pas16 - > irq_ena & PAS16_INT_PCM ) {
pas16 - > irq_stat | = PAS16_INT_PCM ;
pas16_log ( " pas16_pcm_poll : cause IRQ %i %02X \n " , pas16 - > irq , 1 < < pas16 - > irq ) ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > irq ! = - 1 )
picint ( 1 < < pas16 - > irq ) ;
2024-03-27 23:56:55 +01:00
}
2024-03-21 22:00:48 +01:00
}
2024-03-18 17:10:36 +01:00
}
2022-02-22 20:28:56 -05:00
static void
2023-06-09 23:46:54 -04:00
pas16_out_base ( UNUSED ( uint16_t port ) , uint8_t val , void * priv )
2016-06-26 00:34:39 +02:00
{
2023-06-09 23:46:54 -04:00
pas16_t * pas16 = ( pas16_t * ) priv ;
2022-02-22 20:28:56 -05:00
2024-03-27 23:56:55 +01:00
pas16_log ( " [%04X:%08X] PAS16: [W] %04X = %02X \n " , CS , cpu_state . pc , port , val ) ;
if ( pas16 - > master_ff & & ( pas16 - > board_id = = pas16 - > this_id ) )
pas16 - > new_base = val < < 2 ;
else if ( ! pas16 - > master_ff )
pas16 - > board_id = val ;
2022-02-22 20:28:56 -05:00
2024-03-27 23:56:55 +01:00
pas16 - > master_ff = ! pas16 - > master_ff ;
2024-03-21 22:00:48 +01:00
}
static void
pas16_input_msg ( void * priv , uint8_t * msg , uint32_t len )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
if ( pas16 - > sysex )
return ;
if ( pas16 - > midi_uart_in ) {
pas16 - > midi_stat | = 0x04 ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
pas16 - > midi_queue [ pas16 - > midi_w + + ] = msg [ i ] ;
pas16 - > midi_w & = 0xff ;
}
pas16_update_irq ( pas16 ) ;
}
}
static int
pas16_input_sysex ( void * priv , uint8_t * buffer , uint32_t len , int abort )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
if ( abort ) {
pas16 - > sysex = 0 ;
return 0 ;
}
pas16 - > sysex = 1 ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
if ( pas16 - > midi_r = = pas16 - > midi_w )
2024-05-03 17:02:13 +02:00
return ( int ) ( len - i ) ;
2024-03-21 22:00:48 +01:00
pas16 - > midi_queue [ pas16 - > midi_w + + ] = buffer [ i ] ;
pas16 - > midi_w & = 0xff ;
}
pas16 - > sysex = 0 ;
return 0 ;
2016-06-26 00:34:39 +02:00
}
2022-02-22 20:28:56 -05:00
static void
pas16_update ( pas16_t * pas16 )
2016-06-26 00:34:39 +02:00
{
2022-02-22 20:28:56 -05:00
if ( ! ( pas16 - > audiofilt & PAS16_FILT_MUTE ) ) {
for ( ; pas16 - > pos < sound_pos_global ; pas16 - > pos + + ) {
pas16 - > pcm_buffer [ 0 ] [ pas16 - > pos ] = 0 ;
pas16 - > pcm_buffer [ 1 ] [ pas16 - > pos ] = 0 ;
2016-06-26 00:34:39 +02:00
}
2022-02-22 20:28:56 -05:00
} else {
for ( ; pas16 - > pos < sound_pos_global ; pas16 - > pos + + ) {
2024-05-03 17:02:13 +02:00
pas16 - > pcm_buffer [ 0 ] [ pas16 - > pos ] = ( int16_t ) pas16 - > pcm_dat_l ;
pas16 - > pcm_buffer [ 1 ] [ pas16 - > pos ] = ( int16_t ) pas16 - > pcm_dat_r ;
2016-06-26 00:34:39 +02:00
}
2022-02-22 20:28:56 -05:00
}
2016-06-26 00:34:39 +02:00
}
2022-02-22 20:28:56 -05:00
void
2024-05-03 17:02:13 +02:00
pasplus_get_buffer ( int32_t * buffer , int len , void * priv )
2016-06-26 00:34:39 +02:00
{
2024-05-03 17:02:13 +02:00
pas16_t * pas16 = ( pas16_t * ) priv ;
const nsc_mixer_t * mixer = & pas16 - > nsc_mixer ;
double bass_treble ;
2022-02-22 20:28:56 -05:00
sb_dsp_update ( & pas16 - > dsp ) ;
pas16_update ( pas16 ) ;
2024-05-03 17:02:13 +02:00
for ( int c = 0 ; c < len * 2 ; c + = 2 ) {
2024-05-04 11:40:07 +02:00
double out_l = pas16 - > dsp . buffer [ c ] ;
double out_r = pas16 - > dsp . buffer [ c + 1 ] ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > filter ) {
/* We divide by 3 to get the volume down to normal. */
out_l + = low_fir_pas16 ( 0 , ( double ) pas16 - > pcm_buffer [ 0 ] [ c > > 1 ] ) * mixer - > pcm_l ;
out_r + = low_fir_pas16 ( 1 , ( double ) pas16 - > pcm_buffer [ 1 ] [ c > > 1 ] ) * mixer - > pcm_r ;
} else {
out_l + = ( ( double ) pas16 - > pcm_buffer [ 0 ] [ c > > 1 ] ) * mixer - > pcm_l ;
out_r + = ( ( double ) pas16 - > pcm_buffer [ 1 ] [ c > > 1 ] ) * mixer - > pcm_r ;
}
out_l * = mixer - > master_l ;
out_r * = mixer - > master_r ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( mixer - > bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > bass ] ;
if ( mixer - > bass > 6 ) {
out_l + = ( low_iir ( 0 , 0 , out_l ) * bass_treble ) ;
out_r + = ( low_iir ( 0 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > bass < 6 ) {
out_l = ( out_l * bass_treble + low_cut_iir ( 0 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + low_cut_iir ( 0 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
if ( mixer - > treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > treble ] ;
if ( mixer - > treble > 6 ) {
out_l + = ( high_iir ( 0 , 0 , out_l ) * bass_treble ) ;
out_r + = ( high_iir ( 0 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > treble < 6 ) {
out_l = ( out_l * bass_treble + high_cut_iir ( 0 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + high_cut_iir ( 0 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
buffer [ c ] + = ( int32_t ) out_l ;
buffer [ c + 1 ] + = ( int32_t ) out_r ;
}
pas16 - > pos = 0 ;
pas16 - > dsp . pos = 0 ;
}
void
pasplus_get_music_buffer ( int32_t * buffer , int len , void * priv )
{
const pas16_t * pas16 = ( const pas16_t * ) priv ;
const nsc_mixer_t * mixer = & pas16 - > nsc_mixer ;
const int32_t * opl_buf = pas16 - > opl . update ( pas16 - > opl . priv ) ;
double bass_treble ;
for ( int c = 0 ; c < len * 2 ; c + = 2 ) {
2024-05-04 11:40:07 +02:00
double out_l = ( ( ( double ) opl_buf [ c ] ) * mixer - > fm_l ) * 0.7171630859375 ;
double out_r = ( ( ( double ) opl_buf [ c + 1 ] ) * mixer - > fm_r ) * 0.7171630859375 ;
2024-05-03 17:02:13 +02:00
/* TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. */
out_l * = mixer - > master_l ;
out_r * = mixer - > master_r ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( mixer - > bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > bass ] ;
if ( mixer - > bass > 6 ) {
out_l + = ( low_iir ( 1 , 0 , out_l ) * bass_treble ) ;
out_r + = ( low_iir ( 1 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > bass < 6 ) {
out_l = ( out_l * bass_treble + low_cut_iir ( 1 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + low_cut_iir ( 1 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
if ( mixer - > treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > treble ] ;
if ( mixer - > treble > 6 ) {
out_l + = ( high_iir ( 1 , 0 , out_l ) * bass_treble ) ;
out_r + = ( high_iir ( 1 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > treble < 6 ) {
out_l = ( out_l * bass_treble + high_cut_iir ( 1 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + high_cut_iir ( 1 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
buffer [ c ] + = ( int32_t ) out_l ;
buffer [ c + 1 ] + = ( int32_t ) out_r ;
}
pas16 - > opl . reset_buffer ( pas16 - > opl . priv ) ;
}
void
pasplus_filter_cd_audio ( int channel , double * buffer , void * priv )
{
const pas16_t * pas16 = ( const pas16_t * ) priv ;
const nsc_mixer_t * mixer = & pas16 - > nsc_mixer ;
const double cd = channel ? mixer - > cd_r : mixer - > cd_l ;
const double master = channel ? mixer - > master_r : mixer - > master_l ;
const int32_t bass = mixer - > bass ;
const int32_t treble = mixer - > treble ;
double c = ( * buffer ) * cd * master ;
double bass_treble ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ bass ] ;
if ( bass > 6 )
c + = ( low_iir ( 2 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + low_cut_iir ( 2 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
if ( treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ treble ] ;
if ( treble > 6 )
c + = ( high_iir ( 2 , channel , c ) * bass_treble ) ;
2024-03-27 23:56:55 +01:00
else
2024-05-03 17:02:13 +02:00
c = ( c * bass_treble + high_cut_iir ( 2 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
* buffer = c ;
}
void
pasplus_filter_pc_speaker ( int channel , double * buffer , void * priv )
{
const pas16_t * pas16 = ( pas16_t * ) priv ;
const nsc_mixer_t * mixer = & pas16 - > nsc_mixer ;
const double spk = channel ? mixer - > speaker_r : mixer - > speaker_l ;
const double master = channel ? mixer - > master_r : mixer - > master_l ;
const int32_t bass = mixer - > bass ;
const int32_t treble = mixer - > treble ;
double c = ( * buffer ) * spk * master ;
double bass_treble ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ bass ] ;
if ( bass > 6 )
c + = ( low_iir ( 3 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + low_cut_iir ( 3 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
if ( treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ treble ] ;
if ( treble > 6 )
c + = ( high_iir ( 3 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + high_cut_iir ( 3 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
* buffer = c ;
}
void
pas16_get_buffer ( int32_t * buffer , int len , void * priv )
{
pas16_t * pas16 = ( pas16_t * ) priv ;
const mv508_mixer_t * mixer = & pas16 - > mv508_mixer ;
double bass_treble ;
sb_dsp_update ( & pas16 - > dsp ) ;
pas16_update ( pas16 ) ;
for ( int c = 0 ; c < len * 2 ; c + = 2 ) {
2024-05-04 11:40:07 +02:00
double out_l = ( pas16 - > dsp . buffer [ c ] * mixer - > sb_l ) / 3.0 ;
double out_r = ( pas16 - > dsp . buffer [ c + 1 ] * mixer - > sb_r ) / 3.0 ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > filter ) {
/* We divide by 3 to get the volume down to normal. */
out_l + = ( low_fir_pas16 ( 0 , ( double ) pas16 - > pcm_buffer [ 0 ] [ c > > 1 ] ) * mixer - > pcm_l ) / 3.0 ;
out_r + = ( low_fir_pas16 ( 1 , ( double ) pas16 - > pcm_buffer [ 1 ] [ c > > 1 ] ) * mixer - > pcm_r ) / 3.0 ;
} else {
out_l + = ( ( ( double ) pas16 - > pcm_buffer [ 0 ] [ c > > 1 ] ) * mixer - > pcm_l ) / 3.0 ;
out_r + = ( ( ( double ) pas16 - > pcm_buffer [ 1 ] [ c > > 1 ] ) * mixer - > pcm_r ) / 3.0 ;
}
out_l * = mixer - > master_l ;
out_r * = mixer - > master_r ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( mixer - > bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > bass ] ;
if ( mixer - > bass > 6 ) {
out_l + = ( low_iir ( 0 , 0 , out_l ) * bass_treble ) ;
out_r + = ( low_iir ( 0 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > bass < 6 ) {
out_l = ( out_l * bass_treble + low_cut_iir ( 0 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + low_cut_iir ( 0 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
if ( mixer - > treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > treble ] ;
if ( mixer - > treble > 6 ) {
out_l + = ( high_iir ( 0 , 0 , out_l ) * bass_treble ) ;
out_r + = ( high_iir ( 0 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > treble < 6 ) {
out_l = ( out_l * bass_treble + high_cut_iir ( 0 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + high_cut_iir ( 0 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
buffer [ c ] + = ( int32_t ) out_l ;
buffer [ c + 1 ] + = ( int32_t ) out_r ;
2022-02-22 20:28:56 -05:00
}
2016-06-26 00:34:39 +02:00
2022-09-18 17:16:40 -04:00
pas16 - > pos = 0 ;
2022-02-22 20:28:56 -05:00
pas16 - > dsp . pos = 0 ;
2016-06-26 00:34:39 +02:00
}
2024-03-01 06:52:48 +01:00
void
pas16_get_music_buffer ( int32_t * buffer , int len , void * priv )
{
2024-05-03 17:02:13 +02:00
const pas16_t * pas16 = ( const pas16_t * ) priv ;
const mv508_mixer_t * mixer = & pas16 - > mv508_mixer ;
const int32_t * opl_buf = pas16 - > opl . update ( pas16 - > opl . priv ) ;
double bass_treble ;
for ( int c = 0 ; c < len * 2 ; c + = 2 ) {
2024-05-04 11:40:07 +02:00
double out_l = ( ( ( double ) opl_buf [ c ] ) * mixer - > fm_l ) * 0.7171630859375 ;
double out_r = ( ( ( double ) opl_buf [ c + 1 ] ) * mixer - > fm_r ) * 0.7171630859375 ;
2024-05-03 17:02:13 +02:00
/* TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. */
out_l * = mixer - > master_l ;
out_r * = mixer - > master_r ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( mixer - > bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > bass ] ;
if ( mixer - > bass > 6 ) {
out_l + = ( low_iir ( 1 , 0 , out_l ) * bass_treble ) ;
out_r + = ( low_iir ( 1 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > bass < 6 ) {
out_l = ( out_l * bass_treble + low_cut_iir ( 1 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + low_cut_iir ( 1 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
if ( mixer - > treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ mixer - > treble ] ;
2024-03-01 06:52:48 +01:00
2024-05-03 17:02:13 +02:00
if ( mixer - > treble > 6 ) {
out_l + = ( high_iir ( 1 , 0 , out_l ) * bass_treble ) ;
out_r + = ( high_iir ( 1 , 1 , out_r ) * bass_treble ) ;
} else if ( mixer - > treble < 6 ) {
out_l = ( out_l * bass_treble + high_cut_iir ( 1 , 0 , out_l ) * ( 1.0 - bass_treble ) ) ;
out_r = ( out_r * bass_treble + high_cut_iir ( 1 , 1 , out_r ) * ( 1.0 - bass_treble ) ) ;
}
}
buffer [ c ] + = ( int32_t ) out_l ;
buffer [ c + 1 ] + = ( int32_t ) out_r ;
}
2024-03-01 06:52:48 +01:00
pas16 - > opl . reset_buffer ( pas16 - > opl . priv ) ;
}
2024-05-03 17:02:13 +02:00
void
pas16_filter_cd_audio ( int channel , double * buffer , void * priv )
{
const pas16_t * pas16 = ( const pas16_t * ) priv ;
const mv508_mixer_t * mixer = & pas16 - > mv508_mixer ;
const double cd = channel ? mixer - > cd_r : mixer - > cd_l ;
const double master = channel ? mixer - > master_r : mixer - > master_l ;
const int32_t bass = mixer - > bass ;
const int32_t treble = mixer - > treble ;
double c = ( ( ( * buffer ) * cd ) / 3.0 ) * master ;
double bass_treble ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ bass ] ;
if ( bass > 6 )
c + = ( low_iir ( 2 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + low_cut_iir ( 2 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
if ( treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ treble ] ;
if ( treble > 6 )
c + = ( high_iir ( 2 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + high_cut_iir ( 2 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
* buffer = c ;
}
void
pas16_filter_pc_speaker ( int channel , double * buffer , void * priv )
{
const pas16_t * pas16 = ( const pas16_t * ) priv ;
const mv508_mixer_t * mixer = & pas16 - > mv508_mixer ;
const double spk = channel ? mixer - > speaker_r : mixer - > speaker_l ;
const double master = channel ? mixer - > master_r : mixer - > master_l ;
const int32_t bass = mixer - > bass ;
const int32_t treble = mixer - > treble ;
double c = ( ( ( * buffer ) * spk ) / 3.0 ) * master ;
double bass_treble ;
/* This is not exactly how one does bass/treble controls, but the end result is like it.
A better implementation would reduce the CPU usage . */
if ( bass ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ bass ] ;
if ( bass > 6 )
c + = ( low_iir ( 3 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + low_cut_iir ( 3 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
if ( treble ! = 6 ) {
bass_treble = lmc1982_bass_treble_4bits [ treble ] ;
if ( treble > 6 )
c + = ( high_iir ( 3 , channel , c ) * bass_treble ) ;
else
c = ( c * bass_treble + high_cut_iir ( 3 , channel , c ) * ( 1.0 - bass_treble ) ) ;
}
* buffer = c ;
}
2024-03-23 06:15:34 +01:00
static void
pas16_speed_changed ( void * priv )
{
2024-03-27 23:56:55 +01:00
pas16_change_pit_clock_speed ( priv ) ;
2024-03-23 06:15:34 +01:00
}
2024-03-27 23:56:55 +01:00
static void *
pas16_init ( const device_t * info )
2024-03-23 06:15:34 +01:00
{
2024-03-27 23:56:55 +01:00
pas16_t * pas16 = calloc ( 1 , sizeof ( pas16_t ) ) ;
2024-03-23 06:15:34 +01:00
2024-03-27 23:56:55 +01:00
if ( pas16_next > 3 ) {
fatal ( " Attempting to add a Pro Audio Spectrum instance beyond the maximum amount \n " ) ;
2024-03-23 06:15:34 +01:00
2024-03-27 23:56:55 +01:00
free ( pas16 ) ;
return NULL ;
}
2016-06-26 00:34:39 +02:00
2024-03-27 23:56:55 +01:00
pas16 - > type = info - > local & 0xff ;
2024-05-03 20:08:10 +02:00
pas16 - > has_scsi = ( ! pas16 - > type ) | | ( pas16 - > type = = 0x0f ) ;
2022-07-25 20:24:31 +02:00
fm_driver_get ( FM_YMF262 , & pas16 - > opl ) ;
2024-03-21 22:00:48 +01:00
sb_dsp_set_real_opl ( & pas16 - > dsp , 1 ) ;
2022-02-22 20:28:56 -05:00
sb_dsp_init ( & pas16 - > dsp , SB2 , SB_SUBTYPE_DEFAULT , pas16 ) ;
2024-03-18 17:10:36 +01:00
pas16 - > mpu = ( mpu_t * ) malloc ( sizeof ( mpu_t ) ) ;
memset ( pas16 - > mpu , 0 , sizeof ( mpu_t ) ) ;
2024-05-03 17:02:13 +02:00
mpu401_init ( pas16 - > mpu , 0 , 0 , M_UART , device_get_config_int ( " receive_input401 " ) ) ;
2024-03-18 17:10:36 +01:00
sb_dsp_set_mpu ( & pas16 - > dsp , pas16 - > mpu ) ;
2016-11-07 06:39:20 +01:00
2024-04-04 03:09:35 +02:00
pas16 - > sb_compat_base = 0x0000 ;
2024-03-27 23:56:55 +01:00
io_sethandler ( 0x9a01 , 0x0001 , NULL , NULL , NULL , pas16_out_base , NULL , NULL , pas16 ) ;
pas16 - > this_id = 0xbc + pas16_next ;
2024-05-03 17:02:13 +02:00
if ( pas16 - > has_scsi ) {
pas16 - > scsi = device_add ( & scsi_pas_device ) ;
2024-05-06 13:09:08 +02:00
timer_add ( & pas16 - > scsi - > timer , pas16_scsi_callback , pas16 , 0 ) ;
2024-05-03 17:02:13 +02:00
timer_add ( & pas16 - > scsi_timer , pas16_timeout_callback , pas16 , 0 ) ;
other_scsi_present + + ;
}
2024-03-27 23:56:55 +01:00
pas16 - > pit = device_add ( & i8254_ext_io_fast_device ) ;
pas16_reset ( pas16 ) ;
2024-03-21 22:00:48 +01:00
pas16 - > pit - > dev_priv = pas16 ;
2024-03-27 23:56:55 +01:00
pas16 - > irq = pas16 - > type ? 10 : 5 ;
2024-05-03 17:02:13 +02:00
pas16 - > io_conf_3 = pas16 - > type ? 0x07 : 0x04 ;
if ( pas16 - > has_scsi ) {
pas16 - > scsi_irq = pas16 - > type ? 11 : 7 ;
pas16 - > io_conf_3 | = ( pas16 - > type ? 0x80 : 0x60 ) ;
ncr5380_set_irq ( & pas16 - > scsi - > ncr , pas16 - > scsi_irq ) ;
}
2024-03-21 22:00:48 +01:00
pas16 - > dma = 3 ;
2024-03-27 23:56:55 +01:00
for ( uint8_t i = 0 ; i < 3 ; i + + )
pitf_ctr_set_gate ( pas16 - > pit , i , 0 ) ;
2024-03-21 22:00:48 +01:00
2024-03-27 23:56:55 +01:00
pitf_ctr_set_out_func ( pas16 - > pit , 0 , pas16_pit_timer0 ) ;
pitf_ctr_set_out_func ( pas16 - > pit , 1 , pas16_pit_timer1 ) ;
pitf_ctr_set_using_timer ( pas16 - > pit , 0 , 1 ) ;
pitf_ctr_set_using_timer ( pas16 - > pit , 1 , 0 ) ;
pitf_ctr_set_using_timer ( pas16 - > pit , 2 , 0 ) ;
2022-02-20 02:26:27 -05:00
2024-05-03 17:02:13 +02:00
if ( pas16 - > type ) {
sound_add_handler ( pas16_get_buffer , pas16 ) ;
music_add_handler ( pas16_get_music_buffer , pas16 ) ;
sound_set_cd_audio_filter ( pas16_filter_cd_audio , pas16 ) ;
if ( device_get_config_int ( " control_pc_speaker " ) )
sound_set_pc_speaker_filter ( pas16_filter_pc_speaker , pas16 ) ;
} else {
sound_add_handler ( pasplus_get_buffer , pas16 ) ;
music_add_handler ( pasplus_get_music_buffer , pas16 ) ;
sound_set_cd_audio_filter ( pasplus_filter_cd_audio , pas16 ) ;
if ( device_get_config_int ( " control_pc_speaker " ) )
sound_set_pc_speaker_filter ( pasplus_filter_pc_speaker , pas16 ) ;
}
2022-02-20 02:26:27 -05:00
2024-03-21 22:00:48 +01:00
if ( device_get_config_int ( " receive_input " ) )
midi_in_handler ( 1 , pas16_input_msg , pas16_input_sysex , pas16 ) ;
2024-05-03 17:02:13 +02:00
for ( uint8_t i = 0 ; i < 16 ; i + + ) {
if ( i < 6 )
lmc1982_bass_treble_4bits [ i ] = pow ( 10.0 , ( - ( ( double ) ( 12 - ( i < < 1 ) ) ) / 10.0 ) ) ;
else if ( i = = 6 )
lmc1982_bass_treble_4bits [ i ] = 0.0 ;
else if ( ( i > 6 ) & & ( i < = 12 ) )
lmc1982_bass_treble_4bits [ i ] = 1.0 - pow ( 10.0 , ( ( double ) ( ( i - 6 ) < < 1 ) / 10.0 ) ) ;
else
lmc1982_bass_treble_4bits [ i ] = 1.0 - pow ( 10.0 , 1.2 ) ;
}
2024-03-27 23:56:55 +01:00
pas16_next + + ;
2022-02-22 20:28:56 -05:00
return pas16 ;
2016-06-26 00:34:39 +02:00
}
2022-02-22 20:28:56 -05:00
static void
2023-06-09 23:46:54 -04:00
pas16_close ( void * priv )
2016-06-26 00:34:39 +02:00
{
2023-06-09 23:46:54 -04:00
pas16_t * pas16 = ( pas16_t * ) priv ;
2022-02-20 02:26:27 -05:00
2022-02-22 20:28:56 -05:00
free ( pas16 ) ;
2024-03-27 23:56:55 +01:00
pas16_next = 0 ;
2016-06-26 00:34:39 +02:00
}
2024-03-18 17:10:36 +01:00
static const device_config_t pas16_config [ ] = {
2024-05-03 17:02:13 +02:00
{
. name = " control_pc_speaker " ,
. description = " Control PC speaker " ,
. type = CONFIG_BINARY ,
. default_string = " " ,
. default_int = 0
} ,
2024-03-18 17:10:36 +01:00
{
2024-11-10 05:06:09 +01:00
. name = " receive_input " ,
. description = " Receive MIDI input " ,
2024-03-18 17:10:36 +01:00
. type = CONFIG_BINARY ,
. default_string = " " ,
2024-11-10 05:06:09 +01:00
. default_int = 1
2024-03-18 17:10:36 +01:00
} ,
2024-03-21 22:00:48 +01:00
{
2024-11-10 05:06:09 +01:00
. name = " receive_input401 " ,
. description = " Receive MIDI input (MPU-401) " ,
2024-03-21 22:00:48 +01:00
. type = CONFIG_BINARY ,
. default_string = " " ,
2024-11-10 05:06:09 +01:00
. default_int = 0
2024-03-21 22:00:48 +01:00
} ,
2024-03-18 17:10:36 +01:00
{ . name = " " , . description = " " , . type = CONFIG_END }
} ;
2024-03-27 23:56:55 +01:00
const device_t pasplus_device = {
. name = " Pro Audio Spectrum Plus " ,
. internal_name = " pasplus " ,
. flags = DEVICE_ISA ,
. local = 0 ,
. init = pas16_init ,
. close = pas16_close ,
. reset = pas16_reset ,
2024-12-18 18:43:15 -05:00
. available = NULL ,
2024-03-27 23:56:55 +01:00
. speed_changed = pas16_speed_changed ,
. force_redraw = NULL ,
. config = pas16_config
} ;
2022-02-22 20:28:56 -05:00
const device_t pas16_device = {
2022-09-18 17:16:40 -04:00
. name = " Pro Audio Spectrum 16 " ,
2022-03-13 10:03:39 -04:00
. internal_name = " pas16 " ,
2024-03-18 17:10:36 +01:00
. flags = DEVICE_ISA | DEVICE_AT ,
2024-05-03 17:02:13 +02:00
. local = 0x0f ,
. init = pas16_init ,
. close = pas16_close ,
. reset = pas16_reset ,
2024-12-18 18:43:15 -05:00
. available = NULL ,
2024-05-03 17:02:13 +02:00
. speed_changed = pas16_speed_changed ,
. force_redraw = NULL ,
. config = pas16_config
} ;
const device_t pas16d_device = {
2024-05-03 18:50:47 +02:00
. name = " Pro Audio Spectrum 16D " ,
. internal_name = " pas16d " ,
2024-05-03 17:02:13 +02:00
. flags = DEVICE_ISA | DEVICE_AT ,
. local = 0x0c ,
2022-09-18 17:16:40 -04:00
. init = pas16_init ,
. close = pas16_close ,
2024-03-23 06:15:34 +01:00
. reset = pas16_reset ,
2024-12-18 18:43:15 -05:00
. available = NULL ,
2024-03-23 06:15:34 +01:00
. speed_changed = pas16_speed_changed ,
2022-09-18 17:16:40 -04:00
. force_redraw = NULL ,
2024-03-18 17:10:36 +01:00
. config = pas16_config
2016-06-26 00:34:39 +02:00
} ;