Annotation of generator/main/event.c, revision 1.1.1.3

1.1       root        1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
                      2: 
                      3: #include "generator.h"
                      4: #include "vdp.h"
                      5: #include "cpu68k.h"
                      6: #include "cpuz80.h"
                      7: #include "reg68k.h"
                      8: #include "ui.h"
                      9: #include "gensound.h"
                     10: 
                     11: #include "snprintf.h"
                     12: 
1.1.1.2   root       13: /* due to DMA transfers, event_nextevent can be called during an instruction
                     14:    cycle (reg68k_external_execute -> instruction -> vdp write -> dma ->
                     15:    event_freeze -> event_nextevent).  Be careful */
                     16: 
1.1       root       17: /* time for next event - update vdp_event - return when to call again */
                     18: 
                     19: inline void event_nextevent(void)
                     20: {
                     21:   /* call this when it *is* time for the next event as dictated by vdp_event,
                     22:      so we switch on it and update vdp_event at the same time */
                     23: 
1.1.1.2   root       24:   switch (vdp_event++) {
1.1       root       25:   case 0:
1.1.1.2   root       26:   EVENT_NEWLINE:
1.1       root       27:     LOG_DEBUG1(("%08X due %08X, %d A: %d (cd=%d)",
                     28:                 cpu68k_clocks, vdp_event_start,
                     29:                 vdp_line - vdp_visstartline, vdp_reg[10],
                     30:                 vdp_hskip_countdown));
1.1.1.3 ! root       31:     if (vdp_line == 0)
        !            32:       sound_startfield();
1.1.1.2   root       33:     if (vdp_line == (vdp_visstartline - 1)) {
1.1       root       34:       vdp_vblank = 0;
1.1.1.2   root       35:       vdp_hskip_countdown = vdp_reg[10];
1.1       root       36:     }
                     37:     if ((vdp_nextevent = vdp_event_vint - cpu68k_clocks) > 0)
                     38:       break;
                     39:     vdp_event++;
                     40:   case 1:
                     41:     LOG_DEBUG1(("%08X due %08X, %d B: %d (cd=%d)",
                     42:                 cpu68k_clocks, vdp_event_vint,
                     43:                 vdp_line - vdp_visstartline, vdp_reg[10],
                     44:                 vdp_hskip_countdown));
                     45:     if (vdp_line == vdp_visendline) {
                     46:       vdp_vblank = 1;
                     47:       vdp_vsync = 1;
1.1.1.2   root       48:       if (vdp_reg[1] & 1 << 5)
                     49:         reg68k_external_autovector(6);  /* vertical interrupt */
1.1       root       50:     }
                     51:     if ((vdp_nextevent = vdp_event_hint - cpu68k_clocks) > 0)
                     52:       break;
                     53:     vdp_event++;
                     54:   case 2:
                     55:     LOG_DEBUG1(("%08X due %08X, %d C: %d (cd=%d)",
                     56:                 cpu68k_clocks, vdp_event_hint,
                     57:                 vdp_line - vdp_visstartline, vdp_reg[10],
                     58:                 vdp_hskip_countdown));
                     59:     if (vdp_line >= vdp_visstartline && vdp_line < vdp_visendline)
                     60:       vdp_hblank = 1;
1.1.1.2   root       61:     if (vdp_line == (vdp_visstartline - 1) || (vdp_line > vdp_visendline)) {
1.1       root       62:       vdp_hskip_countdown = vdp_reg[10];
                     63:       LOG_DEBUG1(("H counter reset to %d", vdp_hskip_countdown));
                     64:     }
1.1.1.2   root       65:     if (vdp_reg[0] & 1 << 4) {
1.1       root       66:       LOG_DEBUG1(("pre = %d", vdp_hskip_countdown));
                     67:       if (vdp_hskip_countdown-- == 0) {
                     68:         LOG_DEBUG1(("in = %d", vdp_hskip_countdown));
                     69:         /* re-initialise counter */
                     70:         vdp_hskip_countdown = vdp_reg[10];
                     71:         LOG_DEBUG1(("H counter looped to %d", vdp_hskip_countdown));
1.1.1.2   root       72:         if (vdp_line >= vdp_visstartline - 1 && vdp_line < vdp_visendline - 1)
                     73:           reg68k_external_autovector(4);        /* horizontal interrupt */
1.1       root       74:         /* since this game is obviously timing sensitive, we sacrifice
                     75:            executing the right number of 68k clocks this frame in order
                     76:            to accurately do the moments following H-Int */
                     77:         cpu68k_clocks = vdp_event_hint;
                     78:       }
                     79:       LOG_DEBUG1(("post = %d", vdp_hskip_countdown));
                     80:     }
1.1.1.2   root       81:     /* the 68k is frozen for 68k ram to vram copies, see event_freeze */
                     82:     if (vdp_dmabytes) {         /* blank mode ? */
                     83:       vdp_dmabytes -= (vdp_vblank || !(vdp_reg[1] & 1 << 6))
1.1       root       84:         ? ((vdp_reg[12] & 1) ? 205 : 167) : ((vdp_reg[12] & 1) ? 18 : 16);
                     85:       if (vdp_dmabytes <= 0) {
                     86:         vdp_dmabytes = 0;
                     87:         vdp_dmabusy = 0;
                     88:       }
                     89:     }
                     90:     if ((vdp_nextevent = vdp_event_hdisplay - cpu68k_clocks) > 0)
                     91:       break;
                     92:     vdp_event++;
                     93:   case 3:
                     94:     LOG_DEBUG1(("%08X due %08X, %d D: %d (cd=%d)",
                     95:                 cpu68k_clocks, vdp_event_hdisplay,
                     96:                 vdp_line - vdp_visstartline, vdp_reg[10],
                     97:                 vdp_hskip_countdown));
1.1.1.3 ! root       98:     ui_line(vdp_line - vdp_visstartline + 1);
1.1       root       99:     if ((vdp_nextevent = vdp_event_end - cpu68k_clocks) > 0)
                    100:       break;
                    101:     /* vdp_event++; - not required, we set vdp_event to 0 below */
                    102:   case 4:
                    103:     /* end of line, do sound, platform stuff */
                    104:     LOG_DEBUG1(("%08X due %08X, %d E: %d (cd=%d)",
                    105:                 cpu68k_clocks, vdp_event_end,
1.1.1.2   root      106:                 vdp_line - vdp_visstartline, vdp_reg[10],
1.1       root      107:                 vdp_hskip_countdown));
                    108:     if (vdp_line >= vdp_visstartline && vdp_line < vdp_visendline)
                    109:       vdp_hblank = 0;
                    110:     cpuz80_sync();
1.1.1.3 ! root      111:     sound_line();
1.1       root      112:     vdp_line++;
                    113:     if (vdp_line == vdp_visendline)
                    114:       cpuz80_interrupt();
                    115:     if (vdp_line == vdp_totlines) {
1.1.1.3 ! root      116:       /* the order of these is important */
        !           117:       sound_endfield(); /* must be before ui_endfield for GYM log */
1.1       root      118:       ui_endfield();
1.1.1.3 ! root      119:       vdp_endfield(); /* must be after ui_endfield as it alters state */
1.1       root      120:       cpuz80_endfield();
                    121:       cpu68k_endfield();
                    122:       cpu68k_frames++;
                    123:     }
1.1.1.2   root      124:     vdp_event_start += vdp_clksperline_68k;
                    125:     vdp_event_vint += vdp_clksperline_68k;
                    126:     vdp_event_hint += vdp_clksperline_68k;
                    127:     vdp_event_hdisplay += vdp_clksperline_68k;
                    128:     vdp_event_end += vdp_clksperline_68k;
1.1       root      129:     vdp_event = 1;
                    130:     goto EVENT_NEWLINE;
1.1.1.2   root      131:   }                             /* switch */
1.1       root      132: }
                    133: 
                    134: /*** event_doframe - execute until the end of the current frame ***/
                    135: 
                    136: void event_doframe(void)
                    137: {
                    138:   unsigned int startframe = cpu68k_frames;
                    139: 
                    140:   do {
                    141:     while (vdp_nextevent > 0)
                    142:       vdp_nextevent = -reg68k_external_execute(vdp_nextevent);
                    143:     event_nextevent();
1.1.1.2   root      144:   }
                    145:   while (startframe == cpu68k_frames);
1.1       root      146: 
                    147: }
                    148: 
                    149: /*** event_step - execute one instruction with no caching ***/
                    150: 
                    151: void event_dostep(void)
                    152: {
                    153:   /* execute one instruction and subtract from vdp_nextevent those cycles */
1.1.1.2   root      154:   vdp_nextevent -= reg68k_external_step();
1.1       root      155:   /* if negative or 0, i.e. we have done all the cycles we need to this event,
                    156:      call event_nextevent! */
                    157:   while (vdp_nextevent <= 0)
                    158:     event_nextevent();
                    159: }
                    160: 
                    161: /*** event_freeze_clocks - freeze 68k for given clock cycles ***/
                    162: 
                    163: /* NB: this routine is called by event_freeze which is called by
                    164:    vdp routines.  This could all happen IN THE MIDDLE OF A BLOCK at which
                    165:    point cpu68k_clocks will have been updated but vdp_nextevent will not! 
                    166:    therefore we must at this point work out what vdp_nextevent should be
                    167:    at the current moment in time, add on the clocks, wind forward time and
                    168:    then subtract the clocks that will be added later */
                    169: 
                    170: void event_freeze_clocks(unsigned int clocks)
                    171: {
                    172:   int missed = 0;
                    173: 
                    174:   /* first - fix vdp_nextevent to be correct for right now, due to block
                    175:      marking delay */
                    176: 
                    177:   /* find out how many clocks vdp_nextevent has missed */
                    178:   /* modify vdp_nextevent to reflect the real state as of now */
                    179: 
                    180:   switch (vdp_event) {
                    181:   case 0:
                    182:     missed = vdp_nextevent - (vdp_event_start - cpu68k_clocks);
1.1.1.2   root      183:     vdp_nextevent -= missed;
1.1       root      184:     break;
                    185:   case 1:
                    186:     missed = vdp_nextevent - (vdp_event_vint - cpu68k_clocks);
1.1.1.2   root      187:     vdp_nextevent -= missed;
1.1       root      188:     break;
                    189:   case 2:
                    190:     missed = vdp_nextevent - (vdp_event_hint - cpu68k_clocks);
1.1.1.2   root      191:     vdp_nextevent -= missed;
1.1       root      192:     break;
                    193:   case 3:
                    194:     missed = vdp_nextevent - (vdp_event_hdisplay - cpu68k_clocks);
1.1.1.2   root      195:     vdp_nextevent -= missed;
1.1       root      196:     break;
                    197:   case 4:
                    198:     missed = vdp_nextevent - (vdp_event_end - cpu68k_clocks);
1.1.1.2   root      199:     vdp_nextevent -= missed;
1.1       root      200:     break;
                    201:   default:
                    202:     printf("assertion failed: bad vdp_event in event_freeze_clocks: %d\n",
                    203:            vdp_event);
                    204:   }
                    205: 
                    206:   /* move cpu68k_clocks and vdp_nextevent forward in time */
                    207: 
1.1.1.2   root      208:   cpu68k_clocks += clocks;
                    209:   vdp_nextevent -= clocks;
1.1       root      210: 
                    211:   /* now catch up events */
                    212: 
                    213:   while (vdp_nextevent <= 0)
                    214:     event_nextevent();
                    215: 
                    216:   /* and then un-adjust vdp_nextevent, as the block marking code will update
                    217:      this later */
                    218: 
1.1.1.2   root      219:   vdp_nextevent += missed;
1.1       root      220: }
                    221: 
                    222: /*** event_freeze - freeze 68k for given VDP byte transfer ***/
                    223: 
                    224: void event_freeze(unsigned int bytes)
                    225: {
                    226:   int wide = vdp_reg[12] & 1;
                    227:   int clocks, possible;
                    228:   double percent_possible;
                    229:   int togo = (int)bytes;
                    230: 
1.1.1.2   root      231:   cpu68k_frozen = 1;            /* prohibit interrupts since PC is not known in the
                    232:                                    middle of a 68k block due to register mappings */
1.1       root      233: 
                    234:   while (togo > 0) {
                    235:     /* clocks will be negative if we're in the middle of a cpu block */
                    236:     clocks = vdp_event_end - cpu68k_clocks;
                    237:     if (clocks < 0)
                    238:       clocks = 0;
1.1.1.2   root      239:     percent_possible = clocks / vdp_clksperline_68k;
                    240:     if (vdp_reg[1] & 1 << 6 && !vdp_vblank) {
1.1       root      241:       /* vdp active */
1.1.1.2   root      242:       possible = (unsigned int)(percent_possible * (wide ? 18 : 16));
1.1       root      243:     } else {
                    244:       /* vdp inactive */
1.1.1.2   root      245:       possible = (unsigned int)(percent_possible * (wide ? 205 : 167));
1.1       root      246:     }
                    247:     if (togo >= possible) {
                    248:       event_freeze_clocks(clocks);
1.1.1.2   root      249:       togo -= possible;
1.1       root      250:     } else {
1.1.1.2   root      251:       event_freeze_clocks(((double)togo / possible) * clocks);
1.1       root      252:       togo = 0;
                    253:     }
                    254:   }
                    255:   cpu68k_frozen = 0;
                    256: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.