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

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

unix.superglobalmegacorp.com

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