/ MCUME_teensy / teensyvcs / Vmachine.c
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