Vmachine.c
1 /***************************************************************************** 2 3 This file is part of x2600, the Atari 2600 Emulator 4 =================================================== 5 6 Copyright 1996 Alex Hornby. For contributions see the file CREDITS. 7 8 This software is distributed under the terms of the GNU General Public 9 License. This is free software with ABSOLUTELY NO WARRANTY. 10 11 See the file COPYING for details. 12 13 $Id: vmachine.c,v 2.22 1997/11/22 14:27:47 ahornby Exp $ 14 ******************************************************************************/ 15 //This file was modified from its original version for use in PocketVCS 16 // by Stuart Russell 17 18 /* 19 The virtual machine. Contains the RIOT timer code, and hardware 20 initialisation. 21 */ 22 23 #include <stdio.h> 24 #include "types.h" 25 #include "address.h" 26 #include "options.h" 27 #include "display.h" 28 #include "raster.h" 29 #include "cpu.h" 30 #include "collision.h" 31 #include "sound.h" 32 #include "vmachine.h" 33 #include "tiasound.h" 34 35 #include "emuapi.h" 36 37 #define snd 1 38 39 extern void BlitScreen(void); 40 extern int nOptions_SoundBufSize; 41 extern int nOptions_SoundOn; 42 int Touchpadx=0; 43 int Touchpady=0; 44 //extern int Touchpadx; 45 //extern int Touchpady; 46 extern int nOptions_Landscape; 47 extern int nOptions_SkipFrames; 48 49 50 51 /* The Rom define might need altering for paged carts */ 52 /* Enough for 16k carts */ 53 int rom_size; 54 55 /* Used as a simple file buffer to store the data */ 56 // JMH 57 //BYTE theCart[16384]; 58 //BYTE theCart[4096]; 59 BYTE * theCart=0; 60 61 /* Scratch area for those banking types that require memcpy() */ 62 //BYTE cartScratch[4096]; 63 BYTE * cartScratch=0; 64 /* Area for those carts containing RAM */ 65 //BYTE cartRam[1024]; 66 BYTE * cartRam=0; 67 68 /* Pointer to start of ROM data */ 69 BYTE *theRom; 70 71 BYTE theRam[128]; 72 BYTE tiaRead[0x0e]; 73 BYTE tiaWrite[0x2d]; 74 BYTE keypad[2][4]; 75 76 /* These don't strictly need so much space */ 77 BYTE riotRead[0x298]; 78 BYTE riotWrite[0x298]; 79 80 /* 81 Hardware addresses not programmer accessible 82 */ 83 84 /* Set if whole emulator is reset */ 85 int reset_flag = 0; 86 87 /* The timer resolution, can be 1,8,64,1024 */ 88 int timer_res = 32; 89 int timer_count = 0; 90 int timer_clks = 0; 91 extern CLOCK clk; 92 extern int beamadj; 93 94 /* Electron beam position */ 95 int ebeamx, ebeamy, sbeamx; 96 97 /* The state of the electron beam */ 98 #define VSYNCSTATE 1 99 #define VBLANKSTATE 2 100 #define HSYNCSTATE 4 101 #define DRAWSTATE 8 102 #define OVERSTATE 16 103 int vbeam_state; /* 1 2 8 or 16 */ 104 int hbeam_state; /* 4 8 or 16 */ 105 106 /* The tv size, varies with PAL/NTSC */ 107 int tv_width, tv_height, tv_vsync, tv_vblank, tv_overscan, tv_frame, tv_hertz, 108 tv_hsync; 109 110 111 PlayField pf[2]; 112 113 Paddle paddle[4]; 114 115 Player pl[2]; 116 117 Missile ml[3]; 118 119 120 121 #define MAXLIST 80 122 /* The various display lists */ 123 struct RasterChange pl_change[2][MAXLIST], pf_change[1][MAXLIST], unified[MAXLIST]; 124 125 /* The display list counters */ 126 int pl_change_count[2], pf_change_count[1], unified_count; 127 128 129 /*************************************************************************** 130 Let the functions begin! 131 ****************************************************************************/ 132 void 133 init_machine (void) 134 { 135 if (theCart == 0) theCart = (BYTE *)emu_Malloc(16384); 136 if (cartScratch == 0) cartScratch = (BYTE *)emu_Malloc(4096); 137 if (cartRam == 0) cartRam = (BYTE *)emu_Malloc(1024); 138 } 139 140 /* Device independent screen initialisations */ 141 void 142 init_screen (void) 143 { 144 145 /* Set the electron beam to the top left */ 146 ebeamx = -tv_hsync; 147 ebeamy = 0; 148 sbeamx = 0; 149 vbeam_state = VSYNCSTATE; 150 hbeam_state = OVERSTATE; 151 152 tv_vsync = 3; 153 tv_hsync = 68; 154 switch (base_opts.tvtype) 155 { 156 case NTSC: 157 tv_width = 160; 158 tv_height = 192; 159 tv_vblank = 40; 160 tv_overscan = 30; 161 tv_frame = 262; 162 tv_hertz = 60; 163 break; 164 case PAL: 165 case SECAM: 166 tv_width = 160; 167 tv_height = 228; 168 tv_vblank = 48; 169 tv_overscan = 36; 170 tv_frame = 312; 171 tv_hertz = 50; 172 break; 173 } 174 175 } 176 177 /* Displays the tv screen */ 178 void tv_display (void) 179 { 180 /* Only display if the frame is a valid one. */ 181 //if ( (tv_counter % nOptions_SkipFrames) == 0) 182 //{ 183 emu_DrawScreen(VBuf, tv_width, tv_height, tv_width); 184 emu_DrawVsync(); 185 //} 186 //tv_counter++; 187 } 188 189 /* Initialise the RIOT (also known as PIA) */ 190 void 191 init_riot (void) 192 { 193 int i; 194 195 /* Reset the arrays */ 196 for(i=0; i< 0x298;i++) 197 { 198 riotRead[i]=0; 199 riotWrite[i]=0; 200 } 201 202 /* Wipe the RAM */ 203 for (i = 0; i < 0x80; i++) 204 theRam[i] = 0; 205 206 /* Set the timer to zero */ 207 riotRead[INTIM] = 0; 208 209 /* Set the joysticks and switches to input */ 210 riotWrite[SWACNT] = 0; 211 riotWrite[SWBCNT] = 0; 212 213 /* Centre the joysticks */ 214 riotRead[SWCHA] = 0xff; 215 riotRead[SWCHB] = 0x0b; 216 217 /* Set the counter resolution */ 218 timer_res = 32; 219 timer_count = 0; 220 timer_clks = 0; 221 } 222 223 /* Initialise the television interface adaptor (TIA) */ 224 void 225 init_tia (void) 226 { 227 int i; 228 for(i=0; i< 0x2d;i++) 229 { 230 tiaWrite[i]=0; 231 } 232 for(i=0; i< 0x0e;i++) 233 { 234 tiaRead[i]=0; 235 } 236 237 tiaWrite[CTRLPF] = 0x00; 238 for (i = 0; i < 2; i++) 239 { 240 pl[i].hmm = 0x0; 241 pl[i].x = 0x0; 242 pl[i].nusize = 0; 243 pl[i].grp = 0; 244 pl[i].vdel = 0; 245 pl[i].vdel_flag = 0; 246 pl_change_count[i] = 0; 247 } 248 249 pl[0].mask = PL0_MASK; 250 pl[1].mask = PL1_MASK; 251 ml[0].mask = ML0_MASK; 252 ml[1].mask = ML1_MASK; 253 reset_collisions (); 254 255 pf_change_count[0] = 0; 256 unified_count = 0; 257 for (i = 0; i < 3; i++) 258 { 259 ml[i].x = 0; 260 ml[i].hmm = 0; 261 ml[i].enabled = 0; 262 ml[i].locked = 0; 263 ml[i].width = 0; 264 ml[i].vdel = 0; 265 ml[i].vdel_flag = 0; 266 } 267 268 tiaWrite[VBLANK] = 0; 269 tiaRead[INPT4] = 0x80; 270 tiaRead[INPT5] = 0x80; 271 272 /* Set up the colour table */ 273 colour_table[P0M0_COLOUR]= 0; 274 colour_table[P1M1_COLOUR]= 0; 275 colour_table[PFBL_COLOUR] = 0; 276 colour_table[BK_COLOUR] = 0; 277 } 278 279 void 280 init_memory(void) 281 { 282 int i; 283 for(i=0;i<1024; i++) 284 cartRam[i]=0; 285 for(i=0; i<128;i++) 286 theRam[i]=0; 287 } 288 289 void 290 init_banking (void) 291 { 292 /* Set to the first bank */ 293 //dbg_message(DBG_NORMAL, "rom_size is set at %d bytes\n", rom_size); 294 if (rom_size == 2048) 295 theRom = &theCart[rom_size - 2048]; 296 else 297 theRom = &theCart[rom_size - 4096]; 298 //JMH 299 //switch(base_opts.bank) 300 // { 301 // case 3: 302 // /* Parker Brothers 8k E0 */ 303 // memcpy(&cartScratch[0xc00],&theCart[0x1c00],1024); 304 // memcpy(&cartScratch[0],&theCart[0],3072); 305 // theRom=cartScratch; 306 // break; 307 // default: 308 // break; 309 // } 310 } 311 312 extern void init_cpu( ADDRESS addr); 313 314 /* Main hardware startup */ 315 void 316 init_hardware (void) 317 { 318 // dbg_message(DBG_NORMAL,"Setting Up hardware\n"); 319 init_screen (); 320 init_riot (); 321 init_tia (); 322 init_raster (); 323 init_memory(); 324 init_banking(); 325 init_cpu (0xfffc); 326 } 327 328 /* Do a raster change */ 329 __inline void 330 do_raster_change (int i, int type, int val, struct RasterChange *rc) 331 { 332 rc->x = ebeamx + beamadj; 333 rc->type = type; 334 rc->val = val; 335 } 336 337 /* Do a raster change on the unified list */ 338 /* type: type of change */ 339 /* val: value of change */ 340 __inline void 341 do_unified_change (int type, int val) 342 { 343 if (unified_count < MAXLIST) 344 { 345 unified[unified_count].x = ebeamx + beamadj; 346 unified[unified_count].type = type; 347 unified[unified_count].val = val; 348 unified_count++; 349 } 350 } 351 352 /* Do a player raster change */ 353 /* i: player to change. 0 or 1 */ 354 /* type: type of change */ 355 /* val: value of change */ 356 __inline void 357 do_plraster_change (int i, int type, int val) 358 { 359 int plc = pl_change_count[i]; 360 /*printf("Raster change i=%d, x=%d, type=%d, val=%d\n", i, x, type, val); */ 361 if (plc < MAXLIST) 362 { 363 do_raster_change (i, type, val, &pl_change[i][plc]); 364 if (type == 1) 365 pl_change[i][plc].x -= 3; 366 pl_change_count[i]++; 367 } 368 } 369 370 /* Do a playfield raster change */ 371 /* i: playfield to change. Depreciated, as 0 is now only one used */ 372 /* type: type of change */ 373 /* val: value of change */ 374 __inline void 375 do_pfraster_change (int i, int type, int val) 376 { 377 int pfc = pf_change_count[i]; 378 /* 379 if(ebeamy>=100) { 380 printf("Raster change i=%d, x=%d, type=%d, val=%d\n", 381 i, ebeamx+beamadj, type, val); 382 //show(); 383 } 384 */ 385 if (pfc < MAXLIST) 386 { 387 do_raster_change (i, type, val, &pf_change[i][pfc]); 388 pf_change_count[i]++; 389 } 390 } 391 392 393 /* Use a unified change */ 394 /* rc: unified change structure to use */ 395 __inline void 396 use_unified_change (struct RasterChange *rc) 397 { 398 switch (rc->type) 399 { 400 case 0: 401 /* P0MO colour */ 402 colour_table[P0M0_COLOUR] = rc->val; 403 break; 404 case 1: 405 /* POM0 colour */ 406 colour_table[P1M1_COLOUR] = rc->val; 407 break; 408 case 2: 409 /* PFBL colour */ 410 colour_table[PFBL_COLOUR] = rc->val; 411 break; 412 case 3: 413 /* BK colour */ 414 colour_table[BK_COLOUR] = rc->val; 415 break; 416 case 4: 417 /* Priority change Normal */ 418 if(rc->val) 419 norm_val=1; 420 else 421 norm_val=0; 422 colour_lookup=colour_ptrs[norm_val][scores_val]; 423 break; 424 case 5: 425 /* Priority change Scores */ 426 if(rc->val) 427 { 428 if(rc->x < 80) 429 scores_val=1; 430 else 431 scores_val=2; 432 } 433 else 434 scores_val=0; 435 colour_lookup=colour_ptrs[norm_val][scores_val]; 436 break; 437 } 438 } 439 440 /* Use a playfield change */ 441 /* pl: playfield to change */ 442 /* rc: change to make */ 443 __inline void 444 use_pfraster_change (PlayField *pl, struct RasterChange *rc) 445 { 446 switch (rc->type) 447 { 448 case 0: 449 /* PF0 */ 450 pl->pf0 = rc->val; 451 break; 452 case 1: 453 /* PF1 */ 454 pl->pf1 = rc->val; 455 break; 456 case 2: 457 /* PF2 */ 458 pl->pf2 = rc->val; 459 break; 460 case 3: 461 /* Reflection */ 462 pl->ref = rc->val; 463 break; 464 } 465 } 466 467 /* Use a player change */ 468 /* pl: player to change */ 469 /* rc: change to make */ 470 __inline void 471 use_plraster_change ( Player *pl, struct RasterChange *rc) 472 { 473 switch (rc->type) 474 { 475 case 0: 476 /* GRP */ 477 pl->grp = rc->val; 478 break; 479 /* Vertical delay */ 480 case 1: 481 pl->vdel = pl->grp; 482 break; 483 } 484 } 485 486 487 int 488 do_paddle (int padnum) 489 { 490 int res = 0x00; 491 int x=0; 492 if ((tiaWrite[VBLANK] & 0x80) == 0) 493 { 494 if (!nOptions_Landscape){ 495 x=240-Touchpadx; 496 x=x*66; 497 if (paddle[padnum].val > x) 498 res=0x80; 499 500 }else{ 501 x=320-Touchpady; 502 x=x*50; 503 if (paddle[padnum].val > x) 504 res=0x80; 505 } 506 507 if (x > clk) 508 res = 0x00; 509 } 510 return res; 511 } 512 513 /* Calculate the keypad rows */ 514 /* i.e. when reading from INPTx we don't know the row */ 515 BYTE 516 do_keypad (int pad, int col) 517 { 518 BYTE res= 0x80; 519 520 // read_keypad(pad); 521 522 /* Bottom row */ 523 if(pad==0) { 524 if( (riotWrite[SWCHA] & 0x80) && keypad[pad][col]==3) 525 res=0x00; 526 /* Third row */ 527 if( (riotWrite[SWCHA] & 0x40) && keypad[pad][col]==2) 528 res=0x00; 529 if( (riotWrite[SWCHA] & 0x20) && keypad[pad][col]==1) 530 res=0x00; 531 if( (riotWrite[SWCHA] & 0x10) && keypad[pad][col]==0) 532 res=0x00; 533 } 534 else { 535 /* Bottom row */ 536 if( (riotWrite[SWCHA] & 0x80) && keypad[pad][col]==3) 537 res=0x00; 538 /* Third row */ 539 if( (riotWrite[SWCHA] & 0x40) && keypad[pad][col]==2) 540 res=0x00; 541 if( (riotWrite[SWCHA] & 0x20) && keypad[pad][col]==1) 542 res=0x00; 543 if( (riotWrite[SWCHA] & 0x10) && keypad[pad][col]==0) 544 res=0x00; 545 } 546 return res; 547 } 548 549 550 /* 551 Called when the timer is set . 552 Note that res is the bit shift, not absolute value. 553 Assumes that any timer interval set will last longer than the instruction 554 setting it. 555 */ 556 /* res: timer interval resolution as a bit shift value */ 557 /* count: the number of intervals to set */ 558 /* clkadj: the number of CPU cycles into the current instruction */ 559 void 560 set_timer (int res, int count, int clkadj) 561 { 562 timer_count = count << res; 563 timer_clks = clk + clkadj; 564 timer_res = res; 565 } 566 567 /* New timer code, now only called on a read of INTIM */ 568 /* clkadj: the number of CPU cycles into the current instruction */ 569 /* returns: the current timer value */ 570 BYTE 571 do_timer (int clkadj) 572 { 573 BYTE result; 574 int delta; 575 int value; 576 577 delta = clk - timer_clks; 578 value = delta >> timer_res; 579 if (delta <= timer_count) 580 { /* Timer is still going down in res intervals */ 581 result = value; 582 } 583 else 584 { 585 if (value == 0) 586 /* Timer is in holding period */ 587 result = 0; 588 else 589 { 590 /* Timer is descending from 0xff in clock intervals */ 591 set_timer (0, 0xff, clkadj); 592 result = 0; 593 } 594 } 595 596 /* printf("Timer result=%d\n", result); */ 597 return result; 598 } 599 600 #ifdef snd 601 //extern unsigned char *sounddata; 602 //#define SoundBufSize 256 603 //unsigned char sounddata[SoundBufSize]; 604 #endif 605 606 /* Do the screen related part of a write to VBLANK */ 607 /* b: the byte written */ 608 void 609 do_vblank (BYTE b) 610 { 611 612 if (b & 0x02) 613 { 614 /* Start vertical blank */ 615 vbeam_state = VBLANKSTATE; 616 #ifdef snd 617 // Tia_process(sounddata, SoundBufSize); 618 // CESound_play_sample(sounddata, nOptions_SoundBufSize); 619 #endif 620 /* Also means we can update screen */ 621 tv_display (); 622 } 623 else 624 { 625 /* End vblank, and start first hsync drawing */ 626 int i; 627 628 vbeam_state = DRAWSTATE; 629 hbeam_state = HSYNCSTATE; 630 /* Set up the screen */ 631 for (i = 0; i < unified_count; i++) 632 use_unified_change (&unified[i]); 633 /* Hope for a WSYNC, but just in case */ 634 ebeamx = -tv_hsync; 635 ebeamy = 0; 636 } 637 } 638 639 640 //int count = 1; 641 642 /* do a horizontal sync */ 643 void 644 do_hsync (void) 645 { 646 /* Only perform heavy stuff if electron beam is in correct position */ 647 if (vbeam_state == DRAWSTATE && (ebeamx > -tv_hsync)) 648 { 649 // if (!(count--)) 650 // { 651 // count = 2; 652 tv_raster (ebeamy); 653 654 // } 655 /* Fix the clock value */ 656 clk += (ebeamx - tv_width) / 3; 657 ebeamy++; 658 } 659 hbeam_state = HSYNCSTATE; 660 ebeamx = -tv_hsync; 661 sbeamx = 0; 662 } 663 664 /* Main screen logic */ 665 /* clks: CPU clock length of last instruction */ 666 __inline void 667 do_screen (int clks) 668 { 669 switch (vbeam_state) 670 { 671 case VSYNCSTATE: 672 case VBLANKSTATE: 673 switch (hbeam_state) 674 { 675 case HSYNCSTATE: 676 ebeamx += clks * 3; 677 if (ebeamx >= 0) 678 { 679 hbeam_state = DRAWSTATE; 680 } 681 break; 682 case DRAWSTATE: 683 ebeamx += clks * 3; 684 if (ebeamx >= tv_width) 685 { 686 ebeamx -= (tv_hsync + tv_width); 687 /* Insert hsync stuff here */ 688 sbeamx = ebeamx; 689 hbeam_state = HSYNCSTATE; 690 } 691 break; 692 case OVERSTATE: 693 break; 694 } 695 break; 696 case DRAWSTATE: 697 switch (hbeam_state) 698 { 699 case HSYNCSTATE: 700 ebeamx += clks * 3; 701 if (ebeamx >= 0) 702 { 703 hbeam_state = DRAWSTATE; 704 } 705 break; 706 case DRAWSTATE: 707 ebeamx += clks * 3; 708 if (ebeamx >= tv_width) 709 { 710 /* Insert hsync stuff here */ 711 sbeamx = ebeamx; 712 ebeamx -= (tv_hsync + tv_width); 713 tv_raster (ebeamy); 714 ebeamy++; 715 hbeam_state = HSYNCSTATE; 716 } 717 if (ebeamy >= tv_height + tv_overscan) 718 { 719 vbeam_state = OVERSTATE; 720 ebeamy = 0; 721 } 722 break; 723 case OVERSTATE: 724 break; 725 } 726 break; 727 case OVERSTATE: 728 break; 729 } 730 } 731