1 /*
2  * c64cia2.c - Definitions for the second MOS6526 (CIA) chip in the C64
3  * ($DD00).
4  *
5  * Written by
6  *  Andre Fachat <fachat@physik.tu-chemnitz.de>
7  *  Ettore Perazzoli <ettore@comm2000.it>
8  *  Andreas Boose <viceteam@t-online.de>
9  *  Marco van den Heuvel <blackystardust68@yahoo.com>
10  *
11  * This file is part of VICE, the Versatile Commodore Emulator.
12  * See README for copyright notice.
13  *
14  *  This program is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU General Public License as published by
16  *  the Free Software Foundation; either version 2 of the License, or
17  *  (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27  *  02111-1307  USA.
28  * */
29 
30 
31 #include "vice.h"
32 
33 #include <stdio.h>
34 
35 #include "c64.h"
36 #include "c64mem.h"
37 #include "c64iec.h"
38 #include "c64cia.h"
39 #include "c64parallel.h"
40 #include "c64dtv-resources.h"
41 #include "cia.h"
42 #include "drive.h"
43 #include "hummeradc.h"
44 #include "iecbus.h"
45 #include "interrupt.h"
46 #include "joystick.h"
47 #include "keyboard.h"
48 #include "lib.h"
49 #include "log.h"
50 #include "maincpu.h"
51 #include "ps2mouse.h"
52 #include "types.h"
53 #include "userport.h"
54 #include "vicii.h"
55 
56 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
57 #include "rsuser.h"
58 #endif
59 
60 
cia2_store(uint16_t addr,uint8_t data)61 void cia2_store(uint16_t addr, uint8_t data)
62 {
63     if ((addr & 0x1f) == 1) {
64         store_userport_pbx(data);
65 
66         /* The functions below will gradually be removed as the functionality is added to the new userport system. */
67         if (c64dtv_hummer_adc_enabled) {
68             hummeradc_store(data);
69         }
70         if (ps2mouse_enabled) {
71             ps2mouse_store(data);
72         }
73     }
74 
75     ciacore_store(machine_context.cia2, addr, data);
76 }
77 
cia2_read(uint16_t addr)78 uint8_t cia2_read(uint16_t addr)
79 {
80     uint8_t retval = 0xff;
81 
82     if ((addr & 0x1f) == 1) {
83         retval = read_userport_pbx(0x1f, retval);
84 
85         /* The functions below will gradually be removed as the functionality is added to the new userport system. */
86         if (ps2mouse_enabled) {
87             retval &= (ps2mouse_read() | 0x3f);
88         }
89         if (c64dtv_hummer_adc_enabled) {
90             retval &= (hummeradc_read() | 0xf8);
91         }
92         return retval;
93     }
94 
95     /* disable TOD & serial */
96     if (((addr & 0xf) >= 8) && ((addr & 0xf) <= 0xc)) {
97         return 0xff;
98     }
99 
100     return ciacore_read(machine_context.cia2, addr);
101 }
102 
cia2_peek(uint16_t addr)103 uint8_t cia2_peek(uint16_t addr)
104 {
105     return ciacore_peek(machine_context.cia2, addr);
106 }
107 
cia_set_int_clk(cia_context_t * cia_context,int value,CLOCK clk)108 static void cia_set_int_clk(cia_context_t *cia_context, int value, CLOCK clk)
109 {
110     interrupt_set_nmi(maincpu_int_status, cia_context->int_num, value, clk);
111 }
112 
cia_restore_int(cia_context_t * cia_context,int value)113 static void cia_restore_int(cia_context_t *cia_context, int value)
114 {
115     interrupt_restore_nmi(maincpu_int_status, cia_context->int_num, value);
116 }
117 
118 #define MYCIA CIA2
119 
120 /*************************************************************************
121  * I/O
122  */
123 
124 /* Current video bank (0, 1, 2 or 3).  */
125 static int vbank;
126 
127 
do_reset_cia(cia_context_t * cia_context)128 static void do_reset_cia(cia_context_t *cia_context)
129 {
130     store_userport_pbx(0xff);
131 
132     /* The functions below will gradually be removed as the functionality is added to the new userport system. */
133 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
134     rsuser_write_ctrl((uint8_t)0xff);
135     rsuser_set_tx_bit(1);
136 #endif
137 
138     vbank = 0;
139     mem_set_vbank(vbank);
140 }
141 
pre_store(void)142 static void pre_store(void)
143 {
144     vicii_handle_pending_alarms_external_write();
145 }
146 
pre_read(void)147 static void pre_read(void)
148 {
149     vicii_handle_pending_alarms_external(0);
150 }
151 
pre_peek(void)152 static void pre_peek(void)
153 {
154     vicii_handle_pending_alarms_external(0);
155 }
156 
store_ciapa(cia_context_t * cia_context,CLOCK rclk,uint8_t byte)157 static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte)
158 {
159     if (cia_context->old_pa != byte) {
160         uint8_t tmp;
161         int new_vbank;
162 
163 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
164         if (rsuser_enabled && ((cia_context->old_pa ^ byte) & 0x04)) {
165             rsuser_set_tx_bit(byte & 4);
166         }
167 #endif
168         tmp = ~byte;
169         new_vbank = tmp & 3;
170         if (new_vbank != vbank) {
171             vbank = new_vbank;
172             mem_set_vbank(new_vbank);
173         }
174         (*iecbus_callback_write)((uint8_t)tmp, maincpu_clk);
175     }
176 }
177 
undump_ciapa(cia_context_t * cia_context,CLOCK rclk,uint8_t byte)178 static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte)
179 {
180 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
181     if (rsuser_enabled) {
182         rsuser_set_tx_bit((int)(byte & 4));
183     }
184 #endif
185     vbank = (byte ^ 3) & 3;
186     mem_set_vbank(vbank);
187     iecbus_cpu_undump((uint8_t)(byte ^ 0xff));
188 }
189 
190 
store_ciapb(cia_context_t * cia_context,CLOCK rclk,uint8_t byte)191 static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte)
192 {
193     store_userport_pbx(byte);
194 
195     /* The functions below will gradually be removed as the functionality is added to the new userport system. */
196     parallel_cable_cpu_write(DRIVE_PC_STANDARD, (uint8_t)byte);
197 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
198     rsuser_write_ctrl((uint8_t)byte);
199 #endif
200 }
201 
pulse_ciapc(cia_context_t * cia_context,CLOCK rclk)202 static void pulse_ciapc(cia_context_t *cia_context, CLOCK rclk)
203 {
204     parallel_cable_cpu_pulse(DRIVE_PC_STANDARD);
205 }
206 
207 /* FIXME! */
undump_ciapb(cia_context_t * cia_context,CLOCK rclk,uint8_t byte)208 static inline void undump_ciapb(cia_context_t *cia_context, CLOCK rclk,
209                                 uint8_t byte)
210 {
211     store_userport_pbx(byte);
212 
213     /* The functions below will gradually be removed as the functionality is added to the new userport system. */
214     parallel_cable_cpu_undump(DRIVE_PC_STANDARD, (uint8_t)byte);
215 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
216     rsuser_write_ctrl((uint8_t)byte);
217 #endif
218 }
219 
220 /* read_* functions must return 0xff if nothing to read!!! */
read_ciapa(cia_context_t * cia_context)221 static uint8_t read_ciapa(cia_context_t *cia_context)
222 {
223     return ((cia_context->c_cia[CIA_PRA] | ~(cia_context->c_cia[CIA_DDRA]))
224             & 0x3f) | (*iecbus_callback_read)(maincpu_clk);
225 }
226 
227 /* read_* functions must return 0xff if nothing to read!!! */
read_ciapb(cia_context_t * cia_context)228 static uint8_t read_ciapb(cia_context_t *cia_context)
229 {
230     uint8_t byte = 0xff;
231 
232     byte = read_userport_pbx(0x1f, byte);
233 
234     /* The functions below will gradually be removed as the functionality is added to the new userport system. */
235 #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET)
236     if (rsuser_enabled) {
237         byte = rsuser_read_ctrl(byte);
238     } else
239 #endif
240     byte = parallel_cable_cpu_read(DRIVE_PC_STANDARD, byte);
241 
242     byte = (byte & ~(cia_context->c_cia[CIA_DDRB]))
243            | (cia_context->c_cia[CIA_PRB] & cia_context->c_cia[CIA_DDRB]);
244     return byte;
245 }
246 
read_ciaicr(cia_context_t * cia_context)247 static void read_ciaicr(cia_context_t *cia_context)
248 {
249     parallel_cable_cpu_execute(DRIVE_PC_STANDARD);
250 }
251 
read_sdr(cia_context_t * cia_context)252 static void read_sdr(cia_context_t *cia_context)
253 {
254 }
255 
store_sdr(cia_context_t * cia_context,uint8_t byte)256 static void store_sdr(cia_context_t *cia_context, uint8_t byte)
257 {
258 }
259 
260 /* Temporary!  */
cia2_set_flagx(void)261 void cia2_set_flagx(void)
262 {
263     ciacore_set_flag(machine_context.cia2);
264 }
265 
cia2_set_sdrx(uint8_t received_byte)266 void cia2_set_sdrx(uint8_t received_byte)
267 {
268     ciacore_set_sdr(machine_context.cia2, received_byte);
269 }
270 
cia2_init(cia_context_t * cia_context)271 void cia2_init(cia_context_t *cia_context)
272 {
273     ciacore_init(machine_context.cia2, maincpu_alarm_context,
274                  maincpu_int_status, maincpu_clk_guard);
275 }
276 
cia2_set_timing(cia_context_t * cia_context,int tickspersec,int powerfreq)277 void cia2_set_timing(cia_context_t *cia_context, int tickspersec, int powerfreq)
278 {
279     cia_context->power_freq = powerfreq;
280     cia_context->ticks_per_sec = tickspersec;
281     cia_context->todticks = 0;
282     cia_context->power_tickcounter = 0;
283     cia_context->power_ticks = 0;
284 }
285 
cia2_setup_context(machine_context_t * machine_ctx)286 void cia2_setup_context(machine_context_t *machine_ctx)
287 {
288     cia_context_t *cia;
289 
290     machine_ctx->cia2 = lib_calloc(1, sizeof(cia_context_t));
291     cia = machine_ctx->cia2;
292 
293     cia->prv = NULL;
294     cia->context = NULL;
295 
296     cia->rmw_flag = &maincpu_rmw_flag;
297     cia->clk_ptr = &maincpu_clk;
298 
299     cia2_set_timing(cia, C64_PAL_CYCLES_PER_SEC, 0);
300 
301     ciacore_setup_context(cia);
302 
303     cia->debugFlag = 0;
304     cia->irq_line = IK_NMI;
305     cia->myname = lib_msprintf("CIA2");
306 
307     cia->undump_ciapa = undump_ciapa;
308     cia->undump_ciapb = undump_ciapb;
309     cia->store_ciapa = store_ciapa;
310     cia->store_ciapb = store_ciapb;
311     cia->store_sdr = store_sdr;
312     cia->read_ciapa = read_ciapa;
313     cia->read_ciapb = read_ciapb;
314     cia->read_ciaicr = read_ciaicr;
315     cia->read_sdr = read_sdr;
316     cia->cia_set_int_clk = cia_set_int_clk;
317     cia->cia_restore_int = cia_restore_int;
318     cia->do_reset_cia = do_reset_cia;
319     cia->pulse_ciapc = pulse_ciapc;
320     cia->pre_store = pre_store;
321     cia->pre_read = pre_read;
322     cia->pre_peek = pre_peek;
323 }
324