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