DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/snd_pc98/cbus/pc9861k.c
00001 #include        "compiler.h"
00002 
00003 #if defined(SUPPORT_PC9861K)
00004 
00005 #include        "commng.h"
00006 #include        "pccore.h"
00007 #include        "iocore.h"
00008 #include        "cbuscore.h"
00009 #include        "pc9861k.h"
00010 
00011 
00012         _PC9861K        pc9861k;
00013         COMMNG          cm_pc9861ch1;
00014         COMMNG          cm_pc9861ch2;
00015 
00016 
00017 const UINT32 pc9861k_speed[11] = {75, 150, 300, 600, 1200, 2400, 4800,
00018                                                                                         9600, 19200, 38400, 76800};
00019 
00020 static const UINT8 ch1_irq[4] = {IRQ_INT0, IRQ_INT1, IRQ_INT2, IRQ_INT3};
00021 static const UINT8 ch2_irq[4] = {IRQ_INT0, IRQ_INT41, IRQ_INT5, IRQ_INT6};
00022 static const _PC9861CH pc9861def =
00023                                         {0x05, 0xff, 7, 1,
00024                                                 0, 0, 2400, NEVENT_MAXCLOCK, 0, 0, 0};
00025 
00026 
00027 // ----
00028 
00029 static void pc9861k_callback(COMMNG cm, PC9861CH m) {
00030 
00031         BOOL    interrupt;
00032 
00033         interrupt = FALSE;
00034         if ((cm != NULL) && (cm->read(cm, &m->data))) {
00035                 m->result |= 2;
00036                 if (m->signal & 1) {
00037                         interrupt = TRUE;
00038                 }
00039         }
00040         else {
00041                 m->result &= ~2;
00042         }
00043         if (m->signal & 4) {
00044                 if (m->send) {
00045                         m->send = 0;
00046                         interrupt = TRUE;
00047                 }
00048         }
00049         if (interrupt) {
00050                 pic_setirq(m->irq);
00051         }
00052 }
00053 
00054 void pc9861ch1cb(NEVENTITEM item) {
00055 
00056         if (item->flag & NEVENT_SETEVENT) {
00057                 nevent_set(NEVENT_PC9861CH1, pc9861k.ch1.clk, pc9861ch1cb,
00058                                                                                                                 NEVENT_RELATIVE);
00059         }
00060         pc9861k_callback(cm_pc9861ch1, &pc9861k.ch1);
00061 }
00062 
00063 void pc9861ch2cb(NEVENTITEM item) {
00064 
00065         if (item->flag & NEVENT_SETEVENT) {
00066                 nevent_set(NEVENT_PC9861CH2, pc9861k.ch2.clk, pc9861ch2cb,
00067                                                                                                                 NEVENT_RELATIVE);
00068         }
00069         pc9861k_callback(cm_pc9861ch2, &pc9861k.ch2);
00070 }
00071 
00072 static UINT32 pc9861k_getspeed(REG8 dip) {
00073 
00074         UINT    speed;
00075 
00076         speed = (((~dip) >> 2) & 0x0f) + 1;
00077         if (dip & 0x02) {
00078                 if (speed > 4) {
00079                         speed -= 4;
00080                 }
00081                 else {
00082                         speed = 0;
00083                 }
00084         }
00085         if (speed > (NELEMENTS(pc9861k_speed) - 1)) {
00086                 speed = NELEMENTS(pc9861k_speed) - 1;
00087         }
00088         return(pc9861k_speed[speed]);
00089 }
00090 
00091 static void pc9861_makeclk(PC9861CH m, UINT32 mul2) {
00092 
00093         m->clk = pccore.realclock * mul2 / ((m->speed) * 2);
00094 }
00095 
00096 static void pc9861ch1_open(void) {
00097 
00098         cm_pc9861ch1 = commng_create(COMCREATE_PC9861K1);
00099 
00100         pc9861k.ch1.dip = np2cfg.pc9861sw[0];
00101         pc9861k.ch1.speed = pc9861k_getspeed(pc9861k.ch1.dip);
00102         pc9861k.ch1.vect = ((np2cfg.pc9861sw[1] >> 1) & 1) |
00103                                                 ((np2cfg.pc9861sw[1] << 1) & 2);
00104         pc9861k.ch1.irq = ch1_irq[pc9861k.ch1.vect];
00105         pc9861_makeclk(&pc9861k.ch1, 10*2);
00106         nevent_set(NEVENT_PC9861CH1, pc9861k.ch1.clk,
00107                                                                                         pc9861ch1cb, NEVENT_ABSOLUTE);
00108 }
00109 
00110 static void pc9861ch2_open(void) {
00111 
00112         cm_pc9861ch2 = commng_create(COMCREATE_PC9861K2);
00113 
00114         pc9861k.ch2.dip = np2cfg.pc9861sw[2];
00115         pc9861k.ch2.speed = pc9861k_getspeed(pc9861k.ch2.dip);
00116         pc9861k.ch2.vect = ((np2cfg.pc9861sw[1] >> 3) & 1) |
00117                                                 ((np2cfg.pc9861sw[1] >> 1) & 2);
00118         pc9861k.ch2.irq = ch1_irq[pc9861k.ch2.vect];
00119         pc9861_makeclk(&pc9861k.ch2, 10*2);
00120         nevent_set(NEVENT_PC9861CH2, pc9861k.ch2.clk,
00121                                                                                         pc9861ch2cb, NEVENT_ABSOLUTE);
00122 }
00123 
00124 
00125 // -------------------------------------------------------------------------
00126 
00127 static void IOOUTCALL pc9861data_w8(COMMNG cm, PC9861CH m,
00128                                                                                                         UINT port, REG8 value) {
00129 
00130         UINT32  mul2;
00131 
00132         switch(port & 0x3) {
00133                 case 0x01:
00134                         cm->write(cm, (UINT8)value);
00135                         if (m->signal & 4) {
00136                                 m->send = 0;
00137                                 pic_setirq(m->irq);
00138                         }
00139                         else {
00140                                 m->send = 1;
00141                         }
00142                         break;
00143 
00144                 case 0x03:
00145                         if (!(value & 0xfd)) {
00146                                 m->dummyinst += 1;
00147                         }
00148                         else {
00149                                 if ((m->dummyinst >= 3) && (value == 0x40)) {
00150                                         m->pos = 0;
00151                                 }
00152                                 m->dummyinst = 0;
00153                         }
00154                         switch(m->pos) {
00155                                 case 0x00:                      // reset
00156                                         m->pos += 1;
00157                                         break;
00158 
00159                                 case 0x01:                      // mode
00160                                         if (!(value & 0x03)) {
00161                                                 mul2 = 10 * 2;
00162                                         }
00163                                         else {
00164                                                 mul2 = ((value >> 1) & 6) + 10;
00165                                                 if (value & 0x10) {
00166                                                         mul2 += 2;
00167                                                 }
00168                                                 switch(value & 0xc0) {
00169                                                         case 0x80:
00170                                                                 mul2 += 3;
00171                                                                 break;
00172                                                         case 0xc0:
00173                                                                 mul2 += 4;
00174                                                                 break;
00175                                                         default:
00176                                                                 mul2 += 2;
00177                                                                 break;
00178                                                 }
00179                                         }
00180                                         pc9861_makeclk(m, mul2);
00181                                         m->pos += 1;
00182                                         break;
00183 
00184                                 case 0x02:                      // cmd
00185                                         m->pos += 1;
00186                                         break;
00187                         }
00188                         break;
00189         }
00190 }
00191 
00192 static REG8 IOINPCALL pc9861data_r8(COMMNG cm, PC9861CH m, UINT port) {
00193 
00194         switch(port & 0x3) {
00195                 case 0x01:
00196                         return(m->data);
00197 
00198                 case 0x03:
00199                         if (!(cm->getstat(cm) & 0x20)) {
00200                                 return((m->result) | 0x80);
00201                         }
00202                         return(m->result);
00203         }
00204         return(0xff);
00205 }
00206 
00207 
00208 static void IOOUTCALL pc9861k_ob0(UINT port, REG8 dat) {
00209 
00210         if (cm_pc9861ch1 == NULL) {
00211                 pc9861ch1_open();
00212         }
00213         pc9861k.ch1.signal = dat;
00214         (void)port;
00215 }
00216 
00217 static void IOOUTCALL pc9861k_ob2(UINT port, REG8 dat) {
00218 
00219         if (cm_pc9861ch2 == NULL) {
00220                 pc9861ch2_open();
00221         }
00222         pc9861k.ch2.signal = dat;
00223         (void)port;
00224 }
00225 
00226 static REG8 IOINPCALL pc9861k_ib0(UINT port) {
00227 
00228         if (cm_pc9861ch1 == NULL) {
00229                 pc9861ch1_open();
00230         }
00231         (void)port;
00232         return(cm_pc9861ch1->getstat(cm_pc9861ch1) | pc9861k.ch1.vect);
00233 }
00234 
00235 static REG8 IOINPCALL pc9861k_ib2(UINT port) {
00236 
00237         if (cm_pc9861ch2 == NULL) {
00238                 pc9861ch2_open();
00239         }
00240         (void)port;
00241         return(cm_pc9861ch2->getstat(cm_pc9861ch2) | pc9861k.ch2.vect);
00242 }
00243 
00244 
00245 static void IOOUTCALL pc9861k_ob1(UINT port, REG8 dat) {
00246 
00247         if (cm_pc9861ch1 == NULL) {
00248                 pc9861ch1_open();
00249         }
00250         pc9861data_w8(cm_pc9861ch1, &pc9861k.ch1, port, dat);
00251 }
00252 
00253 static REG8 IOINPCALL pc9861k_ib1(UINT port) {
00254 
00255         if (cm_pc9861ch2 == NULL) {
00256                 pc9861ch1_open();
00257         }
00258         return(pc9861data_r8(cm_pc9861ch1, &pc9861k.ch1, port));
00259 }
00260 
00261 
00262 static void IOOUTCALL pc9861k_ob9(UINT port, REG8 dat) {
00263 
00264         if (cm_pc9861ch2 == NULL) {
00265                 pc9861ch2_open();
00266         }
00267         pc9861data_w8(cm_pc9861ch2, &pc9861k.ch2, port, dat);
00268 }
00269 
00270 static REG8 IOINPCALL pc9861k_ib9(UINT port) {
00271 
00272         if (cm_pc9861ch2 == NULL) {
00273                 pc9861ch2_open();
00274         }
00275         return(pc9861data_r8(cm_pc9861ch2, &pc9861k.ch2, port));
00276 }
00277 
00278 
00279 // ---- I/F
00280 
00281 void pc9861k_initialize(void) {
00282 
00283         cm_pc9861ch1 = NULL;
00284         cm_pc9861ch2 = NULL;
00285 }
00286 
00287 void pc9861k_deinitialize(void) {
00288 
00289         commng_destroy(cm_pc9861ch1);
00290         cm_pc9861ch1 = NULL;
00291         commng_destroy(cm_pc9861ch2);
00292         cm_pc9861ch2 = NULL;
00293 }
00294 
00295 void pc9861k_reset(const NP2CFG *pConfig) {
00296 
00297         commng_destroy(cm_pc9861ch1);
00298         cm_pc9861ch1 = NULL;
00299         commng_destroy(cm_pc9861ch2);
00300         cm_pc9861ch2 = NULL;
00301 
00302         pc9861k.ch1 = pc9861def;
00303         pc9861k.ch2 = pc9861def;
00304         pc9861k.en = pConfig->pc9861enable & 1;
00305 }
00306 
00307 void pc9861k_bind(void) {
00308 
00309         pc9861k_deinitialize();
00310         if (pc9861k.en) {
00311                 iocore_attachout(0xb0, pc9861k_ob0);
00312                 iocore_attachout(0xb2, pc9861k_ob2);
00313                 iocore_attachinp(0xb0, pc9861k_ib0);
00314                 iocore_attachinp(0xb2, pc9861k_ib2);
00315 
00316                 iocore_attachout(0xb1, pc9861k_ob1);
00317                 iocore_attachout(0xb3, pc9861k_ob1);
00318                 iocore_attachinp(0xb1, pc9861k_ib1);
00319                 iocore_attachinp(0xb3, pc9861k_ib1);
00320 
00321                 iocore_attachout(0xb9, pc9861k_ob9);
00322                 iocore_attachout(0xbb, pc9861k_ob9);
00323                 iocore_attachinp(0xb9, pc9861k_ib9);
00324                 iocore_attachinp(0xbb, pc9861k_ib9);
00325         }
00326 }
00327 
00328 void pc9861k_midipanic(void) {
00329 
00330         if (cm_pc9861ch1) {
00331                 cm_pc9861ch1->msg(cm_pc9861ch1, COMMSG_MIDIRESET, 0);
00332         }
00333         if (cm_pc9861ch2) {
00334                 cm_pc9861ch2->msg(cm_pc9861ch1, COMMSG_MIDIRESET, 0);
00335         }
00336 }
00337 
00338 #endif
00339