1 /*
2 * viciivsid-irq.c - IRQ related functions for the MOS 6569 (VIC-II) emulation.
3 *
4 * Written by
5 * Andreas Boose <viceteam@t-online.de>
6 * Ettore Perazzoli <ettore@comm2000.it>
7 *
8 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 #include "vice.h"
29
30 #include "alarm.h"
31 #include "interrupt.h"
32 #include "maincpu.h"
33 #include "types.h"
34 #include "vicii-irq.h"
35 #include "viciitypes.h"
36
vicii_irq_set_line(void)37 void vicii_irq_set_line(void)
38 {
39 if (vicii.irq_status & vicii.regs[0x1a]) {
40 vicii.irq_status |= 0x80;
41 maincpu_set_irq(vicii.int_num, 1);
42 } else {
43 vicii.irq_status &= 0x7f;
44 maincpu_set_irq(vicii.int_num, 0);
45 }
46 }
47
vicii_irq_set_line_clk(CLOCK mclk)48 static inline void vicii_irq_set_line_clk(CLOCK mclk)
49 {
50 if (vicii.irq_status & vicii.regs[0x1a]) {
51 vicii.irq_status |= 0x80;
52 maincpu_set_irq_clk(vicii.int_num, 1, mclk);
53 } else {
54 vicii.irq_status &= 0x7f;
55 maincpu_set_irq_clk(vicii.int_num, 0, mclk);
56 }
57 }
58
vicii_irq_raster_set(CLOCK mclk)59 void vicii_irq_raster_set(CLOCK mclk)
60 {
61 vicii.irq_status |= 0x1;
62 vicii_irq_set_line_clk(mclk);
63 }
64
vicii_irq_raster_clear(CLOCK mclk)65 void vicii_irq_raster_clear(CLOCK mclk)
66 {
67 vicii.irq_status &= 0xfe;
68 vicii_irq_set_line_clk(mclk);
69 }
70
vicii_irq_sbcoll_set(void)71 void vicii_irq_sbcoll_set(void)
72 {
73 vicii.irq_status |= 0x2;
74 vicii_irq_set_line();
75 }
76
vicii_irq_sbcoll_clear(void)77 void vicii_irq_sbcoll_clear(void)
78 {
79 vicii.irq_status &= 0xfd;
80 vicii_irq_set_line();
81 }
82
vicii_irq_sscoll_set(void)83 void vicii_irq_sscoll_set(void)
84 {
85 vicii.irq_status |= 0x4;
86 vicii_irq_set_line();
87 }
88
vicii_irq_sscoll_clear(void)89 void vicii_irq_sscoll_clear(void)
90 {
91 vicii.irq_status &= 0xfb;
92 vicii_irq_set_line();
93 }
94
vicii_irq_lightpen_set(CLOCK mclk)95 void vicii_irq_lightpen_set(CLOCK mclk)
96 {
97 vicii.irq_status |= 0x8;
98 vicii_irq_set_line_clk(mclk);
99 }
100
vicii_irq_lightpen_clear(CLOCK mclk)101 void vicii_irq_lightpen_clear(CLOCK mclk)
102 {
103 vicii.irq_status &= 0xf7;
104 vicii_irq_set_line_clk(mclk);
105 }
106
vicii_irq_set_raster_line(unsigned int line)107 void vicii_irq_set_raster_line(unsigned int line)
108 {
109 if (line == vicii.raster_irq_line && vicii.raster_irq_clk != CLOCK_MAX) {
110 return;
111 }
112
113 if (line < (unsigned int)vicii.screen_height) {
114 unsigned int current_line = VICII_RASTER_Y(maincpu_clk);
115
116 vicii.raster_irq_clk = (VICII_LINE_START_CLK(maincpu_clk)
117 + VICII_RASTER_IRQ_DELAY - INTERRUPT_DELAY
118 + (vicii.cycles_per_line
119 * (line - current_line)));
120 /* Raster interrupts on line 0 are delayed by 1 cycle. */
121 if (line == 0) {
122 vicii.raster_irq_clk++;
123 }
124
125 if (line <= current_line) {
126 vicii.raster_irq_clk += (vicii.screen_height * vicii.cycles_per_line);
127 }
128 alarm_set(vicii.raster_irq_alarm, vicii.raster_irq_clk);
129 } else {
130 VICII_DEBUG_RASTER(("update_raster_irq(): "
131 "raster compare out of range ($%04X)!", line));
132 vicii.raster_irq_clk = CLOCK_MAX;
133 alarm_unset(vicii.raster_irq_alarm);
134 }
135
136 VICII_DEBUG_RASTER(("update_raster_irq(): "
137 "vicii.raster_irq_clk = %ul, "
138 "line = $%04X, "
139 "vicii.regs[0x1a] & 1 = %d",
140 vicii.raster_irq_clk, line, vicii.regs[0x1a] & 1));
141
142 vicii.raster_irq_line = line;
143 }
144
vicii_irq_check_state(uint8_t value,unsigned int high)145 void vicii_irq_check_state(uint8_t value, unsigned int high)
146 {
147 unsigned int irq_line, line;
148 unsigned int old_raster_irq_line;
149 CLOCK old_raster_irq_clk = vicii.raster_irq_clk;
150
151 if (high) {
152 irq_line = (vicii.raster_irq_line & 0xff) | ((value & 0x80) << 1);
153 } else {
154 irq_line = (vicii.raster_irq_line & 0x100) | value;
155 }
156
157 if (irq_line == vicii.raster_irq_line) {
158 return;
159 }
160
161 line = VICII_RASTER_Y(maincpu_clk);
162
163 old_raster_irq_line = vicii.raster_irq_line;
164 vicii_irq_set_raster_line(irq_line);
165
166 if (vicii.regs[0x1a] & 0x1) {
167 int trigger_irq;
168
169 trigger_irq = 0;
170
171 if (old_raster_irq_clk == VICII_LINE_START_CLK(maincpu_clk) + (line == 0 ? 1 : 0)) {
172 trigger_irq = 2;
173 }
174
175 if (maincpu_rmw_flag) {
176 if (high) {
177 if (VICII_RASTER_CYCLE(maincpu_clk) == 0
178 && (line & 0xff) == 0) {
179 unsigned int previous_line = VICII_PREVIOUS_LINE(line);
180
181 if (previous_line != old_raster_irq_line
182 && ((old_raster_irq_line & 0xff)
183 == (previous_line & 0xff))) {
184 trigger_irq = 1;
185 }
186 } else {
187 if (line != old_raster_irq_line
188 && (old_raster_irq_line & 0xff) == (line & 0xff)) {
189 trigger_irq = 1;
190 }
191 }
192 } else {
193 if (VICII_RASTER_CYCLE(maincpu_clk) == 0) {
194 unsigned int previous_line = VICII_PREVIOUS_LINE(line);
195
196 if (previous_line != old_raster_irq_line
197 && ((old_raster_irq_line & 0x100)
198 == (previous_line & 0x100))) {
199 trigger_irq = 1;
200 }
201 } else {
202 if (line != old_raster_irq_line
203 && (old_raster_irq_line & 0x100) == (line & 0x100)) {
204 trigger_irq = 1;
205 }
206 }
207 }
208 }
209
210 if (vicii.raster_irq_line == line && line != old_raster_irq_line) {
211 trigger_irq = 1;
212 }
213
214 if (trigger_irq == 1) {
215 vicii_irq_raster_set(maincpu_clk);
216 }
217
218 if (trigger_irq == 2) {
219 vicii_irq_raster_set(old_raster_irq_clk);
220 }
221 }
222 }
223
vicii_irq_next_frame(void)224 void vicii_irq_next_frame(void)
225 {
226 vicii.raster_irq_clk += vicii.screen_height * vicii.cycles_per_line;
227 alarm_set(vicii.raster_irq_alarm, vicii.raster_irq_clk);
228 }
229
230 /* If necessary, emulate a raster compare IRQ. This is called when the raster
231 line counter matches the value stored in the raster line register. */
vicii_irq_alarm_handler(CLOCK offset,void * data)232 void vicii_irq_alarm_handler(CLOCK offset, void *data)
233 {
234 vicii_irq_raster_set(vicii.raster_irq_clk);
235 vicii_irq_next_frame();
236 }
237
vicii_irq_init(void)238 void vicii_irq_init(void)
239 {
240 vicii.int_num = interrupt_cpu_status_int_new(maincpu_int_status, "VICII");
241
242 vicii.raster_irq_alarm = alarm_new(maincpu_alarm_context, "VicIIRasterIrq",
243 vicii_irq_alarm_handler, NULL);
244 }
245