source: buchla-emu/emu/mkdisk.c@ a6da9fb

Last change on this file since a6da9fb was a6da9fb, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Create buchla.disk, a 1.44M FAT12 floppy disk image.

  • Property mode set to 100644
File size: 5.7 KB
Line 
1/*
2 * Copyright (C) 2017 The Contributors
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * A copy of the GNU General Public License can be found in the file
15 * "gpl.txt" in the top directory of this repository.
16 */
17
18#include <stdbool.h>
19#include <stddef.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include <sys/types.h>
26
27#define DISK_FILE_NAME "buchla.disk"
28#define MIDAS_FILE_NAME "midas.abs"
29
30#define N_CYL 80
31#define N_SID 2
32#define N_SEC 18
33#define SZ_SEC 512
34
35#define N_SEC_CLU 1
36
37#define N_BOOT_SEC 1
38#define N_FAT_SEC 9
39#define N_ROOT_SEC 14
40
41#define N_FAT 2
42#define SZ_DIR_ENT 32
43
44#define ROOT_SEC (N_BOOT_SEC + N_FAT_SEC * N_FAT)
45#define N_META_SEC (ROOT_SEC + N_ROOT_SEC)
46
47static uint8_t midas[1024 * 1024];
48static int32_t sz_midas;
49
50static uint8_t disk[N_CYL * N_SID * N_SEC][SZ_SEC];
51
52static int32_t put_sec_8(int32_t sec, int32_t off, int32_t val)
53{
54 disk[sec][off] = (uint8_t)val;
55 return off + 1;
56}
57
58static int32_t put_sec_16(int32_t sec, int32_t off, int32_t val)
59{
60 disk[sec][off + 0] = (uint8_t)(val >> 0);
61 disk[sec][off + 1] = (uint8_t)(val >> 8);
62 return off + 2;
63}
64
65static int32_t put_sec_32(int32_t sec, int32_t off, int32_t val)
66{
67 off = put_sec_16(sec, off, val & 65535);
68 off = put_sec_16(sec, off, val >> 16);
69 return off;
70}
71
72static int32_t put_sec_str(int32_t sec, int32_t off, const char *str, int32_t len)
73{
74 int32_t i;
75
76 for (i = 0; str[i] != 0 && i < len; ++i) {
77 disk[sec][off + i] = (uint8_t)str[i];
78 }
79
80 while (i < len) {
81 disk[sec][off + i] = ' ';
82 ++i;
83 }
84
85 return off + i;
86}
87
88static int32_t put_fat_12(int32_t sec, int32_t ent, int32_t val)
89{
90 uint8_t *fat = disk[sec];
91
92 int32_t off = ent / 2 * 3;
93 int32_t bit = (ent % 2) * 12;
94
95 int32_t tmp = 0;
96
97 tmp |= fat[off + 0] << 0;
98 tmp |= fat[off + 1] << 8;
99 tmp |= fat[off + 2] << 16;
100
101 tmp = (tmp & ~(0xfff << bit)) | (val << bit);
102
103 fat[off + 0] = (uint8_t)(tmp >> 0);
104 fat[off + 1] = (uint8_t)(tmp >> 8);
105 fat[off + 2] = (uint8_t)(tmp >> 16);
106
107 return ent + 1;
108}
109
110static void init_boot_sector(void)
111{
112 int32_t off = 0;
113
114 // magic number
115 off = put_sec_8(0, off, 0xe9);
116 off = put_sec_8(0, off, 0x00);
117
118 // OEM
119 off = put_sec_str(0, off, "EMUL", 6);
120
121 // serial number
122 off = put_sec_8(0, off, 0x01);
123 off = put_sec_8(0, off, 0x02);
124 off = put_sec_8(0, off, 0x03);
125
126 // bytes per sector
127 off = put_sec_16(0, off, SZ_SEC);
128
129 // sectors per cluster
130 off = put_sec_8(0, off, N_SEC_CLU);
131
132 // number of reserved sectors
133 off = put_sec_16(0, off, N_BOOT_SEC);
134
135 // number of FATs
136 off = put_sec_8(0, off, N_FAT);
137
138 // maximum number of root directory entries
139 off = put_sec_16(0, off, N_ROOT_SEC * SZ_SEC / SZ_DIR_ENT);
140
141 // total number of sectors
142 off = put_sec_16(0, off, N_CYL * N_SID * N_SEC);
143
144 // media descriptor (floppy disk, 1.44M)
145 off = put_sec_8(0, off, 0xf0);
146
147 // sectors per FAT (9 * 512 / 3 * 2 = 3072)
148 off = put_sec_16(0, off, N_FAT_SEC);
149
150 // sectors per track
151 off = put_sec_16(0, off, N_SEC);
152
153 // number of sides
154 off = put_sec_16(0, off, N_SID);
155
156 // number of hidden sectors
157 off = put_sec_16(0, off, 0);
158
159 put_sec_8(0, SZ_SEC - 2, 0x55);
160 put_sec_8(0, SZ_SEC - 1, 0xaa);
161}
162
163static void init_fat(int32_t sec)
164{
165 int32_t ent = 0;
166
167 ent = put_fat_12(sec, ent, 0xff0);
168 ent = put_fat_12(sec, ent, 0xfff);
169
170 int32_t n_sec = (sz_midas + SZ_SEC - 1) / SZ_SEC;
171
172 for (int32_t i = 0; i < n_sec - 1; ++i) {
173 ent = put_fat_12(sec, ent, ent + 1);
174 }
175
176 put_fat_12(sec, ent, 0xfff);
177}
178
179static void init_midas(void)
180{
181 int32_t off = 0;
182
183 // file name
184 off = put_sec_str(ROOT_SEC, off, "MIDAS", 8);
185
186 // extension
187 off = put_sec_str(ROOT_SEC, off, "ABS", 3);
188
189 // file attributes (0x20 = archive)
190 off = put_sec_8(ROOT_SEC, off, 0x20);
191
192 // unused
193 for (int32_t i = 0; i < 10; ++i) {
194 off = put_sec_8(ROOT_SEC, off, 0x00);
195 }
196
197 // last modified time (12:34:56)
198 off = put_sec_16(ROOT_SEC, off, (12 << 11) | (34 << 5) | (56 / 2));
199
200 // last modified date (1988-06-20)
201 off = put_sec_16(ROOT_SEC, off, (8 << 9) | (6 << 5) | 20);
202
203 // start cluster
204 off = put_sec_16(ROOT_SEC, off, 2);
205
206 // file size
207 off = put_sec_32(ROOT_SEC, off, sz_midas);
208
209 int32_t n_sec = (sz_midas + SZ_SEC - 1) / SZ_SEC;
210 memcpy(disk[N_META_SEC], midas, (size_t)n_sec * SZ_SEC);
211}
212
213static void write_disk(void)
214{
215 FILE *fh = fopen(DISK_FILE_NAME, "wb");
216
217 if (fh == NULL || fwrite(disk, sizeof disk, 1, fh) != 1) {
218 fprintf(stderr, "error while writing disk file " DISK_FILE_NAME "\n");
219 exit(1);
220 }
221
222 fclose(fh);
223}
224
225static void load_midas(void)
226{
227 FILE *fh = fopen(MIDAS_FILE_NAME, "rb");
228
229 if (fh == NULL) {
230 fprintf(stderr, "error while opening MIDAS file " MIDAS_FILE_NAME "\n");
231 exit(1);
232 }
233
234 if (fseek(fh, 0, SEEK_END) < 0) {
235 fprintf(stderr, "error while seeking in MIDAS file " MIDAS_FILE_NAME "\n");
236 exit(1);
237 }
238
239 ssize_t len = ftell(fh);
240
241 if (len < 0) {
242 fprintf(stderr, "error while determining size of MIDAS file " MIDAS_FILE_NAME "\n");
243 exit(1);
244 }
245
246 sz_midas = (int32_t)len;
247 rewind(fh);
248
249 if (fread(midas, (size_t)sz_midas, 1, fh) != 1) {
250 fprintf(stderr, "error while reading MIDAS file " MIDAS_FILE_NAME "\n");
251 exit(1);
252 }
253
254 fclose(fh);
255}
256
257int32_t main(int32_t argc, char *argv[])
258{
259 (void)argc;
260 (void)argv;
261
262 load_midas();
263 init_boot_sector();
264
265 for (int32_t i = 0; i < N_FAT; ++i) {
266 init_fat(N_BOOT_SEC + i * N_FAT_SEC);
267 }
268
269 init_midas();
270 write_disk();
271 return 0;
272}
Note: See TracBrowser for help on using the repository browser.