1 /*
2 * cmdhd.c - Whole CMDHD emulation
3 *
4 * Written by
5 * Roberto Muscedere (rmusced@uwindsor.ca)
6 *
7 * Based on old code by
8 * Kajtar Zsolt <soci@c64.rulez.org>
9 * Andreas Boose <viceteam@t-online.de>
10 * Andre Fachat <fachat@physik.tu-chemnitz.de>
11 * Daniel Sladic <sladic@eecg.toronto.edu>
12 * Ettore Perazzoli <ettore@comm2000.it>
13 *
14 * This file is part of VICE, the Versatile Commodore Emulator.
15 * See README for copyright notice.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 * 02111-1307 USA.
31 *
32 */
33
34 #include "vice.h"
35
36 #include <stdio.h>
37 #include <stdint.h>
38
39 #include "diskimage.h"
40 #include "debug.h"
41 #include "drive.h"
42 #include "drivesync.h"
43 #include "drivetypes.h"
44 #include "iecbus.h"
45 #include "iecdrive.h"
46 #include "interrupt.h"
47 #include "lib.h"
48 #include "types.h"
49 #include "cmdhd.h"
50 #include "util.h"
51 #include "diskimage/fsimage.h"
52 #include "rtc/rtc-72421.h"
53
54 #define LOG LOG_DEFAULT
55 #define ERR LOG_ERR
56
57 /* #define CMDLOG */
58 /* #define CMDIO */
59 /* #define CMDBUS */
60
61 #ifdef CMDLOG
62 #define CLOG(_x_) log_message _x_
63 #else
64 #define CLOG(_x_)
65 #endif
66
67 #ifdef CMDIO
68 #define IDBG(_x_) log_message _x_
69 #else
70 #define IDBG(_x_)
71 #endif
72
73 #ifdef CMDBUS
74 #define BLOG(_x_) log_message _x_
75 #else
76 #define BLOG(_x_)
77 #endif
78
79 #define CRIT(_x_) log_message _x_
80
81 #define iecbus (viap->v_iecbus)
82
83 cmdbus_t cmdbus;
84
85 typedef struct drivevia_context_s {
86 unsigned int number;
87 struct drive_s *drive;
88 struct iecbus_s *v_iecbus;
89 } drivevia_context_t;
90
91 /* Although SCSI can be a multi-master bus, CMD HD's assume they are the
92 masters so we won't implement all the possible varitions, just a "target"
93 device that will respond to all (0-6) IDs and 0-7 LUNs for each */
94 /* Latest boot rom (2.8) and even earlier have a bug when deleting partitions
95 across multiple drives */
96 /* Although we can support up to 55 (tested), deleting partitions corrupts
97 the data so we will not allow this, at least for now */
98 /* SCSI states are setup to reflect the register values coming out of U13 to
99 simplify the interface */
100 /* All signals asserted high here, opposite in physical implementation
101 (open-collector/drain etc)
102
103 SEL BSY IO MSG CD U9-PB2-0 PHASE
104 0 0 X X X X BUSFREE
105 0 1 X X X X ARBITRATION
106 1 0 X X X X SELECTION (phase 1)
107 1 1 X X X X SELECTION (phase 2)
108 0 1 0 0 0 0 DATA-OUT
109 0 1 0 0 1 1 COMMAND
110 0 1 1 0 0 4 DATA-IN
111 0 1 1 0 1 5 STATUS
112 0 1 0 1 1 3 MESSAGE-OUT
113 0 1 1 1 1 7 MESSAGE-IN
114
115 */
116
117 #define CMD_STATE_DATAOUT 0x00
118 #define CMD_STATE_COMMAND 0x01
119 #define CMD_STATE_DATAIN 0x04
120 #define CMD_STATE_STATUS 0x05
121 #define CMD_STATE_MESSAGEOUT 0x03
122 #define CMD_STATE_MESSAGEIN 0x07
123
124 # undef DEBUG_IEC_DRV_WRITE
125 # undef DEBUG_IEC_DRV_READ
126
127 #ifdef DEBUG
128
129 # define DEBUG_IEC_DRV_WRITE(_data) my_debug_iec_drv_write(_data)
130 # define DEBUG_IEC_DRV_READ(_data) my_debug_iec_drv_read(_data)
131
132 #else
133
134 # define DEBUG_IEC_DRV_WRITE(_data)
135 # define DEBUG_IEC_DRV_READ(_data)
136
137 #endif
138
139 #ifdef DEBUG
140
141 #include "log.h"
142
my_debug_iec_drv_write(unsigned int data)143 void my_debug_iec_drv_write(unsigned int data)
144 {
145 if (debug.iec) {
146 uint8_t value = data;
147 static uint8_t oldvalue = 0;
148
149 if (value != oldvalue) {
150 oldvalue = value;
151
152 log_debug("$1800 store: %s %s %s",
153 value & 0x02 ? "DATA OUT" : " ",
154 value & 0x08 ? "CLK OUT" : " ",
155 value & 0x10 ? "ATNA " : " "
156 );
157 }
158 }
159 }
160
my_debug_iec_drv_read(unsigned int data)161 void my_debug_iec_drv_read(unsigned int data)
162 {
163 if (debug.iec) {
164 uint8_t value = data;
165 static uint8_t oldvalue = { 0 };
166 const char * data_correct = "";
167
168 if (value != oldvalue) {
169 unsigned int atn = value & 0x80 ? 1 : 0;
170 unsigned int atna = value & 0x10 ? 1 : 0;
171 unsigned int ddata = value & 0x01 ? 1 : 0;
172
173 oldvalue = value;
174
175 if (atn && atna) {
176 if (!ddata) {
177 data_correct = " ***** ERROR: ATN, ATNA & DATA! *****";
178 }
179 }
180
181 log_debug("$1800 read: %s %s %s %s %s %s%s",
182 value & 0x02 ? "DATA OUT" : " ",
183 value & 0x08 ? "CLK OUT" : " ",
184 value & 0x10 ? "ATNA " : " ",
185
186 value & 0x01 ? "DATA IN" : " ",
187 value & 0x04 ? "CLK IN" : " ",
188 value & 0x80 ? "ATN" : " ",
189 data_correct
190 );
191 }
192 }
193 }
194 #endif
195
196 /* copy some functions here so we don't make them external */
drive_read_rom(diskunit_context_t * drv,uint16_t address)197 static uint8_t drive_read_rom(diskunit_context_t *drv, uint16_t address)
198 {
199 return drv->rom[address & 0x7fff];
200 }
201
drive_read_ram(diskunit_context_t * drv,uint16_t address)202 static uint8_t drive_read_ram(diskunit_context_t *drv, uint16_t address)
203 {
204 return drv->drive_ram[address];
205 }
206
drive_store_ram(diskunit_context_t * drv,uint16_t address,uint8_t value)207 static void drive_store_ram(diskunit_context_t *drv, uint16_t address, uint8_t value)
208 {
209 drv->drive_ram[address] = value;
210 }
211
reset_alarm_handler(CLOCK offset,void * data)212 static void reset_alarm_handler(CLOCK offset, void *data)
213 {
214 cmdhd_context_t *hd = (cmdhd_context_t *)data;
215
216 CLOG((LOG, "CMDHD: alarm triggered at %u; releasing buttons",
217 *(hd->mycontext->clk_ptr)));
218 /* stop pressing WP, SWAP8, and SWAP9 buttons */
219 hd->i8255a_i[1] |= (0x08 | 0x04 | 0x02);
220 /* update in drive context too */
221 hd->mycontext->button = 0;
222
223 alarm_unset(hd->reset_alarm);
224 }
225
226 /* returns 0 if block has CMCHD signature at end */
cmdhd_has_sig(unsigned char * buf)227 static int cmdhd_has_sig(unsigned char *buf)
228 {
229 unsigned char hdmagic[16]={0x43, 0x4d, 0x44, 0x20, 0x48, 0x44, 0x20, 0x20,
230 0x8d, 0x03, 0x88, 0x8e, 0x02, 0x88, 0xea, 0x60};
231 return memcmp(&(buf[0xf0]), hdmagic, 16);
232 }
233
cmdhd_scsiread(struct scsi_context_s * scsi)234 static void cmdhd_scsiread(struct scsi_context_s *scsi)
235 {
236 cmdhd_context_t *hd = (cmdhd_context_t*)(scsi->p);
237 drive_t *dc = (drive_t *)(hd->mycontext->drives[0]);
238 int unit = hd->mycontext->mynumber + 8;
239 int track;
240
241 /* update track info on status bar; never 100 or above */
242 track = (scsi->address * 200) / ((hd->imagesize >> 9) + 1);
243 if (track >= 200) {
244 track = 199;
245 }
246 dc->current_half_track = track;
247
248 /* correct device number on the fly since it is stored on HD not by switch or EEPROM */
249 if (hd->baselba != UINT32_MAX && scsi->address == hd->baselba + 2) {
250 /* make sure it has the cmd signature first */
251 if (!cmdhd_has_sig(&(scsi->data_buf[256]))) {
252 /* if it isn't what was defined by vice, set it to it */
253 if ( (scsi->data_buf[0x1e1] != unit) ||
254 (scsi->data_buf[0x1e4] != unit) ) {
255 /* tell the user it is happening */
256 CLOG((LOG, "CMDHD: drive number is now %d; was %d in config block",
257 unit, (int)scsi->data_buf[0x1e1]));
258 scsi->data_buf[0x1e1] = unit;
259 scsi->data_buf[0x1e4] = unit;
260 }
261 } else {
262 /* block we had on record no long has signature, invalidate it */
263 hd->baselba = UINT32_MAX;
264 }
265 }
266 }
267
cmdhd_scsiwrite(struct scsi_context_s * scsi)268 static void cmdhd_scsiwrite(struct scsi_context_s *scsi)
269 {
270 cmdhd_context_t *hd = (cmdhd_context_t*)(scsi->p);
271 drive_t *dc = (drive_t *)(hd->mycontext->drives[0]);
272 uint32_t temp;
273
274 /* keep track of the maximum lba written to */
275 temp=(scsi->address + 1) << 9;
276 if (temp > hd->imagesize) {
277 hd->imagesize = temp;
278 }
279
280 /* update track info on status bar */
281 dc->current_half_track = (scsi->address * 200) / ((hd->imagesize >> 9) + 1);
282 }
283
284 /* We don't actually format the disk, we just remove the 16 byte CMD signature */
cmdhd_scsiformat(struct scsi_context_s * scsi)285 static void cmdhd_scsiformat(struct scsi_context_s *scsi)
286 {
287 cmdhd_context_t *hd = (cmdhd_context_t*)(scsi->p);
288 int i;
289
290 /* figure out where to start looking */
291 if (hd->baselba != UINT32_MAX) {
292 /* use what we already have if we found it before */
293 if (hd->baselba < (hd->imagesize >> 9)) {
294 scsi->address = hd->baselba + 2;
295 } else {
296 /* other wise, start from scratch */
297 hd->baselba = UINT32_MAX;
298 scsi->address = 2;
299 }
300 } else {
301 scsi->address = 2;
302 }
303 /* start searching, ever 128 LBAs starting from 2 or known base */
304 while (scsi->address < (hd->imagesize >> 9)) {
305 /* stop if we hit the end of the file */
306 if (scsi_image_read(scsi) < 0) {
307 break;
308 }
309 /* check for the CMD sig */
310 if (!cmdhd_has_sig(&(scsi->data_buf[256]))) {
311 hd->baselba = scsi->address - 2;
312 /* we found it, zero it out */
313 for (i = 0; i < 16; i++) {
314 scsi->data_buf[0x1f0 + i] = 0;
315 }
316 /* write it back */
317 scsi_image_write(scsi);
318 break;
319 }
320 /* otherwise, keep looking */
321 scsi->address += 128;
322 }
323 }
324
325 /* Set all the inputs high, like the pull-up resistors do */
cmdbus_init(void)326 void cmdbus_init(void)
327 {
328 int i;
329
330 cmdbus.cpu_data = 0xff;
331 cmdbus.cpu_bus = 0xff;
332 cmdbus.data = 0xff;
333 cmdbus.bus = 0xff;
334 for (i = 0; i < NUM_DISK_UNITS; i++) {
335 cmdbus.drv_data[i] = 0xff;
336 cmdbus.drv_bus[i] = 0xff;
337 }
338 }
339
340 /* Calculate the data/bus values */
cmdbus_update(void)341 void cmdbus_update(void)
342 {
343 int i;
344
345 /* only allow devices to impact the bus if bit 0 is set on bus part */
346 if (cmdbus.cpu_bus & 1) {
347 cmdbus.bus = cmdbus.cpu_bus;
348 cmdbus.data = cmdbus.cpu_data;
349 } else {
350 cmdbus.bus = 0xff;
351 cmdbus.data = 0xff;
352 }
353 for (i = 0; i < NUM_DISK_UNITS; i++) {
354 /* only allow devices to impact the bus if bit 0 is set on bus part */
355 if (cmdbus.drv_bus[i] & 1) {
356 cmdbus.bus &= cmdbus.drv_bus[i];
357 cmdbus.data &= cmdbus.drv_data[i];
358 }
359 }
360
361 BLOG(("CMDBUS PREADY=%s PCLK=%s PATN=%s",cmdbus.bus&0x80?"LOW ":"HIGH",
362 cmdbus.bus&0x40?"LOW ":"HIGH", cmdbus.bus&0x20?"LOW ":"HIGH"));
363 }
364
365 /* U11 or i8255a interfacing */
366 /* Port A is for CMD Parallel bus, input/output, data only */
set_pa(struct _i8255a_state * ctx,uint8_t byte,int8_t reg)367 static void set_pa(struct _i8255a_state *ctx, uint8_t byte, int8_t reg)
368 {
369 cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p);
370
371 cmdbus.drv_data[hd->mycontext->mynumber] = byte;
372 cmdbus_update();
373 }
374
get_pa(struct _i8255a_state * ctx,int8_t reg)375 static uint8_t get_pa(struct _i8255a_state *ctx, int8_t reg)
376 {
377 uint8_t data = 0xff;
378
379 if (reg == 0) {
380 /* if reg is 0, it is an actual read from the register */
381 data = cmdbus.data;
382 } else {
383 /* otherwise it is a bus change; physically it is pulled up */
384 data = 0xff;
385 }
386
387 return data;
388 }
389
390 /* Port B is for CMD Parallel bus the buttons (input only):
391 PB7 is PATN
392 PB6 is PCLK
393 PB5 is not referenced
394 PB4 is not referenced
395 PB3 is WP (active low)
396 PB2 is SWAP9 (active low)
397 PB1 is SWAP8 (active low)
398 PB0 is PREADY
399 */
set_pb(struct _i8255a_state * ctx,uint8_t byte,int8_t reg)400 static void set_pb(struct _i8255a_state *ctx, uint8_t byte, int8_t reg)
401 {
402 cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p);
403
404 hd->i8255a_o[1] = byte;
405 }
406
get_pb(struct _i8255a_state * ctx,int8_t reg)407 static uint8_t get_pb(struct _i8255a_state *ctx, int8_t reg)
408 {
409 cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p);
410 uint8_t data = 0xff;
411
412 data = ((~cmdbus.bus << 2) & 0x80) | /* PATN */
413 (~cmdbus.bus & 0x40) | /* PCLK */
414 ((~cmdbus.bus >> 7) & 0x01) | /* PREADY */
415 (hd->i8255a_i[1] & 0x3e); /* Everything else */
416
417 return data;
418 }
419
420 /* Called to deal with how PATN changes PREADY */
421 /* "new" and "old", 0 or 1, are PATN, not /PATN */
422 /* CMDHD's have a circuit which drives /PREADY */
423 /* It has a FF where PC7 controls /CLR and PATN is the CLK */
424 /* The output is NANDed with PATN which drives /PREADY */
425 /* /PREADY is also connected to a buffer (OC) driven by PC7 */
cmdhd_patn_changed(unsigned int unit,int new,int old)426 static int cmdhd_patn_changed(unsigned int unit, int new, int old)
427 {
428 cmdhd_context_t *hd;
429 int t;
430
431 /* standard unit range check */
432 if (unit < 8 || unit > 8 + NUM_DISK_UNITS) {
433 return -1;
434 }
435
436 /* check context */
437 if (!diskunit_context[unit - 8]) {
438 return -1;
439 }
440
441 if (diskunit_context[unit - 8]->type != DRIVE_TYPE_CMDHD) {
442 return -1;
443 }
444
445 /* get context */
446 hd = diskunit_context[unit - 8]->cmdhd;
447
448 /* leave if no HD contxt provided */
449 if (!hd) {
450 return -1;
451 }
452
453 /* The drive type is a CMDHD by this point */
454
455 if ((hd->i8255a_o[2] & 0x80) == 0) {
456 /* when PC7 is 0, PREADYFF becomes 0 */
457 hd->preadyff = 0;
458 } else if (old == 0 && new == 1) {
459 /* on rising edge of PATN, PREADYFF = 1 */
460 hd->preadyff = 1;
461 }
462 /* /PREADY = !(NEWATN & PREADYFF) */
463 t = !(new & hd->preadyff);
464 /* The OC buffer */
465 if ((hd->i8255a_o[2] & 0x80) == 0) {
466 t = 0;
467 }
468
469 cmdbus.drv_bus[unit - 8] = (cmdbus.drv_bus[unit - 8] & 0x7f) | (t << 7);
470
471 return 0;
472 }
473
474 /* Update ALL TDE units when PATN changed */
475 /* called from ramlink */
cmdbus_patn_changed(int new,int old)476 void cmdbus_patn_changed(int new, int old)
477 {
478 int unit;
479
480 for (unit = 8; unit < 8 + NUM_DISK_UNITS; unit++ ) {
481 cmdhd_patn_changed(unit, new, old);
482 }
483 }
484
485 /* Port C is for CMD Parallel bus, SCSI, and memory control (output only):
486 PC7 is for used for driving PREADY
487 PC6 is /PCLK
488 PC5 is /PEXT
489 PC4 is SCSI BSY
490 PC3 is SCSI RST
491 PC2 is SCSI ATN
492 PC1 is RAM mapping
493 PC0 is ROM control
494 */
set_pc(struct _i8255a_state * ctx,uint8_t byte,int8_t reg)495 static void set_pc(struct _i8255a_state *ctx, uint8_t byte, int8_t reg)
496 {
497 cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p);
498 scsi_context_t *scsi = (scsi_context_t*)(hd->scsi);
499 /* drivecpu_context_t *cpu = hd->mycontext->cpu; */
500 int t;
501 int mynumber = hd->mycontext->mynumber;
502
503 hd->i8255a_o[2] = byte;
504 scsi->atn = ((hd->i8255a_o[2] & 4)!=0);
505 scsi->rst = ((hd->i8255a_o[2] & 8)!=0);
506 scsi->bsyi = ((hd->i8255a_o[2] & 16)!=0);
507 scsi_process_noack(scsi);
508
509 /* get the PATN state (from /PATN) */
510 t = (cmdbus.bus) & 0x20 ? 0 : 1;
511
512 /* adjust /PREADY */
513 cmdhd_patn_changed(mynumber + 8, t, t);
514
515 /* update bus */
516 cmdbus.drv_bus[mynumber] =
517 (cmdbus.drv_bus[mynumber] & 0xa0) | /* old /PREADY and /PATN */
518 (hd->i8255a_o[2] & 0x40) | /* /PCLK */
519 ((hd->i8255a_o[2] & 0x20)>>1) | /* /PEXT */
520 0x0f; /* everything else */
521 cmdbus_update();
522 }
523
get_pc(struct _i8255a_state * ctx,int8_t reg)524 static uint8_t get_pc(struct _i8255a_state *ctx, int8_t reg)
525 {
526 cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p);
527 uint8_t data = 0xff;
528
529 data = hd->i8255a_i[2];
530
531 return data;
532 }
533
updateleds(diskunit_context_t * ctxptr)534 static void updateleds(diskunit_context_t *ctxptr)
535 {
536 ctxptr->drives[0]->led_status = (ctxptr->cmdhd->LEDs & 0x02) ? 1 : 0;
537 ctxptr->drives[0]->led_status |= (ctxptr->cmdhd->LEDs & 0x01) ? 2 : 0;
538 }
539
cmdhd_store(diskunit_context_t * ctxptr,uint16_t addr,uint8_t data)540 void cmdhd_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data)
541 {
542 #ifdef CMDIO
543 static uint8_t oldd;
544 static uint16_t olda;
545 static CLOCK oldc = 0;
546 drivecpu_context_t *cpu = ctxptr->cpu;
547 #define storedebug() \
548 if (olda != addr || olds != data) { \
549 IDBG((LOG, "CMDHD: IO write %02x to %04x PC=%04x CYCLE=%u", data, addr, \
550 cpu->cpu_R65C02_regs.pc, *(ctxptr->clk_ptr)-oldc); \
551 old=data; \
552 olda=addr; \
553 oldc=*(ctxptr->clk_ptr); \
554 }
555 #else
556 #define storedebug()
557 #endif
558 /* Decode bits 15-12 */
559 switch ( (addr >> 12) & 15 ) {
560 case 0x4:
561 case 0x5:
562 case 0x6:
563 case 0x7:
564 /* Since the ROM wants to read/write from the RAM from 0xC000-0xFFFF,
565 when 0x8802.1 = 0, RAM from 0xC000-0xFFFF maps to 0x4000-0x7FFF */
566 if (ctxptr->cmdhd->i8255a_o[2]&2) {
567 drive_store_ram(ctxptr, (addr & 0x3fff) | 0x4000, data );
568 } else {
569 drive_store_ram(ctxptr, (addr & 0x3fff) | 0xC000, data );
570 }
571 break;
572 case 0x8:
573 /* Decode bits 11-8 */
574 /* Since the kernel is loaded into RAM from the HD on startup, if
575 0x8F00.5=0 then the memory (not IO) above 0x8000 is protected from
576 being written to */
577 switch ((addr >> 8) & 15) {
578 case 0x0: /* 0x80xx U10 */
579 case 0x1: /* 0x81xx U10 */
580 storedebug()
581 viacore_store(ctxptr->cmdhd->via10, addr & 15, data);
582 break;
583 case 0x4: /* 0x84xx U9 */
584 case 0x5: /* 0x85xx U9 */
585 storedebug()
586 viacore_store(ctxptr->cmdhd->via9, addr & 15, data);
587 break;
588 case 0x8: /* 0x88xx U11 */
589 case 0x9: /* 0x89xx U11 */
590 storedebug()
591 i8255a_store(ctxptr->cmdhd->i8255a, addr & 3, data);
592 break;
593 case 0xc: /* 0x8cxx */
594 case 0xd: /* 0x8dxx */
595 storedebug()
596 rtc72421_write(ctxptr->cmdhd->rtc, addr & 15, data);
597 break;
598 case 0xf: /* 0x8fxx U20 */
599 /* Although page 0x8F is RAM, all writes go to U20 */
600 /* OS often reads from 0x8f00 to get past values to OR/AND them */
601 storedebug()
602 ctxptr->cmdhd->LEDs = data;
603 drive_store_ram(ctxptr, (addr & 255) | 0x8f00, data);
604 updateleds(ctxptr);
605 break;
606 case 0xe: /* 0x8exx unprotected RAM */
607 drive_store_ram(ctxptr, (addr & 255) | 0x8e00, data);
608 break;
609 default:
610 /* Everything else writes to RAM if switch is on */
611 if (ctxptr->cmdhd->LEDs&32) {
612 drive_store_ram(ctxptr, addr, data);
613 }
614 break;
615 }
616 break;
617 case 0x9:
618 case 0xa:
619 case 0xb:
620 case 0xc:
621 case 0xd:
622 case 0xe:
623 case 0xf:
624 if (ctxptr->cmdhd->LEDs&32) {
625 drive_store_ram(ctxptr, addr, data);
626 }
627 break;
628 }
629 return;
630 }
631
cmdhd_read(diskunit_context_t * ctxptr,uint16_t addr)632 uint8_t cmdhd_read(diskunit_context_t *ctxptr, uint16_t addr)
633 {
634 #ifdef CMDIO
635 static CLOCK oldc = 0;
636 drivecpu_context_t *cpu = ctxptr->cpu;
637 #define readdebug() \
638 IDBG((LOG, "CMDHD: IO read %02x from %04x PC=%04x CYCLE=%u", data, addr, \
639 cpu->cpu_R65C02_regs.pc, *(ctxptr->clk_ptr)-oldc); \
640 oldc=*(ctxptr->clk_ptr);
641 #else
642 #define readdebug()
643 #endif
644 uint8_t data;
645
646 /* Decode bits 15-12 */
647 switch ( (addr >> 12) & 15 ) {
648 case 0x4:
649 case 0x5:
650 case 0x6:
651 case 0x7:
652 /* Since the ROM wants to read/write from the RAM from 0xC000-0xFFFF,
653 when 0x8802.1 = 0, RAM from 0xC000-0xFFFF maps to 0x4000-0x7FFF */
654 if (ctxptr->cmdhd->i8255a_o[2]&2) {
655 return drive_read_ram(ctxptr, (addr & 0x3fff) | 0x4000 );
656 } else {
657 return drive_read_ram(ctxptr, (addr & 0x3fff) | 0xC000 );
658 }
659 break;
660 case 0x8:
661 /* Decode bits 11-8 */
662 switch ((addr >> 8) & 15) {
663 case 0x0: /* 0x80xx U10 */
664 case 0x1: /* 0x81xx U10 */
665 data = viacore_read(ctxptr->cmdhd->via10, addr & 15);
666 readdebug()
667 return data;
668 break;
669 case 0x4: /* 0x84xx U9 */
670 case 0x5: /* 0x85xx U9 */
671 data = viacore_read(ctxptr->cmdhd->via9, addr & 15);
672 readdebug()
673 return data;
674 break;
675 case 0x8: /* 0x88xx U11 */
676 case 0x9: /* 0x89xx U11 */
677 data = i8255a_read(ctxptr->cmdhd->i8255a, addr & 3);
678 readdebug()
679 return data;
680 break;
681 case 0xc: /* 0x8cxx */
682 case 0xd: /* 0x8dxx */
683 data = rtc72421_read(ctxptr->cmdhd->rtc, addr & 15);
684 readdebug()
685 return data;
686 break;
687 default:
688 return drive_read_ram(ctxptr, addr);
689 break;
690 }
691 break;
692 case 0x9:
693 case 0xa:
694 case 0xb:
695 return drive_read_ram(ctxptr, addr);
696 break;
697 case 0xc:
698 case 0xd:
699 case 0xe:
700 case 0xf:
701 /* ROM is enabled when 0x8802.0 is 1, else RAM */
702 if (ctxptr->cmdhd->i8255a_o[2]&1) {
703 return drive_read_rom(ctxptr, addr & 0x3fff );
704 } else {
705 return drive_read_ram(ctxptr, addr);
706 }
707 break;
708 }
709 return 0;
710 }
711
cmdhd_peek(diskunit_context_t * ctxptr,uint16_t addr)712 uint8_t cmdhd_peek(diskunit_context_t *ctxptr, uint16_t addr)
713 {
714 return 0;
715 }
716
cmdhd_dump(diskunit_context_t * ctxptr,uint16_t addr)717 int cmdhd_dump(diskunit_context_t *ctxptr, uint16_t addr)
718 {
719 return 0;
720 }
721
set_ca2(via_context_t * via_context,int state)722 static void set_ca2(via_context_t *via_context, int state)
723 {
724 }
725
set_cb2(via_context_t * via_context,int state)726 static void set_cb2(via_context_t *via_context, int state)
727 {
728 }
729
set_int(via_context_t * via_context,unsigned int int_num,int value,CLOCK rclk)730 static void set_int(via_context_t *via_context, unsigned int int_num,
731 int value, CLOCK rclk)
732 {
733 cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context;
734 diskunit_context_t *dc = (diskunit_context_t *)(hd->mycontext);
735
736 interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk);
737 }
738
restore_int(via_context_t * via_context,unsigned int int_num,int value)739 static void restore_int(via_context_t *via_context, unsigned int int_num,
740 int value)
741 {
742 cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context;
743 diskunit_context_t *dc = (diskunit_context_t *)(hd->mycontext);
744
745 interrupt_restore_irq(dc->cpu->int_status, int_num, value);
746 }
747
undump_pra(via_context_t * via_context,uint8_t byte)748 static void undump_pra(via_context_t *via_context, uint8_t byte)
749 {
750 }
751
undump_prb10(via_context_t * via_context,uint8_t byte)752 static void undump_prb10(via_context_t *via_context, uint8_t byte)
753 {
754 drivevia_context_t *viap = (drivevia_context_t *)(via_context->prv);
755
756 if (iecbus != NULL) {
757 uint8_t *drive_bus, *drive_data;
758 unsigned int unit;
759
760 drive_bus = &(iecbus->drv_bus[viap->number + 8]);
761 drive_data = &(iecbus->drv_data[viap->number + 8]);
762
763 *drive_data = ~byte;
764 *drive_bus = ((((*drive_data) << 3) & 0x40)
765 | (((*drive_data) << 6)
766 & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80));
767
768 iecbus->cpu_port = iecbus->cpu_bus;
769 for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) {
770 iecbus->cpu_port &= iecbus->drv_bus[unit];
771 }
772
773 iecbus->drv_port = (((iecbus->cpu_port >> 4) & 0x4)
774 | (iecbus->cpu_port >> 7)
775 | ((iecbus->cpu_bus << 3) & 0x80));
776 } else {
777 iec_drive_write((uint8_t)(~byte), viap->number);
778 }
779 }
780
store_pra9(via_context_t * via_context,uint8_t byte,uint8_t oldpa,uint16_t addr)781 static void store_pra9(via_context_t *via_context, uint8_t byte, uint8_t oldpa,
782 uint16_t addr)
783 {
784 cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context;
785 scsi_context_t *scsi = (scsi_context_t*)(hd->scsi);
786 scsi_set_bus(scsi, byte);
787
788 if (scsi->state!=SCSI_STATE_BUSFREE && ((addr & 0xf) == VIA_PRA) ) {
789 scsi_process_ack(scsi);
790 } else {
791 scsi_process_noack(scsi);
792 }
793 }
794
read_pra9(via_context_t * via_context,uint16_t addr)795 static uint8_t read_pra9(via_context_t *via_context, uint16_t addr)
796 {
797 cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context;
798 scsi_context_t *scsi = (scsi_context_t*)(hd->scsi);
799 uint8_t byte;
800
801 byte = scsi_get_bus(scsi);
802 if (scsi->state!=SCSI_STATE_BUSFREE && ((addr & 0xf) == VIA_PRA) ) {
803 scsi_process_ack(scsi);
804 } else {
805 scsi_process_noack(scsi);
806 }
807 return byte;
808 }
809
store_prb9(via_context_t * via_context,uint8_t byte,uint8_t p_oldpb,uint16_t addr)810 static void store_prb9(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb,
811 uint16_t addr)
812 {
813 cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context;
814 scsi_context_t *scsi = (scsi_context_t*)(hd->scsi);
815
816 scsi->sel = (byte & 0x10) ? 1 : 0;
817 hd->scsi_dir = (byte & 0x08) ? 1 : 0;
818 scsi_process_noack(scsi);
819 IDBG((LOG, "CMDHD: sprb9: SEL=%d BSY=%d DATA=%02x RST=%d",
820 scsi->sel, scsi->bsyo, byte, scsi->rst));
821 }
822
read_prb9(via_context_t * via_context)823 static uint8_t read_prb9(via_context_t *via_context)
824 {
825 cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context;
826 scsi_context_t *scsi = (scsi_context_t*)(hd->scsi);
827 uint8_t temp, state;
828
829 scsi_process_noack(scsi);
830 IDBG((LOG, "CMDHD: rprb9: SEL=%d BSY=%d REQ=%d", scsi->sel, scsi->bsyo, scsi->req));
831 if ( (via_context->via[VIA_PCR] & 0xf0) == 0xf0 ) {
832 temp=(scsi->sel) & (scsi->bsyo);
833 } else {
834 temp=(!scsi->sel) & (scsi->bsyo);
835 }
836
837 /* mask scsi state to cmd specific pld value */
838 switch (scsi->state)
839 {
840 case SCSI_STATE_DATAOUT:
841 state = CMD_STATE_DATAOUT;
842 break;
843 case SCSI_STATE_DATAIN:
844 state = CMD_STATE_DATAIN;
845 break;
846 case SCSI_STATE_COMMAND:
847 state = CMD_STATE_COMMAND;
848 break;
849 case SCSI_STATE_STATUS:
850 state = CMD_STATE_STATUS;
851 break;
852 case SCSI_STATE_MESSAGEOUT:
853 state = CMD_STATE_MESSAGEOUT;
854 break;
855 case SCSI_STATE_MESSAGEIN:
856 state = CMD_STATE_MESSAGEIN;
857 break;
858 default:
859 state = CMD_STATE_STATUS;
860 }
861
862 return (scsi->req << 7) | (scsi->ack << 6) | (temp << 5) | (scsi->sel << 4) |
863 (hd->scsi_dir << 3) | (state & 7);
864 }
865
read_prb10(via_context_t * via_context)866 static uint8_t read_prb10(via_context_t *via_context)
867 {
868 uint8_t byte;
869 drivevia_context_t *viap;
870
871 viap = (drivevia_context_t *)(via_context->prv);
872
873 if (iecbus != NULL) {
874 byte = (((via_context->via[VIA_PRB] & 0x1a)
875 | iecbus->drv_port) ^ 0x85);
876 } else {
877 byte = (((via_context->via[VIA_PRB] & 0x1a)
878 | iec_drive_read(viap->number)) ^ 0x85);
879 }
880
881 DEBUG_IEC_DRV_READ(byte);
882
883 DEBUG_IEC_BUS_READ(byte);
884
885 return byte;
886 }
887
store_prb10(via_context_t * via_context,uint8_t byte,uint8_t oldpb,uint16_t addr)888 static void store_prb10(via_context_t *via_context, uint8_t byte, uint8_t oldpb,
889 uint16_t addr)
890 {
891 drivevia_context_t *viap;
892
893 viap = (drivevia_context_t *)(via_context->prv);
894
895 if (byte != oldpb) {
896 DEBUG_IEC_DRV_WRITE(byte);
897
898 if (iecbus != NULL) {
899 uint8_t *drive_data, *drive_bus;
900 unsigned int unit;
901
902 drive_bus = &(iecbus->drv_bus[viap->number + 8]);
903 drive_data = &(iecbus->drv_data[viap->number + 8]);
904
905 *drive_data = ~byte;
906 *drive_bus = ((((*drive_data) << 3) & 0x40)
907 | (((*drive_data) << 6)
908 & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80));
909
910 iecbus->cpu_port = iecbus->cpu_bus;
911 for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) {
912 iecbus->cpu_port &= iecbus->drv_bus[unit];
913 }
914
915 iecbus->drv_port = (((iecbus->cpu_port >> 4) & 0x4)
916 | (iecbus->cpu_port >> 7)
917 | ((iecbus->cpu_bus << 3) & 0x80));
918
919 DEBUG_IEC_BUS_WRITE(iecbus->drv_port);
920 } else {
921 iec_drive_write((uint8_t)(~byte), viap->number);
922 DEBUG_IEC_BUS_WRITE(~byte);
923 }
924
925 iec_fast_drive_direction(byte & 0x20, viap->number);
926 }
927 }
928
undump_prb(via_context_t * via_context,uint8_t byte)929 static void undump_prb(via_context_t *via_context, uint8_t byte)
930 {
931 }
932
store_pra10(via_context_t * via_context,uint8_t byte,uint8_t p_oldpb,uint16_t addr)933 static void store_pra10(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb,
934 uint16_t addr)
935 {
936 }
937
undump_pcr(via_context_t * via_context,uint8_t byte)938 static void undump_pcr(via_context_t *via_context, uint8_t byte)
939 {
940 }
941
store_pcr(via_context_t * via_context,uint8_t byte,uint16_t addr)942 static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr)
943 {
944 return byte;
945 }
946
undump_acr(via_context_t * via_context,uint8_t byte)947 static void undump_acr(via_context_t *via_context, uint8_t byte)
948 {
949 }
950
store_acr(via_context_t * via_context,uint8_t byte)951 static void store_acr(via_context_t *via_context, uint8_t byte)
952 {
953 }
954
store_sr(via_context_t * via_context,uint8_t byte)955 static void store_sr(via_context_t *via_context, uint8_t byte)
956 {
957 }
958
store_sr10(via_context_t * via_context,uint8_t byte)959 static void store_sr10(via_context_t *via_context, uint8_t byte)
960 {
961 drivevia_context_t *viap;
962
963 viap = (drivevia_context_t *)(via_context->prv);
964
965 iec_fast_drive_write(byte, viap->number);
966 }
967
store_t2l(via_context_t * via_context,uint8_t byte)968 static void store_t2l(via_context_t *via_context, uint8_t byte)
969 {
970 }
971
reset(via_context_t * via_context)972 static void reset(via_context_t *via_context)
973 {
974 }
975
read_pra10(via_context_t * via_context,uint16_t addr)976 static uint8_t read_pra10(via_context_t *via_context, uint16_t addr)
977 {
978 return 255;
979 }
980
cmdhd_setup_context(diskunit_context_t * ctxptr)981 void cmdhd_setup_context(diskunit_context_t *ctxptr)
982 {
983 drivevia_context_t *via10p;
984 via_context_t *via10, *via9;
985 scsi_context_t *scsi;
986 i8255a_state *i8255a;
987 char *name = NULL;
988
989 CLOG((LOG, "CMDHD: setup_context"));
990
991 ctxptr->drives[0]->side = 0;
992
993 ctxptr->cmdhd = lib_calloc(1, sizeof(cmdhd_context_t));
994 ctxptr->cmdhd->myname = lib_msprintf("CMDHD%d", ctxptr->mynumber);
995 ctxptr->cmdhd->mycontext = ctxptr;
996
997 ctxptr->cmdhd->image = NULL;
998
999 /* Clear struct as snapshot code may write uninitialized values. */
1000 ctxptr->cmdhd->via10 = lib_calloc(1, sizeof(via_context_t));
1001 via10 = ctxptr->cmdhd->via10;
1002
1003 via10->prv = lib_malloc(sizeof(drivevia_context_t));
1004 via10p = (drivevia_context_t *)(via10->prv);
1005 via10p->number = ctxptr->mynumber;
1006
1007 via10->context = (void *)ctxptr->cmdhd;
1008
1009 via10->rmw_flag = &(ctxptr->cpu->rmw_flag);
1010 via10->clk_ptr = ctxptr->clk_ptr;
1011
1012 via10->myname = lib_msprintf("CMDHD%dVIA10", ctxptr->mynumber);
1013 via10->my_module_name = lib_msprintf("CMDHD%dVIA10", ctxptr->mynumber);
1014
1015 viacore_setup_context(via10);
1016
1017 via10->my_module_name_alt1 = lib_msprintf("CMDHDVIA10-%d", ctxptr->mynumber);
1018 via10->my_module_name_alt2 = lib_msprintf("CMDHDVIA10");
1019
1020 via10->irq_line = IK_IRQ;
1021
1022 via10p->drive = ctxptr->drives[0];
1023 via10p->v_iecbus = iecbus_drive_port();
1024
1025 via10->undump_pra = undump_pra;
1026 via10->undump_prb = undump_prb10;
1027 via10->undump_pcr = undump_pcr;
1028 via10->undump_acr = undump_acr;
1029 via10->store_pra = store_pra10;
1030 via10->store_prb = store_prb10;
1031 via10->store_pcr = store_pcr;
1032 via10->store_acr = store_acr;
1033 via10->store_sr = store_sr10;
1034 via10->store_t2l = store_t2l;
1035 via10->read_pra = read_pra10;
1036 via10->read_prb = read_prb10;
1037 via10->set_int = set_int;
1038 via10->restore_int = restore_int;
1039 via10->set_ca2 = set_ca2;
1040 via10->set_cb2 = set_cb2;
1041 via10->reset = reset;
1042
1043 ctxptr->cmdhd->via9 = lib_calloc(1, sizeof(via_context_t));
1044 via9 = ctxptr->cmdhd->via9;
1045
1046 via9->context = (void *)ctxptr->cmdhd;
1047
1048 via9->rmw_flag = &(ctxptr->cpu->rmw_flag);
1049 via9->clk_ptr = ctxptr->clk_ptr;
1050
1051 via9->myname = lib_msprintf("CMDHD%dVIA9", ctxptr->mynumber);
1052 via9->my_module_name = lib_msprintf("CMDHD%dVIA9", ctxptr->mynumber);
1053
1054 viacore_setup_context(via9);
1055
1056 via9->my_module_name_alt1 = lib_msprintf("CMDHDVIA9-%d", ctxptr->mynumber);
1057 via9->my_module_name_alt2 = lib_msprintf("CMDHDVIA9");
1058
1059 via9->irq_line = IK_IRQ;
1060
1061 via9->undump_pra = undump_pra;
1062 via9->undump_prb = undump_prb;
1063 via9->undump_pcr = undump_pcr;
1064 via9->undump_acr = undump_acr;
1065 via9->store_pra = store_pra9;
1066 via9->store_prb = store_prb9;
1067 via9->store_pcr = store_pcr;
1068 via9->store_acr = store_acr;
1069 via9->store_sr = store_sr;
1070 via9->store_t2l = store_t2l;
1071 via9->read_pra = read_pra9;
1072 via9->read_prb = read_prb9;
1073 via9->set_int = set_int;
1074 via9->restore_int = restore_int;
1075 via9->set_ca2 = set_ca2;
1076 via9->set_cb2 = set_cb2;
1077 via9->reset = reset;
1078
1079 ctxptr->cmdhd->scsi = lib_calloc(1, sizeof(scsi_context_t));
1080 scsi = ctxptr->cmdhd->scsi;
1081 scsi->p = ctxptr->cmdhd;
1082 scsi->myname = lib_msprintf("CMDHD%dSCSI", ctxptr->mynumber);
1083
1084 ctxptr->cmdhd->i8255a = lib_calloc(1, sizeof(i8255a_state));
1085 i8255a = ctxptr->cmdhd->i8255a;
1086 i8255a->p = ctxptr->cmdhd;
1087 i8255a->set_pa = set_pa;
1088 i8255a->set_pb = set_pb;
1089 i8255a->set_pc = set_pc;
1090 i8255a->get_pa = get_pa;
1091 i8255a->get_pb = get_pb;
1092 i8255a->get_pc = get_pc;
1093
1094 name = lib_msprintf("CMDHD%dRTC", ctxptr->mynumber);
1095 ctxptr->cmdhd->rtc = rtc72421_init(name);
1096 lib_free(name);
1097
1098 ctxptr->cmdhd->rtc->stop = 0;
1099
1100 name = lib_msprintf("%sEXEC", ctxptr->cmdhd->myname);
1101 ctxptr->cmdhd->reset_alarm = alarm_new(ctxptr->cpu->alarm_context, name,
1102 reset_alarm_handler, ctxptr->cmdhd);
1103 lib_free(name);
1104 }
1105
cmdhd_init(diskunit_context_t * ctxptr)1106 void cmdhd_init(diskunit_context_t *ctxptr)
1107 {
1108 scsi_context_t *scsi = (scsi_context_t*)(ctxptr->cmdhd->scsi);
1109
1110 CLOG((LOG, "CMDHD: init"));
1111
1112 /* init via cores */
1113 viacore_init(ctxptr->cmdhd->via9, ctxptr->cpu->alarm_context,
1114 ctxptr->cpu->int_status, ctxptr->cpu->clk_guard);
1115 viacore_init(ctxptr->cmdhd->via10, ctxptr->cpu->alarm_context,
1116 ctxptr->cpu->int_status, ctxptr->cpu->clk_guard);
1117
1118 /* reset scsi system */
1119 scsi_reset(scsi);
1120 /* change any defaults */
1121 scsi->max_imagesize = 16777214U << 8;
1122 /* CMDHD can handle 56 drives, but the latest boot rom has a bug which
1123 corrupts data when deleting partitions that span across disk
1124 boundaries. So we only allow it to use one disk. This is fine as
1125 one disk is enough to max out the whole system. */
1126 scsi->max_ids = 1;
1127 /* Setup SCSI user functions */
1128 scsi->user_format = cmdhd_scsiformat;
1129 scsi->user_read = cmdhd_scsiread;
1130 scsi->user_write = cmdhd_scsiwrite;
1131
1132 ctxptr->cmdhd->preadyff = 1;
1133 }
1134
cmdhd_shutdown(cmdhd_context_t * hd)1135 void cmdhd_shutdown(cmdhd_context_t *hd)
1136 {
1137 CLOG((LOG, "CMDHD: shutdown"));
1138
1139 /* leave if no contxt provided */
1140 if (!hd) {
1141 return;
1142 }
1143
1144 rtc72421_destroy(hd->rtc, hd->mycontext->rtc_save);
1145 /* Don't know if we need this, so why is it even available? */
1146 /* alarm_destroy(hd->reset_alarm); */
1147 viacore_shutdown(hd->via9);
1148 viacore_shutdown(hd->via10);
1149 lib_free(hd->scsi->myname);
1150 lib_free(hd->scsi);
1151 lib_free(hd->i8255a);
1152 lib_free(hd->myname);
1153 lib_free(hd);
1154 }
1155
1156 /* Function to find the baselba of the cmd partition. We need this so we
1157 can modify the device number of the drive as it is stored on disk. */
cmdhd_findbaselba(cmdhd_context_t * hd)1158 static void cmdhd_findbaselba(cmdhd_context_t *hd)
1159 {
1160 uint32_t i;
1161 disk_addr_t dadr;
1162 unsigned char buf[256];
1163
1164 CLOG((LOG, "CMDHD: findbaselba"));
1165
1166 /* leave if no contxt provided */
1167 if (!hd) {
1168 return;
1169 }
1170
1171 /* reset value to invalid */
1172 hd->baselba = UINT32_MAX;
1173
1174 /* leave if no image provided */
1175 if (!hd->image) {
1176 return;
1177 }
1178
1179 /* look for configuration block */
1180 i = 2;
1181 /* start at LBA 2 as in 512-byte blocks */
1182 while (i < (hd->imagesize >> 9)) {
1183 /* translate to T/S for DHD images, ie. 65536 for each */
1184 dadr.track = (i / 32768) + 1;
1185 dadr.sector = (i % 32768) * 2 + 1;
1186 /* read the sector */
1187 if (disk_image_read_sector(hd->image, buf, &dadr) < 0) {
1188 /* hit the end of file */
1189 break;
1190 }
1191 /* otherwise check the cmd sig */
1192 if (!cmdhd_has_sig(buf)) {
1193 /* if it has it, update the offset */
1194 hd->baselba = i - 2;
1195 /* quit */
1196 break;
1197 }
1198 /* try next 128 sectors */
1199 i += 128;
1200 }
1201
1202 CLOG((LOG, "CMDHD: findbaselba=%u", hd->baselba));
1203 }
1204
cmdhd_reset(cmdhd_context_t * hd)1205 void cmdhd_reset(cmdhd_context_t *hd)
1206 {
1207 CLOCK c;
1208 size_t i;
1209 int unit;
1210
1211 CLOG((LOG, "CMDHD: reset"));
1212
1213 /* leave if no contxt provided */
1214 if (!hd) {
1215 return;
1216 }
1217
1218 /* reset vias */
1219 viacore_reset(hd->via9);
1220 viacore_reset(hd->via10);
1221
1222 /* setup default inputs to U11 (pullups/downs) */
1223 hd->i8255a_i[0] = 0xff;
1224 hd->i8255a_i[1] = 0x7f;
1225 hd->i8255a_i[2] = 0xe3;
1226 hd->scsi_dir = 0;
1227
1228 /* check RAM for CMC signature */
1229 /* The HD ROM does a series of hardware checks on reset if it doesn't
1230 find a signature in memory. Otherwise it skips to the boot loader.
1231 If the user holds down a button on reset, we need to set the alarm
1232 to remove the button press based on this. So on a cold reset, wait
1233 about 8M cycles, where as if it is a soft reset, wait 500K cycles. */
1234 c = *(hd->mycontext->clk_ptr) +
1235 cmdhd_has_sig(&(hd->mycontext->drive_ram[0x9000])) ? 8000000 : 500000;
1236 CLOG((LOG, "CMDHD: alarm set for %u from %u", c, *(hd->mycontext->clk_ptr)));
1237 alarm_set(hd->reset_alarm, c);
1238
1239 /* look for base lba as it may have changed on reset */
1240 cmdhd_findbaselba(hd);
1241
1242 /* check if write protect button is pressed */
1243 if (hd->mycontext->button&1) {
1244 hd->i8255a_i[1]&=0xf7;
1245 CLOG((LOG, "CMDHD: WP pressed down"));
1246 }
1247 /* check if swap8 button is pressed */
1248 if (hd->mycontext->button&2) {
1249 hd->i8255a_i[1]&=0xfd;
1250 CLOG((LOG, "CMDHD: SWAP8 pressed down"));
1251 }
1252 /* check if swap9 button is pressed */
1253 if (hd->mycontext->button&4) {
1254 hd->i8255a_i[1]&=0xfb;
1255 CLOG((LOG, "CMDHD: SWAP9 pressed down"));
1256 }
1257
1258 /* count the number of connected drives */
1259 unit = 0;
1260 for (i = 0; i < 7; i++) {
1261 if (hd->scsi->file[i]) {
1262 unit++;
1263 }
1264 }
1265
1266 /* if the image size is too small, put the drive in installation mode */
1267 /* but if there is more than one drive connect, go to normal mode */
1268 if (hd->imagesize < 73728) {
1269 if (unit == 1) {
1270 hd->i8255a_i[1]&=0xf9;
1271 CRIT((ERR, "CMDHD: image size too small, starting up in installation mode"));
1272 } else {
1273 /* remove scsi ID 0 */
1274 hd->scsi->file[0] = NULL;
1275 }
1276 }
1277
1278 /* make sure the cmdbus isn't held down */
1279 unit = hd->mycontext->mynumber + 8;
1280 cmdbus.drv_data[unit - 8] = 0xff;
1281 cmdbus.drv_bus[unit - 8] = 0xff;
1282
1283 /* propogate inputs to output */
1284 i8255a_reset(hd->i8255a);
1285 }
1286
cmdhd_attach_image(disk_image_t * image,unsigned int unit)1287 int cmdhd_attach_image(disk_image_t *image, unsigned int unit)
1288 {
1289 cmdhd_context_t *hd;
1290 char *basename, *testname;
1291 size_t i;
1292 FILE *test;
1293 size_t filelength;
1294
1295 CLOG((LOG, "CMDHD: attach_image"));
1296
1297 /* standard unit range check */
1298 if (unit < 8 || unit > 8 + NUM_DISK_UNITS) {
1299 return -1;
1300 }
1301
1302 /* make sure this is a DHD image */
1303 switch (image->type) {
1304 case DISK_IMAGE_TYPE_DHD:
1305 disk_image_attach_log(image, LOG, unit, 0);
1306 break;
1307 default:
1308 return -1;
1309 }
1310
1311 /* get context */
1312 hd = diskunit_context[unit - 8]->cmdhd;
1313
1314 /* leave if no contxt provided */
1315 if (!hd) {
1316 return -1;
1317 }
1318
1319 /* record passed values */
1320 hd->image = image;
1321 hd->imagesize = disk_image_size(image);
1322
1323 /* leave if there is a problem getting the image size */
1324 if (hd->imagesize == UINT32_MAX) {
1325 return -1;
1326 }
1327
1328 /* copy file FD to the scsi module */
1329 hd->scsi->file[0] = image->media.fsimage->fd;
1330
1331 /* find the base lba */
1332 cmdhd_findbaselba(hd);
1333
1334 /* look to see if there are more files with the same base
1335 name, but different extensions: s10, s20, s30,
1336 s<ID><LUN>, no LUN support yet */
1337 hd->scsi->max_ids = 1;
1338 /* copy the file name */
1339 basename = lib_strdup(image->media.fsimage->name);
1340
1341 /* make sure it ends in some form of DHD */
1342 i = strlen(basename);
1343 if (i > 0 &&
1344 (basename[i - 1] == 'd' || basename[i - 1] == 'D') &&
1345 (basename[i - 2] == 'h' || basename[i - 2] == 'H') &&
1346 (basename[i - 3] == 'd' || basename[i - 3] == 'D')) {
1347 /* strip off the last 2 letters */
1348 basename[i - 2] = 0;
1349 /* change the first D to an S */
1350 basename[i - 3] = (basename[i - 3] & ~31) | 'S';
1351 /* cycle through all of them S10-S60 */
1352 for (i = 1; i < 7; i++) {
1353 /* generate the name */
1354 testname = lib_msprintf("%s%1u0", basename, i);
1355 /* open the file */
1356 test = fopen(testname, "rb+");
1357 if (test) {
1358 /* if it is there, check the length */
1359 filelength = util_file_length(test);
1360 /* must be multiple of 512 */
1361 if ((filelength % 512) == 0) {
1362 /* set the FILE pointer */
1363 hd->scsi->file[i] = test;
1364 /* update the max ID */
1365 hd->scsi->max_ids = i + 1;
1366 } else {
1367 /* otherwise make sure it is zero */
1368 hd->scsi->file[i] = NULL;
1369 fclose(test);
1370 }
1371 }
1372 /* release any memory */
1373 lib_free(testname);
1374 }
1375 }
1376
1377 /* release any more memory */
1378 lib_free(basename);
1379
1380 return 0;
1381 }
1382
cmdhd_detach_image(disk_image_t * image,unsigned int unit)1383 int cmdhd_detach_image(disk_image_t *image, unsigned int unit)
1384 {
1385 cmdhd_context_t *hd;
1386 int32_t i;
1387
1388 CLOG((LOG, "CMDHD: detach_image"));
1389
1390 /* standard unit range check */
1391 if (image == NULL || unit < 8 || unit > 8 + NUM_DISK_UNITS) {
1392 return -1;
1393 }
1394
1395 /* make sure this is a DHD image */
1396 switch (image->type) {
1397 case DISK_IMAGE_TYPE_DHD:
1398 disk_image_detach_log(image, LOG, unit, 0);
1399 break;
1400 default:
1401 return -1;
1402 }
1403
1404 /* get context */
1405 hd = diskunit_context[unit - 8]->cmdhd;
1406
1407 /* leave if no contxt provided */
1408 if (!hd) {
1409 return -1;
1410 }
1411
1412 /* remove all image settings in this context */
1413 hd->image = NULL;
1414 hd->imagesize = 0;
1415 hd->baselba = UINT32_MAX;
1416 hd->scsi->file[0] = NULL;
1417
1418 /* close all additional SCSI ID files */
1419 for (i = 1; i < 7; i++) {
1420 /* if it isn't NULL, it must be a file */
1421 if (hd->scsi->file[i]) {
1422 /* close it and set to NULL */
1423 fclose(hd->scsi->file[i]);
1424 hd->scsi->file[i] = NULL;
1425 }
1426 }
1427
1428 /* make sure the cmdbus isn't held down */
1429 cmdbus.drv_data[unit - 8] = 0xff;
1430 cmdbus.drv_bus[unit - 8] = 0xff;
1431
1432 return 0;
1433 }
1434
1435 #define CMDHD_SNAP_MAJOR 1
1436 #define CMDHD_SNAP_MINOR 0
1437
cmdhd_snapshot_write_module(cmdhd_context_t * drv,struct snapshot_s * s)1438 int cmdhd_snapshot_write_module(cmdhd_context_t *drv, struct snapshot_s *s)
1439 {
1440 snapshot_module_t *m;
1441
1442 CLOG((LOG, "CMDHD: snapshot_write_module"));
1443
1444 m = snapshot_module_create(s, drv->myname, CMDHD_SNAP_MAJOR, CMDHD_SNAP_MINOR);
1445
1446 if (m == NULL) {
1447 return -1;
1448 }
1449
1450 if (0
1451 || SMW_B(m, drv->LEDs) < 0
1452 || SMW_BA(m, drv->i8255a_i, 3) < 0
1453 || SMW_BA(m, drv->i8255a_o, 3) < 0
1454 || SMW_B(m, drv->scsi_dir) < 0
1455 || SMW_B(m, drv->preadyff) < 0 ) {
1456 snapshot_module_close(m);
1457 return -1;
1458 }
1459
1460 if (i8255a_snapshot_write_data(drv->i8255a, m) < 0) {
1461 snapshot_module_close(m);
1462 return -1;
1463 }
1464
1465 if (snapshot_module_close(m) < 0) {
1466 return -1;
1467 }
1468
1469 if (viacore_snapshot_write_module(drv->via9, s) < 0) {
1470 return -1;
1471 }
1472
1473 if (viacore_snapshot_write_module(drv->via10, s) < 0) {
1474 return -1;
1475 }
1476
1477 if (scsi_snapshot_write_module(drv->scsi, s) < 0) {
1478 return -1;
1479 }
1480
1481 if (rtc72421_write_snapshot(drv->rtc, s) < 0) {
1482 return -1;
1483 }
1484
1485 return 0;
1486 }
1487
cmdhd_snapshot_read_module(cmdhd_context_t * drv,struct snapshot_s * s)1488 int cmdhd_snapshot_read_module(cmdhd_context_t *drv, struct snapshot_s *s)
1489 {
1490 uint8_t vmajor, vminor;
1491 snapshot_module_t *m;
1492
1493 CLOG((LOG, "CMDHD: snapshot_read_module"));
1494
1495 m = snapshot_module_open(s, drv->myname, &vmajor, &vminor);
1496 if (m == NULL) {
1497 return -1;
1498 }
1499
1500 /* Do not accept higher versions than current */
1501 if (snapshot_version_is_bigger(vmajor, vminor, CMDHD_SNAP_MAJOR, CMDHD_SNAP_MAJOR)) {
1502 snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
1503 snapshot_module_close(m);
1504 return -1;
1505 }
1506
1507 if (0
1508 || SMR_B(m, &drv->LEDs) < 0
1509 || SMR_BA(m, drv->i8255a_i, 3) < 0
1510 || SMR_BA(m, drv->i8255a_o, 3) < 0
1511 || SMR_B(m, &drv->scsi_dir) < 0
1512 || SMR_B(m, &drv->preadyff) < 0 ) {
1513 snapshot_module_close(m);
1514 return -1;
1515 }
1516
1517 if (i8255a_snapshot_read_data(drv->i8255a, m) < 0) {
1518 snapshot_module_close(m);
1519 return -1;
1520 }
1521
1522 if (snapshot_module_close(m) < 0) {
1523 return -1;
1524 }
1525
1526 alarm_unset(drv->reset_alarm);
1527
1528 if (viacore_snapshot_read_module(drv->via9, s) < 0) {
1529 return -1;
1530 }
1531
1532 if (viacore_snapshot_read_module(drv->via10, s) < 0) {
1533 return -1;
1534 }
1535
1536 if (scsi_snapshot_read_module(drv->scsi, s) < 0) {
1537 return -1;
1538 }
1539
1540 if (rtc72421_read_snapshot(drv->rtc, s) < 0) {
1541 return -1;
1542 }
1543
1544 return 0;
1545 }
1546
1547