1 /*
2  *      Create a 320KB boot disk image compatible to the Sharp MZ2500 computer family
3  *
4  *      $Id: mz2500.c $
5  */
6 
7 
8 #include "appmake.h"
9 #include <string.h>
10 #include <ctype.h>
11 
12 
13 
14 static char             *binname      = NULL;
15 static char             *crtfile      = NULL;
16 static char             *outfile      = NULL;
17 static char             *blockname    = NULL;
18 static char              help         = 0;
19 
20 
21 /* Options that are available for this module */
22 option_t mz2500_options[] = {
23     { 'h', "help",     "Display this help",          OPT_BOOL,  &help},
24     { 'b', "binfile",  "Linked binary file",         OPT_STR,   &binname },
25     { 'o', "output",   "Name of output file",        OPT_STR,   &outfile },
26     {  0 , "blockname", "Name for the code block",   OPT_STR,   &blockname},
27     {  0,  NULL,       NULL,                         OPT_NONE,  NULL }
28 };
29 
30 static disc_spec spec = {
31     .name = "MZ2500",
32     .sectors_per_track = 16,
33     .tracks = 40,
34     .sides = 2,
35     .sector_size = 256,
36     .gap3_length = 0x17,
37     .filler_byte = 0xe5,
38     .first_sector_offset = 1,
39     .alternate_sides = 1
40 };
41 
42 static uint8_t    sectorbuf[256];
43 
44 
45 void write_sector(disc_handle *h, int track, int sector, int head)
46 {
47     int  i;
48 
49     for ( i = 0; i < sizeof(sectorbuf);i++ ) {
50         sectorbuf[i] ^= 0xff;
51     }
52     disc_write_sector(h, track, sector, head, sectorbuf);
53 
54 }
55 
56 
57 /*
58  * Execution starts here
59  */
60 
msx_bit(FILE * fpout,unsigned char bit)61 int mz2500_exec(char* target)
62 {
63     char   filename[FILENAME_MAX + 1];
64     FILE*  fpin;
65     int    len;
66     int    i;
67     int    track, sector, head;
68     size_t bytes_read;
69     int    bytes_to_write;
70     disc_handle *h;
71 
72     if (help)
73         return -1;
74 
75     if (binname == NULL ) {
76         return -1;
77     }
78 
79     if (outfile == NULL) {
80         strcpy(filename, binname);
81     } else {
82         strcpy(filename, outfile);
83     }
84 
85 
86     suffix_change(filename, ".dsk");
87 
88 
89     if (strcmp(binname, filename) == 0) {
90         exit_log(1, "Input and output file names must be different\n");
91     }
92 
93     if (blockname == NULL)
94         blockname = zbasename(binname);
95 
96     if ((fpin = fopen_bin(binname, crtfile)) == NULL) {
97         exit_log(1, "Can't open input file %s\n", binname);
98     }
99 
100     suffix_change(blockname, "");
101 
102     if (fseek(fpin, 0, SEEK_END)) {
103         fclose(fpin);
104         exit_log(1,"Couldn't determine size of file\n");
105     }
106 
107     len = ftell(fpin);
108     fseek(fpin, 0L, SEEK_SET);
109 
110     h = disc_create(&spec);
111 
112     /* Disk block #2 (directory) */
113     memset(sectorbuf, 0, sizeof(sectorbuf));
114     sectorbuf[0] = 1;    /* OBJ (machine language program) */
115     memcpy(sectorbuf + 1,"IPLPRO", 6);
116 
117     /* Now the filename from offset 8 */
118     for ( i = 7 ; i < 20; i++ ) {
119         int slen = i - 7;
120         sectorbuf[i] = strlen(blockname) > slen ? blockname[slen] : ' ';
121     }
122     sectorbuf[20] = 0x0d;    // Terminate name
123     // sectorbuf[22] = 0;	 	//
124     // sectorbuf[23] = 0x80;
125     sectorbuf[24] = 0;		// Load address
126     sectorbuf[25] = 0x80;
127     sectorbuf[30] = 0x30;		// Start sector
128     sectorbuf[31] = 0x00;
129 
130     sectorbuf[32] = 12;		// Memory bank for $2000...$e000
131     sectorbuf[33] = 13;		// Next bank
132     sectorbuf[34] = 14;		// Next bank
133     sectorbuf[35] = 0xff;		// Terminate
134 
135     // Banking at start of execution
136     sectorbuf[48] = 8;		// for $000
137     sectorbuf[49] = 9;
138     sectorbuf[50] = 10;
139     sectorbuf[51] = 11;
140     sectorbuf[52] = 12;
141     sectorbuf[53] = 13;
142     sectorbuf[54] = 14;
143     sectorbuf[55] = 15;
144     write_sector(h, 0, 0, 1);
145 
146     // Write info from input file to dsk per sector (in blocks of 256)
147     // Append trailing blanks if bytes_read is smaller than the size of a sector
148     // Start writing on track 2, first sector (block 0x30)
149     track = 1; sector = 0; head = 0;
150     bytes_to_write = len;
151 
152     while ( 0 < bytes_to_write ) {
153        memset(sectorbuf, 0, sizeof(sector));               // Fill sector buffer with data (and evt trailing blanks)
154        bytes_read = fread(sectorbuf, sizeof(uint8_t), 256, fpin);
155        if (bytes_read == 0) { fclose(fpin); exit_log(1, "Could not read required data from <%s>\n", binname); }
156 
157        write_sector(h, track, sector, head);               // Write sector buffer to sector on dsk
158        bytes_to_write -= bytes_read;
159 
160        sector++;                                           // Adjust track, sector, head to write next
161        if ( sector == 16 ) {
162           sector = 0;
163           head ^= 1;
164           if ( head == 1 ) track++;
165        }
166     }
167 
168     fclose(fpin);
169     disc_write_edsk(h, filename);
170     disc_free(h);
171 
172     return 0;
173 }
174