OSDN Git Service

[VM][General][WIP] Apply new (Upstream 2016-02-21) APIs to VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz2500 / interrupt.cpp
1 /*
2         SHARP MZ-2500 Emulator 'EmuZ-2500'
3
4         Author : Takeda.Toshiya
5         Date   : 2007.02.11 -
6
7         [ interrupt ]
8 */
9
10 #include "interrupt.h"
11
12 //#define SUPPURT_CHILD_DEVICE
13
14 void INTERRUPT::reset()
15 {
16         for(int ch = 0; ch < 4; ch++) {
17                 irq[ch].enb_intr = false;
18                 irq[ch].req_intr = false;
19                 irq[ch].in_service = false;
20         }
21         iei = oei = true;
22         req_intr_ch = -1;
23         select = 0;
24 }
25
26 void INTERRUPT::write_io8(uint32 addr, uint32 data)
27 {
28         switch(addr & 0xff) {
29         case 0xc6:
30                 irq[0].enb_intr = ((data & 8) != 0);
31                 irq[1].enb_intr = ((data & 4) != 0);
32                 irq[2].enb_intr = ((data & 2) != 0);
33                 irq[3].enb_intr = ((data & 1) != 0);
34                 select = data;
35                 update_intr();
36                 break;
37         case 0xc7:
38                 if(select & 0x80) {
39                         irq[0].vector = data;   // crtc
40                 }
41                 if(select & 0x40) {
42                         irq[1].vector = data;   // i8253
43                 }
44                 if(select & 0x20) {
45                         irq[2].vector = data;   // printer
46                 }
47                 if(select & 0x10) {
48                         irq[3].vector = data;   // rp5c15
49                 }
50                 break;
51         }
52 }
53
54 void INTERRUPT::write_signal(int id, uint32 data, uint32 mask)
55 {
56         if(id == SIG_INTERRUPT_CRTC) {
57                 bool next = ((data & mask) != 0);
58                 if(next != irq[0].req_intr) {
59                         irq[0].req_intr = next;
60                         update_intr();
61                 }
62         } else if(id == SIG_INTERRUPT_I8253) {
63                 bool next = ((data & mask) != 0);
64                 if(next != irq[1].req_intr) {
65                         irq[1].req_intr = next;
66                         update_intr();
67                 }
68         } else if(id == SIG_INTERRUPT_PRINTER) {
69                 bool next = ((data & mask) != 0);
70                 if(next != irq[2].req_intr) {
71                         irq[2].req_intr = next;
72                         update_intr();
73                 }
74         } else if(id == SIG_INTERRUPT_RP5C15) {
75                 bool next = ((data & mask) != 0);
76                 if(next != irq[3].req_intr) {
77                         irq[3].req_intr = next;
78                         update_intr();
79                 }
80         }
81 }
82
83 void INTERRUPT::set_intr_iei(bool val)
84 {
85         if(iei != val) {
86                 iei = val;
87                 update_intr();
88         }
89 }
90
91 #define set_intr_oei(val) { \
92         if(oei != val) { \
93                 oei = val; \
94                 if(d_child) { \
95                         d_child->set_intr_iei(oei); \
96                 } \
97         } \
98 }
99
100 void INTERRUPT::update_intr()
101 {
102 #ifdef SUPPURT_CHILD_DEVICE
103         // set oei signal
104         bool next = false;
105         if(iei) {
106                 next = true;
107                 for(int ch = 0; ch < 4; ch++) {
108                         if(irq[ch].in_service) {
109                                 next = false;
110                                 break;
111                         }
112                 }
113         }
114         set_intr_oei(next);
115 #endif
116         // set int signal
117         req_intr_ch = -1;
118         if(iei) {
119                 for(int ch = 0; ch < 4; ch++) {
120                         if(irq[ch].in_service) {
121                                 break;
122                         }
123                         if(irq[ch].enb_intr && irq[ch].req_intr) {
124                                 req_intr_ch = ch;
125                                 break;
126                         }
127                 }
128         }
129         if(req_intr_ch != -1) {
130                 d_cpu->set_intr_line(true, true, intr_bit);
131         } else {
132                 d_cpu->set_intr_line(false, true, intr_bit);
133         }
134 }
135
136 uint32 INTERRUPT::get_intr_ack()
137 {
138         // ack (M1=IORQ=L)
139         if(req_intr_ch != -1) {
140                 int ch = req_intr_ch;
141                 irq[ch].req_intr = false;
142                 irq[ch].in_service = true;
143 #ifdef SUPPURT_CHILD_DEVICE
144                 update_intr();
145 #endif
146                 return irq[ch].vector;
147         }
148 #ifdef SUPPURT_CHILD_DEVICE
149         if(d_child) {
150                 return d_child->get_intr_ack();
151         }
152 #endif
153         return 0xff;
154 }
155
156 void INTERRUPT::notify_intr_reti()
157 {
158         // detect RETI
159         for(int ch = 0; ch < 4; ch++) {
160                 if(irq[ch].in_service) {
161                         irq[ch].in_service = false;
162                         update_intr();
163                         return;
164                 }
165         }
166 #ifdef SUPPURT_CHILD_DEVICE
167         if(d_child) {
168                 d_child->notify_intr_reti();
169         }
170 #endif
171 }
172
173 #define STATE_VERSION   1
174
175 void INTERRUPT::save_state(FILEIO* state_fio)
176 {
177         state_fio->FputUint32(STATE_VERSION);
178         state_fio->FputInt32(this_device_id);
179         
180         state_fio->FputUint8(select);
181         state_fio->Fwrite(irq, sizeof(irq), 1);
182         state_fio->FputInt32(req_intr_ch);
183         state_fio->FputBool(iei);
184         state_fio->FputBool(oei);
185         state_fio->FputUint32(intr_bit);
186 }
187
188 bool INTERRUPT::load_state(FILEIO* state_fio)
189 {
190         if(state_fio->FgetUint32() != STATE_VERSION) {
191                 return false;
192         }
193         if(state_fio->FgetInt32() != this_device_id) {
194                 return false;
195         }
196         select = state_fio->FgetUint8();
197         state_fio->Fread(irq, sizeof(irq), 1);
198         req_intr_ch = state_fio->FgetInt32();
199         iei = state_fio->FgetBool();
200         oei = state_fio->FgetBool();
201         intr_bit = state_fio->FgetUint32();
202         return true;
203 }
204