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