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