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