| version 1.6, 2004/08/11 13:53:53 | version 1.17, 2005/02/04 06:42:11 | 
| Line 1 | Line 1 | 
 |  |  | 
 |  | // #define      CTCCOUNTER | 
 |  | #define CTCFAST | 
 |  |  | 
 | #include        "compiler.h" | #include        "compiler.h" | 
 | #include        "z80core.h" | #include        "z80core.h" | 
 | #include        "pccore.h" | #include        "pccore.h" | 
| Line 6 | Line 10 | 
 | #include        "ievent.h" | #include        "ievent.h" | 
 |  |  | 
 |  |  | 
 |  | #if defined(TRACE) && defined(CTCCOUNTER) | 
 |  | extern UINT ctccnt; | 
 |  | #endif | 
 |  |  | 
 |  | static SINT32 minclock(const CTCCH *ch) { | 
 |  |  | 
 |  | UINT32  event; | 
 |  | UINT    i; | 
 |  | UINT32  clock; | 
 |  |  | 
 |  | event = 0x01000000; | 
 |  | for (i=0; i<3; i++) { | 
 |  | if ((ch->s.cmd[i] & 0x82) == 0x80) { | 
 |  | clock = ch->s.count[i]; | 
 |  | event = min(event, clock); | 
 |  | } | 
 |  | } | 
 |  | if ((ch->s.cmd[3] & 0x82) == 0x80) { | 
 |  | clock = ch->s.count[3]; | 
 |  | if (ch->s.cmd[3] & 0x40) { | 
 |  | clock = (clock - 1) * ch->s.countmax[0]; | 
 |  | clock += ch->s.count[0]; | 
 |  | } | 
 |  | event = min(event, clock); | 
 |  | } | 
 |  | if (event == 0) { | 
 |  | event = 1; | 
 |  | } | 
 |  | return(event); | 
 |  | } | 
 |  |  | 
 | static REG8 ctcwork(CTCCH *ch) { | static REG8 ctcwork(CTCCH *ch) { | 
 |  |  | 
 | UINT32  baseclock; | UINT32  baseclock; | 
| Line 15  static REG8 ctcwork(CTCCH *ch) { | Line 50  static REG8 ctcwork(CTCCH *ch) { | 
 | SINT32  pulse; | SINT32  pulse; | 
 | SINT32  count; | SINT32  count; | 
 |  |  | 
 |  | #if defined(TRACE) && defined(CTCCOUNTER) | 
 |  | ctccnt++; | 
 |  | #endif | 
 |  |  | 
 | baseclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; | baseclock = CPU_CLOCK + CPU_BASECLOCK - CPU_REMCLOCK; | 
| stepclock = baseclock - ch->baseclock; | stepclock = baseclock - ch->s.baseclock; | 
|  | #if defined(FIX_Z80A)                   // 2x2MHz | 
|  | ch->s.baseclock += stepclock & (~1); | 
|  | stepclock = stepclock >> 1; | 
|  | #else | 
 | stepclock /= pccore.multiple; | stepclock /= pccore.multiple; | 
| ch->baseclock += stepclock * pccore.multiple; | ch->s.baseclock += stepclock * pccore.multiple; | 
|  | #endif | 
 |  |  | 
 | intr = 0; | intr = 0; | 
 | pulse3 = 0; | pulse3 = 0; | 
 |  |  | 
 | // 0 | // 0 | 
| if (!(ch->cmd[0] & 0x02)) { | if (!(ch->s.cmd[0] & 0x02)) { | 
| pulse = stepclock;                                      // 2MHz | pulse = stepclock; | 
| if (!(ch->cmd[0] & 0x40)) { | count = ch->s.count[0]; | 
| pulse = pulse * 2;                              // 4MHz |  | 
| } |  | 
| count = ch->count[0]; |  | 
 | count -= pulse; | count -= pulse; | 
 | if (count <= 0) { | if (count <= 0) { | 
| pulse3 = (0 - count) / ch->countmax[0]; | #if defined(CTCFAST) | 
|  | count += ch->s.countmax[0]; | 
|  | if (count <= 0) { | 
|  | pulse3 = (0 - count) / ch->s.countmax[0]; | 
|  | pulse3 += 1; | 
|  | count += pulse3 * ch->s.countmax[0]; | 
|  | } | 
|  | pulse3 += 1; | 
|  | #else | 
|  | pulse3 = (0 - count) / ch->s.countmax[0]; | 
 | pulse3 += 1; | pulse3 += 1; | 
| count += pulse3 * ch->countmax[0]; | count += pulse3 * ch->s.countmax[0]; | 
| intr |= (ch->cmd[0] & 0x80) >> (7 - 0); | #endif | 
|  | intr |= (ch->s.cmd[0] & 0x80) >> (7 - 0); | 
 | } | } | 
| ch->count[0] = count; | ch->s.count[0] = count; | 
 | } | } | 
 |  |  | 
 | // 3 | // 3 | 
| if (!(ch->cmd[3] & 0x02)) { | if (!(ch->s.cmd[3] & 0x02)) { | 
| if (!(ch->cmd[3] & 0x40)) { | if (!(ch->s.cmd[3] & 0x40)) { | 
| pulse3 = stepclock * 2;                         // 4MHz | pulse3 = stepclock; | 
 | } | } | 
| count = ch->count[3]; | count = ch->s.count[3]; | 
 | count -= pulse3; | count -= pulse3; | 
 | if (count <= 0) { | if (count <= 0) { | 
| count = ch->countmax[3] - ((0 - count) % ch->countmax[3]); | #if defined(CTCFAST) | 
| intr |= (ch->cmd[3] & 0x80) >> (7 - 3); | count += ch->s.countmax[3]; | 
|  | if (count <= 0) { | 
|  | count = ch->s.countmax[3] - ((0 - count) % ch->s.countmax[3]); | 
|  | } | 
|  | #else | 
|  | count = ch->s.countmax[3] - ((0 - count) % ch->s.countmax[3]); | 
|  | #endif | 
|  | intr |= (ch->s.cmd[3] & 0x80) >> (7 - 3); | 
|  | //                      TRACEOUT(("<- ch.3 %.8x [%.2x:%.2x %.2x:%.2x]", baseclock, | 
|  | //                                                              ch->s.basecnt[0], ch->s.cmd[0], | 
|  | //                                                              ch->s.basecnt[3], ch->s.cmd[3])); | 
 | } | } | 
| ch->count[3] = count; | ch->s.count[3] = count; | 
 | } | } | 
 |  |  | 
 | // 1 | // 1 | 
| if (!(ch->cmd[1] & 0x02)) { | if (!(ch->s.cmd[1] & 0x02)) { | 
| pulse = stepclock;                                      // 2MHz | pulse = stepclock; | 
| if (!(ch->cmd[1] & 0x40)) { | count = ch->s.count[1]; | 
| pulse = pulse * 2;                              // 4MHz |  | 
| } |  | 
| count = ch->count[1]; |  | 
 | count -= pulse; | count -= pulse; | 
 | if (count <= 0) { | if (count <= 0) { | 
| count = ch->countmax[1] - ((0 - count) % ch->countmax[1]); | count = ch->s.countmax[1] - ((0 - count) % ch->s.countmax[1]); | 
| intr |= (ch->cmd[1] & 0x80) >> (7 - 1); | intr |= (ch->s.cmd[1] & 0x80) >> (7 - 1); | 
 | } | } | 
| ch->count[1] = count; | ch->s.count[1] = count; | 
 | } | } | 
 |  |  | 
 | // 2 | // 2 | 
| if (!(ch->cmd[2] & 0x02)) { | if (!(ch->s.cmd[2] & 0x02)) { | 
| pulse = stepclock;                                      // 2MHz | pulse = stepclock; | 
| if (!(ch->cmd[2] & 0x40)) { | count = ch->s.count[2]; | 
| pulse = pulse * 2;                              // 4MHz |  | 
| } |  | 
| count = ch->count[2]; |  | 
 | count -= pulse; | count -= pulse; | 
 | if (count <= 0) { | if (count <= 0) { | 
| count = ch->countmax[2] - ((0 - count) % ch->countmax[2]); | count = ch->s.countmax[2] - ((0 - count) % ch->s.countmax[2]); | 
| intr |= (ch->cmd[2] & 0x80) >> (7 - 2); | intr |= (ch->s.cmd[2] & 0x80) >> (7 - 2); | 
 | } | } | 
| ch->count[2] = count; | ch->s.count[2] = count; | 
 | } | } | 
 | return(intr); | return(intr); | 
 | } | } | 
| Line 92  static void ctcstep(CTCCH *ch) { | Line 147  static void ctcstep(CTCCH *ch) { | 
 |  |  | 
 | intr = ctcwork(ch); | intr = ctcwork(ch); | 
 | if (intr) { | if (intr) { | 
| ch->intr |= intr; | ch->s.intr |= intr; | 
| ievent_set(IEVENT_CTC0 + ch->num); | ievent_set(IEVENT_CTC0 + ch->s.num); | 
 | } | } | 
 | } | } | 
 |  |  | 
 | static void ctcnextevent(CTCCH *ch) { | static void ctcnextevent(CTCCH *ch) { | 
 |  |  | 
 | UINT32  event; | UINT32  event; | 
 | UINT    i; |  | 
 | UINT32  clock; |  | 
 |  |  | 
| if (ch->intr) { | if (ch->s.intr) { | 
 | return; | return; | 
 | } | } | 
| event = 0x04000000; | #if defined(FIX_Z80A) | 
| for (i=0; i<3; i++) { | event = minclock(ch) * 2; | 
| if ((ch->cmd[i] & 0x82) == 0x80) { | #else | 
| clock = ch->count[i]; | event = minclock(ch) * pccore.multiple; | 
| if (ch->cmd[i] & 0x40) { | #endif | 
| clock = clock * 2; | nevent_set(NEVENT_CTC0 + ch->s.num, event, neitem_ctc, NEVENT_ABSOLUTE); | 
| } |  | 
| event = min(event, clock); |  | 
| } |  | 
| } |  | 
| if ((ch->cmd[3] & 0x82) == 0x80) { |  | 
| clock = ch->count[3]; |  | 
| if (ch->cmd[3] & 0x40) { |  | 
| clock = (clock - 1) * ch->countmax[0]; |  | 
| clock += ch->count[0]; |  | 
| if (ch->cmd[0] & 0x40) { |  | 
| clock = clock * 2; |  | 
| } |  | 
| } |  | 
| event = min(event, clock); |  | 
| } |  | 
| event /= 2; |  | 
| event *= pccore.multiple; |  | 
| nevent_set(NEVENT_CTC0 + ch->num, event, neitem_ctc, NEVENT_ABSOLUTE); |  | 
 | } | } | 
 |  |  | 
 | void neitem_ctc(UINT id) { | void neitem_ctc(UINT id) { | 
| Line 140  void neitem_ctc(UINT id) { | Line 175  void neitem_ctc(UINT id) { | 
 | ch = ctc.ch + (id - NEVENT_CTC0); | ch = ctc.ch + (id - NEVENT_CTC0); | 
 | intr = ctcwork(ch); | intr = ctcwork(ch); | 
 | if (intr) { | if (intr) { | 
| ch->intr |= intr; | ch->s.intr |= intr; | 
| ievent_set(IEVENT_CTC0 + ch->num); | ievent_set(IEVENT_CTC0 + ch->s.num); | 
 | } | } | 
 | else { | else { | 
 | ctcnextevent(ch); | ctcnextevent(ch); | 
| Line 158  BRESULT ieitem_ctc(UINT id) { | Line 193  BRESULT ieitem_ctc(UINT id) { | 
 |  |  | 
 | ch = ctc.ch + (id - IEVENT_CTC0); | ch = ctc.ch + (id - IEVENT_CTC0); | 
 | intr = ctcwork(ch); | intr = ctcwork(ch); | 
| intr |= ch->intr; | intr |= ch->s.intr; | 
 | r = FALSE; | r = FALSE; | 
 | if (intr) { | if (intr) { | 
| for (i=0, bit=1; i<4; i++, bit<<=1) { | for (i=0, bit=1; i<4; i++, bit<<=1) | 
|  | //              for (i=4, bit=8; i--; bit>>=1) | 
|  | { | 
 | if (intr & bit) { | if (intr & bit) { | 
| #if 1                   // アークスのタイミング→あとで修正 | if (!(ch->s.cmd[i] & 0x80)) { | 
| if (0) |  | 
| #elif 0 |  | 
| if (((ch->count[i] * 17) >> 4) < ch->countmax[i]) |  | 
| #else |  | 
| if (ch->count[i] != ch->countmax[i]) |  | 
| #endif |  | 
| { |  | 
| intr ^= bit; |  | 
| } |  | 
| else if (!(ch->cmd[i] & 0x80)) { |  | 
 | intr ^= bit; | intr ^= bit; | 
 | } | } | 
 | else if (!r) { | else if (!r) { | 
 | r = TRUE; | r = TRUE; | 
 | intr ^= bit; | intr ^= bit; | 
| Z80_INTERRUPT((REG8)(ch->vector + (i << 1))); | ch->s.irq = (UINT8)i; | 
|  | //      TRACEOUT(("ctc int %d %d [%.2x]", ch->s.num, i, ch->s.cmd[i])); | 
|  | Z80_INTERRUPT((REG8)(ch->s.vector + (i << 1))); | 
 | } | } | 
 | } | } | 
 | } | } | 
 | } | } | 
| ch->intr = intr; | ch->s.intr = intr; | 
 | if (intr) { | if (intr) { | 
| ievent_set(IEVENT_CTC0 + ch->num); | ievent_set(IEVENT_CTC0 + ch->s.num); | 
 | } | } | 
 | else { | else { | 
 | ctcnextevent(ch); | ctcnextevent(ch); | 
| Line 194  BRESULT ieitem_ctc(UINT id) { | Line 223  BRESULT ieitem_ctc(UINT id) { | 
 | return(r); | return(r); | 
 | } | } | 
 |  |  | 
 |  | void ieeoi_ctc(UINT id) { | 
 |  |  | 
 |  | CTCCH   *ch; | 
 |  | REG8    intr; | 
 |  | UINT    curirq; | 
 |  |  | 
 |  | ch = ctc.ch + (id - IEVENT_CTC0); | 
 |  | intr = ctcwork(ch) | ch->s.intr; | 
 |  | curirq = ch->s.irq; | 
 |  | if (intr & (1 << curirq)) {                     // 割り込み中に割り込んだ… | 
 |  | // カウンタが0でなければ割り込みを消す | 
 |  | if ((ch->s.countmax[curirq] - ch->s.count[curirq]) | 
 |  | >= ch->s.range[curirq]) { | 
 |  | intr ^= (1 << curirq); | 
 |  | } | 
 |  | } | 
 |  | ch->s.intr = intr; | 
 |  | if (intr) { | 
 |  | ievent_set(id); | 
 |  | } | 
 |  | else { | 
 |  | ctcnextevent(ch); | 
 |  | } | 
 |  | } | 
 |  |  | 
 |  |  | 
 | // ---- | // ---- | 
 |  |  | 
| Line 203  static void ctcch_o(CTCCH *ch, UINT port | Line 257  static void ctcch_o(CTCCH *ch, UINT port | 
 | REG8    scale; | REG8    scale; | 
 |  |  | 
 | port &= 3; | port &= 3; | 
| if (ch->cmd[port] & 0x04) { | if (ch->s.cmd[port] & 0x04) { | 
 | ctcstep(ch); | ctcstep(ch); | 
| ch->basecnt[port] = value; | ch->s.basecnt[port] = value; | 
| count = 256; | count = ((value - 1) & 0xff) + 1; | 
| if (value) { |  | 
| count = (SINT32)value; |  | 
| } |  | 
 | scale = 0; | scale = 0; | 
| if (!(ch->cmd[port] & 0x40)) { | if (!(ch->s.cmd[port] & 0x40)) { | 
| if (ch->cmd[port] & 0x20) { | if (ch->s.cmd[port] & 0x20) { | 
| scale = 8; | scale = 8 - 1; | 
 | } | } | 
 | else { | else { | 
| scale = 4; | scale = 4 - 1; | 
 | } | } | 
 | } | } | 
| count <<= scale; | ch->s.scale[port] = scale; | 
| ch->countmax[port] = count; | ch->s.countmax[port] = count << scale; | 
| ch->count[port] = count; | ch->s.count[port] = count << scale; | 
| ch->cmd[port] &= ~6; | ch->s.range[port] = 1 << scale; | 
|  | ch->s.cmd[port] &= ~6; | 
 | ctcnextevent(ch); | ctcnextevent(ch); | 
 | } | } | 
 | else if (value & 1) { | else if (value & 1) { | 
 | ctcstep(ch); | ctcstep(ch); | 
| ch->cmd[port] = value; | ch->s.cmd[port] = value; | 
 | ctcnextevent(ch); | ctcnextevent(ch); | 
 | } | } | 
 | else if (!port) {                                                                                               // ver0.25 | else if (!port) {                                                                                               // ver0.25 | 
| ch->vector = (UINT8)(value & 0xf8); | ch->s.vector = (UINT8)(value & 0xf8); | 
 | } | } | 
 | } | } | 
 |  |  | 
 | static REG8 ctcch_i(CTCCH *ch, UINT port) { | static REG8 ctcch_i(CTCCH *ch, UINT port) { | 
 |  |  | 
 | REG8    scale; |  | 
 |  |  | 
 | port &= 3; | port &= 3; | 
 | if (port != 3) { | if (port != 3) { | 
| return(ch->basecnt[port]); | return(ch->s.basecnt[port]); | 
 | } | } | 
 | else { | else { | 
 | ctcstep(ch); | ctcstep(ch); | 
| scale = 0; | return((REG8)(ch->s.count[3] >> ch->s.scale[3])); | 
| if (!(ch->cmd[3] & 0x40)) { |  | 
| if (ch->cmd[3] & 0x20) { |  | 
| scale = 8; |  | 
| } |  | 
| else { |  | 
| scale = 4; |  | 
| } |  | 
| } |  | 
| return((REG8)(ch->count[3] >> scale)); |  | 
 | } | } | 
 | } | } | 
 |  |  | 
| Line 265  static CTCCH *getctcch(UINT port) { | Line 306  static CTCCH *getctcch(UINT port) { | 
 |  |  | 
 | port &= ~3; | port &= ~3; | 
 | if (port == 0x1fa0) { | if (port == 0x1fa0) { | 
| return(ctc.ch + 0); | return(ctc.ch + CTC_TURBO1); | 
 | } | } | 
 | if (port == 0x1fa8) { | if (port == 0x1fa8) { | 
| return(ctc.ch + 1); | return(ctc.ch + CTC_TURBO2); | 
 | } | } | 
 | if (port == 0x0704) { | if (port == 0x0704) { | 
| return(ctc.ch + 2); | return(ctc.ch + CTC_OPM); | 
 | } | } | 
 | return(NULL); | return(NULL); | 
 | } | } | 
| Line 310  void ctc_reset(void) { | Line 351  void ctc_reset(void) { | 
 |  |  | 
 | ZeroMemory(&ctc, sizeof(ctc)); | ZeroMemory(&ctc, sizeof(ctc)); | 
 | for (i=0; i<3; i++) { | for (i=0; i<3; i++) { | 
| ctc.ch[i].num = (UINT8)i; | ctc.ch[i].s.num = (UINT8)i; | 
 | for (j=0; j<4; j++) { | for (j=0; j<4; j++) { | 
| ctc.ch[i].cmd[j] = 0x03; | ctc.ch[i].s.cmd[j] = 0x23; | 
| ctc.ch[i].count[j] = 256 << 8; | ctc.ch[i].s.scale[j] = 7; | 
| ctc.ch[i].countmax[j] = 256 << 8; | ctc.ch[i].s.count[j] = 256 << 7; | 
|  | ctc.ch[i].s.countmax[j] = 256 << 7; | 
 | } | } | 
 | } | } | 
 | } | } |