1 /**************************************************************************************\
2 *                                                                                      *
3 *              The Lisa Emulator Project  V1.2.6      DEV 2007.12.04                   *
4 *                             http://lisaem.sunder.net                                 *
5 *                                                                                      *
6 *                  Copyright (C) 1998, 2007 Ray A. Arachelian                          *
7 *                                All Rights Reserved                                   *
8 *                                                                                      *
9 *           This program is free software; you can redistribute it and/or              *
10 *           modify it under the terms of the GNU General Public License                *
11 *           as published by the Free Software Foundation; either version 2             *
12 *           of the License, or (at your option) any later version.                     *
13 *                                                                                      *
14 *           This program is distributed in the hope that it will be useful,            *
15 *           but WITHOUT ANY WARRANTY; without even the implied warranty of             *
16 *           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
17 *           GNU General Public License for more details.                               *
18 *                                                                                      *
19 *           You should have received a copy of the GNU General Public License          *
20 *           along with this program;  if not, write to the Free Software               *
21 *           Foundation, Inc., 59 Temple Place #330, Boston, MA 02111-1307, USA.        *
22 *                                                                                      *
23 *                   or visit: http://www.gnu.org/licenses/gpl.html                     *
24 *                                                                                      *
25 *                                                                                      *
26 *                                                                                      *
27 *                 CPU Board ROM loader and associated functions                        *
28 *                                                                                      *
29 \**************************************************************************************/
30 
31 #define IN_ROM_C 1
32 
33 #include "vars.h"
34 
35 
36 
ishex(char c)37 uint8 ishex(char c)
38 {	if (c>='0' && c<='9') return 1;
39 	if (c>='a' && c<='f') return 1;
40 	if (c>='A' && c<='F') return 1;
41 	return 0;
42 }
43 
gethex(char c)44 uint8 gethex(char c)
45 {	if (c>='0' && c<='9') return c-'0';
46 	if (c>='a' && c<='f') return c-'a'+10;
47 	if (c>='A' && c<='F') return c-'A'+10;
48 	return 0;
49 }
50 
51 
52 
53 
54 
55 // shamelessly stolen from ROL in generator so they match  -- used to fake the Lisa ROM checksum.
lrol(uint32 outdata,uint8 loop)56 uint32 lrol(uint32 outdata, uint8 loop)
57 {
58     uint32 cflag=0;
59 
60 	while(loop) {
61         cflag = outdata & 1<<31 ? 1 : 0;
62 		outdata<<= 1;
63 		if (cflag)
64 			outdata |= 1;
65 		loop--;
66 	}
67 
68 	return outdata;
69 }
70 
71 
wrol(uint16 outdata,uint8 loop)72 uint16 wrol(uint16 outdata, uint8 loop)
73 {
74 	uint16 cflag=0;
75 
76 	while(loop) {
77 		cflag = outdata & 1<<15 ? 1 : 0;
78 		outdata<<= 1;
79 		if (cflag)
80 			outdata |= 1;
81 		loop--;
82 	}
83 
84 	return outdata;
85 }
86 
brol(uint8 outdata,uint8 loop)87 uint8 brol(uint8 outdata, uint8 loop)
88 {
89     uint8 cflag=0;
90 
91 	while(loop) {
92         cflag = outdata & 1<<7 ? 1 : 0;
93 		outdata<<= 1;
94 		if (cflag)
95 			outdata |= 1;
96 		loop--;
97 	}
98 
99 	return outdata;
100 }
101 
102 
vidfixromchk(uint8 * s)103 void vidfixromchk(uint8 *s)
104 {
105  int i;  uint16 chksum, sum;
106 
107  s[0]=0xff; s[7]=0xff;
108  chksum=(s[24]*100) + (s[25]*10) + s[26];
109 
110  for (sum=0,i=0; i<24; i++) sum+=(s[i]>>4)+(s[i]&15); sum+=s[27]; sum-=60;
111 
112 // DEBUG_LOG(0,"serno:checksum I calculated: %04x, checksum stored: %04x lisa calculated 0x82",sum,chksum);
113 
114 
115 /*  The checksum the lisa does is the addition of vals of addresses 0x250-0x268  -60 + s[27]
116  *
117  *
118  */
119 
120  if ( chksum==sum) return;
121 
122  s[24]=sum/100; sum=sum % 100;
123  s[25]=sum/10;  sum=sum % 10;
124  s[26]=sum;
125 
126 // DEBUG_LOG(0,"Corrected checksum bytes from (%d) to (%d) (%d %d %d)",chksum,sum,s[24],s[25],s[26]);
127 }
128 
chksum_a_rom_range(uint8 * rom,uint32 a0,uint32 a1)129 uint16 chksum_a_rom_range(uint8 *rom, uint32 a0, uint32 a1)
130 {
131     uint16 d0=0;
132 
133     do                                      //DOSUM
134 	{
135         d0+=(rom[a0]<<8)+rom[a0+1];         //ADD(A0)+,D0
136 		a0+=2;
137 		d0=wrol(d0,1);						//ROL #1,D0
138 	}										//CMPA.L A0,A1
139 	while (a0!=a1);							//BNE.S DOSUM
140 
141     return d0;
142 }
143 
fixromchk(void)144 void fixromchk(void)
145 {
146 
147 	/* C ROM */ if (lisarom[0x3ffc]==0x02 && lisarom[0x3ffd]==0x11) ALERT_LOG(0,"C ROM 0x275:%02x",lisarom[0x0275]);
148 
149 
150 
151     // don't touch any ROM except H
152     if (lisarom[0x3ffc] != 0x02 || lisarom[0x3ffd] != 'H')  return;
153 
154     if (cheat_ram_test)
155     {
156 
157        /* Only apply these patches if we're fairly sure it's the 2.H ROM */
158 
159        /*
160         * Patch the check in MEMTST2 to decide how many tests to run based on
161         * warmstart/coldstart to instead jump straight to TSTDONE always.
162         */
163 
164        ALERT_LOG(0,"H ROM patched with ram-test cheats")
165 
166        lisarom[0x0e1a] = 0x60;
167        lisarom[0x0e1b] = 0x32;
168 
169        /* Instead of jumping to BEGIN go to SETMMU. */
170        lisarom[0x0006] = 0x02;
171        lisarom[0x0007] = 0xc6;
172     }
173 
174     /* Simulate all but the final add of the ROM checksum routine */
175     uint16 d0;
176     uint32 a0,a1;
177 
178 	d0=0;									// CLR.L D0
179 	a0=0;									// LEA BASE,A0
180 	a1=0x3ffe;								// LEA LAST,A1
181 
182     d0=chksum_a_rom_range(lisarom,a0,a1);
183 
184 //    ALERT_LOG(1,"Lisa ROM Checksum is %04x,negated it's %04x, zero=%04x",d0,(~d0)+1,d0+(~d0)+1);
185 
186 	/* negate checksum so when lisa rom adds it, it will be zero. */
187 	d0=(~d0)+1;
188 
189 	lisarom[0x3ffe]=(d0>>8);
190 	lisarom[0x3fff]=(d0 & 0xff);
191 }
192 
193 // not sure if this will work with non 2.x ROMs (i.e. Lisa 1 or 3A), worst case
194 // it'll just send an alert.
checkromchksum(void)195 int checkromchksum(void)
196 {
197     /* Simulate all including final add of the ROM checksum routine */
198 	uint16 d0;
199 	uint32 a0,a1;
200 
201 	d0=0;									// CLR.L D0
202 	a0=0;									// LEA BASE,A0
203     a1=0x4000;                              // LEA LAST,A1
204 
205     d0=chksum_a_rom_range(lisarom,a0,a1);
206 
207 //    ALERT_LOG(1,"Original Lisa ROM CHKSUM is %02x%02x",lisarom[0x3ffe],lisarom[0x3fff]);
208 //    ALERT_LOG(1,"Lisa ROM Checksum is %04x,negated it's %04x, zero=%04x",d0,(~d0)+1,d0+(~d0)+1);
209 
210 	/* negate checksum so when lisa rom adds it, it will be zero. */
211     return (~d0)+1;
212 }
213 
214 
has_xl_screenmod(void)215 int has_xl_screenmod(void)
216 {
217 
218  //      |VERSION|CHKSUM
219  //3ffc::|03 41 |d9 05 | <-3A ROM
220  //3ffc: |02 48 |3f 7b |  <-H ROM
221  //3ffc  |02 46 |f6 f5 |  <-F ROM
222  //3ffc  |02 11 |b2 67 |  <-C ROM
223  //3ffc  |02 09 |5E 4B |  <-B ROM
224  //------|------|------|-----------
225  //      |0c 0d |0e 0f |
226  return (lisarom[0x3ffc]==0x03);
227 }
228 
229 
230 /**************************************************************************************\
231 * This function loads in a ROM image from the source code as provided by DTC.  This    *
232 * expects the ASSEMBLED source file as input.  It can also read a hex dump made by a   *
233 * debugger if in the same format, and the dump is less than 28 chars wide.             *
234 * i.e.: 0000| AA AB BC CD FF                                                           *
235 *       addr| hex byte data.                                                           *
236 *                                                                                      *
237 * The main reason for this is so that during debugging I can see what the ROM is       *
238 * attempting to execute and the results.  This way I can output the ROM source instead *
239 * of hard to read uncommented machine code without symbols.                            *
240 \**************************************************************************************/
241 
read_dtc_rom(char * filename,uint8 * ROM)242 int16 read_dtc_rom(char *filename, uint8 *ROM)
243 {
244 
245  char *line; // line buffer
246  unsigned long address;
247  unsigned int  data;
248  long fileposition;
249  int i;
250  int ok=0;
251 
252  rom_source_file=fopen(filename,"rt");
253  if (!rom_source_file) return -1;
254 
255  line=(char *)malloc(1024); if (!line) return -2;
256 
257  if (rom_source_file)
258  {
259 #ifdef DEBUG
260 	dtc_rom_fseeks=(long *)malloc(sizeof(long)*0x4000); // fseeks for source code.
261 	if (!dtc_rom_fseeks)
262 	{
263 		EXITR(5,0,"Couldn't allocate enough memory for ROM source pointers!\n");
264 	}
265     memset(dtc_rom_fseeks,0,sizeof(long)*0x4000);
266 #endif
267 
268    // Fill ROM with NOP's incase there are "holes" in the ROM    NOP=0x4e71
269 
270 
271     // Repair ROM holes in DTC rom
272     //memset(ROM,0,16383);
273     for ( i=0; i<0x4000; i+=2) {ROM[i]=0x4e; ROM[i|1]=0x71;}
274     memset(&ROM[0x39C3],0xff,0x3fff-0x39c3);
275 
276     DEBUG_LOG(0,"Reading source assembled ROM\n");
277 
278 	while (!feof(rom_source_file))
279 	{
280 		fileposition=ftell(rom_source_file);
281 		fgets(line,1024,rom_source_file);
282 		if (ishex(line[0]) && ishex(line[1]) && ishex(line[2]) && ishex(line[3]) && line[4]=='|' && line[5]==' ')
283         {   address=(gethex(line[0])<<12) + (gethex(line[1])<<8 ) +  (gethex(line[2])<<4 ) + gethex(line[3]);
284             //DEBUG_LOG(0,("%04x:",address);
285             for (i=6; i<29; i++)
286 				if (ishex(line[i]) && ishex(line[i+1]))
287 				{	data=(gethex(line[i])<<4)+gethex(line[i+1]);
288                     //DEBUG_LOG(0,("%02x ",data);
289 					if (address<0x4000)
290 					{
291 						ROM[address]=data; ok=1;
292 #ifdef DEBUG
293 						if (dtc_rom_fseeks) dtc_rom_fseeks[address]=fileposition;
294 #endif
295 					}
296 					i++;       // since we read another in line(i+1)
297 					address++; // since this could be a word, or long
298 				}
299 		} // If hex data on line
300 		//printf("\n");
301 	} // file reading while loop
302 
303 
304 
305 #ifdef DEBUG
306     fseek(rom_source_file,0L,SEEK_SET);
307 #else
308     if (rom_source_file)	fclose(rom_source_file);
309 #endif
310  }
311 // See if we have the object file.
312 
313   snprintf(line,1024,"%s.obj",filename);
314   rom_source_file=fopen(line,"rt");
315   if ( !rom_source_file && ok)
316   {  fprintf(buglog,"Warning! Lisa rom source is filled with 'holes' - the emulator will fail!\n");
317      fprintf(buglog,"Add the object code file, or use a real ROM, but the source won't match it.\n\n");
318          return ok ? 0:1;
319 
320   // "Imagine if every Thursday your shoes exploded if you tied them the
321   //  usual way.  This happens to us all the time with computers, and nobody
322   //  thinks of complaining." -- Jef Raskin, interviewed in Doctor Dobb's Journal
323 
324 
325 
326   }
327 
328   if ( !ok)                             // If we didn't get the source rom, plug the holes.
329   {
330       for ( i=0; i<0x4000; i+=2) {ROM[i]=0x4e; ROM[i|1]=0x71;}
331       memset(&ROM[0x39C3],0xff,0x3fff-0x39c3);
332   }
333 
334   if ( rom_source_file)
335   {
336 
337 #define OBJOFF 0x0038
338 #define READ_HEX_QUAD(i)                                                                        \
339          if ( ishex(line[i+0]) && ishex(line[i+1]) && ishex(line[i+2]) && ishex(line[i+3]))     \
340          {                                                                                      \
341            if ( address>OBJOFF-1 && address<0x3ffe )                                            \
342              {                                                                                  \
343                uint8 a,b;                                                                       \
344                a=ROM[address-OBJOFF]; b=ROM[address-OBJOFF+1];                                  \
345                ROM[address-OBJOFF]=(gethex(line[i+0])<<4)|gethex(line[i+1]); address++;         \
346                ROM[address-OBJOFF]=(gethex(line[i+2])<<4)|gethex(line[i+3]); address++;         \
347              } else address+=2;                                                                 \
348          }
349 
350 
351     while ( !feof(rom_source_file))
352     {
353       //   01234567890123456789012345678901234567890123456789
354       //             1         2         3         4
355       //   00aaaa: xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx [................]
356 
357       fgets(line,1024,rom_source_file);
358 
359       if ( line[7]==' ' && line[6]==':' && line[0]=='0' && line[1]=='0' && ishex(line[2]) && ishex(line[3]) && ishex(line[4]) && ishex(line[5]) )
360        {
361          address=(gethex(line[2])<<12 ) + (gethex(line[3])<<8) + (gethex(line[4])<<4) + gethex(line[5]);
362          if ( address>0x4039)
363                 {
364                     if (rom_source_file) fclose(rom_source_file);
365                     free(line);
366 #ifdef DEBUG
367                     rom_source_file=fopen(filename,"rt");
368                     fseek(rom_source_file,0L,SEEK_SET);
369 #endif
370                     return 0;}
371          READ_HEX_QUAD( 8);
372          READ_HEX_QUAD(13);
373          READ_HEX_QUAD(18);
374          READ_HEX_QUAD(23);
375          READ_HEX_QUAD(28);
376          READ_HEX_QUAD(33);
377          READ_HEX_QUAD(38);
378          READ_HEX_QUAD(43);
379        }
380     }
381   }
382 
383 
384   if (rom_source_file) fclose(rom_source_file);
385   free(line);
386 #ifdef DEBUG
387                     rom_source_file=fopen(filename,"rt");
388                     fseek(rom_source_file,0L,SEEK_SET);
389 #endif
390 
391 return (ok ? 0 : 1);
392 }
393 
394 /**************************************************************************************\
395 * This function loads in a ROM image that is split up into even and odd bytes as       *
396 * as provided by the MESS project.                                                     *
397 \**************************************************************************************/
398 extern void rename_rompath(char *rompath);
399 
read_split_rom(char * filename,uint8 * ROMMX)400 int16 read_split_rom(char *filename, uint8 *ROMMX)
401 {
402     int i,j;
403     char myfilename[FILENAME_MAX];
404     char infilename[FILENAME_MAX];
405     char *s;
406     uint8 *ROMLO, *ROMHI;
407     FILE  *low,   *high, *out;
408 
409 
410 	if (!filename || !ROMMX) return -3;
411     strncpy(infilename,filename,FILENAME_MAX);         // copy the original file name
412 
413     s=strstr(infilename,".lo");  if (s) *s=0;  // strip off any possible .lo
414     s=strstr(infilename,".hi");  if (s) *s=0;  // strip off any possible .hi
415 
416     ROMLO=(uint8 *) malloc(8194); if (!ROMLO) {return -2;}
417     ROMHI=(uint8 *) malloc(8194); if (!ROMHI) {free(ROMLO); return -2;}
418 
419     snprintf(myfilename,FILENAME_MAX,"%s.lo",infilename);
420     low=fopen(myfilename,"rb");
421     if (!low) {free(ROMHI); free(ROMLO); return -1;}
422     DEBUG_LOG(0,"Opened %s\n",myfilename);
423 
424 
425     snprintf(myfilename,FILENAME_MAX,"%s.hi",infilename);
426     high=fopen(myfilename,"rb");
427     if (!high) {fclose(low); free(ROMHI); free(ROMLO); return -1;}
428     DEBUG_LOG(0,"Opened %s\n",myfilename);
429 
430 
431     fread(ROMLO,8192,1,low);
432     fread(ROMHI,8192,1,high);
433 
434     fclose(low);
435     fclose(high);
436 
437     // stitch the ROMs
438     for (i=0,j=0; i<16384; i+=2, j++)
439         {
440           ROMMX[i+1]=ROMLO[j];
441           ROMMX[i  ]=ROMHI[j];
442         }
443 
444     free(ROMHI);
445     free(ROMLO);
446 
447 
448     snprintf(myfilename,1024,"%s.ROM",infilename);
449     out=fopen(myfilename,"wb");
450     if (out) {  fwrite(ROMMX,16384,1,out); fflush(out);  fclose(out); rename_rompath(myfilename);}
451 
452     DEBUG_LOG(0,"Saved merged rom file as %s\n",myfilename);
453 
454 
455     if (ROMMX[0]==0x00 &&
456         ROMMX[1]==0x00 &&
457         ROMMX[2]==0x80 &&
458         ROMMX[3]==0x04   )  return 0;
459 
460     return -3;
461 }
462 
463 
464 
465 /**************************************************************************************\
466 * This function loads in a straight/raw 16k rom dump.                                      *
467 \**************************************************************************************/
468 
read_rom(char * filename,uint8 * ROMMX)469 int16 read_rom(char *filename, uint8 *ROMMX)
470 {	FILE *rom;
471 	if (!filename || !ROMMX) return -3;
472 	rom=fopen(filename,"rb"); if (!rom) {return -1;}
473 	fread(ROMMX,16384,1,rom); fclose(rom);
474 
475     #ifdef DEBUG
476     DEBUG_LOG(0,"Checking for screenmod:%02x subver %02x",ROMMX[0x3ffc],ROMMX[0x3ffd]);
477     if (has_xl_screenmod()) DEBUG_LOG(0,"Is screenmod ROM");
478     #endif
479 
480     ALERT_LOG(0,"Lisa ROM CHKSUM is %02x%02x version:%02x.%c (%02x)",ROMMX[0x3ffe],ROMMX[0x3fff],ROMMX[0x3ffc],ROMMX[0x3ffd],ROMMX[0x3ffd]);
481 #ifdef DEBUG
482     if (lisarom[0x3ffd]<'F') debug_on("C-ROM");
483 #endif
484 	return 0;
485 
486 }
487 
488 extern int romless_dualparallel(void);
489 
read_parallel_card_rom(char * filename)490 int read_parallel_card_rom(char *filename)
491 {
492     int ret=1;
493     uint16 newchks;
494 
495     FILE *ROMFILE;
496     ROMFILE=fopen(filename,"rb");
497     if (!ROMFILE) {ALERT_LOG(0,"Could not open %s\n",filename); perror(""); ret=0;}
498     else
499     {
500     ret=fread(dualparallelrom,2048,1,ROMFILE);
501     fclose(ROMFILE);
502     }
503 
504     // Skip over dual parallel ROM test if cheats are enabled by clearing D0 and returning in status routine
505     // of card.  our checksum of the rom (excl chkword) says 632b, but the word there is 9cd5 which is
506     // (~632b)+1. :)
507 
508     uint16 cardid= (dualparallelrom[0]<<8)|(dualparallelrom[1] );
509     uint16 words=( (dualparallelrom[2]<<8)|(dualparallelrom[3]) )*2  +4;
510 
511 //    ALERT_LOG(0,"Opened %s as card:%04x of size:%04x",filename,cardid,words);
512 
513     // if the ROM size is wrong, or the card ID doesn't indicate a parallel card,
514     // or if the checksum is wrong, we failed to load the ROM we wanted.  Don't bother
515     // passing it to the virtual Lisa.
516     //
517     // For future versions of the emulator we can edit the dualparallel filter
518     // if the emulator handles that type of card, and it'safe to disable the status
519     // routine as a time saving cheat.
520     //
521     if (words>0x1fff || (cardid & 0xff00)!=0xe000) ret=0;
522     else
523         if (chksum_a_rom_range(dualparallelrom,0,words+2) ) ret=0;
524 
525     // Ensure that we have a good ROM, that cheats enabled, and that this ROM has a status routine.
526     if (ret==1 && cheat_ram_test && (cardid & 0x4000) )
527     {
528        uint16 newchks;
529 
530        // blow away status routine, always returning a successful test.
531        dualparallelrom[4+ 0x0a]=0x42; dualparallelrom[4+ 0x0b]=0x40;  // CLR.W D0
532        dualparallelrom[4+ 0x0c]=0x4e; dualparallelrom[4+ 0x0d]=0x75;  // RTS
533 
534        // recalculate checksum so the BOOT ROM won't complain.
535        dualparallelrom[words]=0; dualparallelrom[words+1]=0;
536        newchks=chksum_a_rom_range(dualparallelrom,0,words );
537        newchks=(~newchks)+1;
538        dualparallelrom[words]=(newchks>>8); dualparallelrom[words+1]=(newchks & 0xff);
539     }
540 
541 
542 	if (!ret) return romless_dualparallel();
543 
544     return (ret!=1);
545 }
546 
547 
548 
decode_lisa_icon(uint8 * icon)549 uint8 *decode_lisa_icon(uint8 *icon)
550 {
551     int iindex=0, oindex=0;
552     int octals, mapbyte, obit;
553     static uint8 output[6*33+1  ];
554 
555       memset(output,0,6*33   );
556 
557   for (octals=0; octals<24; octals++) {
558       mapbyte=icon[iindex++]|256;
559       while(mapbyte) {
560          obit=mapbyte & 1; mapbyte=mapbyte>>1; if (!mapbyte) break;
561          if (obit) output[oindex++]=0;
562          else      output[oindex++]=icon[iindex++];
563 
564          if (iindex>6*33 || oindex>6*32) return output;
565       }
566    }
567 
568    return output;
569 
570 }
571 
572 
573