1 /*
2  *        BIN to Sega SC-3000 formats
3  *
4  *        Creates a Basic loader with M/C put in a REM line, and a program block.
5  *
6  *        Stefano Bodrato Jun 2010
7  *
8  *        $Id: sc3000.c,v 1.8 2016-06-26 00:46:55 aralbrec Exp $
9  */
10 
11 #include "appmake.h"
12 
13 static char             *binname      = NULL;
14 static char             *crtfile      = NULL;
15 static char             *outfile      = NULL;
16 static char             *blockname    = NULL;
17 static int               origin       = -1;
18 static char              help         = 0;
19 static char              audio        = 0;
20 static char              fast         = 0;
21 static char              khz_22       = 0;
22 static char              survivors    = 0;
23 static char              sf7000       = 0;
24 
25 static unsigned long     checksum;
26 
27 
28 /* Options that are available for this module */
29 option_t sc3000_options[] = {
30     { 'h', "help",     "Display this help",          OPT_BOOL,  &help},
31     { 'b', "binfile",  "Linked binary file",         OPT_STR,   &binname },
32     { 'c', "crt0file", "crt0 file used in linking",  OPT_STR,   &crtfile },
33     { 'o', "output",   "Name of output file",        OPT_STR,   &outfile },
34     {  0,  "audio",    "Create also a WAV file",     OPT_BOOL,  &audio },
35     {  0,  "fast",     "Create a fast loading WAV",  OPT_BOOL,  &fast },
36     {  0,  "22",       "22050hz bitrate option",     OPT_BOOL,  &khz_22 },
37     {  0,  "survivors", "Add an 'SC Survivors' flash player file", OPT_BOOL,  &survivors },
38     {  0 , "org",      "Origin of the binary (CLOADM only)",       OPT_INT,   &origin },
39     {  0,  "sf7000",    "Simpler CLOADM format for SF-7000 only",  OPT_BOOL,  &sf7000 },
40     {  0 , "blockname", "Name of the code block in tap file", OPT_STR, &blockname},
41     {  0,  NULL,       NULL,                         OPT_NONE,  NULL }
42 };
43 
44 /* It is a sort of a fast mode KansasCity format:    */
45 /* four fast cycles for '1', two slow cycles for '0' */
46 
sc3000_bit(FILE * fpout,unsigned char bit)47 void sc3000_bit(FILE* fpout, unsigned char bit)
48 {
49     int i, period0, period1;
50 
51     if (survivors) {
52 
53         if (bit) {
54             /* '1' */
55             fputc('1', fpout);
56         } else {
57             /* '0' */
58             fputc('0', fpout);
59         }
60 
61     } else {
62 
63         if (fast) {
64             period1 = 8;
65             period0 = 16;
66         } else {
67             period1 = 9;
68             period0 = 18;
69         }
70 
71         if (bit) {
72             /* '1' */
73             for (i = 0; i < period1; i++)
74                 fputc(0xe0, fpout);
75             for (i = 0; i < period1; i++)
76                 fputc(0x20, fpout);
77             for (i = 0; i < period1; i++)
78                 fputc(0xe0, fpout);
79             for (i = 0; i < period1; i++)
80                 fputc(0x20, fpout);
81         } else {
82             /* '0' */
83             for (i = 0; i < (period0); i++)
84                 fputc(0xe0, fpout);
85             for (i = 0; i < (period0); i++)
86                 fputc(0x20, fpout);
87         }
88     }
89 }
90 
sc3000_rawout(FILE * fpout,unsigned char b)91 void sc3000_rawout(FILE* fpout, unsigned char b)
92 {
93     /* bit order is reversed ! */
94     static unsigned char c[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
95     int i;
96 
97     /* 1 start bit */
98     sc3000_bit(fpout, 0);
99 
100     /* byte */
101     for (i = 0; i < 8; i++)
102         sc3000_bit(fpout, (b & c[i]));
103 
104     /* 2 stop bits */
105     sc3000_bit(fpout, 1);
106     sc3000_bit(fpout, 1);
107 }
108 
sc3000_exec(char * target)109 int sc3000_exec(char* target)
110 {
111     char filename[FILENAME_MAX + 1];
112     char wavfile[FILENAME_MAX + 1];
113     char name[17];
114     FILE *fpin, *fpout;
115     long pos=0, blocklen;
116     int c, i, len;
117 
118     if (help)
119         return -1;
120 
121     if (binname == NULL || (crtfile == NULL && origin == -1)) {
122         return -1;
123     }
124 
125     if (outfile == NULL) {
126         strcpy(filename, binname);
127         suffix_change(filename, ".tap");
128     } else {
129         strcpy(filename, outfile);
130     }
131 
132     if (blockname == NULL)
133         blockname = zbasename(binname);
134 
135     if (origin != -1) {
136         pos = origin;
137     } else {
138         if (!sf7000)
139             if ((pos = get_org_addr(crtfile)) == -1) {
140                 exit_log(1,"Could not find parameter ZORG (not z88dk compiled?)\n");
141             }
142     }
143 
144     if ((fpin = fopen_bin(binname, crtfile)) == NULL) {
145         exit_log(1,"Can't open input file %s\n", binname);
146     }
147 
148     /*
149  *        Now we try to determine the size of the file
150  *        to be converted
151  */
152     if (fseek(fpin, 0, SEEK_END)) {
153         fclose(fpin);
154         exit_log(1,"Couldn't determine size of file\n");
155     }
156 
157     len = ftell(fpin);
158     fseek(fpin, 0, SEEK_SET);
159 
160     if ((fpout = fopen(filename, "wb")) == NULL) {
161         exit_log(1, "Can't open output file %s\n", filename);
162     }
163 
164     /* Write out the .tap file */
165 
166     if (sf7000) {
167 
168         /* CLOADM mode header type */
169         writeword(24, fpout); /* header block size */
170         fputc(0x26, fpout); /* M/C header type (SF-7000 only) */
171 
172         /* Deal with the filename */
173         checksum = 255;
174 
175         snprintf(name, sizeof(name), "%-*s", (int) sizeof(name)-1, blockname);
176 
177         for (i = 0; i <= 15; i++)
178             writebyte_cksum(name[i], fpout, &checksum);
179 
180         /* len */
181         writebyte_cksum(len / 256, fpout, &checksum); /* MSB */
182         writebyte_cksum(len % 256, fpout, &checksum); /* LSB */
183         /* start */
184         writebyte_cksum(pos / 256, fpout, &checksum); /* MSB */
185         writebyte_cksum(pos % 256, fpout, &checksum); /* LSB */
186 
187         fputc((checksum % 256) ^ 0xff, fpout);
188         /* extra dummy data to prevent read overflows */
189         fputc(0, fpout);
190         fputc(0, fpout);
191 
192         /* CLOADM object file body*/
193         writeword(len + 4, fpout); /* header block size */
194         fputc(0x27, fpout); /* M/C data block type */
195 
196         checksum = 255;
197         for (i = 0; i < len; i++) {
198             c = getc(fpin);
199             writebyte_cksum(c, fpout, &checksum);
200         }
201         fputc((checksum % 256) ^ 0xff, fpout);
202         /* extra dummy data to prevent read overflows */
203         fputc(0, fpout);
204         fputc(0, fpout);
205 
206         fclose(fpin);
207         fclose(fpout);
208 
209     } else {
210 
211         /* BASIC loader header */
212         writeword(22, fpout); /* header block size */
213         fputc(0x16, fpout); /* BASIC header type */
214 
215         /* Deal with the filename */
216         checksum = 255;
217 
218         snprintf(name, sizeof(name), "%-*s", (int) sizeof(name)-1, blockname);
219 
220         for (i = 0; i <= 15; i++)
221             writebyte_cksum(name[i], fpout, &checksum);
222 
223         /* len */
224         writebyte_cksum((24 + len) / 256, fpout, &checksum); /* MSB */
225         writebyte_cksum((24 + len) % 256, fpout, &checksum); /* LSB */
226 
227         fputc((checksum % 256) ^ 0xff, fpout);
228         /* extra dummy data to prevent read overflows */
229         fputc(0, fpout);
230         fputc(0, fpout);
231 
232         /* BASIC loader body */
233         writeword(24 + len + 4, fpout); /* header block size */
234         fputc(0x17, fpout); /* BASIC block type */
235 
236         checksum = 255;
237 
238         /* PROGRAM LINE #1 */
239         writebyte_cksum(8, fpout, &checksum); /* prg line length */
240         writebyte_cksum(1, fpout, &checksum); /* prg line number */
241         writebyte_cksum(0, fpout, &checksum);
242         writebyte_cksum(0, fpout, &checksum);
243         writebyte_cksum(0, fpout, &checksum);
244         /* Line size count starts here */
245         writebyte_cksum(174, fpout, &checksum); /* CALL */
246         writebyte_cksum(' ', fpout, &checksum);
247         writebyte_cksum('&', fpout, &checksum);
248         writebyte_cksum('H', fpout, &checksum);
249         writebyte_cksum('9', fpout, &checksum);
250         writebyte_cksum('8', fpout, &checksum);
251         writebyte_cksum('1', fpout, &checksum);
252         writebyte_cksum('7', fpout, &checksum);
253         writebyte_cksum(':', fpout, &checksum);
254         writebyte_cksum(151, fpout, &checksum); /* STOP */
255         /* Line size count ends here */
256         writebyte_cksum(13, fpout, &checksum); /* CR */
257 
258         /* PROGRAM LINE #2 (code inside) */
259         writebyte_cksum(6, fpout, &checksum); /* prg line length (just a fake value) */
260         writebyte_cksum(2, fpout, &checksum); /* prg line number */
261         writebyte_cksum(0, fpout, &checksum);
262         writebyte_cksum(0, fpout, &checksum);
263         writebyte_cksum(0, fpout, &checksum);
264         /* Line size count starts here */
265         writebyte_cksum(144, fpout, &checksum); /* REM */
266         writebyte_cksum(' ', fpout, &checksum);
267         /* CODE (location $9817) */
268         for (i = 0; i < len; i++) {
269             c = getc(fpin);
270             writebyte_cksum(c, fpout, &checksum);
271         }
272         /* Line size count ends here */
273         writebyte_cksum(13, fpout, &checksum); /* CR */
274 
275         fputc((checksum % 256) ^ 0xff, fpout);
276 
277         /* extra dummy data to prevent read overflows */
278         fputc(0, fpout);
279         fputc(0, fpout);
280     }
281 
282     fclose(fpin);
283     fclose(fpout);
284 
285     /* ***************************************** */
286     /*  Now, if requested, create the audio file */
287     /* ***************************************** */
288     if ((audio) || (fast) || (khz_22)) {
289         if ((fpin = fopen(filename, "rb")) == NULL) {
290             exit_log(1, "Can't open file %s for wave conversion\n", filename);
291         }
292 
293         if (fseek(fpin, 0, SEEK_END)) {
294             fclose(fpin);
295             exit_log(1,"Couldn't determine size of file\n");
296         }
297         len = ftell(fpin);
298         fseek(fpin, 0, SEEK_SET);
299 
300         strcpy(wavfile, filename);
301 
302         if (survivors)
303             suffix_change(wavfile, ".bit");
304         else
305             suffix_change(wavfile, ".RAW");
306 
307         if ((fpout = fopen(wavfile, "wb")) == NULL) {
308             exit_log(1,"Can't open output raw audio file %s\n", wavfile);
309         }
310 
311         /* leading silence */
312         if (survivors) {
313             for (i = 0; i < 30; i++)
314                 fputc(' ', fpout);
315         } else {
316 
317             for (i = 0; i < 0x3000; i++)
318                 fputc(0x20, fpout);
319         }
320 
321         /* Data blocks */
322         while (ftell(fpin) < len) {
323             /* leader tone (3600 records of bit 1) */
324             for (i = 0; i < 3600; i++)
325                 sc3000_bit(fpout, 1);
326             /* data block */
327             blocklen = (getc(fpin) + 256 * getc(fpin));
328             for (i = 0; (i < blocklen); i++) {
329                 c = getc(fpin);
330                 sc3000_rawout(fpout, c);
331             }
332         }
333 
334         /* trailing silence */
335         if (survivors) {
336             for (i = 0; i < 100; i++)
337                 fputc(' ', fpout);
338         } else {
339             for (i = 0; i < 0x10000; i++)
340                 fputc(0x20, fpout);
341         }
342 
343         fclose(fpin);
344         fclose(fpout);
345 
346         /* Now complete with the WAV header */
347         if (!survivors) {
348 			if (khz_22)
349 				raw2wav_22k(wavfile,2);
350 			else
351 				raw2wav(wavfile);
352 		}
353     }
354 
355     exit(0);
356 }
357