1 /*
2 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
3 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
4 * TT EE OO OO
5 * TT EE OO OO
6 * TT EE OO OO
7 * TT EEEEEEEEEE OO OO
8 * TT EEEEEEEEEE OO OO
9 * TT EE OO OO
10 * TT EE OO OO
11 * TT EE OO OO
12 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
13 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
14 *
15 * L'�mulateur Thomson TO8
16 *
17 * Copyright (C) 1997-2017 Gilles F�tis, Eric Botcazou, Alexandre Pukall,
18 * J�r�mie Guillaume, Fran�ois Mouret,
19 * Samuel Devulder
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 */
35
36 /*
37 * Module : to8.c
38 * Version : 1.8.4
39 * Cr�� par : Gilles F�tis
40 * Modifi� par: Eric Botcazou 03/11/2003
41 * Fran�ois Mouret 25/09/2006 26/01/2010 18/03/2012
42 * 02/11/2012 18/09/2013 10/05/2014
43 * 31/07/2016 20/10/2017
44 * Gilles F�tis 27/07/2011
45 * Samuel Devulder 05/02/2012
46 *
47 * Module de pilotage de l'�mulateur.
48 */
49
50
51 #ifndef SCAN_DEPEND
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #endif
56
57 #include "defs.h"
58 #include "teo.h"
59 #include "errors.h"
60 #include "image.h"
61 #include "ini.h"
62 #include "std.h"
63 #include "hardware.h"
64 #include "media/disk.h"
65 #include "media/joystick.h"
66 #include "media/keyboard.h"
67 #include "media/cass.h"
68 #include "media/mouse.h"
69 #include "media/printer.h"
70 #include "mc68xx/mc6809.h"
71 #include "mc68xx/mc6804.h"
72
73 int is_fr=0;
74
75 /* fonctions importables requises */
76 void (*teo_SetColor)(int, int, int, int);
77 void (*teo_DrawGPL)(int, int, int, int);
78 void (*teo_PutSoundByte)(unsigned long long int, unsigned char);
79 void (*teo_SetPointer)(int);
80
81 /* fonctions importables optionnelles */
82 int (*teo_DebugBreakPoint)(int pc) = NULL;
83 void (*teo_SetBorderColor)(int, int)=NULL;
84 void (*teo_DrawBorderLine)(int, int)=NULL;
85 void (*teo_SetKeyboardLed)(int)=NULL;
86 void (*teo_SetDiskLed)(int)=NULL;
87 int (*teo_DirectIsDiskWritable)(int)=NULL;
88 int (*teo_DirectReadSector)(int, int, int, int, unsigned char [])=NULL;
89 int (*teo_DirectWriteSector)(int, int, int, int, const unsigned char [])=NULL;
90 int (*teo_DirectFormatTrack)(int, int, const unsigned char [])=NULL;
91
92 /* variables publiques */
93 int teo_new_video_params;
94
95 /* variables priv�es */
96 static int teo_alive = 0;
97
98
99
100 /* LoadFile:
101 * Charge un fichier de taille donn�e.
102 */
LoadFile(const char filename[],unsigned char dest[],int size)103 static int LoadFile(const char filename[], unsigned char dest[], int size)
104 {
105 FILE *file;
106
107 if ((file=fopen(filename,"rb")) == NULL)
108 return error_Message(TEO_ERROR_FILE_NOT_FOUND, filename);
109
110 if (fread(dest, sizeof(char), size, file) != (size_t)size) {
111 fclose(file);
112 return error_Message(TEO_ERROR_FILE_OPEN, filename);
113 }
114 fclose(file);
115
116 return 0;
117 }
118
119
120
121 /* memory_hard_reset:
122 * Reset � froid de toute la RAM.
123 */
memory_hard_reset(void)124 static void memory_hard_reset(void)
125 {
126 int bank;
127 int addr;
128
129 for (bank=0; bank<mem.ram.nbank; bank++)
130 {
131 for (addr=0; addr<mem.ram.size; addr+=512)
132 {
133 memset (&mem.ram.bank[bank][addr], 0x00, 128);
134 memset (&mem.ram.bank[bank][addr+128], 0xff, 256);
135 memset (&mem.ram.bank[bank][addr+384], 0x00, 128);
136 }
137 }
138 }
139
140
141
142 /* InitMemory:
143 * Initialisation de la carte m�moire et chargement des ROMS.
144 */
InitMemory(void)145 static int InitMemory(void)
146 {
147 register int i;
148
149 /* 64 ko de ROM logiciels */
150 for (i=0; i<mem.rom.nbank; i++)
151 if ((mem.rom.bank[i] = malloc(mem.rom.size*sizeof(uint8))) == NULL)
152 return error_Message(TEO_ERROR_ALLOC, NULL);
153
154 /* 512 ko de RAM */
155 for (i=0; i<mem.ram.nbank; i++)
156 if ((mem.ram.bank[i] = calloc(mem.ram.size, sizeof(uint8))) == NULL)
157 return error_Message(TEO_ERROR_ALLOC, NULL);
158 memory_hard_reset();
159
160 /* 16 ko de ROM moniteur */
161 for (i=0; i<mem.mon.nbank; i++)
162 if ((mem.mon.bank[i] = malloc(mem.mon.size*sizeof(uint8))) == NULL)
163 return error_Message(TEO_ERROR_ALLOC, NULL);
164
165 for (i=0; i<mem.rom.nbank; i++)
166 if (LoadFile(mem.rom.filename[i], mem.rom.bank[i], mem.rom.size) < 0)
167 return TEO_ERROR;
168
169 for (i=0; i<mem.mon.nbank; i++)
170 if (LoadFile(mem.mon.filename[i], mem.mon.bank[i], mem.mon.size) < 0)
171 return TEO_ERROR;
172
173 /* modification de la page d'affichage de la date */
174 mem.rom.bank[3][0x25D3]=TEO_TRAP_CODE;
175 mem.rom.bank[3][0x2619]=0x21;
176
177 /* modification de la page de r�glage de la palette de couleurs */
178 mem.rom.bank[3][0x3579]=TEO_TRAP_CODE;
179 mem.rom.bank[3][0x3685]=TEO_TRAP_CODE;
180 mem.rom.bank[3][0x38EB]=0x7E;
181 mem.rom.bank[3][0x38EC]=0x39;
182 mem.rom.bank[3][0x38ED]=0x10;
183 mem.rom.bank[3][0x395F]=0x12;
184 mem.rom.bank[3][0x3960]=0x12;
185 mem.rom.bank[3][0x396F]=0x12;
186 mem.rom.bank[3][0x3970]=0x12;
187
188 LOCK_DATA(mem.ram.bank[0], sizeof(uint8)*mem.ram.size);
189 LOCK_DATA(mem.ram.bank[1], sizeof(uint8)*mem.ram.size);
190 LOCK_DATA(mem.ram.bank[2], sizeof(uint8)*mem.ram.size);
191 LOCK_DATA(mem.ram.bank[3], sizeof(uint8)*mem.ram.size);
192 LOCK_DATA(mem.mon.bank[1], sizeof(uint8)*mem.rom.size);
193
194 return 0;
195 }
196
197
198
199 /* DoLines:
200 * Fait tourner le MC6809E en le synchronisant sur le
201 * faisceau vid�o ligne par ligne.
202 */
DoLines(int nlines,mc6809_clock_t * exact_clock)203 static int DoLines(int nlines, mc6809_clock_t *exact_clock)
204 {
205 register int i;
206
207 for (i=0; i<nlines; i++)
208 {
209 /* bordure gauche de la ligne */
210 *exact_clock+=(LEFT_SHADOW_CYCLES+LEFT_BORDER_CYCLES);
211 if (mc6809_TimeExec(*exact_clock)<0) return 0;
212
213 /* partie centrale de la ligne */
214 mode_page.lp4|=0x20;
215
216 *exact_clock+=WINDOW_LINE_CYCLES;
217 if (mc6809_TimeExec(*exact_clock)<0) return 0;
218
219 mode_page.lp4&=0xDF;
220
221 /* bordure droite de la ligne */
222 *exact_clock+=(RIGHT_BORDER_CYCLES+RIGHT_SHADOW_CYCLES);
223 if (mc6809_TimeExec(*exact_clock)<0) return 0;
224 }
225 return 1;
226 }
227
228
229
230 /* DoLinesAndRetrace:
231 * Fait tourner le MC6809E en retra�ant l'�cran ligne par ligne.
232 */
DoLinesAndRetrace(int nlines,mc6809_clock_t * exact_clock)233 static int DoLinesAndRetrace(int nlines, mc6809_clock_t *exact_clock)
234 {
235 register int i,j,k;
236 int vram_addr=0;
237
238 for (i=0; i<nlines; i++)
239 {
240 /* bordure gauche de la ligne */
241 if (teo_DrawBorderLine)
242 {
243 *exact_clock+=LEFT_SHADOW_CYCLES;
244 if (mc6809_TimeExec(*exact_clock)<0) return 0;
245
246 teo_DrawBorderLine(TEO_LEFT_BORDER, TOP_BORDER_LINES+i);
247 *exact_clock+=LEFT_BORDER_CYCLES;
248 if (mc6809_TimeExec(*exact_clock)<0) return 0;
249 }
250 else
251 {
252 *exact_clock+=(LEFT_SHADOW_CYCLES+LEFT_BORDER_CYCLES);
253 if (mc6809_TimeExec(*exact_clock)<0) return 0;
254 }
255
256 /* partie centrale de la ligne */
257 mode_page.lp4|=0x20;
258
259 /* on d�coupe la ligne en petits groupes d'octets dont la
260 longueur est LINE_GRANULARITY */
261 for (j=0; j<WINDOW_LINE_CYCLES/LINE_GRANULARITY; j++)
262 {
263 for (k=0; k<LINE_GRANULARITY; k++)
264 DrawGPL(vram_addr++);
265
266 *exact_clock+=LINE_GRANULARITY;
267 if (mc6809_TimeExec(*exact_clock)<0) return 0;
268 }
269
270 mode_page.lp4&=0xDF;
271
272 /* bordure droite de la ligne */
273 if (teo_DrawBorderLine)
274 teo_DrawBorderLine(TEO_RIGHT_BORDER, TOP_BORDER_LINES+i);
275
276 *exact_clock+=RIGHT_BORDER_CYCLES+RIGHT_SHADOW_CYCLES;
277 if (mc6809_TimeExec(*exact_clock)<0) return 0;
278 }
279 return 1;
280 }
281
282
283
284 #ifndef TEO_NO_BORDER
285
286 /* DoBorderLinesAndRetrace:
287 * Fait tourner le MC6809E en retra�ant le pourtour ligne par ligne.
288 */
DoBorderLinesAndRetrace(int border,int nlines,mc6809_clock_t * exact_clock)289 static int DoBorderLinesAndRetrace(int border, int nlines, mc6809_clock_t *exact_clock)
290 {
291 register int i,j,k;
292 int offset=0;
293
294 if (border==BOTTOM_BORDER)
295 offset=TOP_BORDER_LINES+WINDOW_LINES;
296
297 for (i=0; i<nlines; i++)
298 {
299 /* bordure gauche de la ligne */
300 *exact_clock+=LEFT_SHADOW_CYCLES;
301 if (mc6809_TimeExec(*exact_clock)<0) return 0;
302
303 teo_DrawBorderLine(TEO_LEFT_BORDER, offset+i);
304 *exact_clock+=LEFT_BORDER_CYCLES;
305 if (mc6809_TimeExec(*exact_clock)<0) return 0;
306
307 /* partie centrale de la ligne */
308 mode_page.lp4|=0x20;
309
310 /* on d�coupe la ligne en petits groupes d'octets dont la
311 longueur est LINE_GRANULARITY */
312 for (j=0; j<WINDOW_LINE_CYCLES/LINE_GRANULARITY; j++)
313 {
314 for (k=0; k<LINE_GRANULARITY; k++)
315 teo_DrawBorderLine(j*LINE_GRANULARITY+k, offset+i);
316
317 *exact_clock+=LINE_GRANULARITY;
318 if (mc6809_TimeExec(*exact_clock)<0) return 0;
319 }
320
321 mode_page.lp4&=0xDF;
322
323 /* bordure droite de la ligne */
324 teo_DrawBorderLine(TEO_RIGHT_BORDER, offset+i);
325 *exact_clock+=RIGHT_BORDER_CYCLES+RIGHT_SHADOW_CYCLES;
326 if (mc6809_TimeExec(*exact_clock)<0) return 0;
327 }
328 return 1;
329 }
330 #endif
331
332
333
334 /* ------------------------------------------------------------------------- */
335
336
337 /* teo_Reset:
338 * Simulate a warm reset.
339 */
teo_Reset(void)340 void teo_Reset(void)
341 {
342 /* Back to 40 columns display */
343 mode_page.lgamod=0x00;
344 teo_new_video_params=TRUE;
345
346 mc6809_Reset();
347 }
348
349
350
351 /* teo_ColdReset:
352 * Simulate a soft cold reset.
353 */
teo_ColdReset(void)354 void teo_ColdReset(void)
355 {
356 /* initialisation du PIA 6846 syst�me */
357 mc6846_Init(&mc6846, 0x80, 0xE5, 0x3D);
358
359 /* initialisation du PIA 6804 syst�me */
360 mc6804_Init(&mc6846);
361
362 /* initialisation du PIA 6821 syst�me */
363 mc6821_Init(&pia_int.porta, 0, 0);
364
365 /* les bits 3-7 (�mul�s sur le TO8) sont � 1 en entr�e
366 (voir le manuel technique TO8/9/9+ page 44) */
367 mc6821_Init(&pia_int.portb, 0, 0xFC);
368
369 /* initialisation du PIA 6821 musique et jeux */
370 mc6821_Init(&pia_ext.porta, 0xC0, 0xFF);
371 mc6821_Init(&pia_ext.portb, 0xC0, 0xCF);
372
373 /* initialisation du gate array mode page */
374 memset(&mode_page, 0, sizeof(struct GATE_ARRAY));
375
376 /* initialisation des pages m�moire */
377 mempager.cart.page = 0;
378 mempager.cart.rom_page = 0;
379 mempager.cart.ram_page = 0;
380 mempager.cart.update();
381
382 mempager.screen.page = 1;
383 mempager.screen.vram_page = 0;
384 mempager.screen.update();
385
386 mempager.system.page = 1;
387 mempager.system.update();
388
389 mempager.data.reg_page = 0;
390 mempager.data.pia_page = 2;
391 mempager.data.update();
392
393 mempager.mon.page = 0;
394 mempager.mon.update();
395
396 STORE_BYTE(0x60FF, 0x00);
397
398 teo_Reset();
399 }
400
401
402
403 /* teo_FullReset:
404 * Simulate an electrical cold reset.
405 */
teo_FullReset(void)406 void teo_FullReset(void)
407 {
408 memory_hard_reset();
409 teo_ColdReset();
410 }
411
412
413
414 /* DoFrame:
415 * Fait tourner le TO8 pendant une trame vid�o.
416 */
teo_DoFrame(void)417 int teo_DoFrame(void)
418 {
419 screen_clock=mb.exact_clock;
420
421 if (teo_new_video_params)
422 {
423 teo_new_video_params=FALSE;
424 mb.direct_screen_mode=FALSE;
425
426 /* d�but de la frame vid�o: bordure haute de l'�cran */
427 #ifndef TEO_NO_BORDER
428 if (teo_DrawBorderLine)
429 {
430 if (DoLines(TOP_SHADOW_LINES, &mb.exact_clock) == 0)
431 return 0;
432 if (DoBorderLinesAndRetrace(TOP_BORDER, TOP_BORDER_LINES, &mb.exact_clock) == 0)
433 return 0;
434 }
435 else
436 #endif
437 if (DoLines(TOP_SHADOW_LINES+TOP_BORDER_LINES, &mb.exact_clock) == 0)
438 return 0;
439
440 /* fen�tre centrale de l'�cran */
441 mode_page.lp4|=0x80;
442 if (DoLinesAndRetrace(WINDOW_LINES, &mb.exact_clock) == 0)
443 return 0;
444 mode_page.lp4&=0x7F;
445
446 /* bordure du bas de l'�cran et remont�e du faisceau */
447 #ifndef TEO_NO_BORDER
448 if (teo_DrawBorderLine)
449 {
450 if (DoBorderLinesAndRetrace(BOTTOM_BORDER, BOTTOM_BORDER_LINES, &mb.exact_clock) == 0)
451 return 0;
452 if (DoLines(BOTTOM_SHADOW_LINES, &mb.exact_clock) == 0)
453 return 0;
454 }
455 else
456 #endif
457 if (DoLines(BOTTOM_BORDER_LINES+BOTTOM_SHADOW_LINES, &mb.exact_clock) == 0)
458 return 0;
459 }
460 else
461 {
462 /* d�but de la frame vid�o: bordure haute de l'�cran */
463 if (DoLines(TOP_SHADOW_LINES+TOP_BORDER_LINES, &mb.exact_clock) == 0)
464 return 0;
465
466 /* fen�tre centrale de l'�cran */
467 mode_page.lp4|=0x80;
468
469 if (mb.direct_screen_mode)
470 {
471 if (DoLines(WINDOW_LINES, &mb.exact_clock) == 0)
472 return 0;
473 }
474 else
475 {
476 mb.direct_screen_mode=TRUE;
477 if (DoLinesAndRetrace(WINDOW_LINES, &mb.exact_clock) == 0)
478 return 0;
479 }
480
481 mode_page.lp4&=0x7F;
482
483 /* bordure du bas de l'�cran et remont�e du faisceau */
484 if (DoLines(BOTTOM_BORDER_LINES+BOTTOM_SHADOW_LINES, &mb.exact_clock) == 0)
485 return 0;
486 }
487 return 1;
488 }
489
490
491
492 /* teo_FlushFrame:
493 * Complete the frame.
494 */
teo_FlushFrame(void)495 void teo_FlushFrame(void)
496 {
497 if ((mb.exact_clock%TEO_CYCLES_PER_FRAME) != 0LL)
498 {
499 mb.exact_clock += TEO_CYCLES_PER_FRAME-
500 (mb.exact_clock%TEO_CYCLES_PER_FRAME);
501 mc6809_TimeExec(mb.exact_clock);
502 }
503 }
504
505
506
507 /* InputReset:
508 * Remet � z�ro les p�riph�riques d'entr�e.
509 */
teo_InputReset(int mask,int value)510 void teo_InputReset(int mask, int value)
511 {
512 keyboard_Reset(mask, value);
513 joystick_Reset();
514 mouse_Reset();
515 }
516
517
518
519 /* Exit:
520 * Arr�te l'�mulateur et restitue les ressources utilis�es.
521 * (il n'est pas n�cessaire de l'appeler explicitement, elle est
522 * automatiquement invoqu�e � la sortie du programme)
523 */
teo_Exit(void)524 void teo_Exit(void)
525 {
526 register int i;
527
528 if (!teo_alive)
529 return;
530
531 /* Referme l'imprimante */
532 printer_Close();
533
534 /* on lib�re la m�moire */
535 for (i=0; i<mem.rom.nbank; i++)
536 mem.rom.bank[i] = std_free (mem.rom.bank[i]);
537
538 for (i=0; i<mem.ram.nbank; i++)
539 mem.ram.bank[i] = std_free (mem.ram.bank[i]);
540
541 for (i=0; i<mem.mon.nbank; i++)
542 mem.mon.bank[i] = std_free (mem.mon.bank[i]);
543
544 for (i=0; i<mem.cart.nbank; i++)
545 mem.cart.bank[i] = std_free (mem.cart.bank[i]);
546
547 /* Free the disks structure */
548 disk_Free();
549
550 /* Lib�re l'occupation du message d'erreur */
551 teo_error_msg = std_free (teo_error_msg);
552
553 teo_alive = FALSE;
554 }
555
556
557
558 /* Init:
559 * Initialise l'�mulateur et r�serve les ressources n�cessaires.
560 */
teo_Init(int num_joy)561 int teo_Init(int num_joy)
562 {
563 /* on d�tecte les instances multiples */
564 if (teo_alive)
565 return error_Message(TEO_ERROR_MULTIPLE_INIT, NULL);
566
567 hardware_Init();
568
569 if (InitMemory() < 0)
570 {
571 teo_Exit();
572 return TEO_ERROR;
573 }
574
575 if (keyboard_Init(num_joy) < 0)
576 {
577 teo_Exit();
578 return TEO_ERROR;
579 }
580
581 joystick_Init();
582 mouse_Init();
583
584 if (disk_Init() < 0)
585 {
586 teo_Exit();
587 return TEO_ERROR;
588 }
589
590 cass_Init();
591 printer_Init();
592
593 teo_alive = TRUE;
594 atexit(teo_Exit);
595
596 teo_new_video_params = FALSE;
597 return 0;
598 }
599
600