1 2 /* 3 * BIN to .cas program file (NEC PC computers) 4 * 5 * Original code name: hex2cas,(c) 2003-2007 6 * by Takahide Matsutsuka. 7 * 8 * MC loader by Stefano Bodrato, (c) 2013 9 * 10 * $Id: nec.c,v 1.9 2016-06-26 00:46:55 aralbrec Exp $ 11 */ 12 13 #include "appmake.h" 14 15 static char* binname = NULL; 16 static char* crtfile = NULL; 17 static char* outfile = NULL; 18 static int origin = -1; 19 static int mode = -1; 20 static char help = 0; 21 static char audio = 0; 22 23 char nec_fast = 0; 24 char nec_22 = 0; 25 //static char dumb = 0; 26 27 /* Options that are available for this module */ 28 option_t nec_options[] = { 29 { 'h', "help", "Display this help", OPT_BOOL, &help }, msxrom_exec(char * target)30 { 'b', "binfile", "Linked binary file", OPT_STR, &binname }, 31 { 'c', "crt0file", "crt0 file used in linking", OPT_STR, &crtfile }, 32 { 'o', "output", "Name of output file", OPT_STR, &outfile }, 33 { 0, "audio", "Create also a WAV file", OPT_BOOL, &audio }, 34 { 0, "fast", "Create a fast loading WAV", OPT_BOOL, &nec_fast }, 35 { 0, "22", "22050hz bitrate option", OPT_BOOL, &nec_22 }, 36 // { 0, "dumb", "Just convert to WAV a tape file", OPT_BOOL, &dumb }, 37 { 0, "org", "Origin of the binary", OPT_INT, &origin }, 38 { 0, "mode", "0..5: 16k,32k,mk2,n,ROM,n88", OPT_INT, &mode }, 39 { 0, NULL, NULL, OPT_NONE, NULL } 40 }; 41 42 /* modes */ 43 enum { 44 MODE1, 45 MODE2, 46 MODE5, 47 MODEN, 48 MODEROM, 49 MODEN88, 50 MODE_QUIT 51 }; 52 53 /* A default architecture-depend file name. */ 54 #define DEFAULT_ARCH_FILENAME "noname" 55 56 /* Definitions of code segment for each mode. */ 57 //#define MODE1_ADDRESS_CODESEG 0xc40f 58 //#define MODE2_ADDRESS_CODESEG 0x840f 59 //#define MODE5_ADDRESS_CODESEG 0x800f 60 #define MODE1_ADDRESS_CODESEG 0xc437 61 #define MODE2_ADDRESS_CODESEG 0x8437 62 #define MODE5_ADDRESS_CODESEG 0x8037 63 #define MODEN88_ADDRESS_CODESEG 0x0100 64 #define MODEROM_ADDRESS_CODESEG 0x4004 65 66 /* It is a sort of a fast mode KansasCity format, */ 67 /* very close to the SC-3000 */ 68 /* four fast cycles for '1', two slow cycles for '0' */ 69 /* but the samples I've seen seem to have also an aplitude */ 70 /* variation, so here it is ! */ 71 72 extern void nec_bit(FILE* fpout, unsigned char bit) 73 { 74 int i, period0, period1; 75 76 if (nec_fast) { 77 period1 = 8; 78 period0 = 14; 79 } else { 80 period1 = 9; 81 period0 = 21; 82 } 83 84 if (bit) { 85 /* '1' */ 86 for (i = 0; i < period1; i++) 87 fputc(0x30, fpout); 88 for (i = 0; i < period1; i++) 89 fputc(0xd0, fpout); 90 for (i = 0; i < period1; i++) 91 fputc(0x30, fpout); 92 for (i = 0; i < period1; i++) 93 fputc(0xd0, fpout); 94 } else { 95 /* '0' */ 96 for (i = 0; i < (period0); i++) 97 fputc(0x10, fpout); 98 for (i = 0; i < (period0); i++) 99 fputc(0xf0, fpout); 100 } 101 } 102 103 extern void nec_rawout(FILE* fpout, unsigned char b) 104 { 105 /* bit order is reversed ! */ 106 static unsigned char c[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; 107 int i; 108 109 /* 1 start bit */ 110 nec_bit(fpout, 0); 111 112 /* byte */ 113 for (i = 0; i < 8; i++) 114 nec_bit(fpout, (b & c[i])); 115 116 /* 2 stop bits */ 117 nec_bit(fpout, 1); 118 nec_bit(fpout, 1); 119 } 120 121 // output file structure 122 // 1/ prefix (prefix_length bytes) 123 // 2/ startup (STARTUP_LENGTH bytes) 124 // 3/ a little patch for rst8 (3 bytes) 125 // 4/ codeseg 126 127 static unsigned char prefix_p6[] = { 128 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 129 0xd3, 0xd3, 0x47, 0x6f, 0x00, 0x00, 0x00, 0x00, 130 0x0d, 0x84, 0x0a, 0x00, 0xa5, '&', 'H', '8', 131 '4', '0', 'F', 0x00, 0x00, 0x00, // 30 bytes so far 132 133 // LOADER: Here we're at pos $840f or $c40f 134 // puts the code just after itself and falls in it when finished 135 205, 0x9a, 0x25, // call $259a ; start tape 136 6, 5, // ld b,5 137 205, 0x70, 0x1a, // call $1a70 ; read a single byte 138 254, 0xaf, // cp $af ; leader tone (af,af,---) 139 32, 0xf7, // jr nz,$f7 ; -8 140 16, 0xf7, // djnz $f7 ; -8 141 142 // pos [45] and [46] 143 33, 0x37, 0x84, // ld hl,loc 144 // pos [48] and [49] 145 1, 0, 0, // ld bc,len 146 0xe5, // push hl ; keep entry location 147 148 0x1e, 0, // ld e,0 149 205, 0x70, 0x1a, // call $1a70 ; read a single byte 150 151 0x57, // ld d,a 152 0x83, // add a,e 153 0x5f, // ld e,a 154 0x72, // ld (hl),d 155 0x23, // inc hl 156 0x0b, // dec bc 157 0x78, // ld a,b 158 0xb1, // or c 159 0x20, 0xf3, // jr nz,$f3 ;-12 160 161 205, 0xaa, 0x1a, // call $1aaa ; stop tape 162 163 0xe1, // pop hl ; restore program entry loc 164 165 // loader size: 40 bytes 166 167 0, 0, 0, 0, 0, 0, 0, 0, 168 0, 0, 0, 0, 0, 0, 0, 0, 169 0, 0, 0, 170 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, // lead for next block 171 0xAF, 0xAF, 0xAF, 0xAF, 0xAF 172 }; 173 174 static int prefix_length_p6 = 100; 175 176 static unsigned char prefix_p88[] = { 177 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0x64, 0x65, 0x66, 0x61, 0x6c, 0x74, 178 0x0d, 0x00, 0x0a, 0x00, 0x97, 0x20, 0xe0, 0xf1, 0x0c, 0x00, 0x01, 0x00, 0x18, 0x00, 0x14, 0x00, 179 0x41, 0xf1, 0xe0, 0x28, 0x11, 0x29, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 180 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 181 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 182 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 183 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 184 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 185 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 186 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 187 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 188 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 189 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 190 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 191 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 192 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 193 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 194 }; 195 static int prefix_length_p88 = 0x10e; 196 197 // char prefix_p88[] = { 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 198 // 0xd3, 0xd3, 0x47, 0x6f, 0x00, 0x00, 0x00, 0x00, 199 // /* 0x0001 */ 0x0d, 0x00, 0x0a, 0x00, 0x97, 0x20, 0xe0, 0xf1, 200 // 0x0c, 0x1a, 0x00, 0x00, 0x18, 0x00, 0x14, 0x00, 201 // // ~~~~~~~~~~ start address 202 // /* 0x0011 */ 0x41, 0xf1, 0xe0, 0x28, 0x11, 0x29, 0x00, 0x00, 203 // 0x00 }; /* followed by 12 bytes long startup code */ 204 // // 8 9 10 11 12 (here) 205 206 unsigned char prefix_rom[] = { 'A', 'B', 0x04, 0x40 }; 207 int prefix_length_rom = 0x4; 208 209 int nec_exec(char* target) 210 { 211 char filename[FILENAME_MAX + 1]; 212 char wavfile[FILENAME_MAX + 1]; 213 FILE *fpin, *fpout; 214 int c, i, j; 215 int len, stage; 216 int zerocount = 0; 217 218 unsigned char* prefix; 219 int prefix_length; 220 // int codeseg = 0; 221 222 if (binname == NULL) { 223 return -1; 224 } 225 226 // if (dumb) { 227 // strcpy(filename,binname); 228 // } else { 229 230 if (origin == -1) { 231 if ((origin = get_org_addr(crtfile)) == -1) { 232 fprintf(stderr, "Warning: could not get the code ORG, ORG defaults to MODE1 ($C437)\n"); 233 origin = 0xC437; 234 } 235 } 236 237 if (mode == -1) { 238 switch (origin) { 239 case MODE1_ADDRESS_CODESEG: 240 mode = MODE1; 241 break; 242 case MODE2_ADDRESS_CODESEG: 243 mode = MODE2; 244 break; 245 case MODE5_ADDRESS_CODESEG: 246 mode = MODE5; 247 break; 248 case MODEROM_ADDRESS_CODESEG: 249 mode = MODEROM; 250 break; 251 case MODEN88_ADDRESS_CODESEG: 252 mode = MODEN88; 253 break; 254 default: 255 fprintf(stderr, "Unhandled value for ORG: %i\n", origin); 256 return -1; 257 } 258 } 259 //fprintf(stderr,"Mode: %i\n",mode); 260 261 if (strcmp(binname, filename) == 0) { 262 exit_log(1, "Input and output file names must be different\n"); 263 } 264 265 if ((fpin = fopen_bin(binname, crtfile)) == NULL) { 266 exit_log(1,"Can't open input file %s\n", binname); 267 } 268 269 /* 270 * Now we try to determine the size of the file 271 * to be converted 272 */ 273 if (fseek(fpin, 0, SEEK_END)) { 274 fclose(fpin); 275 exit_log(1,"Couldn't determine size of file\n"); 276 } 277 278 len = ftell(fpin); 279 280 fseek(fpin, 0L, SEEK_SET); 281 282 if (outfile == NULL) { 283 strcpy(filename, binname); 284 suffix_change(filename, ".cas"); 285 } else { 286 strcpy(filename, outfile); 287 } 288 289 if ((fpout = fopen(filename, "wb")) == NULL) { 290 fclose(fpin); 291 exit_log(1, "Can't open output file %s\n", filename); 292 } 293 294 // MSB of BASIC RAM start address 295 switch (mode) { 296 case MODE1: 297 prefix = prefix_p6; 298 prefix_length = prefix_length_p6; 299 prefix[17] = 0xc4; 300 prefix[46] = 0xc4; 301 prefix[23] = 'C'; 302 prefix[24] = '4'; 303 prefix[48] = len % 256; 304 prefix[49] = len / 256; 305 // codeseg = MODE1_ADDRESS_CODESEG; 306 break; 307 case MODE5: 308 prefix = prefix_p6; 309 prefix_length = prefix_length_p6; 310 prefix[17] = 0x80; 311 prefix[46] = 0x80; 312 prefix[23] = '8'; 313 prefix[24] = '0'; 314 prefix[48] = len % 256; 315 prefix[49] = len / 256; 316 // codeseg = MODE5_ADDRESS_CODESEG; 317 break; 318 case MODEN88: 319 prefix = prefix_p88; 320 prefix_length = prefix_length_p88; 321 // codeseg = MODEN88_ADDRESS_CODESEG; 322 break; 323 case MODEROM: 324 prefix = prefix_rom; 325 prefix_length = prefix_length_rom; 326 // codeseg = MODEROM_ADDRESS_CODESEG; 327 break; 328 case MODE2: 329 default: 330 prefix = prefix_p6; 331 prefix_length = prefix_length_p6; 332 //prefix[23] = '8'; 333 //prefix[24] = '4'; 334 prefix[48] = len % 256; 335 prefix[49] = len / 256; 336 // codeseg = MODE2_ADDRESS_CODESEG; 337 break; 338 } 339 // set p6 file name 340 for (i = 0; i < 6; i++) { 341 prefix[i + 0x0a] = filename[i]; 342 } 343 344 // write prefix 345 for (i = 0; i < prefix_length; i++) { 346 fputc(prefix[i], fpout); 347 } 348 349 /* ... M/C ...*/ 350 for (i = 0; i < len; i++) { 351 c = getc(fpin); 352 fputc(c, fpout); 353 } 354 355 if (mode != MODEROM) { 356 // write suffix 357 for (i = 0; i < 12; i++) { 358 fputc(0, fpout); 359 } 360 } else { 361 // write trailing bytes 362 for (; i < (0x8000 - MODEROM_ADDRESS_CODESEG); i++) { 363 //putc(memory[i], out); 364 fputc(0, fpout); 365 } 366 } 367 368 fclose(fpin); 369 fclose(fpout); 370 // } 371 372 /* ***************************************** */ 373 /* Now, if requested, create the audio file */ 374 /* ***************************************** */ 375 if ((audio) || (nec_fast) || (nec_22)) { 376 if ((fpin = fopen(filename, "rb")) == NULL) { 377 exit_log(1, "Can't open file %s for wave conversion\n", filename); 378 } 379 380 if (fseek(fpin, 0, SEEK_END)) { 381 fclose(fpin); 382 exit_log(1,"Couldn't determine size of file\n"); 383 } 384 len = ftell(fpin); 385 fseek(fpin, 0, SEEK_SET); 386 387 strcpy(wavfile, filename); 388 389 suffix_change(wavfile, ".RAW"); 390 391 if ((fpout = fopen(wavfile, "wb")) == NULL) { 392 exit_log(1, "Can't open output raw audio file %s\n", wavfile); 393 } 394 395 /* leading silence */ 396 for (i = 0; i < 0x3000; i++) 397 fputc(0x20, fpout); 398 399 /* leading tone */ 400 for (i = 0; i < 3600; i++) 401 nec_bit(fpout, 1); 402 403 stage = 0; 404 405 for (i = 0; (i < len); i++) { 406 c = getc(fpin); 407 switch (stage) { 408 // BASIC Header: seek for the filename termination 409 case 0: 410 if (c == 0) { 411 nec_rawout(fpout, 0); 412 stage++; 413 for (j = 0; j < 600; j++) 414 nec_bit(fpout, 1); 415 c = getc(fpin); 416 } 417 break; 418 // BASIC Block + MC stub: seek for more than 3 zeroes in sequence 419 case 1: 420 if ((c == 0) && (zerocount == 3)) { 421 stage++; 422 while ((c = getc(fpin)) == 0) 423 zerocount++; 424 for (j = 3; j <= zerocount; j++) 425 nec_rawout(fpout, 0); 426 zerocount = 0; // Not necessary 427 for (j = 0; j < 600; j++) 428 nec_bit(fpout, 1); 429 } 430 break; 431 default: 432 break; 433 //fprintf(stderr,"Problems",origin); 434 //return -1; 435 } 436 nec_rawout(fpout, c); 437 if (c) 438 zerocount = 0; 439 else 440 zerocount++; 441 } 442 443 // tail 444 for (j = 0; j < 200; j++) 445 nec_bit(fpout, 1); 446 447 /* Data blocks */ 448 //while (ftell(fpin) < len) { 449 /* leader tone (3600 records of bit 1) */ 450 // for (i=0; i < 3600; i++) 451 // nec_bit (fpout,1); 452 /* data block */ 453 // blocklen = (getc(fpin) + 256 * getc(fpin)); 454 // for (i=0; (i < blocklen); i++) { 455 // c=getc(fpin); 456 // nec_rawout(fpout,c); 457 // } 458 //} 459 460 /* trailing silence */ 461 for (i = 0; i < 0x10000; i++) 462 fputc(0x20, fpout); 463 464 fclose(fpin); 465 fclose(fpout); 466 467 /* Now complete with the WAV header */ 468 if (nec_22) 469 raw2wav_22k(wavfile,2); 470 else 471 raw2wav(wavfile); 472 } 473 474 exit(0); 475 } 476