]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/piscsi.c
9f9500b2bf88f798ea11c2d3e5ac010dcc34872b
[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_dbg[8];
20 uint32_t piscsi_rom_size = 0;
21 uint8_t *piscsi_rom_ptr;
22
23 extern unsigned char ac_piscsi_rom[];
24
25 static const char *op_type_names[4] = {
26     "BYTE",
27     "WORD",
28     "LONGWORD",
29     "MEM",
30 };
31
32 void piscsi_init() {
33     for (int i = 0; i < 8; i++) {
34         devs[i].fd = -1;
35         devs[i].lba = 0;
36         devs[i].c = devs[i].h = devs[i].s = 0;
37     }
38
39     FILE *in = fopen("./platforms/amiga/piscsi/piscsi.rom", "rb");
40     if (in == NULL) {
41         printf("[PISCSI] Could not open PISCSI Boot ROM file for reading.\n");
42         ac_piscsi_rom[20] = 0;
43         ac_piscsi_rom[21] = 0;
44         ac_piscsi_rom[22] = 0;
45         ac_piscsi_rom[23] = 0;
46         return;
47     }
48     fseek(in, 0, SEEK_END);
49     piscsi_rom_size = ftell(in);
50     fseek(in, 0, SEEK_SET);
51     piscsi_rom_ptr = malloc(piscsi_rom_size);
52     fread(piscsi_rom_ptr, piscsi_rom_size, 1, in);
53     fclose(in);
54     printf("[PISCSI] Loaded Boot ROM.\n");
55 }
56
57 void piscsi_map_drive(char *filename, uint8_t index) {
58     if (index > 7) {
59         printf("[PISCSI] Drive index %d out of range.\nUnable to map file %s to drive.\n", index, filename);
60         return;
61     }
62
63     int32_t tmp_fd = open(filename, O_RDWR);
64     if (tmp_fd == -1) {
65         printf("[PISCSI] Failed to open file %s, could not map drive %d.\n", filename, index);
66         return;
67     }
68
69     struct piscsi_dev *d = &devs[index];
70
71     uint64_t file_size = lseek(tmp_fd, 0, SEEK_END);
72     lseek(tmp_fd, 0, SEEK_SET);
73     printf("[PISCSI] Map %d: [%s] - %llu bytes.\n", index, filename, file_size);
74     d->h = 64;
75     d->s = 63;
76     d->c = (file_size / 512) / (d->s * d->h);
77     printf("[PISCSI] CHS: %d %d %d\n", d->c, d->h, d->s);
78     d->fs = file_size;
79     d->fd = tmp_fd;
80 }
81
82 void piscsi_unmap_drive(uint8_t index) {
83     if (devs[index].fd != -1) {
84         printf("[PISCSI] Unmapped drive %d.\n", index);
85         close (devs[index].fd);
86         devs[index].fd = -1;
87     }
88 }
89
90 #define TDF_EXTCOM (1<<15)
91
92 #define CMD_INVALID     0
93 #define CMD_RESET       1
94 #define CMD_READ        2
95 #define CMD_WRITE       3
96 #define CMD_UPDATE      4
97 #define CMD_CLEAR       5
98 #define CMD_STOP        6
99 #define CMD_START       7
100 #define CMD_FLUSH       8
101 #define CMD_NONSTD      9
102
103 #define TD_MOTOR        (CMD_NONSTD+0)
104 #define TD_SEEK         (CMD_NONSTD+1)
105 #define TD_FORMAT       (CMD_NONSTD+2)
106 #define TD_REMOVE       (CMD_NONSTD+3)
107 #define TD_CHANGENUM    (CMD_NONSTD+4)
108 #define TD_CHANGESTATE  (CMD_NONSTD+5)
109 #define TD_PROTSTATUS   (CMD_NONSTD+6)
110 #define TD_RAWREAD      (CMD_NONSTD+7)
111 #define TD_RAWWRITE     (CMD_NONSTD+8)
112 #define TD_GETDRIVETYPE (CMD_NONSTD+9)
113 #define TD_GETNUMTRACKS (CMD_NONSTD+10)
114 #define TD_ADDCHANGEINT (CMD_NONSTD+11)
115 #define TD_REMCHANGEINT (CMD_NONSTD+12)
116 #define TD_GETGEOMETRY  (CMD_NONSTD+13)
117 #define TD_EJECT        (CMD_NONSTD+14)
118 #define TD_LASTCOMM     (CMD_NONSTD+15)
119
120 #define ETD_WRITE       (CMD_WRITE|TDF_EXTCOM)
121 #define ETD_READ        (CMD_READ|TDF_EXTCOM)
122 #define ETD_MOTOR       (TD_MOTOR|TDF_EXTCOM)
123 #define ETD_SEEK        (TD_SEEK|TDF_EXTCOM)
124 #define ETD_FORMAT      (TD_FORMAT|TDF_EXTCOM)
125 #define ETD_UPDATE      (CMD_UPDATE|TDF_EXTCOM)
126 #define ETD_CLEAR       (CMD_CLEAR|TDF_EXTCOM)
127 #define ETD_RAWREAD     (TD_RAWREAD|TDF_EXTCOM)
128 #define ETD_RAWWRITE    (TD_RAWWRITE|TDF_EXTCOM)
129
130 #define HD_SCSICMD 28
131
132 char *io_cmd_name(int index) {
133     switch (index) {
134         case CMD_INVALID: return "INVALID";
135         case CMD_RESET: return "RESET";
136         case CMD_READ: return "READ";
137         case CMD_WRITE: return "WRITE";
138         case CMD_UPDATE: return "UPDATE";
139         case CMD_CLEAR: return "CLEAR";
140         case CMD_STOP: return "STOP";
141         case CMD_START: return "START";
142         case CMD_FLUSH: return "FLUSH";
143         case TD_MOTOR: return "TD_MOTOR";
144         case TD_SEEK: return "SEEK";
145         case TD_FORMAT: return "FORMAT";
146         case TD_REMOVE: return "REMOVE";
147         case TD_CHANGENUM: return "CHANGENUM";
148         case TD_CHANGESTATE: return "CHANGESTATE";
149         case TD_PROTSTATUS: return "PROTSTATUS";
150         case TD_RAWREAD: return "RAWREAD";
151         case TD_RAWWRITE: return "RAWWRITE";
152         case TD_GETDRIVETYPE: return "GETDRIVETYPE";
153         case TD_GETNUMTRACKS: return "GETNUMTRACKS";
154         case TD_ADDCHANGEINT: return "ADDCHANGEINT";
155         case TD_REMCHANGEINT: return "REMCHANGEINT";
156         case TD_GETGEOMETRY: return "GETGEOMETRY";
157         case TD_EJECT: return "EJECT";
158         case TD_LASTCOMM: return "LASTCOMM";
159         case HD_SCSICMD: return "HD_SCSICMD";
160         default:
161             return "!!!Unhandled IO command";
162     }
163 }
164
165 char *scsi_cmd_name(int index) {
166     switch(index) {
167         case 0x00: return "TEST UNIT READY";
168         case 0x12: return "INQUIRY";
169         case 0x08: return "READ";
170         case 0x0A: return "WRITE";
171         case 0x25: return "READ CAPACITY";
172         case 0x1A: return "MODE SENSE";
173         case 0x37: return "READ DEFECT DATA";
174         default:
175             return "!!!Unhandled SCSI command";
176     }
177 }
178
179 void print_piscsi_debug_message(int index) {
180     switch (index) {
181         case DBG_INIT:
182             printf("[PISCSI] Initializing devices.\n");
183             break;
184         case DBG_OPENDEV:
185             printf("[PISCSI] Opening device %d (%d). Flags: %d (%.2X)\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2], piscsi_dbg[2]);
186             break;
187         case DBG_CLEANUP:
188             printf("[PISCSI] Cleaning up.\n");
189             break;
190         case DBG_CHS:
191             printf("[PISCSI] C/H/S: %d / %d / %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2]);
192             break;
193         case DBG_BEGINIO:
194             printf("[PISCSI] BeginIO: io_Command: %d - io_Flags = %d - quick: %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2]);
195             break;
196         case DBG_ABORTIO:
197             printf("[PISCSI] AbortIO!\n");
198             break;
199         case DBG_SCSICMD:
200             printf("[PISCSI] SCSI Command %d (%s)\n", piscsi_dbg[1], scsi_cmd_name(piscsi_dbg[1]));
201             printf("Len: %d - %.2X %.2X %.2X - Command Length: %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2], piscsi_dbg[3], piscsi_dbg[4]);
202             break;
203         case DBG_SCSI_UNKNOWN_MODESENSE:
204             printf("SCSI: Unknown modesense %.4X\n", piscsi_dbg[0]);
205             break;
206         case DBG_SCSI_UNKNOWN_COMMAND:
207             printf("SCSI: Unknown command %.4X\n", piscsi_dbg[0]);
208             break;
209         case DBG_SCSIERR:
210             printf("SCSI: An error occured: %.4X\n", piscsi_dbg[0]);
211             break;
212         case DBG_IOCMD:
213             printf("[PISCSI] IO Command %d (%s)\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
214             break;
215         case DBG_IOCMD_UNHANDLED:
216             printf("[PISCSI] WARN: IO command %d (%s) is unhandled by driver.\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
217     }
218 }
219
220 extern struct emulator_config *cfg;
221 extern void stop_cpu_emulation(uint8_t disasm_cur);
222
223 void handle_piscsi_write(uint32_t addr, uint32_t val, uint8_t type) {
224     int32_t r;
225
226     struct piscsi_dev *d = &devs[piscsi_cur_drive];
227
228     switch (addr & 0xFFFF) {
229         case PISCSI_CMD_READ:
230             d = &devs[val];
231             if (d->fd == -1) {
232                 printf ("[PISCSI] BUG: Attempted read from unmapped drive %d.\n", piscsi_cur_drive);
233                 break;
234             }
235             printf("[PISCSI] %d byte READ from block %d to address %.8X\n", piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
236             d->lba = piscsi_u32[0];
237             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
238             if (r != -1 && cfg->map_type[r] == MAPTYPE_RAM) {
239                 printf("[PISCSI] \"DMA\" Read goes to mapped range %d.\n", r);
240                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
241                 read(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
242             }
243             else {
244                 printf("[PISCSI] No mapped range found for read.\n");
245                 uint8_t c = 0;
246                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
247                 for (int i = 0; i < piscsi_u32[1]; i++) {
248                     read(d->fd, &c, 1);
249 #ifndef FAKESTORM
250                     write8(piscsi_u32[2] + i, (uint32_t)c);
251 #endif
252                 }
253             }
254             break;
255         case PISCSI_CMD_WRITE:
256             d = &devs[val];
257             if (d->fd == -1) {
258                 printf ("[PISCSI] BUG: Attempted write to unmapped drive %d.\n", piscsi_cur_drive);
259                 break;
260             }
261             d->lba = piscsi_u32[0];
262             printf("[PISCSI] %d byte WRITE to block %d from address %.8X\n", piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
263             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
264             if (r != -1) {
265                 printf("[PISCSI] \"DMA\" Write comes from mapped range %d.\n", r);
266                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
267                 write(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
268             }
269             else {
270                 printf("[PISCSI] No mapped range found for write.\n");
271                 uint8_t c = 0;
272                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
273                 for (int i = 0; i < piscsi_u32[1]; i++) {
274 #ifndef FAKESTORM
275                     c = read8(piscsi_u32[2] + i);
276 #endif
277                     write(d->fd, &c, 1);
278                 }
279             }
280             break;
281         case PISCSI_CMD_ADDR1: case PISCSI_CMD_ADDR2: case PISCSI_CMD_ADDR3: case PISCSI_CMD_ADDR4: {
282             int i = ((addr & 0xFFFF) - PISCSI_CMD_ADDR1) / 4;
283             piscsi_u32[i] = val;
284             break;
285         }
286         case PISCSI_CMD_DRVNUM:
287             if (val != 0) {
288                 if (val < 10) // Kludge for GiggleDisk
289                     piscsi_cur_drive = val;
290                 else if (val >= 10 && val % 10 != 0)
291                     piscsi_cur_drive = 255;
292                 else
293                     piscsi_cur_drive = val / 10;
294             }
295             else
296                 piscsi_cur_drive = val;
297             printf("[PISCSI] (%s) Drive number set to %d (%d)\n", op_type_names[type], piscsi_cur_drive, val);
298             break;
299         case PISCSI_CMD_DEBUGME:
300             printf("[PISCSI] DebugMe triggered (%d).\n", val);
301             stop_cpu_emulation(1);
302             break;
303         case PISCSI_CMD_DRIVER: {
304             printf("[PISCSI] Driver copy/patch called, destination address %.8X.\n", val);
305             int r = get_mapped_item_by_address(cfg, val);
306             if (r != -1) {
307                 uint32_t addr = val - cfg->map_offset[r];
308                 uint32_t rt_offs = 0;
309                 uint8_t *dst_data = cfg->map_data[r];
310                 memcpy(dst_data + addr, piscsi_rom_ptr + 0x400, 0x3C00);
311                 
312                 uint32_t base_offs = be32toh(*((uint32_t *)&dst_data[addr + 0x170])) + 2;
313                 rt_offs = val + 0x16E;
314                 printf ("Offset 1: %.8X -> %.8X\n", base_offs, rt_offs);
315                 *((uint32_t *)&dst_data[addr + 0x170]) = htobe32(rt_offs);
316
317                 uint32_t offs = be32toh(*((uint32_t *)&dst_data[addr + 0x174]));
318                 printf ("Offset 2: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
319                 *((uint32_t *)&dst_data[addr + 0x174]) = htobe32((offs - base_offs) + rt_offs);
320
321                 dst_data[addr + 0x178] |= 0x07;
322
323                 offs = be32toh(*((uint32_t *)&dst_data[addr + 0x17C]));
324                 printf ("Offset 3: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
325                 *((uint32_t *)&dst_data[addr + 0x17C]) = htobe32((offs - base_offs) + rt_offs);
326
327                 offs = be32toh(*((uint32_t *)&dst_data[addr + 0x180]));
328                 printf ("Offset 4: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
329                 *((uint32_t *)&dst_data[addr + 0x180]) = htobe32((offs - base_offs) + rt_offs);
330
331                 offs = be32toh(*((uint32_t *)&dst_data[addr + 0x184]));
332                 printf ("Offset 5: %.8X -> %.8X\n", offs, (offs - base_offs) + rt_offs);
333                 *((uint32_t *)&dst_data[addr + 0x184]) = htobe32((offs - base_offs) + rt_offs);
334
335             }
336             else {
337                 for (int i = 0; i < 0x3C00; i++) {
338                     uint8_t src = piscsi_rom_ptr[0x400 + i];
339                     write8(addr + i, src);
340                 }
341             }
342             break;
343         }
344         case PISCSI_DBG_VAL1: case PISCSI_DBG_VAL2: case PISCSI_DBG_VAL3: case PISCSI_DBG_VAL4:
345         case PISCSI_DBG_VAL5: case PISCSI_DBG_VAL6: case PISCSI_DBG_VAL7: case PISCSI_DBG_VAL8: {
346             int i = ((addr & 0xFFFF) - PISCSI_DBG_VAL1) / 4;
347             piscsi_dbg[i] = val;
348             break;
349         }
350         case PISCSI_DBG_MSG:
351             print_piscsi_debug_message(val);
352             break;
353         default:
354             printf("[PISCSI] WARN: Unhandled %s register write to %.8X: %d\n", op_type_names[type], addr, val);
355             break;
356     }
357 }
358
359 #define PIB 0x00
360
361 uint32_t handle_piscsi_read(uint32_t addr, uint8_t type) {
362     if (type) {}
363
364     if ((addr & 0xFFFF) >= PISCSI_CMD_ROM) {
365         uint32_t romoffs = (addr & 0xFFFF) - PISCSI_CMD_ROM;
366         if (romoffs < (piscsi_rom_size + PIB)) {
367             printf("[PISCSI] %s read from Boot ROM @$%.4X (%.8X): ", op_type_names[type], romoffs, addr);
368             uint32_t v = 0;
369             switch (type) {
370                 case OP_TYPE_BYTE:
371                     v = piscsi_rom_ptr[romoffs - PIB];
372                     printf("%.2X\n", v);
373                     break;
374                 case OP_TYPE_WORD:
375                     v = be16toh(*((uint16_t *)&piscsi_rom_ptr[romoffs - PIB]));
376                     printf("%.4X\n", v);
377                     break;
378                 case OP_TYPE_LONGWORD:
379                     v = be32toh(*((uint32_t *)&piscsi_rom_ptr[romoffs - PIB]));
380                     printf("%.8X\n", v);
381                     break;
382             }
383             return v;
384         }
385         return 0;
386     }
387     
388     switch (addr & 0xFFFF) {
389         case PISCSI_CMD_DRVTYPE:
390             if (devs[piscsi_cur_drive].fd == -1) {
391                 printf("[PISCSI] %s Read from DRVTYPE %d, drive not attached.\n", op_type_names[type], piscsi_cur_drive);
392                 return 0;
393             }
394             printf("[PISCSI] %s Read from DRVTYPE %d, drive attached.\n", op_type_names[type], piscsi_cur_drive);
395             return 1;
396             break;
397         case PISCSI_CMD_DRVNUM:
398             return piscsi_cur_drive;
399             break;
400         case PISCSI_CMD_CYLS:
401             printf("[PISCSI] %s Read from CYLS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].c);
402             return devs[piscsi_cur_drive].c;
403             break;
404         case PISCSI_CMD_HEADS:
405             printf("[PISCSI] %s Read from HEADS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].h);
406             return devs[piscsi_cur_drive].h;
407             break;
408         case PISCSI_CMD_SECS:
409             printf("[PISCSI] %s Read from SECS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].s);
410             return devs[piscsi_cur_drive].s;
411             break;
412         case PISCSI_CMD_BLOCKS: {
413             uint32_t blox = devs[piscsi_cur_drive].fs / 512;
414             printf("[PISCSI] %s Read from BLOCKS %d: %d\n", op_type_names[type], piscsi_cur_drive, (uint32_t)(devs[piscsi_cur_drive].fs / 512));
415             printf("fs: %lld (%d)\n", devs[piscsi_cur_drive].fs, blox);
416             return blox;
417             break;
418         }
419         default:
420             printf("[PISCSI] Unhandled %s register read from %.8X\n", op_type_names[type], addr);
421             break;
422     }
423
424     return 0;
425 }