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

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 */
1.1.1.4 ! root      117:       sound_endfield(); /* must be before ui_endfield for GYM log and also
        !           118:                            for avi output */
1.1       root      119:       ui_endfield();
1.1.1.3   root      120:       vdp_endfield(); /* must be after ui_endfield as it alters state */
1.1       root      121:       cpuz80_endfield();
                    122:       cpu68k_endfield();
                    123:       cpu68k_frames++;
                    124:     }
1.1.1.2   root      125:     vdp_event_start += vdp_clksperline_68k;
                    126:     vdp_event_vint += vdp_clksperline_68k;
                    127:     vdp_event_hint += vdp_clksperline_68k;
                    128:     vdp_event_hdisplay += vdp_clksperline_68k;
                    129:     vdp_event_end += vdp_clksperline_68k;
1.1       root      130:     vdp_event = 1;
                    131:     goto EVENT_NEWLINE;
1.1.1.2   root      132:   }                             /* switch */
1.1       root      133: }
                    134: 
                    135: /*** event_doframe - execute until the end of the current frame ***/
                    136: 
                    137: void event_doframe(void)
                    138: {
                    139:   unsigned int startframe = cpu68k_frames;
                    140: 
                    141:   do {
                    142:     while (vdp_nextevent > 0)
                    143:       vdp_nextevent = -reg68k_external_execute(vdp_nextevent);
                    144:     event_nextevent();
1.1.1.2   root      145:   }
                    146:   while (startframe == cpu68k_frames);
1.1       root      147: 
                    148: }
                    149: 
                    150: /*** event_step - execute one instruction with no caching ***/
                    151: 
                    152: void event_dostep(void)
                    153: {
                    154:   /* execute one instruction and subtract from vdp_nextevent those cycles */
1.1.1.2   root      155:   vdp_nextevent -= reg68k_external_step();
1.1       root      156:   /* if negative or 0, i.e. we have done all the cycles we need to this event,
                    157:      call event_nextevent! */
                    158:   while (vdp_nextevent <= 0)
                    159:     event_nextevent();
                    160: }
                    161: 
                    162: /*** event_freeze_clocks - freeze 68k for given clock cycles ***/
                    163: 
                    164: /* NB: this routine is called by event_freeze which is called by
                    165:    vdp routines.  This could all happen IN THE MIDDLE OF A BLOCK at which
                    166:    point cpu68k_clocks will have been updated but vdp_nextevent will not! 
                    167:    therefore we must at this point work out what vdp_nextevent should be
                    168:    at the current moment in time, add on the clocks, wind forward time and
                    169:    then subtract the clocks that will be added later */
                    170: 
                    171: void event_freeze_clocks(unsigned int clocks)
                    172: {
                    173:   int missed = 0;
                    174: 
                    175:   /* first - fix vdp_nextevent to be correct for right now, due to block
                    176:      marking delay */
                    177: 
                    178:   /* find out how many clocks vdp_nextevent has missed */
                    179:   /* modify vdp_nextevent to reflect the real state as of now */
                    180: 
                    181:   switch (vdp_event) {
                    182:   case 0:
                    183:     missed = vdp_nextevent - (vdp_event_start - cpu68k_clocks);
1.1.1.2   root      184:     vdp_nextevent -= missed;
1.1       root      185:     break;
                    186:   case 1:
                    187:     missed = vdp_nextevent - (vdp_event_vint - cpu68k_clocks);
1.1.1.2   root      188:     vdp_nextevent -= missed;
1.1       root      189:     break;
                    190:   case 2:
                    191:     missed = vdp_nextevent - (vdp_event_hint - cpu68k_clocks);
1.1.1.2   root      192:     vdp_nextevent -= missed;
1.1       root      193:     break;
                    194:   case 3:
                    195:     missed = vdp_nextevent - (vdp_event_hdisplay - cpu68k_clocks);
1.1.1.2   root      196:     vdp_nextevent -= missed;
1.1       root      197:     break;
                    198:   case 4:
                    199:     missed = vdp_nextevent - (vdp_event_end - cpu68k_clocks);
1.1.1.2   root      200:     vdp_nextevent -= missed;
1.1       root      201:     break;
                    202:   default:
                    203:     printf("assertion failed: bad vdp_event in event_freeze_clocks: %d\n",
                    204:            vdp_event);
                    205:   }
                    206: 
                    207:   /* move cpu68k_clocks and vdp_nextevent forward in time */
                    208: 
1.1.1.2   root      209:   cpu68k_clocks += clocks;
                    210:   vdp_nextevent -= clocks;
1.1       root      211: 
                    212:   /* now catch up events */
                    213: 
                    214:   while (vdp_nextevent <= 0)
                    215:     event_nextevent();
                    216: 
                    217:   /* and then un-adjust vdp_nextevent, as the block marking code will update
                    218:      this later */
                    219: 
1.1.1.2   root      220:   vdp_nextevent += missed;
1.1       root      221: }
                    222: 
                    223: /*** event_freeze - freeze 68k for given VDP byte transfer ***/
                    224: 
                    225: void event_freeze(unsigned int bytes)
                    226: {
                    227:   int wide = vdp_reg[12] & 1;
                    228:   int clocks, possible;
                    229:   double percent_possible;
                    230:   int togo = (int)bytes;
                    231: 
1.1.1.2   root      232:   cpu68k_frozen = 1;            /* prohibit interrupts since PC is not known in the
                    233:                                    middle of a 68k block due to register mappings */
1.1       root      234: 
                    235:   while (togo > 0) {
                    236:     /* clocks will be negative if we're in the middle of a cpu block */
                    237:     clocks = vdp_event_end - cpu68k_clocks;
                    238:     if (clocks < 0)
                    239:       clocks = 0;
1.1.1.2   root      240:     percent_possible = clocks / vdp_clksperline_68k;
                    241:     if (vdp_reg[1] & 1 << 6 && !vdp_vblank) {
1.1       root      242:       /* vdp active */
1.1.1.2   root      243:       possible = (unsigned int)(percent_possible * (wide ? 18 : 16));
1.1       root      244:     } else {
                    245:       /* vdp inactive */
1.1.1.2   root      246:       possible = (unsigned int)(percent_possible * (wide ? 205 : 167));
1.1       root      247:     }
                    248:     if (togo >= possible) {
                    249:       event_freeze_clocks(clocks);
1.1.1.2   root      250:       togo -= possible;
1.1       root      251:     } else {
1.1.1.2   root      252:       event_freeze_clocks(((double)togo / possible) * clocks);
1.1       root      253:       togo = 0;
                    254:     }
                    255:   }
                    256:   cpu68k_frozen = 0;
                    257: }

unix.superglobalmegacorp.com

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