st.cpp
1 /* 2 * Castaway 3 * (C) 1994 - 2002 Martin Doering, Joachim Hoenig 4 * 5 * IO.c - ST hardware emulation 6 * 7 * This file is distributed under the GPL, version 2 or at your 8 * option any later version. See doc/license.txt for details. 9 * 10 * revision history 11 * 23.05.2002 JH FAST1.0.1 code import: KR -> ANSI, restructuring 12 * 09.06.2002 JH Renamed io.c to st.c again (io.h conflicts with system headers) 13 * 12.06.2002 JH Correct bus error/address error exception stack frame 14 * 14.06.2002 JH Implemented STOP, shutdown CPU after multiple bus errors. 15 * Removed inst parameter from CPU opcode functions. 16 * 20.08.2002 JH Fixed sign bug in DoIORW() and DoIORL() 17 * 10.09.2002 JH Bugfix: MOVE.L 0xfffa00,d0 and the like should not raise bus error 18 * 16.09.2002 JH Bugfix: Word access on unmapped I/O address stacked 19 * two bus error stack frames. Fault address corrected. 20 * Merged some code from JH_TOS206_patches branch. 21 * 02.10.2002 JH Eliminated a lot of silly bugs introduced recently. Shame on me. 22 No more CPU bus errors from blitter.c::bitblt(). 23 * 10.10.2002 JH Compatibility improvements. 24 */ 25 static char sccsid[] = "$Id: st.c,v 1.14 2002/10/10 19:41:27 jhoenig Exp $"; 26 #include <stdio.h> 27 #include "dcastaway.h" 28 #include "st.h" 29 #include "mem.h" 30 #include "m68k_intrf.h" 31 #ifndef NO_SOUND 32 #include "sound.h" 33 #endif 34 35 36 #ifdef DEBUG 37 #include <assert.h> 38 #endif 39 40 #include <Arduino.h> 41 42 #define VALUE_OPEN 0xff 43 /* 44 * startup display mode 45 */ 46 int display_mode = COL4; 47 48 /* 49 * I/O Registers 50 */ 51 uint8 memconf; 52 53 //Video shifter 54 uint32 vid_adr; 55 uint8 vid_baseh, vid_basem; 56 uint32 vid_mem=0x10000; 57 uint8 vid_syncmode=2, vid_shiftmode; 58 int16 vid_col[16]; 59 int vid_flag; 60 61 uint16 dma_car, dma_scr, dma_sr, dma_mode; 62 uint8 dma_adrh, dma_adrm, dma_adrl; 63 uint8 mfp_gpip, mfp_aer, mfp_ddr, mfp_iera, mfp_ierb, mfp_ipra, 64 mfp_iprb, mfp_isra, mfp_isrb, mfp_imra, mfp_imrb, mfp_ivr, 65 mfp_tacr, mfp_tbcr, mfp_tcdcr, mfp_scr, mfp_ucr, mfp_rsr, mfp_tsr, mfp_udr; 66 67 68 //Mfp delay timer variables 69 int32 mfp_reg[12]; 70 #define mfp_tadr mfp_reg[0] 71 #define mfp_tbdr mfp_reg[1] 72 #define mfp_tcdr mfp_reg[2] 73 #define mfp_tddr mfp_reg[3] 74 #define mfp_acount mfp_reg[4] 75 #define mfp_bcount mfp_reg[5] 76 #define mfp_ccount mfp_reg[6] 77 #define mfp_dcount mfp_reg[7] 78 #define mfp_ascale mfp_reg[8] 79 #define mfp_bscale mfp_reg[9] 80 #define mfp_cscale mfp_reg[10] 81 #define mfp_dscale mfp_reg[11] 82 83 uint8 acia1_cr, acia1_sr, acia1_dr, acia2_cr, acia2_sr, acia2_dr; 84 85 uint16 blt_halftone[16]; 86 int16 blt_src_x_inc, blt_src_y_inc; 87 uint32 blt_src_addr; 88 int16 blt_end_1, blt_end_2, blt_end_3; 89 int16 blt_dst_x_inc, blt_dst_y_inc; 90 uint32 blt_dst_addr; 91 uint16 blt_x_cnt, blt_y_cnt; 92 int8 blt_hop, blt_op, blt_status, blt_skew; 93 int8 blt_ready; 94 95 uint32 psg[26]; 96 //unsigned char sample[10000]; 97 #define phase0 psg[16] 98 #define phase1 psg[17] 99 #define phase2 psg[18] 100 #define phase3 psg[19] 101 #define psg_epos psg[20] 102 #define psgcontrol psg[21] 103 #define phase4 psg[22] 104 #define nrand psg[23] 105 #define sampos psg[24] 106 #define lastpsg psg[25] 107 108 PROGMEM static const int samvol[16]={0,0,0,1,1,1,2,3,5,7,11,17,25,38,57,85}; 109 static int samvol2[4096]; 110 111 const int32 mfpcycletab[16] = {0,80402,32161,20100,6432,5025,3216,1608,1,0,0,0,0,0,0,0}; 112 113 PROGMEM void IOInit(void) 114 { 115 int n,a,b,c; 116 //Create sample lookup table (4096 entries) 117 for (a=0; a<16; a++) { 118 for (b=0; b<16; b++) { 119 for (c=0; c<16; c++) { 120 samvol2[(a<<8)+(b<<4)+c]=samvol[a]+samvol[b]+samvol[c]; 121 } 122 } 123 } 124 //Reset mfp variables 125 mfp_tadr=256<<20; mfp_tbdr=256<<20; mfp_tcdr=256<<20; mfp_tddr=256<<20; 126 mfp_tacr=0; mfp_tbcr=0; mfp_tcdcr=0; 127 mfp_acount=256<<20; mfp_bcount=256<<20; mfp_ccount=256<<20; mfp_dcount=256<<20; 128 mfp_ascale=0; mfp_bscale=0; mfp_cscale=0; mfp_dscale=0; 129 for (n=0; n<24; n++) psg[n]=0; 130 nrand=1; 131 //Other stuff 132 vid_baseh = 0; 133 vid_basem = 0; 134 vid_shiftmode = display_mode; 135 dma_sr = 1; /* DMA status ready */ 136 if (display_mode == MONO) { 137 mfp_gpip = 0x39; /* no lpr, no blt, no interrupt, monochrome */ 138 } else { 139 mfp_gpip = 0xb9; /* no lpr, no blt, no interrupt, color */ 140 } 141 #ifdef sun 142 act.sa_handler = Sigbus; 143 (void) sigaction (SIGBUS, &act, &oldsigbus); 144 #endif 145 #ifdef USE_MMAP 146 act.sa_handler = Sigsegv; 147 (void) sigaction (SIGSEGV, &act, &oldsigsegv); 148 #endif 149 } 150 151 PROGMEM static void update_psg(uint8 value) { 152 #ifndef NO_SOUND 153 Sound_Update(); 154 #endif 155 //Update psg register 156 psg[psgcontrol]=value; 157 158 switch(psgcontrol) 159 { 160 case 13: 161 #ifndef NO_SOUND 162 bEnvelopeFreqFlag = 1; 163 bWriteEnvelopeFreq = 1; 164 #endif 165 break; 166 case 12: 167 psg_epos=0; 168 break; 169 case 8: 170 #ifndef NO_SOUND 171 bWriteChannelAAmp= 1; 172 #endif 173 break; 174 case 9: 175 #ifndef NO_SOUND 176 bWriteChannelBAmp= 1; 177 #endif 178 break; 179 case 10: 180 #ifndef NO_SOUND 181 bWriteChannelCAmp= 1; 182 #endif 183 break; 184 } 185 } 186 187 PROGMEM void DoIOWB(uint32 address, uint8 value) 188 { 189 address&=0x7fff; 190 191 //Video and dma emu 192 if (address<0x800) { 193 switch (address) { 194 case MEM_CONF&0x7fff: 195 memconf = value; 196 break; 197 case VID_BASEH&0x7fff: 198 vid_baseh = value; 199 vid_mem = (vid_baseh<<16)+(vid_basem<<8); 200 break; 201 case VID_BASEM&0x7fff: 202 vid_basem = value; 203 vid_mem = (vid_baseh<<16)+(vid_basem<<8); 204 break; 205 case VID_SYNCMODE&0x7fff: 206 vid_syncmode = value; 207 maybe_border++; 208 break; 209 case VID_SHIFTMODE&0x7fff: 210 vid_shiftmode = value; 211 vid_flag=1; 212 break; 213 case DMA_ADRH&0x7fff: 214 dma_adrh = value; 215 break; 216 case DMA_ADRM&0x7fff: 217 dma_adrm = value; 218 break; 219 case DMA_ADRL&0x7fff: 220 dma_adrl = value; 221 break; 222 } 223 return; 224 } 225 226 //Sound emu 227 if (address<0x900) { 228 #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH) 229 static unsigned back_cycles=0; 230 static unsigned back_value=0; 231 static unsigned back_ctrl=0; 232 static unsigned new_value=0; 233 #endif 234 if (address<0x804) 235 waitstate+=1; 236 address&=3; 237 if (address==0) { 238 psgcontrol=value; //&15; 239 #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH) 240 if ((M68KCONTEXT.cycles_counter+IO_CYCLE)==back_cycles) { 241 psg[back_ctrl]=back_value; 242 update_psg(new_value); 243 } 244 #endif 245 }else if (address==2 && psgcontrol<16) { 246 #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH) 247 back_ctrl=psgcontrol; 248 back_value=psg[psgcontrol]; 249 new_value=value; 250 #endif 251 update_psg(value); 252 } 253 #if defined(USE_FAME_CORE) && defined(USE_MOVEM_FAME_PATCH) 254 back_cycles=IO_CYCLE+M68KCONTEXT.cycles_counter; 255 #endif 256 return; 257 } 258 259 //Bus error? 260 if (address<0xb00) { 261 ExceptionGroup0(BUSERR, address|0xff8000, 0); 262 return; 263 } 264 265 //MFP emu 266 if (address<0x7c00) { 267 waitstate+=4; 268 switch(address) { 269 case MFP_AER&0x7fff: 270 mfp_aer = value; 271 break; 272 case MFP_DDR&0x7fff: 273 mfp_ddr = value; 274 break; 275 case MFP_IERA&0x7fff: 276 mfp_iera = value; 277 mfp_ipra &= mfp_iera; 278 break; 279 case MFP_IERB&0x7fff: 280 mfp_ierb = value; 281 mfp_iprb &= mfp_ierb; 282 break; 283 case MFP_IPRA&0x7fff: 284 mfp_ipra &= value; 285 break; 286 case MFP_IPRB&0x7fff: 287 mfp_iprb &= value; 288 break; 289 case MFP_ISRA&0x7fff: 290 mfp_isra &= value; 291 #ifndef USE_FAME_CORE 292 recalc_int = 1; 293 #endif 294 break; 295 case MFP_ISRB&0x7fff: 296 mfp_isrb &= value; 297 #ifndef USE_FAME_CORE 298 recalc_int = 1; 299 #endif 300 break; 301 case MFP_IMRA&0x7fff: 302 mfp_imra = value; 303 #ifndef USE_FAME_CORE 304 recalc_int = 1; 305 #endif 306 break; 307 case MFP_IMRB&0x7fff: 308 mfp_imrb = value; 309 #ifndef USE_FAME_CORE 310 recalc_int = 1; 311 #endif 312 break; 313 case MFP_IVR&0x7fff: 314 mfp_ivr = value; 315 break; 316 case MFP_TACR&0x7fff: 317 mfp_tacr = value&15; 318 #if defined(USE_FAME_CORE) && defined(USE_SHORT_SLICE) 319 if (mfp_ascale) 320 m68k_stop_emulating(); 321 #endif 322 mfp_ascale = mfpcycletab[mfp_tacr]; 323 break; 324 case MFP_TBCR&0x7fff: 325 mfp_tbcr = value&15; 326 #if defined(USE_FAME_CORE) && defined(USE_SHORT_SLICE) 327 if (mfp_bscale) 328 m68k_stop_emulating(); 329 #endif 330 mfp_bscale = mfpcycletab[mfp_tbcr]; 331 break; 332 case MFP_TCDCR&0x7fff: 333 mfp_tcdcr = value&0x77; 334 #if defined(USE_FAME_CORE) && defined(USE_SHORT_SLICE) 335 if (mfp_cscale || mfp_dscale) 336 m68k_stop_emulating(); 337 #endif 338 mfp_cscale = mfpcycletab[mfp_tcdcr>>4]; 339 mfp_dscale = mfpcycletab[mfp_tcdcr&7]; 340 break; 341 case MFP_TADR&0x7fff: 342 if (value==0) mfp_tadr=256<<20; else mfp_tadr=value<<20; 343 if (mfp_ascale==0) mfp_acount=mfp_tadr; 344 break; 345 case MFP_TBDR&0x7fff: 346 if (value==0) mfp_tbdr=256<<20; else mfp_tbdr=value<<20; 347 if (mfp_bscale==0) mfp_bcount=mfp_tbdr; 348 break; 349 case MFP_TCDR&0x7fff: 350 if (value==0) mfp_tcdr=256<<20; else mfp_tcdr=value<<20; 351 if (mfp_cscale==0) mfp_ccount=mfp_tcdr; 352 break; 353 case MFP_TDDR&0x7fff: 354 if (value==0) mfp_tddr=256<<20; else mfp_tddr=value<<20; 355 if (mfp_dscale==0) mfp_dcount=mfp_tddr; 356 break; 357 case MFP_SCR&0x7fff: 358 mfp_scr = value; 359 break; 360 case MFP_UCR&0x7fff: 361 mfp_ucr = value; 362 break; 363 case MFP_RSR&0x7fff: 364 mfp_rsr = value; 365 break; 366 case MFP_TSR&0x7fff: 367 mfp_tsr = value; 368 break; 369 case MFP_UDR&0x7fff: 370 mfp_udr = value; 371 break; 372 } 373 return; 374 } 375 376 switch(address) { 377 case ACIA1_SR&0x7fff: 378 waitstate+=8; 379 acia1_cr = value; 380 break; 381 case ACIA1_DR&0x7fff: 382 waitstate+=8; 383 IkbdRecv (value); 384 break; 385 case ACIA2_SR&0x7fff: 386 waitstate+=8; 387 acia2_cr = value; 388 break; 389 case ACIA2_DR&0x7fff: 390 waitstate+=8; 391 break; 392 } 393 394 } 395 396 PROGMEM void DoIOWW(uint32 address, uint16 value) 397 { 398 if (address >= VID_COL0 && address <= VID_COL15) { 399 vid_col[(address & 0x1f) >> 1] = value&0x777; 400 vid_flag = 1; 401 return; 402 } 403 else 404 switch (address) { 405 case DMA_MODE: 406 dma_mode = value; 407 break; 408 case DMA_CAR: 409 waitstate+=4; 410 if (dma_mode & 0x10) dma_scr = value; 411 else if (dma_mode & 0x8) dma_car = value; 412 else { 413 switch (dma_mode & 0x6) { 414 case 0: 415 fdc_command = value; 416 FDCCommand (); 417 break; 418 case 2: 419 fdc_track = value; 420 break; 421 case 4: 422 fdc_sector = value; 423 break; 424 case 6: 425 fdc_data = value; 426 break; 427 } 428 } 429 break; 430 default: 431 DoIOWB(address, value>>8); 432 DoIOWB(address+1, value); 433 break; 434 } 435 } 436 437 PROGMEM void DoIOWL(uint32 address, uint32 value) 438 { 439 DoIOWW(address, value>>16); 440 DoIOWW(address+2, value); 441 } 442 443 static __inline__ void calculate_vid_adr(void) 444 { 445 unsigned yet=(vid_cycle[cyclenext-IO_CYCLE]-vid_adr_cycleyet)&(~3); 446 vid_adr+=yet; 447 vid_adr_cycleyet+=yet; 448 } 449 450 PROGMEM uint8 DoIORB(uint32 address) 451 { 452 address&=0x7fff; 453 454 //Video and dma emu 455 if (address<0x800) { 456 switch (address) { 457 case MEM_CONF&0x7fff: 458 return memconf; 459 case VID_BASEH&0x7fff: 460 return vid_baseh; 461 case VID_BASEM&0x7fff: 462 return vid_basem; 463 case VID_ADRH&0x7fff: 464 calculate_vid_adr(); 465 return (unsigned char)(vid_adr>>16); 466 case VID_ADRM&0x7fff: 467 calculate_vid_adr(); 468 return (unsigned char)(vid_adr>>8); 469 case VID_ADRL&0x7fff: 470 calculate_vid_adr(); 471 return (unsigned char)(vid_adr); 472 case VID_SYNCMODE&0x7fff: 473 return vid_syncmode; 474 case VID_LINEWIDTH&0x7fff: 475 return 0xff; 476 case VID_SHIFTMODE&0x7fff: 477 return vid_shiftmode; 478 case DMA_ADRH&0x7fff: 479 return dma_adrh; 480 case DMA_ADRM&0x7fff: 481 return dma_adrm; 482 case DMA_ADRL&0x7fff: 483 return dma_adrl; 484 } 485 return VALUE_OPEN; 486 } 487 488 //Sound emu 489 if (address<0x900) { 490 address&=3; 491 if (!address) 492 { 493 waitstate+=4; 494 if (psgcontrol>=16) return 0xff; 495 return psg[psgcontrol]; 496 } 497 else if (address<4) 498 waitstate++; 499 return VALUE_OPEN; 500 } 501 502 //Bus error? 503 if (address<0xb00) { 504 ExceptionGroup0(BUSERR, address|0xff8000, 0); 505 return VALUE_OPEN; 506 } 507 508 //MFP emu 509 if (address<0x7c00) { 510 waitstate+=4; 511 switch(address) { 512 case MFP_GPIP&0x7fff: 513 return mfp_gpip; 514 case MFP_AER&0x7fff: 515 return mfp_aer; 516 case MFP_DDR&0x7fff: 517 return mfp_ddr; 518 case MFP_IERA&0x7fff: 519 return mfp_iera; 520 case MFP_IERB&0x7fff: 521 return mfp_ierb; 522 case MFP_IPRA&0x7fff: 523 return mfp_ipra; 524 case MFP_IPRB&0x7fff: 525 return mfp_iprb; 526 case MFP_ISRA&0x7fff: 527 return mfp_isra; 528 case MFP_ISRB&0x7fff: 529 return mfp_isrb; 530 case MFP_IMRA&0x7fff: 531 return mfp_imra; 532 case MFP_IMRB&0x7fff: 533 return mfp_imrb; 534 case MFP_IVR&0x7fff: 535 return mfp_ivr; 536 case MFP_TACR&0x7fff: 537 return mfp_tacr; 538 case MFP_TBCR&0x7fff: 539 return mfp_tbcr; 540 case MFP_TCDCR&0x7fff: 541 return mfp_tcdcr; 542 case MFP_TADR&0x7fff: 543 return (mfp_acount+0xfffff)>>20; 544 case MFP_TBDR&0x7fff: 545 return (mfp_bcount+0xfffff)>>20; 546 case MFP_TCDR&0x7fff: 547 return (mfp_ccount+0xfffff)>>20; 548 case MFP_TDDR&0x7fff: 549 return (mfp_dcount+0xfffff)>>20; 550 case MFP_SCR&0x7fff: 551 return mfp_scr; 552 case MFP_UCR&0x7fff: 553 return mfp_ucr; 554 case MFP_RSR&0x7fff: 555 return mfp_rsr; 556 case MFP_TSR&0x7fff: 557 return mfp_tsr; 558 case MFP_UDR&0x7fff: 559 return mfp_udr; 560 } 561 return VALUE_OPEN; 562 } 563 564 //Acia emu 565 switch(address) { 566 case ACIA1_SR&0x7fff: 567 waitstate+=8; 568 return 2 | acia1_sr; 569 case ACIA1_DR&0x7fff: 570 waitstate+=8; 571 if (!(acia1_cr & 0x20)) {acia1_sr&=0x7e; mfp_gpip|=0x10;} 572 return acia1_dr; 573 case ACIA2_SR&0x7fff: 574 waitstate+=8; 575 return 2; 576 case ACIA2_DR&0x7fff: 577 waitstate+=8; 578 return 1; 579 } 580 return VALUE_OPEN; 581 582 } 583 584 PROGMEM uint16 DoIORW(uint32 address) 585 { 586 if (address >= VID_COL0 && address <= VID_COL15) { 587 return vid_col[(address & 0x1f) >> 1]; 588 } 589 switch (address) { 590 case DMA_SR: 591 return dma_sr; 592 case DMA_CAR: 593 waitstate+=4; 594 if (dma_mode & 0x10) return dma_scr; 595 else if (dma_mode & 0x8) return dma_car; 596 else { 597 switch (dma_mode & 0x6) { 598 case 0: 599 if (!fdc_int) mfp_gpip |= 0x20; 600 return fdc_status; 601 case 2: 602 return fdc_track; 603 case 4: 604 return fdc_sector; 605 case 6: 606 return fdc_data; 607 } 608 return 0; 609 } 610 default: 611 return (((uint32)DoIORB(address))<<8)+DoIORB(address+1); 612 } 613 } 614 615 PROGMEM uint32 DoIORL(uint32 address) 616 { 617 return (((uint32)DoIORW(address))<<16)+DoIORW(address+2); 618 } 619