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