]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/piscsi.c
Add PiSCSI readme with a brief setup tutorial for now
[pistorm] / platforms / amiga / piscsi / piscsi.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <endian.h>
8 #include "piscsi.h"
9 #include "piscsi-enums.h"
10 #include "../../../config_file/config_file.h"
11 #include "../../../gpio/gpio.h"
12
13 // Comment this line to restore debug output:
14 #define printf(...)
15
16 struct piscsi_dev devs[8];
17 uint8_t piscsi_cur_drive = 0;
18 uint32_t piscsi_u32[4];
19 uint32_t piscsi_rom_size = 0;
20 uint8_t *piscsi_rom_ptr;
21
22 extern unsigned char ac_piscsi_rom[];
23
24 static const char *op_type_names[4] = {
25     "BYTE",
26     "WORD",
27     "LONGWORD",
28     "MEM",
29 };
30
31 void piscsi_init() {
32     for (int i = 0; i < 8; i++) {
33         devs[i].fd = -1;
34         devs[i].c = devs[i].h = devs[i].s = 0;
35     }
36
37     FILE *in = fopen("./platforms/amiga/piscsi/piscsi.rom", "rb");
38     if (in == NULL) {
39         printf("[PISCSI] Could not open PISCSI Boot ROM file for reading.\n");
40         ac_piscsi_rom[20] = 0;
41         ac_piscsi_rom[21] = 0;
42         ac_piscsi_rom[22] = 0;
43         ac_piscsi_rom[23] = 0;
44         return;
45     }
46     fseek(in, 0, SEEK_END);
47     piscsi_rom_size = ftell(in);
48     fseek(in, 0, SEEK_SET);
49     piscsi_rom_ptr = malloc(piscsi_rom_size);
50     fread(piscsi_rom_ptr, piscsi_rom_size, 1, in);
51     fclose(in);
52     printf("[PISCSI] Loaded Boot ROM.\n");
53 }
54
55 void piscsi_map_drive(char *filename, uint8_t index) {
56     if (index > 7) {
57         printf("[PISCSI] Drive index %d out of range.\nUnable to map file %s to drive.\n", index, filename);
58         return;
59     }
60
61     int32_t tmp_fd = open(filename, O_RDWR);
62     if (tmp_fd == -1) {
63         printf("[PISCSI] Failed to open file %s, could not map drive %d.\n", filename, index);
64         return;
65     }
66
67     struct piscsi_dev *d = &devs[index];
68
69     uint64_t file_size = lseek(tmp_fd, 0, SEEK_END);
70     lseek(tmp_fd, 0, SEEK_SET);
71     printf("[PISCSI] Map %d: [%s] - %llu bytes.\n", index, filename, file_size);
72     d->h = 64;
73     d->s = 63;
74     d->c = (file_size / 512) / (d->s * d->h);
75     printf("[PISCSI] CHS: %d %d %d\n", d->c, d->h, d->s);
76     d->fs = file_size;
77     d->fd = tmp_fd;
78 }
79
80 void piscsi_unmap_drive(uint8_t index) {
81     if (devs[index].fd != -1) {
82         printf("[PISCSI] Unmapped drive %d.\n", index);
83         close (devs[index].fd);
84         devs[index].fd = -1;
85     }
86 }
87
88 extern struct emulator_config *cfg;
89 extern void stop_cpu_emulation(uint8_t disasm_cur);
90
91 void handle_piscsi_write(uint32_t addr, uint32_t val, uint8_t type) {
92     int32_t r;
93
94     struct piscsi_dev *d = &devs[piscsi_cur_drive];
95
96     switch (addr & 0xFFFF) {
97         case PISCSI_CMD_READ:
98             if (d->fd == -1) {
99                 printf ("[PISCSI] BUG: Attempted read from unmapped drive %d.\n", piscsi_cur_drive);
100                 break;
101             }
102             printf("[PISCSI] %d byte READ from block %d to address %.8X\n", piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
103             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
104             if (r != -1 && cfg->map_type[r] == MAPTYPE_RAM) {
105                 printf("[PISCSI] \"DMA\" Read goes to mapped range %d.\n", r);
106                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
107                 read(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
108             }
109             else {
110                 printf("[PISCSI] No mapped range found for read.\n");
111                 uint8_t c = 0;
112                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
113                 for (int i = 0; i < piscsi_u32[1]; i++) {
114                     read(d->fd, &c, 1);
115 #ifndef FAKESTORM
116                     write8(piscsi_u32[2] + i, (uint32_t)c);
117 #endif
118                 }
119             }
120             break;
121         case PISCSI_CMD_WRITE:
122             if (d->fd == -1) {
123                 printf ("[PISCSI] BUG: Attempted write to unmapped drive %d.\n", piscsi_cur_drive);
124                 break;
125             }
126             printf("[PISCSI] %d byte WRITE to block %d to address %.8X\n", piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
127             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
128             if (r != -1) {
129                 printf("[PISCSI] \"DMA\" Write comes from mapped range %d.\n", r);
130                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
131                 write(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
132             }
133             else {
134                 printf("[PISCSI] No mapped range found for write.\n");
135                 uint8_t c = 0;
136                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
137                 for (int i = 0; i < piscsi_u32[1]; i++) {
138 #ifndef FAKESTORM
139                     c = read8(piscsi_u32[2] + i);
140 #endif
141                     write(d->fd, &c, 1);
142                 }
143             }
144             break;
145         case PISCSI_CMD_ADDR1:
146             piscsi_u32[0] = val;
147             printf("[PISCSI] Write to ADDR1: %.8x\n", piscsi_u32[0]);
148             break;
149         case PISCSI_CMD_ADDR2:
150             piscsi_u32[1] = val;
151             printf("[PISCSI] Write to ADDR2: %.8x\n", piscsi_u32[1]);
152             break;
153         case PISCSI_CMD_ADDR3:
154             piscsi_u32[2] = val;
155             printf("[PISCSI] Write to ADDR3: %.8x\n", piscsi_u32[2]);
156             break;
157         case PISCSI_CMD_ADDR4:
158             piscsi_u32[3] = val;
159             printf("[PISCSI] Write to ADDR4: %.8x\n", piscsi_u32[3]);
160             break;
161         case PISCSI_CMD_DRVNUM:
162             if (val != 0) {
163                 if (val < 10) // Kludge for GiggleDisk
164                     piscsi_cur_drive = val;
165                 else if (val >= 10 && val % 10 != 0)
166                     piscsi_cur_drive = 255;
167                 else
168                     piscsi_cur_drive = val / 10;
169             }
170             else
171                 piscsi_cur_drive = val;
172             printf("[PISCSI] (%s) Drive number set to %d (%d)\n", op_type_names[type], piscsi_cur_drive, val);
173             break;
174         case PISCSI_CMD_DEBUGME:
175             printf("[PISCSI] DebugMe triggered.\n");
176             stop_cpu_emulation(1);
177             break;
178         case PISCSI_CMD_DRIVER: {
179             printf("[PISCSI] Driver copy/patch called, destination address %.8X.\n", val);
180             int r = get_mapped_item_by_address(cfg, val);
181             if (r != -1) {
182                 uint32_t addr = val - cfg->map_offset[r];
183                 uint32_t rt_offs = 0;
184                 uint8_t *dst_data = cfg->map_data[r];
185                 memcpy(dst_data + addr, piscsi_rom_ptr + 0x400, 0x3C00);
186                 
187                 uint32_t base_offs = be32toh(*((uint32_t *)&dst_data[addr + 0x170])) + 2;
188                 rt_offs = val + 0x16E;
189                 printf ("Offset 1: %.8X -> %.8X\n", base_offs, rt_offs);
190                 *((uint32_t *)&dst_data[addr + 0x170]) = htobe32(rt_offs);
191
192                 uint32_t offs = be32toh(*((uint32_t *)&dst_data[addr + 0x174]));
193                 printf ("Offset 2: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
194                 *((uint32_t *)&dst_data[addr + 0x174]) = htobe32((offs - base_offs) + rt_offs);
195
196                 dst_data[addr + 0x178] |= 0x07;
197
198                 offs = be32toh(*((uint32_t *)&dst_data[addr + 0x17C]));
199                 printf ("Offset 3: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
200                 *((uint32_t *)&dst_data[addr + 0x17C]) = htobe32((offs - base_offs) + rt_offs);
201
202                 offs = be32toh(*((uint32_t *)&dst_data[addr + 0x180]));
203                 printf ("Offset 4: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
204                 *((uint32_t *)&dst_data[addr + 0x180]) = htobe32((offs - base_offs) + rt_offs);
205
206                 offs = be32toh(*((uint32_t *)&dst_data[addr + 0x184]));
207                 printf ("Offset 5: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
208                 *((uint32_t *)&dst_data[addr + 0x184]) = htobe32((offs - base_offs) + rt_offs);
209
210             }
211             else {
212                 for (int i = 0; i < 0x3C00; i++) {
213                     uint8_t src = piscsi_rom_ptr[0x400 + i];
214                     write8(addr + i, src);
215                 }
216             }
217             break;
218         }
219         default:
220             printf("[PISCSI] Unhandled %s register write to %.8X: %d\n", op_type_names[type], addr, val);
221             break;
222     }
223 }
224
225 uint8_t piscsi_diag_area[] = {
226     0x90,
227     0x00,
228     0x00, 0x40,
229     0x2C, 0x00,
230     0x2C, 0x00,
231     0x00, 0x00,
232     0x00, 0x00,
233     0x00, 0x00,
234 };
235
236 uint8_t fastata_diag_area[] = {
237     0x90,
238     0x00,
239     0x00, 0x10,
240     0x9e, 0x08,
241     0x00, 0x00,
242     0x00, 0x00,
243     0x00, 0x02,
244     0x00, 0x00,
245 };
246
247 uint8_t piscsi_diag_read;
248
249 #define PIB 0x00
250
251 uint32_t handle_piscsi_read(uint32_t addr, uint8_t type) {
252     if (type) {}
253     uint8_t *diag_area = piscsi_diag_area;
254
255     if ((addr & 0xFFFF) >= PISCSI_CMD_ROM) {
256         uint32_t romoffs = (addr & 0xFFFF) - PISCSI_CMD_ROM;
257         /*if (romoffs < 14 && !piscsi_diag_read) {
258             printf("[PISCSI] %s read from DiagArea @$%.4X: ", op_type_names[type], romoffs);
259             uint32_t v = 0;
260             switch (type) {
261                 case OP_TYPE_BYTE:
262                     v = diag_area[romoffs];
263                     printf("%.2X\n", v);
264                     break;
265                 case OP_TYPE_WORD:
266                     v = *((uint16_t *)&diag_area[romoffs]);
267                     printf("%.4X\n", v);
268                     break;
269                 case OP_TYPE_LONGWORD:
270                     v = (*((uint16_t *)&diag_area[romoffs]) << 16) | *((uint16_t *)&diag_area[romoffs + 2]);
271                     //v = *((uint32_t *)&diag_area[romoffs]);
272                     printf("%.8X\n", v);
273                     break;
274             }
275             if (romoffs == 0x0D)
276                 piscsi_diag_read = 1;
277             return v;   
278         }*/
279         if (romoffs < (piscsi_rom_size + PIB)) {
280             printf("[PISCSI] %s read from Boot ROM @$%.4X (%.8X): ", op_type_names[type], romoffs, addr);
281             uint32_t v = 0;
282             switch (type) {
283                 case OP_TYPE_BYTE:
284                     v = piscsi_rom_ptr[romoffs - PIB];
285                     printf("%.2X\n", v);
286                     break;
287                 case OP_TYPE_WORD:
288                     v = be16toh(*((uint16_t *)&piscsi_rom_ptr[romoffs - PIB]));
289                     printf("%.4X\n", v);
290                     break;
291                 case OP_TYPE_LONGWORD:
292                     //v = (*((uint16_t *)&piscsi_rom_ptr[romoffs - 14]) << 16) | *((uint16_t *)&piscsi_rom_ptr[romoffs - 12]);
293                     v = be32toh(*((uint32_t *)&piscsi_rom_ptr[romoffs - PIB]));
294                     printf("%.8X\n", v);
295                     break;
296             }
297             return v;
298         }
299         return 0;
300     }
301     
302     switch (addr & 0xFFFF) {
303         case PISCSI_CMD_DRVTYPE:
304             if (devs[piscsi_cur_drive].fd == -1) {
305                 printf("[PISCSI] %s Read from DRVTYPE %d, drive not attached.\n", op_type_names[type], piscsi_cur_drive);
306                 return 0;
307             }
308             printf("[PISCSI] %s Read from DRVTYPE %d, drive attached.\n", op_type_names[type], piscsi_cur_drive);
309             return 1;
310             break;
311         case PISCSI_CMD_DRVNUM:
312             return piscsi_cur_drive;
313             break;
314         case PISCSI_CMD_CYLS:
315             printf("[PISCSI] %s Read from CYLS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].c);
316             return devs[piscsi_cur_drive].c;
317             break;
318         case PISCSI_CMD_HEADS:
319             printf("[PISCSI] %s Read from HEADS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].h);
320             return devs[piscsi_cur_drive].h;
321             break;
322         case PISCSI_CMD_SECS:
323             printf("[PISCSI] %s Read from SECS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].s);
324             return devs[piscsi_cur_drive].s;
325             break;
326         case PISCSI_CMD_BLOCKS: {
327             uint32_t blox = devs[piscsi_cur_drive].fs / 512;
328             printf("[PISCSI] %s Read from BLOCKS %d: %d\n", op_type_names[type], piscsi_cur_drive, (uint32_t)(devs[piscsi_cur_drive].fs / 512));
329             printf("fs: %lld (%d)\n", devs[piscsi_cur_drive].fs, blox);
330             return blox;
331             break;
332         }
333         default:
334             printf("[PISCSI] Unhandled %s register read from %.8X\n", op_type_names[type], addr);
335             break;
336     }
337
338     return 0;
339 }
340
341 void piscsi_block_op(uint8_t type, uint8_t num, uint32_t dest, uint32_t len) {
342     if (type || num || dest || len) {}
343 }