fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/vic20/setup.c *
7 * Created: 2020-04-19 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2020-2022 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "keybd.h"
25#include "msg.h"
26#include "vic20.h"
27#include "video.h"
28
29#include <stdlib.h>
30#include <string.h>
31
32#include <chipset/e6522.h>
33
34#include <cpu/e6502/e6502.h>
35
36#include <devices/cassette.h>
37#include <devices/memory.h>
38
39#include <drivers/pti/pti-io.h>
40#include <drivers/sound/sound.h>
41#include <drivers/video/terminal.h>
42
43#include <lib/brkpt.h>
44#include <lib/iniram.h>
45#include <lib/initerm.h>
46#include <lib/load.h>
47#include <lib/log.h>
48
49#include <libini/libini.h>
50
51
52#define V20_CLOCK_PAL ((443361875 + 200) / 400)
53#define V20_CLOCK_NTSC (14318181 / 14)
54
55
56static
57void v20_setup_vic20 (vic20_t *sim, ini_sct_t *ini)
58{
59 unsigned speed;
60 int pal, aspeed;
61 ini_sct_t *sct;
62
63 sct = ini_next_sct (ini, NULL, "system");
64
65 ini_get_uint16 (sct, "speed", &speed, 1);
66 ini_get_bool (sct, "pal", &pal, 0);
67 ini_get_bool (sct, "auto_speed", &aspeed, 1);
68
69 sim->pal = (pal != 0);
70 sim->clock = sim->pal ? V20_CLOCK_PAL : V20_CLOCK_NTSC;
71
72 sim->speed = speed;
73 sim->speed_base = speed;
74 sim->speed_auto = (aspeed != 0);
75 sim->speed_tape = 0;
76
77 sim->framedrop_base = 0;
78 sim->framedrop_tape = 0;
79
80 pce_log_tag (MSG_INF, "VIC20:",
81 "cpu=6502 clock=%lu speed=%u autospeed=%d pal=%d\n",
82 sim->clock, sim->speed, sim->speed_auto, sim->pal
83 );
84
85 if ((sim->cpu = e6502_new()) == NULL) {
86 pce_log (MSG_ERR, "*** creating the cpu failed\n");
87 return;
88 }
89
90 e6502_set_flags (sim->cpu, E6502_FLAG_UNDEF);
91
92 if ((sim->mem = mem_new()) == NULL) {
93 pce_log (MSG_ERR, "*** creating memory failed\n");
94 return;
95 }
96
97 e6502_set_mem_f (sim->cpu, sim->mem, mem_get_uint8, mem_set_uint8);
98}
99
100static
101void v20_setup_mem (vic20_t *sim, ini_sct_t *ini)
102{
103 mem_set_fct (sim->mem, sim,
104 v20_get_uint8, NULL, NULL,
105 v20_set_uint8, NULL, NULL
106 );
107
108 ini_get_ram (sim->mem, ini, NULL);
109 ini_get_rom (sim->mem, ini);
110}
111
112static
113void v20_setup_via (vic20_t *sim, ini_sct_t *ini)
114{
115 pce_log_tag (MSG_INF, "VIA:", "initialized\n");
116
117 sim->ira1 = 0xfe;
118 sim->irb2 = 0xff;
119
120 e6522_init (&sim->via1, 0);
121 e6522_set_irq_fct (&sim->via1, sim, v20_set_via1_irq);
122 e6522_set_ora_fct (&sim->via1, sim, v20_set_via1_ora);
123 e6522_set_orb_fct (&sim->via1, sim, v20_set_via1_orb);
124 e6522_set_ca2_fct (&sim->via1, sim, v20_set_via1_ca2);
125
126 e6522_init (&sim->via2, 0);
127 e6522_set_irq_fct (&sim->via2, sim, v20_set_via2_irq);
128 e6522_set_ora_fct (&sim->via2, sim, v20_set_via2_ora);
129 e6522_set_orb_fct (&sim->via2, sim, v20_set_via2_orb);
130
131 e6522_set_ca1_inp (&sim->via1, 1);
132 e6522_set_ira_inp (&sim->via1, sim->ira1);
133 e6522_set_irb_inp (&sim->via2, sim->irb2);
134}
135
136static
137void v20_setup_video (vic20_t *sim, ini_sct_t *ini)
138{
139 int pal, border;
140 int hue;
141 unsigned sat, brt, drop;
142 unsigned long srate;
143 const char *snd;
144 ini_sct_t *sct;
145
146 sct = ini_next_sct (ini, NULL, "video");
147
148 ini_get_bool (sct, "pal", &pal, sim->pal);
149 ini_get_bool (sct, "border", &border, 0);
150 ini_get_sint16 (sct, "hue", &hue, 0);
151 ini_get_uint16 (sct, "saturation", &sat, 50);
152 ini_get_uint16 (sct, "brightness", &brt, 100);
153 ini_get_uint16 (sct, "framedrop", &drop, 0);
154 ini_get_string (sct, "sound", &snd, NULL);
155 ini_get_uint32 (sct, "sample_rate", &srate, 44100);
156
157 pce_log_tag (MSG_INF, "VIC:",
158 "pal=%d drop=%u hue=%d sat=%u brt=%u srate=%lu\n",
159 pal, drop, hue, sat, brt, srate
160 );
161
162 if (snd != NULL) {
163 pce_log_tag (MSG_INF, "VIC:", "sound=%s\n", snd);
164 }
165
166 sim->framedrop_base = drop;
167
168 v20_video_init (&sim->video);
169
170 v20_video_set_clock (&sim->video, sim->clock);
171 v20_video_set_srate (&sim->video, srate);
172
173 v20_video_set_pal (&sim->video, pal, border);
174 v20_video_set_memmap (&sim->video, sim->mem);
175
176 v20_video_set_framedrop (&sim->video, drop);
177
178 v20_video_set_hue (&sim->video, hue);
179 v20_video_set_saturation (&sim->video, sat / 100.0);
180 v20_video_set_brightness (&sim->video, brt / 100.0);
181
182 if (v20_video_set_sound_driver (&sim->video, snd)) {
183 pce_log (MSG_ERR, "*** sound driver failed\n");
184 }
185}
186
187static
188void v20_setup_terminal (vic20_t *sim, ini_sct_t *ini)
189{
190 sim->trm = ini_get_terminal (ini, par_terminal);
191
192 if (sim->trm == NULL) {
193 return;
194 }
195
196 trm_set_msg_fct (sim->trm, sim, v20_set_msg);
197 trm_set_key_fct (sim->trm, sim, v20_keybd_set_key);
198
199 v20_video_set_term (&sim->video, sim->trm);
200}
201
202static
203void v20_setup_keybd (vic20_t *sim, ini_sct_t *ini)
204{
205 unsigned i;
206 int joy;
207 ini_sct_t *sct;
208
209 sct = ini_next_sct (ini, NULL, "keyboard");
210
211 ini_get_bool (sct, "keypad_joystick", &joy, 0);
212
213 sim->keypad_joystick = (joy != 0);
214
215 pce_log_tag (MSG_INF, "KEYBOARD:", "joystick=%d\n",
216 sim->keypad_joystick
217 );
218
219 sim->joymat = 0;
220
221 for (i = 0; i < 8; i++) {
222 sim->keymat[i] = 0;
223 }
224}
225
226static
227void v20_setup_datasette (vic20_t *sim, ini_sct_t *ini)
228{
229 const char *read_name, *write_name;
230 unsigned long delay;
231 ini_sct_t *sct;
232
233 cas_init (&sim->cas);
234
235 if ((sct = ini_next_sct (ini, NULL, "datasette")) == NULL) {
236 return;
237 }
238
239 ini_get_string (sct, "file", &write_name, NULL);
240 ini_get_string (sct, "write", &write_name, write_name);
241 ini_get_string (sct, "read", &read_name, write_name);
242 ini_get_uint32 (sct, "motor_delay", &delay, 50);
243
244 pce_log_tag (MSG_INF, "CASSETTE:", "read=%s write=%s motor_delay=%lu\n",
245 (read_name != NULL) ? read_name : "<none>",
246 (write_name != NULL) ? write_name : "<none>",
247 delay
248 );
249
250 delay = (unsigned long) (((double) delay * sim->clock) / 1000.0);
251
252 cas_set_inp_fct (&sim->cas, sim, v20_cas_set_inp);
253 cas_set_play_fct (&sim->cas, sim, v20_cas_set_play);
254 cas_set_run_fct (&sim->cas, sim, v20_set_speed_tape);
255
256 cas_set_clock (&sim->cas, sim->clock);
257 cas_set_motor_delay (&sim->cas, delay);
258
259 pti_set_default_clock (sim->clock);
260
261 if (cas_set_read_name (&sim->cas, read_name)) {
262 pce_log (MSG_ERR, "*** opening read file failed (%s)\n",
263 read_name
264 );
265 }
266
267 if (cas_set_write_name (&sim->cas, write_name, 1)) {
268 pce_log (MSG_ERR, "*** opening write file failed (%s)\n",
269 write_name
270 );
271 }
272}
273
274static
275void v20_set_memmap (vic20_t *sim)
276{
277 unsigned i;
278 mem_blk_t *blk;
279
280 e6502_set_mem_map_rd (sim->cpu, 0x0000, 0xffff, NULL);
281 e6502_set_mem_map_wr (sim->cpu, 0x0000, 0xffff, NULL);
282
283 for (i = 0; i < sim->mem->cnt; i++) {
284 blk = sim->mem->lst[i].blk;
285
286 if (blk->data == NULL) {
287 continue;
288 }
289
290 e6502_set_mem_map_rd (sim->cpu, blk->addr1, blk->addr2, blk->data);
291
292 if (blk->readonly) {
293 continue;
294 }
295
296 e6502_set_mem_map_wr (sim->cpu, blk->addr1, blk->addr2, blk->data);
297 }
298}
299
300vic20_t *v20_new (ini_sct_t *ini)
301{
302 vic20_t *sim;
303
304 if ((sim = malloc (sizeof (vic20_t))) == NULL) {
305 return (NULL);
306 }
307
308 memset (sim, 0, sizeof (vic20_t));
309
310 sim->cfg = ini;
311
312 sim->brk = 0;
313 sim->irq_via1 = 0;
314 sim->irq_via2 = 0;
315 sim->clk_div = 0;
316
317 bps_init (&sim->bps);
318
319 v20_setup_vic20 (sim, ini);
320 v20_setup_mem (sim, ini);
321 v20_setup_via (sim, ini);
322 v20_setup_video (sim, ini);
323 v20_setup_keybd (sim, ini);
324 v20_setup_datasette (sim, ini);
325 v20_setup_terminal (sim, ini);
326
327 pce_load_mem_ini (sim->mem, ini);
328
329 v20_set_memmap (sim);
330
331 v20_set_msg (sim, "term.title", "VIC-20");
332
333 /* v20_debug_mem (sim); */
334
335 return (sim);
336}
337
338void v20_del (vic20_t *sim)
339{
340 if (sim == NULL) {
341 return;
342 }
343
344 cas_free (&sim->cas);
345
346 v20_video_free (&sim->video);
347
348 trm_del (sim->trm);
349
350 e6522_free (&sim->via2);
351 e6522_free (&sim->via1);
352
353 e6502_del (sim->cpu);
354
355 mem_del (sim->mem);
356
357 bps_free (&sim->bps);
358
359 free (sim);
360}