1 /* 2 * BIN to MZ Sharp M/C file 3 * 4 * $Id: mz.c $ 5 * 6 * bin2m12 by: Stefano Bodrato 4/5/2000 7 * portions from mzf2wav by: Jeroen F. J. Laros. Sep 11 2003. 8 * turbo loader comes from TransManager by Miroslav Nemecek. 9 * 10 * Original copyright message from mzf2wav: 11 * ----------------------------------------- 12 * This program is freeware and may be used without paying any registration 13 * fees. It may be distributed freely provided it is done so using the 14 * original, unmodified version. Usage of parts of the source code is granted, 15 * provided the author is referenced. For private use only. Re-selling or any 16 * commercial use of this program or parts of it is strictly forbidden. The 17 * author is not responsible for any damage or data loss as a result of using 18 * this program. 19 */ 20 21 #include "appmake.h" 22 23 static char *binname = NULL; 24 static char *crtfile = NULL; 25 static char *outfile = NULL; 26 static char *blockname = NULL; 27 static int origin = -1; 28 static char help = 0; 29 static char audio = 0; 30 static char fast = 0; 31 static char khz_22 = 0; 32 static char loud = 0; 33 static char mz80b = 0; 34 static char turbo = 0; 35 static char dumb = 0; 36 static char *src = NULL; 37 static char *dst = NULL; 38 static char foopatch = 0; 39 static char aggressive_patch = 0; 40 41 /* patching global variables */ 42 unsigned int *src_codes = 0; 43 unsigned int *dst_codes = 0; 44 45 /* mzf2wav global variables */ 46 47 static unsigned char mz_h_lvl; 48 static unsigned char mz_l_lvl; 49 50 static FILE *rawout; 51 52 static int LONG_UP = 0, /* These variables define the long wave */ 53 LONG_DOWN = 0, 54 SHORT_UP = 0, /* These variables define the short wave */ 55 SHORT_DOWN = 0; 56 57 58 /* Options that are available for this module */ 59 option_t mz_options[] = { 60 { 'h', "help", "Display this help", OPT_BOOL, &help}, 61 { 'b', "binfile", "Linked binary file", OPT_STR, &binname }, 62 { 'c', "crt0file", "crt0 file used in linking", OPT_STR, &crtfile }, 63 { 'o', "output", "Name of output file", OPT_STR, &outfile }, 64 { 0, "audio", "Create also a WAV file", OPT_BOOL, &audio }, 65 { 0, "fast", "Create a fast loading WAV", OPT_BOOL, &fast }, 66 { 0, "22", "22050hz bitrate option", OPT_BOOL, &khz_22 }, 67 { 0, "loud", "Louder audio volume", OPT_BOOL, &loud }, 68 { 0, "turbo", "Turbo tape loader", OPT_BOOL, &turbo }, 69 { 0, "mz80b", "MZ80B mode (faster 1800bps)", OPT_BOOL, &mz80b }, 70 { 0, "src", "Patch from (80B,700,2000,sos)", OPT_STR, &src }, 71 { 0, "dst", "Patch to (80B,700,2000,sos)", OPT_STR, &dst }, 72 { 0, "foopatch", "Patch unknown locations with BEEP", OPT_BOOL, &foopatch }, 73 { 0, "patchall", "Patch more types of JPs and CALLs", OPT_BOOL, &aggressive_patch }, 74 { 0, "dumb", "Just convert to WAV a tape file", OPT_BOOL, &dumb }, 75 { 0 , "org", "Origin of the binary", OPT_INT, &origin }, 76 { 0 , "blockname", "Opt name for the code block", OPT_STR, &blockname}, 77 { 0, NULL, NULL, OPT_NONE, NULL } 78 }; 79 80 81 /* Tables for patching */ 82 83 unsigned int mz700_codes[] = { 84 0x003E, // BEEP (keep always in first position) 85 0x0003, // GETL - Get LINE (up to 80 characters) 86 0x0006, // Double newline (1 line space) 87 0x0009, // Newline 88 0x000c, // print space 89 0x000f, // print TAB 90 0x0012, // print character 91 0x0015, // print message (control characters transcoding) 92 0x0018, // print messageX 93 0x001B, // GETKY - Get Key 94 0x001E, // test BREAK 95 0x0021, // write header info (located in $10f0) 96 0x0024, // write data 97 0x0027, // read header info (header is located in $10F0) 98 0x002A, // read tape data 99 0x002D, // verify tape data 100 0x0030, // SOUND (play melody) 101 0x0033, // set time 102 0x003b, // read time 103 0x0041, // set tempo (melody) 104 0x0044, // start continous sound 105 0x0047, // stop continous sound 106 107 0x0577, // BEEP 108 0x07e6, // GETL - Get LINE (up to 80 characters) 109 0x090E, // Double newline (1 line space) 110 0x0918, // Newline 111 0x0920, // print space 112 0x0924, // print TAB 113 0x0935, // print character 114 0x0893, // print message (control characters transcoding) 115 0x08A1, // print messageX 116 0x08BD, // GETKY - Get Key (ASCII code) 117 0x0A32, // test BREAK 118 0x0436, // write header info (located in $10f0) 119 0x0475, // write data 120 0x04D8, // read header info (header is located in $10F0) 121 0x04F8, // read tape data 122 0x0588, // verify tape data 123 0x01C7, // SOUND (play melody) 124 0x0308, // set time 125 0x0358, // read time 126 0x02e5, // set tempo (melody) 127 0x02ab, // start continous sound 128 0x02be, // stop continous sound 129 130 0x00AD, // MONITOR entry 131 132 0x03ba, // print hex value of HL 133 0x03c3, // print hex value of A 134 0x03da, // format hex digit to ascii 135 0x03E5, // format ascii to hex digit 136 0x03F9, // format ascii to hex digit 137 0x09b3, // Wait for a key and get key code 138 139 0x0bb9, // ASCII code to display code conversion 140 // 0x0fb1, // console stuff ? (c53) 141 0x0946, // console stuff ? (8ee) 142 0x0947, // console stuff ? (8ef) 143 // 0x0939, // console stuff ? (91a) 144 // 0x0db5, // console stuff ? (c7a) 145 // 0x096c, // raw character output ? 146 0x0bcd, // display code to ASCII conversion 147 0x0bce, // display code to ASCII conversion 148 0x0ddc, // screen control (scroll, cursor, etc..) 149 0x0822, // break in 150 0x0ee5, // POP HL,DE,BC,AF and ret 151 0x0ee6, // POP DE,BC,AF and ret 152 0x0700, // (0x4ce) 153 0x0da6, // (0x446) 154 0x0038, // Interrupt handler 155 0x1038, // Interrupt handler 156 0x038D, // Interrupt handler 157 0x0EE9, // ??? = $D18 on mz80b = $CEE on mz2000 ** RET ** 158 0 159 }; 160 161 // MZ-80B, MONITOR SB-1510 162 unsigned int mz80b_codes[] = { 163 0x0EBE, // BEEP (keep always in first position) 164 0x06A4, // GETL - Get LINE (up to 80 characters) 165 0x08b0, // Double newline (1 line space) 166 0x08ab, // Newline 167 0x08b9, // print space 168 0x08be, // print TAB 169 0x0916, // print character 170 0x08cd, // print message (control characters transcoding) 171 //0x08cd, // print messageX 172 0x08db, // print messageX 173 0x0871, // GETKY - Get Key 174 0x0562, // test BREAK 175 0x0251, // write header info (located in $10c0 ..was $10f0 on MZ80A) 176 0x0282, // write data 177 0x028E, // read header info (located in $10c0 ..was $10f0 on MZ80A) 178 0x02b2, // read tape data 179 0x02BE, // verify tape data 180 0x0EE9, // SOUND (play melody) 181 0x0E06, // set time 182 0x0e51, // read time 183 0x0DF8, // set tempo (melody) 184 0x0790, // start continous sound ** RET ** 185 0x0790, // stop continous sound ** RET ** 186 187 0x0EBE, // BEEP (keep always in first position) 188 0x06A4, // GETL - Get LINE (up to 80 characters) 189 0x08b0, // Double newline (1 line space) 190 0x08ab, // Newline 191 0x08b9, // print space 192 0x08be, // print TAB 193 0x0916, // print character 194 0x08cd, // print message (control characters transcoding) 195 //0x08cd, // print messageX 196 0x08db, // print messageX 197 0x0871, // GETKY - Get Key 198 0x0562, // test BREAK 199 0x0251, // write header info (located in $10c0, ..was $10f0 on MZ80A) 200 0x0282, // write data 201 0x028E, // read header info (located in $10c0 ..was $10f0 on MZ80A) 202 0x02b2, // read tape data 203 0x02BE, // verify tape data 204 0x0EE9, // SOUND (play melody) ** RET ** 205 0x0E06, // set time 206 0x0e51, // read time 207 0x0DF8, // set tempo (melody) 208 0x0790, // start continous sound ** RET ** 209 0x0790, // stop continous sound ** RET ** 210 211 0x00B1, // MONITOR entry 212 213 0x05D8, // print hex value of HL 214 0x05DD, // print hex value of A 215 0x05f3, // format hex digit to ascii 216 0x05fd, // format ascii to hex digit 217 0x05fd, // format ascii to hex digit 218 0x0871, // Wait for a key and get key code 219 220 0x0790, // console stuff (bb9) ; ASCII code to display code conversion. ** RET ** 221 // 0x0c53, // console stuff ? (fb1) 222 0x08EE, // console stuff ? (946) 223 0x08EF, // console stuff ? (947) 224 // 0x091A, // console stuff ? (939) 225 // 0x0C7a, // console stuff ? (db5) 226 // 0x0916, // raw character output ? (normal putchar, 96c) 227 0x0790, // display code to ASCII conversion ** RET ** 228 0x0790, // display code to ASCII conversion ** RET ** 229 0x0790, // screen control (scroll, cursor, etc..) ** RET ** 230 0x0872, // break in 231 0x078c, // POP HL,DE,BC,AF and ret 232 0x078d, // POP DE,BC,AF and ret 233 0x04ce, // (0x700) 234 0x0446, // (0xda6) 235 0x0038, // Interrupt handler 236 0x0D31, // Interrupt handler 237 0x0D31, // Interrupt handler 238 0x0d18, // ??? = $CEE on mz2000 239 0 240 }; 241 242 // MZ-2000, MONITOR MZ-1Z001M 243 unsigned int mz2000_codes[] = { 244 0x0F14, // BEEP (keep always in first position) 245 0x06A4, // GETL - Get LINE (up to 80 characters) 246 0x0A2E, // Double newline (1 line space) 247 0x0A29, // Newline 248 0x08c4, // print space 249 0x086c, // print TAB 250 0x08c6, // print character 251 0x087B, // print message (control characters transcoding) 252 //0x087B, // print messageX 253 0x0889, // print messageX 254 0x0832, // GETKY - Get Key 255 0x0562, // test BREAK 256 0x0251, // write header info (located in $1140) 257 0x0282, // write data 258 0x028E, // read header info (located in $1140) 259 0x02b2, // read tape data 260 0x02BE, // verify tape data 261 0x0F3F, // SOUND (play melody) 262 0x0E5E, // set time 263 0x0EA9, // read time 264 0x0E50, // set tempo (melody) 265 0x0768, // start continous sound ** RET ** 266 0x0768, // stop continous sound ** RET ** 267 268 0x0F14, // BEEP (keep always in first position) 269 0x06A4, // GETL - Get LINE (up to 80 characters) 270 0x0A2E, // Double newline (1 line space) 271 0x0A29, // Newline 272 0x08c4, // print space 273 0x086c, // print TAB 274 0x08c6, // print character 275 0x087B, // print message (control characters transcoding) 276 //0x087B, // print messageX 277 0x0889, // print messageX 278 0x0832, // GETKY - Get Key 279 0x0562, // test BREAK 280 0x0251, // write header info (located in $1140) 281 0x0282, // write data 282 0x028E, // read header info (located in $1140) 283 0x02b2, // read tape data 284 0x02BE, // verify tape data 285 0x0F3F, // SOUND (play melody) 286 0x0E5E, // set time 287 0x0EA9, // read time 288 0x0E50, // set tempo (melody) 289 0x0768, // start continous sound ** RET ** 290 0x0768, // stop continous sound ** RET ** 291 292 0x00B1, // MONITOR entry 293 294 0x05D8, // print hex value of HL 295 0x05DD, // print hex value of A 296 0x05f3, // format hex digit to ascii 297 0x05fd, // format ascii to hex digit 298 0x05fd, // format ascii to hex digit 299 0x0832, // Wait for a key and get key code 300 301 0x0768, // console stuff (bb9) ; ASCII code to display code conversion. **RET** 302 // 0x0c29, // console stuff ? (fb1) 303 0x089C, // console stuff ? (946) 304 0x089D, // console stuff ? (947) 305 // 0x08cb, // console stuff ? (939) 306 // 0x0C50, // console stuff ? (db5) 307 // 0x08c6, // raw character output ? (normal putchar, 96c) 308 0x0768, // display code to ASCII conversion ** RET ** 309 0x0768, // display code to ASCII conversion ** RET ** 310 0x0768, // screen control (scroll, cursor, etc..) ** RET ** 311 0x0833, // break in 312 0x0764, // POP HL,DE,BC,AF and ret 313 0x0765, // POP DE,BC,AF and ret 314 0x04ce, // (0x700) 315 0x0446, // (0xda6) 316 0x0038, // Interrupt handler 317 0x0D07, // Interrupt handler 318 0x0D07, // Interrupt handler 319 0x0CEE, // ??? = $D18 on mz80b 320 0 321 }; 322 323 324 unsigned int sos_codes[] = { 325 0x1fc4, // BEEP (keep always in first position) 326 0x1fd3, // GETL - Get LINE (up to 80 characters) 327 0x1feb, // Double newline (1 line space) 328 0x1fee, // Newline 329 0x1ff1, // print space 330 0x1fdf, // print TAB (not sure this is right) 331 0x1ff4, // print character 332 0x1fe5, // print message (control characters transcoding) 333 0x1fe8, // print messageX 334 0x1fd0, // GETKY - Get Key 335 0x1fcd, // test BREAK 336 0x1fd6, // write header info (located in $10f0) 337 0x1fd6, // write data 338 0x1fd6, // read header info (header is located in $10F0) 339 0x1fd6, // read tape data 340 0x1fd6, // verify tape data 341 0x1fd6, // SOUND (play melody) 342 0x1fd6, // set time 343 0x1fd6, // read time 344 0x1fd6, // set tempo (melody) 345 0x1fd6, // start continous sound 346 0x0047, // stop continous sound 347 348 0x1fc4, // BEEP 349 0x1fd3, // GETL - Get LINE (up to 80 characters) 350 0x1feb, // Double newline (1 line space) 351 0x1fee, // Newline 352 0x1ff1, // print space 353 0x1fdf, // print TAB (not sure this is right) 354 0x1ff4, // print character 355 0x1fe5, // print message (control characters transcoding) 356 0x1fe8, // print messageX 357 0x1fd0, // GETKY - Get Key (ASCII code) 358 0x1fcd, // test BREAK 359 0x1fd6, // write header info (located in $10f0) 360 0x1fd6, // write data 361 0x1fd6, // read header info (header is located in $10F0) 362 0x1fd6, // read tape data 363 0x1fd6, // verify tape data 364 0x1fd6, // SOUND (play melody) 365 0x1fd6, // set time 366 0x1fd6, // read time 367 0x1fd6, // set tempo (melody) 368 0x1fd6, // start continous sound 369 0x1fd6, // stop continous sound 370 371 0x1f8e, // MONITOR entry 372 373 0x1fbe, // print hex value of HL 374 0x1fc1, // print hex value of A 375 0x1fb8, // format hex digit to ascii 376 0x1fb5, // format ascii to hex digit 377 0x1fb5, // format ascii to hex digit 378 0x1fca, // Wait for a key and get key code 379 380 0x1fd6, // ASCII code to display code conversion 381 // 0x0fb1, // console stuff ? (c53) 382 0x1fd6, // console stuff ? (8ee) 383 0x1fd6, // console stuff ? (8ef) 384 // 0x0939, // console stuff ? (91a) 385 // 0x0db5, // console stuff ? (c7a) 386 // 0x096c, // raw character output ? 387 0x1fd6, // display code to ASCII conversion 388 0x1fd6, // display code to ASCII conversion 389 0x1fd6, // screen control (scroll, cursor, etc..) 390 0x1ffa, // break in (will HOT boot be ok ?) 391 0x1fd6, // POP HL,DE,BC,AF and ret (** NO MATCH **) 392 0x1fd6, // POP DE,BC,AF and ret (** NO MATCH **) 393 0x1fd6, // (0x4ce) 394 0x1fd6, // (0x446) 395 0x0038, // Interrupt handler 396 0x0038, // Interrupt handler 397 0x0038, // Interrupt handler 398 0x1fd6, // ??? = $D18 on mz80b = $CEE on mz2000 ** RET ** 399 0 400 }; 401 402 /* Code from mzf2wav (physical.c) */ 403 404 /* Write a long pulse */ 405 void lp(void) { 406 int j = 0; 407 408 for (j = 0; j < LONG_UP; j++) 409 fputc(mz_l_lvl, rawout); 410 for (j = 0; j < LONG_DOWN; j++) 411 fputc(mz_h_lvl, rawout); 412 } 413 414 /* Write a short pulse */ 415 void sp(void) { 416 int j = 0; 417 418 for (j = 0; j < SHORT_UP; j++) 419 fputc (mz_l_lvl,rawout); 420 for (j = 0; j < SHORT_DOWN; j++) 421 fputc (mz_h_lvl, rawout); 422 } 423 424 /* Write a gap of i short pulses */ 425 void gap(int i) { 426 int j = 0; 427 428 for (j = 0; j < i; j++) 429 sp(); 430 } 431 432 /* Write a tapemark of i long pulses, i short pulses and one long pulse */ 433 void tapemark(int i) { 434 int j = 0; 435 436 for (j = 0; j < i; j++) 437 lp(); 438 for (j = 0; j < i; j++) 439 sp(); 440 lp(); 441 lp(); 442 } 443 444 /* Write the checksum */ 445 void writecs(unsigned int cs) { 446 unsigned char i = 0; 447 int j = 0; 448 449 cs &= 0xffff; 450 for (j = 0x3; j; j /= 2) { 451 for (i = 0xff; i; i /= 2) { 452 if (cs & 0x8000) /* If the most significant bit is set */ 453 lp(); /* wite a one. */ 454 else 455 sp(); /* Else write a zero. */ 456 cs *= 2; /* Go to the next bit. */ 457 } 458 lp(); 459 } 460 lp(); 461 } 462 463 /* Write a byte and count the bits set to 'one' for the checksum */ 464 unsigned int mz_rawout(unsigned char b) { 465 unsigned int cs = 0; 466 unsigned char i = 0; 467 468 for (i = 0xff; i; i /= 2) { 469 if (b & 0x80) { 470 lp(); 471 cs++; 472 } 473 else 474 sp(); 475 b *= 2; 476 } 477 lp(); 478 return cs; 479 } 480 481 482 /* Patch the code, locate static calls and jumps, fix locations */ 483 484 void mz_patch (unsigned char *image, unsigned int *src_table, unsigned int *dst_table) { 485 486 int i, len, x, patched; 487 unsigned int org_location, call_location; 488 489 /* Get the actual file length (header + data) */ 490 len = (image[0x12] + (image[0x13] * 256) + 0x80); 491 org_location = image[0x14] + (image[0x15] * 256); 492 493 for (i = 0x80; i < len; i++) { /* The mzf body. */ 494 /* call or jump ? */ 495 if ( (image[i]==0xCD) || (image[i]==0xC3) || (image[i]==0xCC) || (image[i]==0xCA) || 496 ( aggressive_patch && ( 497 (image[i]==0xDC) || (image[i]==0xFC) || (image[i]==0xD4) || 498 (image[i]==0xC4) || (image[i]==0xF4) || (image[i]==0xEC) || (image[i]==0xE4) || 499 (image[i]==0xDA) || (image[i]==0xFA) || (image[i]==0xD2) || 500 (image[i]==0xC2) || (image[i]==0xF2) || (image[i]==0xEA) || (image[i]==0xE2) )) ) { 501 502 x=0; patched=0; 503 call_location = image[i+1] + (image[i+2] * 256); 504 while (dst_table[x]!=0) { 505 if (call_location == src_table[x]) { 506 printf("\nInfo: Patching location %x, opcode '%x', address $%x->$%x", org_location + i - 0x80, image[i], call_location, dst_table[x]); 507 image[i+1]=dst_table[x]%256; 508 image[i+2]=dst_table[x]/256; 509 patched=1; 510 } 511 x++; 512 } 513 514 if ( !patched && (call_location < org_location) && (call_location != 0) ) { 515 printf("\nWarning: Location %x, opcode '%x', unknown address $%x", org_location + i - 0x80, image[i], call_location); 516 if (foopatch) { 517 printf(" -> BEEP"); 518 image[i+1]=dst_table[0]%256; 519 image[i+2]=dst_table[0]/256; 520 } 521 } 522 523 } 524 } 525 } 526 527 528 529 /* Generate the raw audio track from the program data */ 530 531 void mz_encode (unsigned char *image) { 532 533 unsigned int cs; /* checksum */ 534 int i, len; 535 536 /* Get the actual file length (header + data) */ 537 len = (image[0x12] + (image[0x13] * 256) + 0x80); 538 539 cs = 0; 540 gap(15000); /* Long gap. */ 541 542 tapemark(40); /* Long tapemark. */ 543 544 for (i = 0; i < 0x80; i++) { /* The mzf header. */ 545 cs += mz_rawout(image[i]); 546 } 547 writecs(cs); /* The checksum of the mzf header. */ 548 549 if (!fast) { 550 gap(256); /* 256 short pulses. */ 551 552 for (i = 0; i < 0x80; i++) /* The copy of the mzf header. */ 553 mz_rawout(image[i]); 554 writecs(cs); /* The copy of the checksum of the mzf header. */ 555 } 556 557 gap(8000); /* Short gap. */ 558 559 tapemark(20); /* Short tapemark. */ 560 561 cs = 0; 562 563 for (i = 0x80; i < len; i++) /* The mzf body. */ 564 cs += mz_rawout(image[i]); 565 writecs(cs); /* The checksum of the body. */ 566 567 if (!fast) { 568 gap(256); /* 256 short pulses. */ 569 570 for (i = 0x80; i < len; i++) /* The copy of the mzf body. */ 571 mz_rawout(image[i]); 572 writecs(cs); /* The copy of checksum of the body. */ 573 } 574 } 575 576 577 /* This is the turbo loader in MZF format. */ 578 unsigned char turboldr[300] = { 579 0x01, // Program type. 580 581 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, // Room for the 582 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, // image name. 583 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 584 585 0x5a, 0x00, // File size. 586 0x00, 0xd4, // Load adress. 587 0x00, 0xd4, // Execution adress. 588 '[', 't', 'u', 'r', 'b', 'o', ']', // The first 7 bytes. 589 590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Room for comment. 591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // minus 7 bytes. 592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 600 0x00, 0x00, 0x00, 0x00, 0x00, 601 602 0xcd, 0x00, // End Header. 603 604 // Begin Program. 605 0x3e, 0x08, // D400: LD A, 08h 606 0xd3, 0xce, // D402: OUT (0ceh), A ; Set video mode? 607 608 0xe5, // D404: PUSH HL 609 610 0x21, 0x00, 0x00, // D405: LD HL, 0000h 611 0xd3, 0xe4, // D408: OUT (0e4h), A ; Bank switch to ROM? 612 613 0x7e, // D40A: LD A, (HL) 614 0xd3, 0xe0, // D40B: OUT (0e0h), A ; Bank switch to RAM? 615 616 0x77, // D40D: LD (HL), A 617 0x23, // D40E: INC HL 618 619 0x7c, // D40F: LD A, H 620 0xfe, 0x10, // D410: CP 10h 621 0x20, 0xf4, // D412: JR NZ, f4h ; Jump 0xf4 forward if A != 0x10 622 623 0x3a, 0x4b, 0xd4, // D414: LD A, (d44bh) 624 0x32, 0x4b, 0x0a, // D417: LD (0a4bh), A ; (0x0a4b) = (0xd44b) 625 0x3a, 0x4c, 0xd4, // D41A: LD A, (d44ch) 626 0x32, 0x12, 0x05, // D41D: LD (0512h), A ; (0xd44c) = (0x0512) 627 0x21, 0x4d, 0xd4, // D420: LD HL, d44dh 628 0x11, 0x02, 0x11, // D423: LD DE, 1102h 629 0x01, 0x0d, 0x00, // D426: LD BC, 000dh 630 0xed, 0xb0, // D429: LDIR ; Copy 0x0d bytes from (HL) to (DE) 631 632 0xe1, // D42B: POP HL 633 634 0x7c, // D42C: LD A, H 635 0xfe, 0xd4, // D42D: CP d4h 636 0x28, 0x12, // D42F: JR Z, 12h ; Jump to label #1 if A == 0xd4 637 638 0x2a, 0x04, 0x11, // D431: LD HL, (1104h) 639 0xd9, // D434: EXX ; BC/DE/HL <-> BC'/DE'/HL' 640 0x21, 0x00, 0x12, // D435: LD HL, 1200h 641 0x22, 0x04, 0x11, // D438: LD (1104h), HL 642 0xcd, 0x2a, 0x00, // D43B: CALL 002ah ; Read data subroutine. 643 0xd3, 0xe4, // D43E: OUT (0e4h), A ; Bank switch to ROM? 644 0xc3, 0x9a, 0xe9, // D440: JP e99ah ; Jump to 0xe99a 645 646 0xcd, 0x2a, 0x00, // D443: CALL (002ah) ; Label #1 (read data sub). 647 0xd3, 0xe4, // D446: OUT (0e4h), A ; Bank switch to ROM? 648 0xc3, 0x24, 0x01, // D448: JP (0124h) 649 // End program. 650 651 0x15, 0x01, // D44B: 652 653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Room for the address information 654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // + the first 7 bytes of comment. 655 }; 656 657 658 /* Main entry */ 659 660 int mz_exec(char *target) 661 { 662 char filename[FILENAME_MAX+1]; 663 char wavfile[FILENAME_MAX+1]; 664 char name[18]; 665 FILE *fpin, *fpout; 666 long pos; 667 int c; 668 int i, len; 669 670 unsigned char *image; 671 672 if ( help ) 673 return -1; 674 675 if ( binname == NULL || (!dumb && ( crtfile == NULL && origin == -1) ) ) { 676 return -1; 677 } 678 679 if ( dst != NULL ) 680 { 681 if ( src == NULL ) { 682 exit_log(1,"Please specify the source model for patching\n"); 683 } 684 if ((strcmp(dst,"80b") == 0) || (strcmp(dst,"80b") == 0)) 685 dst_codes = mz80b_codes; 686 687 if (strcmp(dst,"700") == 0) 688 dst_codes = mz700_codes; 689 690 if (strcmp(dst,"2000") == 0) 691 dst_codes = mz2000_codes; 692 693 if (strcmp(dst,"sos") == 0) 694 dst_codes = sos_codes; 695 696 if (dst_codes == 0) { 697 exit_log(1,"Specified dst model for patching is not valid\n"); 698 } 699 } 700 701 if ( src != NULL ) 702 { 703 if ( dst == NULL ) { 704 exit_log(1,"Please specify the destination model for patching\n"); 705 } 706 if ((strcmp(src,"80b") == 0) || (strcmp(src,"80b") == 0)) 707 src_codes = mz80b_codes; 708 709 if (strcmp(src,"700") == 0) 710 src_codes = mz700_codes; 711 712 if (strcmp(src,"2000") == 0) 713 src_codes = mz2000_codes; 714 715 if (strcmp(src,"sos") == 0) 716 src_codes = sos_codes; 717 718 if (src_codes == 0) { 719 exit_log(1,"Specified src model for patching is not valid\n"); 720 } 721 722 if (src_codes == dst_codes) { 723 exit_log(1,"MZ src and dst models must be different for patching\n"); 724 } 725 } 726 727 if (loud) { 728 mz_h_lvl = 0xFF; 729 mz_l_lvl = 0x00; 730 } else { 731 mz_h_lvl = 0xe0; 732 mz_l_lvl = 0x20; 733 } 734 735 if (dumb) { 736 strcpy(filename,binname); 737 738 } else { 739 740 if ( outfile == NULL ) { 741 strcpy(filename,binname); 742 suffix_change(filename,".mzt"); 743 } else { 744 strcpy(filename,outfile); 745 } 746 747 if ( blockname == NULL ) 748 blockname = zbasename(binname); 749 750 if ( strcmp(binname,filename) == 0 ) { 751 exit_log(1,"Input and output file names must be different\n"); 752 } 753 754 if ( origin != -1 ) { 755 pos = origin; 756 } else { 757 if ( (pos = get_org_addr(crtfile)) == -1 ) { 758 exit_log(1,"Could not find parameter ZORG (not z88dk compiled?)\n"); 759 } 760 } 761 762 if ( (fpin=fopen_bin(binname, crtfile) ) == NULL ) { 763 printf("Can't open input file %s\n",binname); 764 exit(1); 765 } 766 767 768 /* 769 * Now we try to determine the size of the file 770 * to be converted 771 */ 772 if (fseek(fpin,0,SEEK_END)) { 773 fclose(fpin); 774 exit_log(1,"Couldn't determine size of file\n"); 775 } 776 777 len=ftell(fpin); 778 779 fseek(fpin,0L,SEEK_SET); 780 781 if ( (fpout=fopen(filename,"wb") ) == NULL ) { 782 fclose(fpin); 783 exit_log(1,"Can't open output file %s\n",filename); 784 } 785 786 787 /* Write out the MZ file */ 788 789 /* ******** */ 790 /* HEADER */ 791 /* ******** */ 792 793 fputc(1,fpout); /* MZ80K M/C progtam file type */ 794 795 /* Deal with the filename */ 796 797 memset(name, '\15', sizeof(name)-1); 798 name[sizeof(name)-1] = 0; 799 memcpy(name, blockname, (strlen(blockname) < sizeof(name)-1) ? strlen(blockname) : sizeof(name)-1); 800 801 for (i=0;i<17;i++) /* File name */ 802 if(name[i]<32) 803 fputc(13,fpout); 804 else 805 fputc(toupper(name[i]),fpout); 806 807 writeword(len,fpout); /* Block byte size */ 808 writeword(pos,fpout); /* Binary block location */ 809 writeword(pos,fpout); /* Execution address (autorun) */ 810 if (mz80b) { 811 for (i=0;i<7;i++) 812 fputc(0,fpout); 813 fputc(0x3a,fpout); 814 815 for (i=0;i<48;i++) { 816 fputc(0x00,fpout); 817 fputc(0xFF,fpout); 818 } 819 } else { 820 /* Comment area in header */ 821 for (i=0;i<104;i++) 822 fputc(0,fpout); 823 } 824 825 /* *********** */ 826 /* ... M/C ... */ 827 /* *********** */ 828 for (i=0; i<len;i++) { 829 c=getc(fpin); 830 fputc(c,fpout); 831 } 832 833 fclose(fpin); 834 fclose(fpout); 835 } 836 837 /* ************************************************** */ 838 /* Now, if requested, mzf2wav creates the audio file */ 839 /* ************************************************** */ 840 if ((audio) || (fast) || (khz_22) || (loud) || (src_codes != 0)) { 841 842 strcpy(wavfile,filename); 843 844 if ( (fpin=fopen(filename,"rb") ) == NULL ) { 845 exit_log(1,"Can't open file %s for wave conversion\n",filename); 846 } 847 848 if (fseek(fpin,0,SEEK_END)) { 849 fclose(fpin); 850 exit_log(1,"Couldn't determine size of file\n"); 851 } 852 len=ftell(fpin); 853 fseek(fpin,0L,SEEK_SET); 854 855 image = (unsigned char *) malloc(len+2); 856 i = 0; 857 858 if (!image) { 859 exit_log(1,"Can't allocate temp memory to load '%s' for audio conversion\n",filename); 860 } 861 862 /* Load program in a temp memory space */ 863 if (dumb) printf("\nInfo: name found in header: "); 864 for (i=0; i<len; i++) { 865 image[i]=fgetc(fpin); 866 if ((dumb) && (image[i]>=32) && (image[i]<=126) && (i>0) && (i<17) ) 867 printf("%c",image[i]); 868 } 869 if (dumb) { 870 printf("\n\n"); 871 printf("Info: file type: %u\n", image[0]); 872 printf("Info: program location: $%x\n", image[0x14] + (image[0x15] * 256)); 873 printf("Info: binary block size: $%x\n", image[0x12] + (image[0x13] * 256)); 874 if (image[0] == 1) { 875 printf("Info: start address: $%x\n", image[0x16] + (image[0x17] * 256)); 876 if ((image[0x14] + image[0x15] + image[0x16] + image[0x17])==0) { 877 printf("Info: probably this is an MZ80B IPL file\n"); 878 if (!mz80b) printf("Warning: use the '--mz80b' parameter\n"); 879 } 880 } 881 } 882 fclose(fpin); 883 884 /* Check the file comparing the declared size to its real one */ 885 if ((image[0x12] + (image[0x13] * 256) + 0x80)!=len) { 886 exit_log(1,"MZF file corrupt: %s\n",filename); 887 } 888 889 if (src_codes != 0) { 890 if ((image[0]) == 1) { 891 mz_patch (image, src_codes, dst_codes); 892 893 suffix_change(filename,"_patched.mzf"); 894 if ( (fpout=fopen(filename,"wb") ) == NULL ) { 895 exit_log(1,"Can't open output patched file %s\n",filename); 896 } 897 for (i=0; i<len; i++) fputc (image[i],fpout); 898 fclose(fpout); 899 } else { 900 fprintf(stderr,"File %s is not an object file, cannot patch\n",filename); 901 } 902 } 903 904 if ( audio ) { 905 906 suffix_change(wavfile,".RAW"); 907 if ( (rawout=fopen(wavfile,"wb") ) == NULL ) { 908 exit_log(1,"Can't open output raw audio file %s\n",wavfile); 909 } 910 911 if (turbo) { 912 fast = -1; 913 for (i = 0x1; i < 0x12; i++) /* Copy the name. */ 914 turboldr[i] = image[i]; 915 for (i = 0x1f; i < 0x80; i++) /* Copy the comment. */ 916 turboldr[i] = image[i]; 917 for (i = 0x12; i < 0x1f; i++) /* Copy the info. */ 918 turboldr[i + 0x3b + 0x80] = image[i]; 919 } 920 921 922 if (fast) { 923 LONG_UP = 18; 924 LONG_DOWN = 21; 925 SHORT_UP = 9; 926 SHORT_DOWN = 11; 927 } else { 928 LONG_UP = 21; 929 LONG_DOWN = 22; 930 SHORT_UP = 11; 931 SHORT_DOWN = 12; 932 } 933 934 if (mz80b) { 935 LONG_UP = 14; 936 LONG_DOWN = 15; 937 SHORT_UP = 7; 938 SHORT_DOWN = 8; 939 if (fast) { 940 LONG_UP = 13; 941 LONG_DOWN = 14; 942 SHORT_UP = 6; 943 SHORT_DOWN = 7; 944 } 945 } 946 947 if (turbo) { 948 mz_encode(turboldr); 949 950 LONG_UP = 11; 951 LONG_DOWN = 12; 952 SHORT_UP = 5; 953 SHORT_DOWN = 6; 954 955 mz_encode(image); 956 957 } else { 958 mz_encode(image); 959 } 960 961 962 fclose(rawout); 963 free(image); 964 965 /* Now let's think at the WAV format */ 966 if (khz_22) 967 raw2wav_22k(wavfile,2); 968 else 969 raw2wav(wavfile); 970 } 971 } 972 return 0; 973 } 974