1 /* pro_rx.c: RX50 floppy controller
2 
3    Copyright (c) 1997-2003, Tarik Isani (xhomer@isani.org)
4 
5    This file is part of Xhomer.
6 
7    Xhomer is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License version 2
9    as published by the Free Software Foundation.
10 
11    Xhomer is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Xhomer; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 
22 /* TBD:
23 		-writing a write-protected disk under DCL returns
24 		 different error than real PRO
25 		-check byte enables?
26 		-implement write sector command with error checks
27 */
28 
29 #ifdef PRO
30 #include "pdp11_defs.h"
31 #include "sim_defs.h" /* For sim_gtime() */
32 #include <sys/stat.h>
33 #include <unistd.h>
34 
35 #define PRO_RX_TRACKS	80	/* tracks per disk */
36 #define PRO_RX_SPT	10	/* sectors per track */
37 #define PRO_RX_BPS	512	/* bytes per sector */
38 #define PRO_RX_SIZE	(PRO_RX_TRACKS*PRO_RX_SPT*PRO_RX_BPS)
39 
40 
41 char		*pro_rx_dir[4];
42 char		*pro_rx_file[4];
43 
44 int		pro_rx_closed[4] = {0,0,0,0};	/* initial floppy door status */
45 
46 LOCAL FILE	*pro_rx_fptr[4];
47 
48 LOCAL unsigned char PRO_RX_SECBUF[PRO_RX_BPS];
49 
50 LOCAL int	pro_rx_csr0_c;			/* csr0 for command mode */
51 LOCAL int	pro_rx_csr1_c;
52 LOCAL int	pro_rx_csr2_c;
53 LOCAL int	pro_rx_csr3_c;
54 LOCAL int	pro_rx_csr5_c;
55 
56 LOCAL int	pro_rx_csr0_s;			/* csr0 for maint/status */
57 LOCAL int	pro_rx_csr1_s;
58 LOCAL int	pro_rx_csr2_s;
59 LOCAL int	pro_rx_csr3_s;
60 LOCAL int	pro_rx_csr4_s;
61 
62 LOCAL int	pro_rx_secbuf_addr;
63 LOCAL int	pro_rx_intb_en;			/* enable interrupt B */
64 
65 LOCAL int	pro_rx_exist[4];		/* existence of 4 floppy drives */
66 LOCAL int	pro_rx_ready[4] = {0,0,0,0};	/* diskette present */
67 LOCAL int	pro_rx_wprot[4] = {0,0,0,0};	/* write protection status */
68 LOCAL int	pro_rx_vchanged[4];		/* volume changed bits */
69 
70 
71 /* Volume-changed interrupt generator */
72 
pro_rx_intb()73 LOCAL void pro_rx_intb ()
74 {
75 	/* Check if intb is enabled */
76 
77 	/* XXX use better int name */
78 
79 	if (pro_rx_intb_en == 1)
80 	  pro_int_set(PRO_INT_1B);
81 
82 	/* Disable generation of future interrupts until status is read */
83 
84 	pro_rx_intb_en = 0;
85 }
86 
87 
88 /* Open floppy door */
89 
pro_rx_open_door(int disknum)90 void pro_rx_open_door (int disknum)
91 {
92 	if (pro_rx_ready[disknum] == 1)
93 	{
94 	  /* XXX */
95 
96 	  printf("Open floppy %d\r\n", disknum);
97 
98 	  /* Close image file */
99 
100 	  fclose(pro_rx_fptr[disknum]);
101 
102 	  pro_rx_ready[disknum] = 0;
103 
104 	  pro_rx_wprot[disknum] = 0;
105 
106 	  pro_rx_vchanged[disknum] = 1;
107 
108 	  /* Generate interrupt, if needed */
109 
110 	  pro_rx_intb();
111 	}
112 	else
113 	  printf("Floppy %d already open!\r\n", disknum);
114 }
115 
116 
117 /* Close floppy door */
118 
pro_rx_close_door(int disknum)119 void pro_rx_close_door (int disknum)
120 {
121 struct stat	statbuf;
122 char		*fname;
123 
124 
125 	if (pro_rx_ready[disknum] == 0)
126 	{
127 	  /* Construct filename */
128 
129 	  fname = malloc(strlen(pro_rx_dir[disknum]) + strlen(pro_rx_file[disknum]) + 1);
130 	  strcpy(fname, pro_rx_dir[disknum]);
131 	  strcat(fname, pro_rx_file[disknum]);
132 
133 	  /* Get file status */
134 
135 	  stat(fname, &statbuf);
136 
137 	  /* Check if writeable, and open new image file */
138 
139 	  if ((statbuf.st_mode & S_IWUSR) != 0)
140 	    pro_rx_fptr[disknum] = fopen(fname, "r+");
141 	  else
142 	  {
143 	    pro_rx_fptr[disknum] = fopen(fname, "r");
144 	    pro_rx_wprot[disknum] = 1;
145 	  }
146 
147 	  if (pro_rx_fptr[disknum] != NULL)
148 	  {
149 	    /* Check if image is correct size */
150 
151 	    if (statbuf.st_size == PRO_RX_SIZE)
152 	    {
153 	      /* XXX */
154 
155 	      printf("Close floppy %d\r\n", disknum);
156 
157 	      pro_rx_ready[disknum] = 1;
158 
159 	      pro_rx_vchanged[disknum] = 1;
160 
161 	      /* Generate interrupt, if needed */
162 
163 	      pro_rx_intb();
164 	    }
165 	    else
166 	    {
167 	      printf("Floppy %d image filesize %d incorrect! (should be %d)\r\n",
168 	              disknum, (int)statbuf.st_size, PRO_RX_SIZE);
169 	      pro_rx_wprot[disknum] = 0;
170 	      fclose(pro_rx_fptr[disknum]);
171 	    }
172 	  }
173 	  else
174 	  {
175 	    printf("Floppy %d close failed!\r\n", disknum);
176 	    pro_rx_wprot[disknum] = 0;
177 	  }
178 
179 	  free(fname);
180 	}
181 	else
182 	  printf("Floppy %d already closed!\r\n", disknum);
183 }
184 
185 
186 /* Set maintenance status registers */
187 
pro_rx_set_maintstat()188 LOCAL void pro_rx_set_maintstat ()
189 {
190 int	disknum;
191 
192 	disknum = (pro_rx_csr0_c & PRO_RX_DISKNUM) >> 1;
193 
194 	pro_rx_csr0_s = (pro_rx_csr0_c & (PRO_RX_FUNC | PRO_RX_DISKNUM)) | PRO_RX_DONE;
195 
196 	pro_rx_csr1_s = 0;
197 
198 	pro_rx_csr2_s = pro_rx_csr1_c;
199 
200 	pro_rx_csr3_s = (pro_rx_vchanged[3] << 7)
201 	                | (pro_rx_vchanged[2] << 6)
202 	                | (pro_rx_vchanged[1] << 5)
203 	                | (pro_rx_vchanged[0] << 4)
204 	                | (pro_rx_wprot[disknum] << 3)
205 	                | (pro_rx_ready[disknum] << 2)
206 	                | pro_rx_exist[disknum];
207 
208 	pro_rx_csr4_s = (pro_rx_exist[3] << 6)
209 	                | (pro_rx_exist[2] << 4)
210 	                | (pro_rx_exist[1] << 2)
211 	                | pro_rx_exist[0];
212 }
213 
214 
215 /* Set read/write status registers */
216 
pro_rx_set_rwstat()217 LOCAL void pro_rx_set_rwstat ()
218 {
219 	pro_rx_csr0_s = (pro_rx_csr0_c & (PRO_RX_FUNC | PRO_RX_DISKNUM)) | PRO_RX_DONE;
220 
221 	pro_rx_csr1_s = 0;
222 
223 	pro_rx_csr2_s = pro_rx_csr1_c;
224 
225 	pro_rx_csr3_s = pro_rx_csr2_c;
226 
227 	pro_rx_csr4_s = 0;
228 }
229 
230 
231 /* Read sector */
232 
pro_rx_readsec()233 LOCAL void pro_rx_readsec ()
234 {
235 int	i, disk, track, sector, offset;
236 
237 	disk = (pro_rx_csr0_c & PRO_RX_DISKNUM) >> 1;
238 
239 	track = pro_rx_csr1_c;
240 
241 	sector = pro_rx_csr2_c-1;
242 
243 	offset = (track*PRO_RX_SPT+sector)*PRO_RX_BPS;
244 
245 	/* XXX */
246 
247 /*
248 	printf("READ sector: disk %d track %d sector %d!\r\n", disk, track, sector);
249 */
250 
251 	/* Perform error checks */
252 
253 	if ((pro_rx_exist[disk] != 1) || (pro_rx_ready[disk] != 1))
254 	  pro_rx_csr1_s = 0220; /* unavailable diskette */
255 	else if (track >= PRO_RX_TRACKS)
256 	  pro_rx_csr1_s = 0040; /* unspecified track number */
257 	else if ((sector < 0) || (sector >= PRO_RX_SPT))
258 	  pro_rx_csr1_s = 0270; /* unspecified sector number */
259 	else
260 	{
261 	  /* Read sector */
262 
263 	  fseek(pro_rx_fptr[disk], offset, 0);
264 
265 	  for(i=0; i<PRO_RX_BPS; i++)
266 	    PRO_RX_SECBUF[i] = getc(pro_rx_fptr[disk]);
267 	}
268 }
269 
270 
271 /* Write sector */
272 
pro_rx_writesec()273 LOCAL void pro_rx_writesec ()
274 {
275 int	i, disk, track, sector, offset;
276 
277 	disk = (pro_rx_csr0_c & PRO_RX_DISKNUM) >> 1;
278 
279 	track = pro_rx_csr1_c;
280 
281 	sector = pro_rx_csr2_c-1;
282 
283 	offset = (track*PRO_RX_SPT+sector)*PRO_RX_BPS;
284 
285 	/* XXX */
286 
287 /*
288 	printf("WRITE sector: disk %d track %d sector %d!\r\n", disk, track, sector);
289 */
290 
291 	/* Perform error checks */
292 
293 	if ((pro_rx_exist[disk] != 1) || (pro_rx_ready[disk] != 1))
294 	  pro_rx_csr1_s = 0220; /* unavailable diskette */
295 	else if (pro_rx_wprot[disk] == 1)
296 	  pro_rx_csr1_s = 0260; /* write protected */
297 	else if (track >= PRO_RX_TRACKS)
298 	  pro_rx_csr1_s = 0040; /* unspecified track number */
299 	else if ((sector < 0) || (sector >= PRO_RX_SPT))
300 	  pro_rx_csr1_s = 0270; /* unspecified sector number */
301 	else
302 	{
303 	  /* Write sector */
304 
305 	  fseek(pro_rx_fptr[disk], offset, 0);
306 
307 	  for(i=0; i<PRO_RX_BPS; i++)
308 	    putc(PRO_RX_SECBUF[i], pro_rx_fptr[disk]);
309 
310 	  fflush(pro_rx_fptr[disk]);
311 	}
312 }
313 
314 
315 /* Start Command */
316 
pro_rx_start_command(void)317 LOCAL void pro_rx_start_command(void)
318 {
319 int	i;
320 
321 	switch ((pro_rx_csr0_c & PRO_RX_FUNC) >> 4)
322 	{
323 	  case PRO_RX_CMD_STAT:
324 	    pro_rx_set_maintstat();
325 
326 	    /* Reset volume change bits */
327 
328 	    for(i=0; i<4; i++)
329 	      pro_rx_vchanged[i] = 0;
330 
331 	    /* Enable generation of volume changed interrupt */
332 
333 	    pro_rx_intb_en = 1;
334 
335 	    break;
336 
337 	  case PRO_RX_CMD_MAINT:
338 	    pro_rx_set_maintstat();
339 
340 	    break;
341 
342 	  case PRO_RX_CMD_RESTORE:
343 	    pro_rx_set_maintstat();
344 
345 	    break;
346 
347 	  case PRO_RX_CMD_INIT:
348 	    pro_rx_set_maintstat();
349 
350 	    break;
351 
352 	  case PRO_RX_CMD_READ:
353 	    pro_rx_set_rwstat();
354 
355 	    pro_rx_readsec();
356 
357 	    break;
358 
359 	  case PRO_RX_CMD_EXTEND:
360 	    switch (pro_rx_csr5_c & PRO_RX_EXTEND)
361 	    {
362 	      case PRO_RX_CMD_RETRY:
363 	        pro_rx_set_rwstat();
364 
365 	        pro_rx_readsec();
366 
367 	        break;
368 
369 	      case PRO_RX_CMD_DELETE:
370 	        pro_rx_set_rwstat();
371 
372 	        pro_rx_writesec();
373 
374 	        break;
375 
376 	      case PRO_RX_CMD_RFORMAT:
377 	        /* XXX */
378 
379 	        /* Update csr2, etc. */
380 
381 	        printf("Read format not implemented in RX50!\r\n");
382 
383 	        break;
384 
385 	      case PRO_RX_CMD_SFORMAT:
386 	        /* XXX */
387 
388 	        /* Read csr2, etc. */
389 
390 	        printf("Set format not implemented in RX50!\r\n");
391 
392 	        break;
393 
394 	      case PRO_RX_CMD_VERSION:
395 	        pro_rx_csr2_s = PRO_RX_VERSION;
396 
397 	        break;
398 
399 	      case PRO_RX_CMD_COMPARE:
400 	        /* XXX */
401 
402 	        printf("Read and compare not implemented in RX50!\r\n");
403 
404 	        break;
405 
406 	      default:
407 	        printf("Warning: unknown extended function command in RX50!\r\n");
408 
409 	        break;
410 	    }
411 
412 	    break;
413 
414 	  case PRO_RX_CMD_ADDR:
415 	    pro_rx_set_rwstat();
416 
417 	    /* XXX */
418 	    printf("%10.0f Warning: read address command not implemented in RX50!\r\n", sim_gtime());
419 	    break;
420 
421 	  case PRO_RX_CMD_WRITE:
422 	    pro_rx_set_rwstat();
423 
424 	    pro_rx_writesec();
425 
426 	    break;
427 
428 	  default:
429 	    break;
430 	}
431 
432 	/* XXX use better int name */
433 
434 	pro_int_set(PRO_INT_1A);
435 }
436 
437 
438 /* RX registers */
439 
pro_rx_rd(int pa)440 int pro_rx_rd (int pa)
441 {
442 int	data;
443 
444 	switch (pa & 017777776)
445 	{
446 	  case 017774200:
447 	    data = PRO_ID_RX;
448 	    break;
449 
450 	  case 017774204:
451 	    data = pro_rx_csr0_s;
452 	    break;
453 
454 	  case 017774206:
455 	    data = pro_rx_csr1_s;
456 	    break;
457 
458 	  case 017774210:
459 	    data = pro_rx_csr2_s;
460 	    break;
461 
462 	  case 017774212:
463 	    data = pro_rx_csr3_s;
464 	    break;
465 
466 	  case 017774214:
467 	    data = pro_rx_csr4_s;
468 	    break;
469 
470 	  case 017774216:
471 	    /* XXX correct? */
472 
473 	    data = pro_rx_csr5_c;
474 	    break;
475 
476 	  case 017774220:
477 	    /* Empty data buffer */
478 
479 	    data = PRO_RX_SECBUF[pro_rx_secbuf_addr];
480 
481 	    pro_rx_secbuf_addr++;
482 
483 	    if (pro_rx_secbuf_addr == PRO_RX_BPS)
484 	      pro_rx_secbuf_addr = 0;
485 
486 	    break;
487 
488 	  case 017774222:
489 	    /* Clear sector buffer address */
490 
491 	    pro_rx_secbuf_addr = 0;
492 
493 	    /* XXX what does the real PRO return? */
494 
495 	    data = 0;
496 	    break;
497 
498 	  case 017774224:
499 	    /* Start command */
500 
501 	    pro_rx_start_command();
502 
503 	    data = 0;
504 	    break;
505 
506 	  default:
507 	    data = 0;
508 	    break;
509 	}
510 
511 	return data;
512 }
513 
pro_rx_wr(int data,int pa,int access)514 void pro_rx_wr (int data, int pa, int access)
515 {
516 	switch (pa & 017777776)
517 	{
518 	  case 017774204:
519 	    WRITE_WB(pro_rx_csr0_c, PRO_RX_CSR0_C_W, access);
520 	    break;
521 
522 	  case 017774206:
523 	    WRITE_WB(pro_rx_csr1_c, PRO_RX_CSR1_C_W, access);
524 	    break;
525 
526 	  case 017774210:
527 	    WRITE_WB(pro_rx_csr2_c, PRO_RX_CSR2_C_W, access);
528 	    break;
529 
530 	  case 017774212:
531 	    WRITE_WB(pro_rx_csr3_c, PRO_RX_CSR3_C_W, access);
532 	    break;
533 
534 	  case 017774216:
535 	    WRITE_WB(pro_rx_csr5_c, PRO_RX_CSR5_C_W, access);
536 	    break;
537 
538 	  case 017774222:
539 	    /* Clear sector buffer address */
540 
541 	    pro_rx_secbuf_addr = 0;
542 
543 	    break;
544 
545 	  case 017774224:
546 	    /* Start command */
547 
548 	    pro_rx_start_command();
549 
550 	    break;
551 
552 	  /* The PRO technical manual specifies 17774226.
553 	     Venix 1.0/2.0  use this address.
554 	     However, P/OS 3.2 uses 17774220. */
555 
556 	  case 017774220:
557 	  case 017774226:
558 	    /* Fill sector buffer */
559 
560 	    PRO_RX_SECBUF[pro_rx_secbuf_addr] = (data & 0377);
561 
562 	    pro_rx_secbuf_addr++;
563 
564 	    if (pro_rx_secbuf_addr == PRO_RX_BPS)
565 	      pro_rx_secbuf_addr = 0;
566 
567 	    break;
568 
569 	  default:
570 	    break;
571 	}
572 }
573 
pro_rx_reset()574 void pro_rx_reset ()
575 {
576 int	i;
577 
578 
579 	/* Clear the 512-byte sector buffer */
580 
581         memset(&PRO_RX_SECBUF, 0, sizeof(PRO_RX_SECBUF));
582 
583 	pro_rx_secbuf_addr = 0;
584 
585 	pro_rx_csr0_c = 0;
586 	pro_rx_csr1_c = 0;
587 	pro_rx_csr2_c = 0;
588 	pro_rx_csr3_c = 0;
589 	pro_rx_csr5_c = 0;
590 
591 	pro_rx_csr0_s = PRO_RX_DONE;
592 	pro_rx_csr1_s = 0;
593 	pro_rx_csr2_s = 0;
594 	pro_rx_csr3_s = 0;
595 	pro_rx_csr4_s = 0;
596 
597 	/* XXX The following is hardcoded for now */
598 
599 	pro_rx_exist[0] = 1;
600 	pro_rx_exist[1] = 1;
601 	pro_rx_exist[2] = 0;
602 	pro_rx_exist[3] = 0;
603 
604 	pro_rx_vchanged[0] = 0;
605 	pro_rx_vchanged[1] = 0;
606 	pro_rx_vchanged[2] = 0;
607 	pro_rx_vchanged[3] = 0;
608 
609 	pro_rx_intb_en = 0;
610 
611 	/* Open floppy image files by "closing" door */
612 
613 	for(i=0; i<4; i++)
614 	  if (pro_rx_closed[i] == 1)
615 	    pro_rx_close_door(i);
616 }
617 
618 
619 /* Exit routine */
620 
pro_rx_exit()621 void pro_rx_exit ()
622 {
623 int	i;
624 
625 	/* Close all floppy image files by "opening" door */
626 
627 	for(i=0; i<4; i++)
628 	  if (pro_rx_ready[i] == 1)
629 	    pro_rx_open_door(i);
630 }
631 #endif
632