1 /*
2  * petvia.c - VIA emulation in the PET.
3  *
4  * Written by
5  *  Andre Fachat <fachat@physik.tu-chemnitz.de>
6  *  Andreas Boose <viceteam@t-online.de>
7  *  Marco van den Heuvel <blackystardust68@yahoo.com>
8  *
9  * This file is part of VICE, the Versatile Commodore Emulator.
10  * See README for copyright notice.
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25  *  02111-1307  USA.
26  *
27  */
28 
29 #include "vice.h"
30 
31 #include <stdio.h>
32 
33 #include "crtc.h"
34 #include "datasette.h"
35 #include "drive.h"
36 #include "interrupt.h"
37 #include "joystick.h"
38 #include "keyboard.h"
39 #include "lib.h"
40 #include "log.h"
41 #include "maincpu.h"
42 #include "parallel.h"
43 #include "pet.h"
44 #include "petsound.h"
45 #include "petvia.h"
46 #include "tapeport.h"
47 #include "types.h"
48 #include "userport.h"
49 #include "via.h"
50 
51 
via_store(uint16_t addr,uint8_t data)52 void via_store(uint16_t addr, uint8_t data)
53 {
54     viacore_store(machine_context.via, addr, data);
55 }
56 
via_read(uint16_t addr)57 uint8_t via_read(uint16_t addr)
58 {
59     return viacore_read(machine_context.via, addr);
60 }
61 
via_peek(uint16_t addr)62 uint8_t via_peek(uint16_t addr)
63 {
64     return viacore_peek(machine_context.via, addr);
65 }
66 
67 /* switching PET charrom with CA2 */
set_ca2(via_context_t * via_context,int state)68 static void set_ca2(via_context_t *via_context, int state)
69 {
70     crtc_set_chargen_offset(state ? 256 : 0);
71 }
72 
73 /* switching userport strobe with CB2 */
set_cb2(via_context_t * via_context,int state)74 static void set_cb2(via_context_t *via_context, int state)
75 {
76     store_userport_pa2((uint8_t)state);
77 }
78 
set_int(via_context_t * via_context,unsigned int int_num,int value,CLOCK rclk)79 static void set_int(via_context_t *via_context, unsigned int int_num,
80                     int value, CLOCK rclk)
81 {
82     interrupt_set_irq(maincpu_int_status, int_num, value, rclk);
83 }
84 
restore_int(via_context_t * via_context,unsigned int int_num,int value)85 static void restore_int(via_context_t *via_context, unsigned int int_num, int value)
86 {
87     interrupt_restore_irq(maincpu_int_status, int_num, value);
88 }
89 
undump_pra(via_context_t * via_context,uint8_t byte)90 static void undump_pra(via_context_t *via_context, uint8_t byte)
91 {
92     store_userport_pbx(byte);
93 }
94 
store_pra(via_context_t * via_context,uint8_t byte,uint8_t myoldpa,uint16_t addr)95 static void store_pra(via_context_t *via_context, uint8_t byte, uint8_t myoldpa,
96                       uint16_t addr)
97 {
98     store_userport_pbx(byte);
99 }
100 
undump_prb(via_context_t * via_context,uint8_t byte)101 static void undump_prb(via_context_t *via_context, uint8_t byte)
102 {
103     parallel_cpu_set_nrfd((uint8_t)(!(byte & 0x02)));
104     parallel_cpu_restore_atn((uint8_t)(!(byte & 0x04)));
105 }
106 
store_prb(via_context_t * via_context,uint8_t byte,uint8_t myoldpb,uint16_t addr)107 static void store_prb(via_context_t *via_context, uint8_t byte, uint8_t myoldpb,
108                       uint16_t addr)
109 {
110     if ((addr == VIA_DDRB) && (via_context->via[addr] & 0x20)) {
111         log_warning(via_context->log,
112                     "PET: Killer POKE! might kill a real PET!\n");
113     }
114     parallel_cpu_set_nrfd((uint8_t)(!(byte & 0x02)));
115     parallel_cpu_set_atn((uint8_t)(!(byte & 0x04)));
116     if ((byte ^ myoldpb) & 0x8) {
117         tapeport_toggle_write_bit((~(via_context->via[VIA_DDRB]) | byte) & 0x8);
118     }
119 }
120 
undump_pcr(via_context_t * via_context,uint8_t byte)121 static void undump_pcr(via_context_t *via_context, uint8_t byte)
122 {
123 #if 0
124     register uint8_t tmp = byte;
125     /* first set bit 1 and 5 to the real output values */
126     if ((tmp & 0x0c) != 0x0c) {
127         tmp |= 0x02;
128     }
129     if ((tmp & 0xc0) != 0xc0) {
130         tmp |= 0x20;
131     }
132     crtc_set_char(byte & 2); /* switching PET charrom with CA2 */
133                              /* switching userport strobe with CB2 */
134 #endif
135     petsound_store_manual((byte & 0xe0) == 0xe0);   /* Manual control of CB2 sound */
136 }
137 
store_pcr(via_context_t * via_context,uint8_t byte,uint16_t addr)138 static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr)
139 {
140 #if 0
141     if (byte != via_context->via[VIA_PCR]) {
142         register uint8_t tmp = byte;
143         /* first set bit 1 and 5 to the real output values */
144         if ((tmp & 0x0c) != 0x0c) {
145             tmp |= 0x02;
146         }
147         if ((tmp & 0xc0) != 0xc0) {
148             tmp |= 0x20;
149         }
150         crtc_set_char(byte & 2); /* switching PET charrom with CA2 */
151                                  /* switching userport strobe with CB2 */
152         store_userport_pa2((byte & 0x20) >> 5);
153     }
154 #endif
155     petsound_store_manual((byte & 0xe0) == 0xe0);   /* Manual control of CB2 sound */
156     return byte;
157 }
158 
undump_acr(via_context_t * via_context,uint8_t byte)159 static void undump_acr(via_context_t *via_context, uint8_t byte)
160 {
161     petsound_store_onoff(via_context->via[VIA_T2LL]
162                          ? (((byte & 0x1c) == 0x10) ? 1 : 0) : 0);
163 }
164 
store_acr(via_context_t * via_context,uint8_t byte)165 static void store_acr(via_context_t *via_context, uint8_t byte)
166 {
167     petsound_store_onoff(via_context->via[VIA_T2LL]
168                          ? (((byte & 0x1c) == 0x10) ? 1 : 0) : 0);
169 }
170 
store_sr(via_context_t * via_context,uint8_t byte)171 static void store_sr(via_context_t *via_context, uint8_t byte)
172 {
173     petsound_store_sample(byte);
174 }
175 
store_t2l(via_context_t * via_context,uint8_t byte)176 static void store_t2l(via_context_t *via_context, uint8_t byte)
177 {
178     petsound_store_rate(2 * byte + 4);
179     if (!byte) {
180         petsound_store_onoff(0);
181     } else {
182         petsound_store_onoff(((via_context->via[VIA_ACR] & 0x1c) == 0x10)
183                              ? 1 : 0);
184     }
185 }
186 
reset(via_context_t * via_context)187 static void reset(via_context_t *via_context)
188 {
189     /* set IEC output lines */
190     parallel_cpu_set_atn(0);
191     parallel_cpu_set_nrfd(0);
192 
193     store_userport_pbx(0xff);
194     store_userport_pa2(1);
195 }
196 
read_pra(via_context_t * via_context,uint16_t addr)197 inline static uint8_t read_pra(via_context_t *via_context, uint16_t addr)
198 {
199     uint8_t byte = 0xff;
200 
201     byte = read_userport_pbx((uint8_t)~via_context->via[VIA_DDRA], byte);
202 
203     /* The functions below will gradually be removed as the functionality is added to the new userport system. */
204 
205     /* joystick always pulls low, even if high output, so no
206        masking with DDRA */
207     /*return ((j & ~(via_context->via[VIA_DDRA]))
208         | (via_context->via[VIA_PRA] & via_context->via[VIA_DDRA]));*/
209     return byte;
210 }
211 
read_prb(via_context_t * via_context)212 static uint8_t read_prb(via_context_t *via_context)
213 {
214     uint8_t byte;
215 
216     drive_cpu_execute_all(maincpu_clk);
217 
218     /* read parallel IEC interface line states */
219     byte = 255
220            - (parallel_nrfd ? 64 : 0)
221            - (parallel_ndac ? 1 : 0)
222            - (parallel_dav ? 128 : 0);
223     /* vertical retrace */
224     byte -= crtc_offscreen() ? 32 : 0;
225 
226     /* none of the load changes output register value -> std. masking */
227     byte = ((byte & ~(via_context->via[VIA_DDRB]))
228             | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]));
229     return byte;
230 }
231 
via_init(via_context_t * via_context)232 void via_init(via_context_t *via_context)
233 {
234     viacore_init(machine_context.via, maincpu_alarm_context,
235                  maincpu_int_status, maincpu_clk_guard);
236 }
237 
petvia_setup_context(machine_context_t * machinecontext)238 void petvia_setup_context(machine_context_t *machinecontext)
239 {
240     via_context_t *via;
241 
242     machinecontext->via = lib_malloc(sizeof(via_context_t));
243     via = machinecontext->via;
244 
245     via->prv = NULL;
246     via->context = NULL;
247 
248     via->rmw_flag = &maincpu_rmw_flag;
249     via->clk_ptr = &maincpu_clk;
250 
251     via->myname = lib_msprintf("Via");
252     via->my_module_name = lib_msprintf("VIA");
253 
254     viacore_setup_context(via);
255 
256     via->irq_line = IK_IRQ;
257 
258     via->undump_pra = undump_pra;
259     via->undump_prb = undump_prb;
260     via->undump_pcr = undump_pcr;
261     via->undump_acr = undump_acr;
262     via->store_pra = store_pra;
263     via->store_prb = store_prb;
264     via->store_pcr = store_pcr;
265     via->store_acr = store_acr;
266     via->store_sr = store_sr;
267     via->store_t2l = store_t2l;
268     via->read_pra = read_pra;
269     via->read_prb = read_prb;
270     via->set_int = set_int;
271     via->restore_int = restore_int;
272     via->set_ca2 = set_ca2;
273     via->set_cb2 = set_cb2;
274     via->reset = reset;
275 }
276