1 /*
2 * via4000.c - VIA emulation in the 4000 disk drive.
3 *
4 * Written by
5 * Kajtar Zsolt <soci@c64.rulez.org>
6 *
7 * Based on old code by
8 * Andreas Boose <viceteam@t-online.de>
9 * Andre Fachat <fachat@physik.tu-chemnitz.de>
10 * Daniel Sladic <sladic@eecg.toronto.edu>
11 * Ettore Perazzoli <ettore@comm2000.it>
12 *
13 * This file is part of VICE, the Versatile Commodore Emulator.
14 * See README for copyright notice.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 * 02111-1307 USA.
30 *
31 */
32
33 #include "vice.h"
34
35 #include <stdio.h>
36
37 #include "debug.h"
38 #include "drive.h"
39 #include "drivesync.h"
40 #include "drivetypes.h"
41 #include "iecbus.h"
42 #include "iecdrive.h"
43 #include "interrupt.h"
44 #include "lib.h"
45 #include "rotation.h"
46 #include "types.h"
47 #include "via.h"
48 #include "via4000.h"
49 #include "viad.h"
50 #include "pc8477.h"
51
52
53 #define iecbus (viap->v_iecbus)
54
55 typedef struct drivevia_context_s {
56 unsigned int number;
57 struct drive_s *drive;
58 struct iecbus_s *v_iecbus;
59 } drivevia_context_t;
60
61
via4000_store(diskunit_context_t * ctxptr,uint16_t addr,uint8_t data)62 void via4000_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data)
63 {
64 viacore_store(ctxptr->via4000, addr, data);
65 }
66
via4000_read(diskunit_context_t * ctxptr,uint16_t addr)67 uint8_t via4000_read(diskunit_context_t *ctxptr, uint16_t addr)
68 {
69 return viacore_read(ctxptr->via4000, addr);
70 }
71
via4000_peek(diskunit_context_t * ctxptr,uint16_t addr)72 uint8_t via4000_peek(diskunit_context_t *ctxptr, uint16_t addr)
73 {
74 return viacore_peek(ctxptr->via4000, addr);
75 }
76
via4000_dump(diskunit_context_t * ctxptr,uint16_t addr)77 int via4000_dump(diskunit_context_t *ctxptr, uint16_t addr)
78 {
79 viacore_dump(ctxptr->via4000);
80 return 0;
81 }
82
set_ca2(via_context_t * via_context,int state)83 static void set_ca2(via_context_t *via_context, int state)
84 {
85 }
86
set_cb2(via_context_t * via_context,int state)87 static void set_cb2(via_context_t *via_context, int state)
88 {
89 }
90
set_int(via_context_t * via_context,unsigned int int_num,int value,CLOCK rclk)91 static void set_int(via_context_t *via_context, unsigned int int_num,
92 int value, CLOCK rclk)
93 {
94 diskunit_context_t *dc = (diskunit_context_t *)(via_context->context);
95
96 interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk);
97 }
98
restore_int(via_context_t * via_context,unsigned int int_num,int value)99 static void restore_int(via_context_t *via_context, unsigned int int_num,
100 int value)
101 {
102 diskunit_context_t *dc = (diskunit_context_t *)(via_context->context);
103
104 interrupt_restore_irq(dc->cpu->int_status, int_num, value);
105 }
106
undump_pra(via_context_t * via_context,uint8_t byte)107 static void undump_pra(via_context_t *via_context, uint8_t byte)
108 {
109 drivevia_context_t *viap = (drivevia_context_t *)(via_context->prv);
110
111 if (iecbus != NULL) {
112 uint8_t *drive_bus, *drive_data;
113 unsigned int unit;
114
115 drive_bus = &(iecbus->drv_bus[viap->number + 8]);
116 drive_data = &(iecbus->drv_data[viap->number + 8]);
117
118 *drive_data = ~byte;
119 *drive_bus = ((((*drive_data) << 3) & 0x40)
120 | (((*drive_data) << 6)
121 & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80));
122
123 iecbus->cpu_port = iecbus->cpu_bus;
124 for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) {
125 iecbus->cpu_port &= iecbus->drv_bus[unit];
126 }
127
128 iecbus->drv_port = (((iecbus->cpu_port >> 4) & 0x4)
129 | (iecbus->cpu_port >> 7)
130 | ((iecbus->cpu_bus << 3) & 0x80));
131 } else {
132 iec_drive_write((uint8_t)(~byte), viap->number);
133 }
134 }
135
store_pra(via_context_t * via_context,uint8_t byte,uint8_t oldpa,uint16_t addr)136 static void store_pra(via_context_t *via_context, uint8_t byte, uint8_t oldpa,
137 uint16_t addr)
138 {
139 drivevia_context_t *viap;
140
141 viap = (drivevia_context_t *)(via_context->prv);
142
143 if (byte != oldpa) {
144 DEBUG_IEC_DRV_WRITE(byte);
145
146 if (iecbus != NULL) {
147 uint8_t *drive_data, *drive_bus;
148 unsigned int unit;
149
150 drive_bus = &(iecbus->drv_bus[viap->number + 8]);
151 drive_data = &(iecbus->drv_data[viap->number + 8]);
152
153 *drive_data = ~byte;
154 *drive_bus = ((((*drive_data) << 3) & 0x40)
155 | (((*drive_data) << 6)
156 & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80));
157
158 iecbus->cpu_port = iecbus->cpu_bus;
159 for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) {
160 iecbus->cpu_port &= iecbus->drv_bus[unit];
161 }
162
163 iecbus->drv_port = (((iecbus->cpu_port >> 4) & 0x4)
164 | (iecbus->cpu_port >> 7)
165 | ((iecbus->cpu_bus << 3) & 0x80));
166
167 DEBUG_IEC_BUS_WRITE(iecbus->drv_port);
168 } else {
169 iec_drive_write((uint8_t)(~byte), viap->number);
170 DEBUG_IEC_BUS_WRITE(~byte);
171 }
172
173 iec_fast_drive_direction(byte & 0x20, viap->number);
174 }
175 }
176
undump_prb(via_context_t * via_context,uint8_t byte)177 static void undump_prb(via_context_t *via_context, uint8_t byte)
178 {
179 drivevia_context_t *viap;
180
181 viap = (drivevia_context_t *)(via_context->prv);
182
183 viap->drive->led_status = (byte & 0x40) ? 1 : 0;
184 viap->drive->led_status |= (byte & 0x20) ? 2 : 0;
185 }
186
store_prb(via_context_t * via_context,uint8_t byte,uint8_t p_oldpb,uint16_t addr)187 static void store_prb(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb,
188 uint16_t addr)
189 {
190 drivevia_context_t *viap;
191
192 viap = (drivevia_context_t *)(via_context->prv);
193
194 viap->drive->led_status = (byte & 0x40) ? 1 : 0;
195 viap->drive->led_status |= (byte & 0x20) ? 2 : 0;
196 }
197
undump_pcr(via_context_t * via_context,uint8_t byte)198 static void undump_pcr(via_context_t *via_context, uint8_t byte)
199 {
200 }
201
store_pcr(via_context_t * via_context,uint8_t byte,uint16_t addr)202 static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr)
203 {
204 return byte;
205 }
206
undump_acr(via_context_t * via_context,uint8_t byte)207 static void undump_acr(via_context_t *via_context, uint8_t byte)
208 {
209 }
210
store_acr(via_context_t * via_context,uint8_t byte)211 static void store_acr(via_context_t *via_context, uint8_t byte)
212 {
213 }
214
store_sr(via_context_t * via_context,uint8_t byte)215 static void store_sr(via_context_t *via_context, uint8_t byte)
216 {
217 drivevia_context_t *viap;
218
219 viap = (drivevia_context_t *)(via_context->prv);
220
221 iec_fast_drive_write((uint8_t)(~byte), viap->number);
222 }
223
store_t2l(via_context_t * via_context,uint8_t byte)224 static void store_t2l(via_context_t *via_context, uint8_t byte)
225 {
226 }
227
reset(via_context_t * via_context)228 static void reset(via_context_t *via_context)
229 {
230 }
231
read_pra(via_context_t * via_context,uint16_t addr)232 static uint8_t read_pra(via_context_t *via_context, uint16_t addr)
233 {
234 uint8_t byte;
235 drivevia_context_t *viap;
236
237 viap = (drivevia_context_t *)(via_context->prv);
238
239 if (iecbus != NULL) {
240 byte = (((via_context->via[VIA_PRA] & 0x1a)
241 | iecbus->drv_port) ^ 0x85);
242 } else {
243 byte = (((via_context->via[VIA_PRA] & 0x1a)
244 | iec_drive_read(viap->number)) ^ 0x85);
245 }
246
247 DEBUG_IEC_DRV_READ(byte);
248
249 DEBUG_IEC_BUS_READ(byte);
250
251 return byte;
252 }
253
read_prb(via_context_t * via_context)254 static uint8_t read_prb(via_context_t *via_context)
255 {
256 uint8_t byte;
257 drivevia_context_t *viap;
258 diskunit_context_t *drive;
259
260 viap = (drivevia_context_t *)(via_context->prv);
261 drive = (diskunit_context_t *)(via_context->context);
262
263 byte = (viap->number << 3) | (pc8477_irq(drive->pc8477) ? 0x80 : 0);
264
265 return byte;
266 }
267
via4000_init(diskunit_context_t * ctxptr)268 void via4000_init(diskunit_context_t *ctxptr)
269 {
270 viacore_init(ctxptr->via4000, ctxptr->cpu->alarm_context,
271 ctxptr->cpu->int_status, ctxptr->cpu->clk_guard);
272 }
273
via4000_setup_context(diskunit_context_t * ctxptr)274 void via4000_setup_context(diskunit_context_t *ctxptr)
275 {
276 drivevia_context_t *viap;
277 via_context_t *via;
278
279 /* Clear struct as snapshot code may write uninitialized values. */
280 ctxptr->via4000 = lib_calloc(1, sizeof(via_context_t));
281 via = ctxptr->via4000;
282
283 via->prv = lib_malloc(sizeof(drivevia_context_t));
284 viap = (drivevia_context_t *)(via->prv);
285 viap->number = ctxptr->mynumber;
286
287 via->context = (void *)ctxptr;
288
289 via->rmw_flag = &(ctxptr->cpu->rmw_flag);
290 via->clk_ptr = ctxptr->clk_ptr;
291
292 via->myname = lib_msprintf("4000Drive%dVia1", ctxptr->mynumber);
293 via->my_module_name = lib_msprintf("4000VIA1D%d", ctxptr->mynumber);
294
295 viacore_setup_context(via);
296
297 via->my_module_name_alt1 = lib_msprintf("VIA1D%d", ctxptr->mynumber);
298 via->my_module_name_alt2 = lib_msprintf("VIA4000");
299
300 via->irq_line = IK_IRQ;
301
302 viap->drive = ctxptr->drives[0];
303 iecbus = iecbus_drive_port();
304
305 via->undump_pra = undump_pra;
306 via->undump_prb = undump_prb;
307 via->undump_pcr = undump_pcr;
308 via->undump_acr = undump_acr;
309 via->store_pra = store_pra;
310 via->store_prb = store_prb;
311 via->store_pcr = store_pcr;
312 via->store_acr = store_acr;
313 via->store_sr = store_sr;
314 via->store_t2l = store_t2l;
315 via->read_pra = read_pra;
316 via->read_prb = read_prb;
317 via->set_int = set_int;
318 via->restore_int = restore_int;
319 via->set_ca2 = set_ca2;
320 via->set_cb2 = set_cb2;
321 via->reset = reset;
322 }
323