1495 lines
58 KiB
C
1495 lines
58 KiB
C
/* s100_icom.c: iCOM FD3712/FD3812 Flexible Disk System
|
|
|
|
Created by Patrick Linstruth (patrick@deltecent.com)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
PETER SCHORN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Patrick Linstruth shall not
|
|
be used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Patrick Linstruth.
|
|
*/
|
|
|
|
/*
|
|
These functions support simulated iCOM FD3712 and FD3812
|
|
floppy disk systems. The FD3712 supports IBM Diskette type 1
|
|
single-density and the FD3812 also supports IBM Diskette
|
|
type 2D double-density. The density of the media attached
|
|
is determined by file size. If a read or write is made
|
|
where the media doesn't match the density setting of the
|
|
controller, a CRC error status will be set.
|
|
|
|
The interface board provides 2 I/O ports:
|
|
|
|
Command Register Port C0 Output
|
|
Data In Register Port C0 Input
|
|
Data Out Register Port C1 Output
|
|
|
|
+---------------------------------------------------------+
|
|
| |
|
|
| COMMAND SET |
|
|
| |
|
|
+---------------------------------------------------------+
|
|
| COMMAND | 7 6 5 4 3 2 1 0 | BUSY | HEX CODE |
|
|
+---------------------------------------------------------+
|
|
| EXAMINE STATUS | 0 0 0 0 0 0 0 0 | No | 00 |
|
|
| READ | 0 0 0 0 0 0 1 1 | Yes | 03 |
|
|
| WRITE | 0 0 0 0 0 1 0 1 | Yes | 05 |
|
|
| READ CRC | 0 0 0 0 0 1 1 1 | Yes | 07 |
|
|
| SEEK | 0 0 0 0 1 0 0 1 | Yes | 09 |
|
|
| CLEAR ERROR FLAGS | 0 0 0 0 1 0 1 1 | No | 0B |
|
|
| SEEK TRACK ZERO | 0 0 0 0 1 1 0 1 | Yes | 0D |
|
|
| WRITE DEL DATA MARK | 0 0 0 0 1 1 1 1 | Yes | 0F |
|
|
| LOAD TRACK ADDRESS | 0 0 0 1 0 0 0 1 | No | 11 |
|
|
| LOAD UNIT/SECTOR | 0 0 1 0 0 0 0 1 | No | 21 |
|
|
| LOAD WRITE BUFFER* | 0 0 1 1 0 0 0 1 | No | 30 |
|
|
| LOAD WRITE BUFFER+ | 0 0 1 1 0 0 0 1 | No | 31 |
|
|
| EXAMINE READ BUFFER | 0 1 0 0 0 0 0 0 | No | 40 |
|
|
| SHIFT READ BUFFER | 0 1 0 0 0 0 0 1 | No | 41 |
|
|
| CLEAR CONTROLLER | 1 0 0 0 0 0 0 1 | No | 81 |
|
|
| LOAD CONFIGURATION* | 0 0 0 1 1 0 0 1 | No | 15 |
|
|
+---------------------------------------------------------+
|
|
| + FD3712 Only |
|
|
| * FD3812 Only |
|
|
+---------------------------------------------------------+
|
|
|
|
+---------------------------------------------------------------+
|
|
| |
|
|
| DISK STATUS BITS |
|
|
| |
|
|
+---------------------------------------------------------------+
|
|
| BIT | STATUS SIGNAL | DESCRIPTION |
|
|
+---------------------------------------------------------------+
|
|
| 7 | DELETED DATA MARK | The simulator does not implement |
|
|
| | | this bit. |
|
|
+---------------------------------------------------------------+
|
|
| 6 | MEDIA STATUS | This bit is always set. |
|
|
+---------------------------------------------------------------+
|
|
| 5 | DRIVE FAIL | This bit is set if any if a drive |
|
|
| | | is not attached using the |
|
|
| | | "ATTACH" command or there is a |
|
|
| | | problem reading from or writing |
|
|
| | | to the attached file. |
|
|
+---------------------------------------------------------------+
|
|
| 4 | WRITE PROTECT | This bit is set if the selected |
|
|
| | | drive contains a write protected |
|
|
| | | diskette. This condition should |
|
|
| | | not be tested if the selected |
|
|
| | | drive has a "DRIVE FAIL" status. |
|
|
| | | Use "SET ICOM WRTPROT" to write |
|
|
| | | protect an attached diskette and |
|
|
| | | "SET ICOM WRTENB" to enable |
|
|
| | | writing. |
|
|
+---------------------------------------------------------------+
|
|
| 3 | CRC ERROR | This bit is set when an error has |
|
|
| | | occurred during the previous |
|
|
| | | command. This bit must be tested |
|
|
| | | after all read, write, and seek |
|
|
| | | operations. The simulator does |
|
|
| | | not implement this bit. |
|
|
+---------------------------------------------------------------+
|
|
| 2 | UNIT SELECT MSB | Bits 2 and 1 contain the address |
|
|
+---------------------------| of the drive currently being |
|
|
| 1 | UNIT SELECT LSB | selected by the controller. |
|
|
+---------------------------------------------------------------+
|
|
| 0 | BUSY | This bit is set when a read, |
|
|
| | | write, seek command is sent to |
|
|
| | | the controller. |
|
|
+---------------------------------------------------------------+
|
|
|
|
B = Memory Size - 16K
|
|
|
|
32K: B = 32K - 16K = 16K = 04000H
|
|
48K: B = 48K = 16K = 32K = 08000H
|
|
62K: B = 62K = 16K = 46K = 0B800H
|
|
64K: B = 64K = 16K = 48K = 0C000H
|
|
|
|
+----------------------------------------------------------------------+
|
|
| |
|
|
| CP/M 1.41 Single Density Disk Layout |
|
|
| |
|
|
+----------------------------------------------------------------------+
|
|
| Track | Sector | Image Offset | Memory Address | Module |
|
|
+----------------------------------------------------------------------+
|
|
| 00 | 01 | 0000-007FH | 0080H | SD Disk Boot Loader |
|
|
+----------------------------------------------------------------------+
|
|
| 00 | 02-17 | 0080-087FH | 2900H+B | CCP |
|
|
+----------------------------------------------------------------------+
|
|
| 00 | 18-26 | 0880-0CFFH | 3100H+B | BDOS |
|
|
| 01 | 01-17 | 0D00-157FH | 3580H+B | BDOS |
|
|
+----------------------------------------------------------------------+
|
|
| 01 | 18-21 | 1580-177FH | 3E00H+B | BIOS |
|
|
+----------------------------------------------------------------------+
|
|
| 01 | 22-26 | | Not Used |
|
|
+----------------------------------------------------------------------+
|
|
|
|
+----------------------------------------------------------------------+
|
|
| |
|
|
| CP/M 1.41 Double Density Disk Layout |
|
|
| |
|
|
+----------------------------------------------------------------------+
|
|
| Track | Sector | Image Offset | Memory Address | Module |
|
|
+----------------------------------------------------------------------+
|
|
| 00 | 01 | 0000-007FH | 0080H | DD Disk Boot Loader |
|
|
+----------------------------------------------------------------------+
|
|
| 00 | 02-26 | | | Not Used |
|
|
+----------------------------------------------------------------------+
|
|
| 01 | 01-09 | 0D00-14FFH | 2900H+B | CCP |
|
|
+----------------------------------------------------------------------+
|
|
| 01 | 10-21 | 1500-21FFH | 3100H+B | BDOS |
|
|
+----------------------------------------------------------------------+
|
|
| 01 | 22-23 | 2200-23FFH | 3E00H+B | BIOS |
|
|
+----------------------------------------------------------------------+
|
|
| 01 | 24-26 | | | Not Used |
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
/* #define DBG_MSG */
|
|
|
|
#include "altairz80_defs.h"
|
|
#include "sim_imd.h"
|
|
|
|
#ifdef DBG_MSG
|
|
#define DBG_PRINT(args) sim_printf args
|
|
#else
|
|
#define DBG_PRINT(args)
|
|
#endif
|
|
|
|
extern t_stat set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
extern t_stat set_iobase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
|
int32 (*routine)(const int32, const int32, const int32), const char* name, uint8 unmap);
|
|
|
|
#define ICOM_MAX_DRIVES 4
|
|
#define ICOM_SD_SECTOR_LEN 128
|
|
#define ICOM_DD_SECTOR_LEN 256
|
|
#define ICOM_SPT 26
|
|
#define ICOM_TRACKS 77
|
|
#define ICOM_SD_CAPACITY (256256) /* Default iCOM Single Density Disk Capacity */
|
|
#define ICOM_DD_CAPACITY (509184) /* Default iCOM Double Density Disk Capacity */
|
|
|
|
#define ICOM_IO_BASE 0xc0
|
|
#define ICOM_IO_SIZE 2
|
|
|
|
#define ICOM_PROM_BASE 0xf000
|
|
#define ICOM_PROM_SIZE 1024
|
|
#define ICOM_PROM_MASK (ICOM_PROM_SIZE-1)
|
|
#define ICOM_MEM_BASE 0xf400
|
|
#define ICOM_MEM_SIZE 256 /* Must be on a page boundary */
|
|
#define ICOM_MEM_MASK (ICOM_MEM_SIZE-1)
|
|
|
|
static uint8 icom_mem[ICOM_MEM_SIZE];
|
|
|
|
/* iCOM PROMs are 1024 bytes */
|
|
|
|
static uint8 icom_3712_prom[ICOM_PROM_SIZE] = {
|
|
0xc3, 0x73, 0xf0, 0x20, 0x41, 0x4c, 0x54, 0x41,
|
|
0x49, 0x52, 0x43, 0x20, 0xc3, 0x85, 0xf0, 0x15,
|
|
0xc3, 0xa6, 0xf0, 0xc3, 0xc7, 0xf0, 0xc3, 0x06,
|
|
0xf4, 0xc3, 0x09, 0xf4, 0xc3, 0x0c, 0xf4, 0xc3,
|
|
0x0f, 0xf4, 0xc3, 0x12, 0xf4, 0xc3, 0x15, 0xf4,
|
|
0xc3, 0x6b, 0xf1, 0xc3, 0x73, 0xf1, 0xc3, 0x6e,
|
|
0xf1, 0xc3, 0x7d, 0xf1, 0xc3, 0x82, 0xf1, 0xc3,
|
|
0x88, 0xf1, 0xc3, 0xc5, 0xf1, 0xc9, 0x00, 0x00,
|
|
0xc3, 0x64, 0xf1, 0xc3, 0x5a, 0xf2, 0x20, 0x33,
|
|
0x37, 0x31, 0x32, 0x2d, 0x56, 0x32, 0x31, 0x20,
|
|
0x28, 0x43, 0x29, 0x20, 0x4c, 0x49, 0x46, 0x45,
|
|
0x42, 0x4f, 0x41, 0x54, 0x20, 0x41, 0x53, 0x53,
|
|
0x4f, 0x43, 0x49, 0x41, 0x54, 0x45, 0x53, 0x20,
|
|
0x31, 0x39, 0x37, 0x39, 0x20, 0x21, 0xe0, 0xf3,
|
|
0xc3, 0x7f, 0xf0, 0x21, 0xf0, 0xf3, 0xc3, 0x7f,
|
|
0xf0, 0x21, 0x68, 0xf3, 0xc3, 0x7f, 0xf0, 0x31,
|
|
0x80, 0x00, 0xcd, 0x8f, 0xf2, 0x31, 0x80, 0x00,
|
|
0xcd, 0x5a, 0xf2, 0x0e, 0x00, 0xcd, 0x6e, 0xf1,
|
|
0x01, 0x80, 0x00, 0xcd, 0x82, 0xf1, 0xcd, 0x88,
|
|
0xf1, 0xc2, 0x88, 0xf0, 0x21, 0x00, 0xf4, 0xeb,
|
|
0x21, 0x10, 0xf0, 0xc3, 0x80, 0x00, 0x22, 0x40,
|
|
0xf4, 0x11, 0xf0, 0xff, 0x19, 0x11, 0x20, 0xf4,
|
|
0x06, 0x10, 0xcd, 0x86, 0xf2, 0x11, 0x80, 0xff,
|
|
0x19, 0xaf, 0x32, 0x48, 0xf4, 0xcd, 0x4f, 0xf1,
|
|
0xaf, 0x32, 0x04, 0x00, 0xc3, 0x28, 0xf1, 0x31,
|
|
0x00, 0x01, 0xcd, 0x5a, 0xf2, 0x0e, 0x00, 0xcd,
|
|
0x6e, 0xf1, 0x2a, 0x40, 0xf4, 0x11, 0x00, 0xeb,
|
|
0x19, 0x24, 0x3e, 0x04, 0xcd, 0xf7, 0xf0, 0x0e,
|
|
0x01, 0xcd, 0x6e, 0xf1, 0x2a, 0x40, 0xf4, 0x11,
|
|
0x00, 0xeb, 0x19, 0x11, 0x80, 0x0c, 0x19, 0x3e,
|
|
0x01, 0xcd, 0xf7, 0xf0, 0xc3, 0x28, 0xf1, 0x32,
|
|
0x32, 0xf4, 0x22, 0x33, 0xf4, 0x3a, 0x41, 0xf4,
|
|
0x3d, 0xbc, 0xda, 0x0b, 0xf1, 0xcd, 0x88, 0xf1,
|
|
0xc2, 0xc7, 0xf0, 0x2a, 0x33, 0xf4, 0x11, 0x80,
|
|
0x01, 0x19, 0x3a, 0x32, 0xf4, 0xc6, 0x03, 0xfe,
|
|
0x1b, 0xda, 0xf7, 0xf0, 0xd6, 0x1a, 0x11, 0x00,
|
|
0xf3, 0x19, 0xfe, 0x01, 0xc2, 0xf7, 0xf0, 0xc9,
|
|
0x01, 0x80, 0x00, 0xcd, 0x82, 0xf1, 0x3e, 0xc3,
|
|
0x32, 0x00, 0x00, 0x32, 0x05, 0x00, 0x2a, 0x40,
|
|
0xf4, 0x23, 0x23, 0x23, 0x22, 0x01, 0x00, 0x11,
|
|
0x03, 0xf3, 0x19, 0x22, 0x06, 0x00, 0x3a, 0x04,
|
|
0x00, 0x4f, 0x11, 0xfa, 0xf7, 0x19, 0xe9, 0x7e,
|
|
0xb7, 0xc8, 0x4e, 0x23, 0xe5, 0xcd, 0x5c, 0xf1,
|
|
0xe1, 0xc3, 0x4f, 0xf1, 0x2a, 0x40, 0xf4, 0x11,
|
|
0x0c, 0x00, 0x19, 0xe9, 0x21, 0x00, 0xf4, 0x06,
|
|
0x00, 0x09, 0xc9, 0xc3, 0x67, 0xf2, 0x79, 0x32,
|
|
0x31, 0xf4, 0xc9, 0x79, 0x32, 0x30, 0xf4, 0x3e,
|
|
0xff, 0x32, 0x27, 0xf4, 0xc9, 0x79, 0x32, 0x32,
|
|
0xf4, 0xc9, 0x60, 0x69, 0x22, 0x33, 0xf4, 0xc9,
|
|
0xcd, 0x0a, 0xf2, 0xc2, 0x06, 0xf2, 0x0e, 0x0a,
|
|
0x3e, 0x03, 0xcd, 0x71, 0xf2, 0xe6, 0x28, 0xca,
|
|
0xa4, 0xf1, 0xcd, 0x7e, 0xf2, 0x0d, 0xc2, 0x90,
|
|
0xf1, 0xc3, 0x06, 0xf2, 0x2a, 0x33, 0xf4, 0x0e,
|
|
0x80, 0x3e, 0x40, 0xd3, 0xc0, 0xdb, 0xc0, 0x77,
|
|
0x23, 0xaf, 0xd3, 0xc0, 0x0d, 0x3e, 0x41, 0xd3,
|
|
0xc0, 0xdb, 0xc0, 0x77, 0x23, 0xaf, 0xd3, 0xc0,
|
|
0x0d, 0xc2, 0xb5, 0xf1, 0xc9, 0xcd, 0x0a, 0xf2,
|
|
0xc2, 0x06, 0xf2, 0x2a, 0x33, 0xf4, 0x0e, 0x80,
|
|
0x7e, 0xd3, 0xc1, 0x3e, 0x31, 0xd3, 0xc0, 0xaf,
|
|
0xd3, 0xc0, 0x23, 0x0d, 0xc2, 0xd0, 0xf1, 0x0e,
|
|
0x0a, 0x3e, 0x05, 0xcd, 0x71, 0xf2, 0xe6, 0x20,
|
|
0xca, 0xf1, 0xf1, 0xcd, 0x7e, 0xf2, 0xc3, 0x06,
|
|
0xf2, 0x3a, 0x2f, 0xf4, 0xe6, 0x40, 0xc8, 0x3e,
|
|
0x07, 0xcd, 0x71, 0xf2, 0xe6, 0x28, 0xc8, 0xcd,
|
|
0x7e, 0xf2, 0x0d, 0xc2, 0xe1, 0xf1, 0x3e, 0x01,
|
|
0xb7, 0xc9, 0xaf, 0xd3, 0xc1, 0x3e, 0x15, 0xcd,
|
|
0x80, 0xf2, 0xcd, 0x19, 0xf2, 0xcd, 0x2d, 0xf2,
|
|
0xc9, 0x3a, 0x30, 0xf4, 0xe6, 0x03, 0x0f, 0x0f,
|
|
0x4f, 0x3a, 0x32, 0xf4, 0xb1, 0xd3, 0xc1, 0x3e,
|
|
0x21, 0xcd, 0x80, 0xf2, 0xc9, 0x0e, 0x02, 0x3a,
|
|
0x31, 0xf4, 0x21, 0x27, 0xf4, 0xbe, 0xc8, 0x77,
|
|
0x3a, 0x31, 0xf4, 0xd3, 0xc1, 0x3e, 0x11, 0xcd,
|
|
0x80, 0xf2, 0x3e, 0x09, 0xcd, 0x71, 0xf2, 0xe6,
|
|
0x28, 0xc8, 0xcd, 0x7e, 0xf2, 0x36, 0xff, 0x0d,
|
|
0xc2, 0x2d, 0xf2, 0xcd, 0x62, 0xf2, 0x3e, 0x02,
|
|
0xb7, 0xc9, 0xaf, 0x32, 0x30, 0xf4, 0x3c, 0x32,
|
|
0x32, 0xf4, 0x3e, 0x81, 0xcd, 0x80, 0xf2, 0xcd,
|
|
0x19, 0xf2, 0x3e, 0xff, 0x32, 0x27, 0xf4, 0x3e,
|
|
0x0d, 0xcd, 0x80, 0xf2, 0xdb, 0xc0, 0xe6, 0x01,
|
|
0xc2, 0x74, 0xf2, 0xdb, 0xc0, 0xc9, 0x3e, 0x0b,
|
|
0xd3, 0xc0, 0xaf, 0xd3, 0xc0, 0xc9, 0x7e, 0x12,
|
|
0x23, 0x13, 0x05, 0xc2, 0x86, 0xf2, 0xc9, 0x11,
|
|
0x00, 0xf4, 0x06, 0x08, 0x3e, 0xc3, 0x12, 0x13,
|
|
0x7e, 0x12, 0x23, 0x13, 0x7e, 0x12, 0x23, 0x13,
|
|
0x05, 0xc2, 0x94, 0xf2, 0xc9, 0x3e, 0x03, 0xd3,
|
|
0x10, 0x3e, 0x11, 0xd3, 0x10, 0xc9, 0xdb, 0x10,
|
|
0xe6, 0x01, 0x3e, 0x00, 0xc8, 0x2f, 0xc9, 0xdb,
|
|
0x10, 0xe6, 0x01, 0xca, 0xb7, 0xf2, 0xdb, 0x11,
|
|
0xe6, 0x7f, 0xca, 0xb7, 0xf2, 0xc9, 0xdb, 0x10,
|
|
0xe6, 0x02, 0xca, 0xc6, 0xf2, 0x79, 0xd3, 0x11,
|
|
0xc9, 0xc9, 0xc9, 0xdb, 0x00, 0xe6, 0x01, 0x3e,
|
|
0x00, 0xc0, 0x2f, 0xc9, 0xdb, 0x00, 0xe6, 0x01,
|
|
0xc2, 0xdc, 0xf2, 0xdb, 0x01, 0xe6, 0x7f, 0xca,
|
|
0xdc, 0xf2, 0xc9, 0xdb, 0x00, 0xe6, 0x80, 0xc2,
|
|
0xeb, 0xf2, 0x79, 0xd3, 0x01, 0xc9, 0x3a, 0x48,
|
|
0xf4, 0xb7, 0xc2, 0x0c, 0xf3, 0x3e, 0x11, 0xd3,
|
|
0x03, 0xaf, 0xd3, 0x02, 0x32, 0x47, 0xf4, 0x3e,
|
|
0x84, 0x32, 0x48, 0xf4, 0x79, 0xfe, 0x0a, 0xc2,
|
|
0x1a, 0xf3, 0x32, 0x49, 0xf4, 0x3a, 0x47, 0xf4,
|
|
0xb7, 0xc8, 0x79, 0xfe, 0x08, 0xca, 0x4f, 0xf3,
|
|
0xfe, 0x09, 0xca, 0x5a, 0xf3, 0xfe, 0x0d, 0xca,
|
|
0x38, 0xf3, 0xd8, 0x3a, 0x47, 0xf4, 0x3c, 0xe5,
|
|
0x21, 0x48, 0xf4, 0xbe, 0xe1, 0xc2, 0x48, 0xf3,
|
|
0x3a, 0x47, 0xf4, 0xb7, 0xc2, 0x47, 0xf3, 0x3a,
|
|
0x49, 0xf4, 0xfe, 0x0d, 0xc8, 0x0e, 0x0a, 0xaf,
|
|
0x32, 0x47, 0xf4, 0x79, 0x32, 0x49, 0xf4, 0xdb,
|
|
0x02, 0xe6, 0x11, 0xca, 0x4f, 0xf3, 0x79, 0xd3,
|
|
0x03, 0xc9, 0x0e, 0x20, 0xcd, 0x0c, 0xf3, 0x3a,
|
|
0x47, 0xf4, 0xe6, 0x07, 0xc2, 0x5a, 0xf3, 0xc9,
|
|
0xa8, 0xf3, 0xd2, 0xf2, 0xa1, 0xf3, 0x78, 0xf3,
|
|
0x8e, 0xf3, 0xf6, 0xf2, 0x8e, 0xf3, 0x78, 0xf3,
|
|
0xcd, 0x84, 0xf3, 0xca, 0x78, 0xf3, 0x7e, 0xe6,
|
|
0x7f, 0x36, 0x00, 0xc9, 0x21, 0x4b, 0xf4, 0x7e,
|
|
0xb7, 0xcc, 0x1f, 0xc0, 0x77, 0xc9, 0x3a, 0x4a,
|
|
0xf4, 0xfe, 0x0d, 0xc2, 0x98, 0xf3, 0xb9, 0xc8,
|
|
0x79, 0x32, 0x4a, 0xf4, 0x41, 0xcd, 0x19, 0xc0,
|
|
0xc9, 0xcd, 0x84, 0xf3, 0xc8, 0x3e, 0xff, 0xc9,
|
|
0x21, 0x00, 0x00, 0x22, 0x4a, 0xf4, 0xc9, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xd1, 0xf2, 0xd2, 0xf2, 0xd3, 0xf2, 0xdc, 0xf2,
|
|
0xeb, 0xf2, 0xf6, 0xf2, 0xeb, 0xf2, 0xdc, 0xf2,
|
|
0xa5, 0xf2, 0xd2, 0xf2, 0xae, 0xf2, 0xb7, 0xf2,
|
|
0xc6, 0xf2, 0xf6, 0xf2, 0xc6, 0xf2, 0xb7, 0xf2,
|
|
};
|
|
|
|
static uint8 icom_3812_prom[ICOM_PROM_SIZE] = {
|
|
0xc3, 0x46, 0xf0, 0x06, 0x80, 0x7e, 0x12, 0x23,
|
|
0x13, 0x05, 0xc2, 0x05, 0xf0, 0xc9, 0xff, 0x3a,
|
|
0xc3, 0x6d, 0xf0, 0xc3, 0x8a, 0xf0, 0x79, 0x32,
|
|
0x31, 0xf4, 0xc9, 0x79, 0x32, 0x32, 0xf4, 0xc9,
|
|
0x60, 0x69, 0x22, 0x33, 0xf4, 0xc9, 0xff, 0xff,
|
|
0xc3, 0x08, 0xf1, 0xc3, 0x14, 0xf1, 0xc3, 0x16,
|
|
0xf0, 0xc3, 0x1b, 0xf0, 0xc3, 0x20, 0xf0, 0xc3,
|
|
0x30, 0xf1, 0xc3, 0x7b, 0xf1, 0xc3, 0x21, 0xf1,
|
|
0xc3, 0x61, 0xf3, 0xc3, 0xa4, 0xf3, 0x31, 0x80,
|
|
0x00, 0xcd, 0xa4, 0xf3, 0x21, 0x00, 0x00, 0x22,
|
|
0x30, 0xf4, 0x0e, 0x01, 0xcd, 0x1b, 0xf0, 0x21,
|
|
0x80, 0x00, 0x22, 0x33, 0xf4, 0xcd, 0x30, 0xf1,
|
|
0xc2, 0x46, 0xf0, 0x21, 0x00, 0xf4, 0xeb, 0x21,
|
|
0x10, 0xf0, 0xc3, 0x80, 0x00, 0x22, 0x40, 0xf4,
|
|
0x11, 0xf0, 0xff, 0x19, 0x11, 0x20, 0xf4, 0x06,
|
|
0x10, 0xcd, 0x05, 0xf0, 0x11, 0x80, 0xff, 0x19,
|
|
0xcd, 0xdf, 0xf3, 0xaf, 0x32, 0x04, 0x00, 0xc3,
|
|
0xe1, 0xf0, 0x31, 0x00, 0x01, 0xcd, 0xa4, 0xf3,
|
|
0x21, 0x00, 0x01, 0x22, 0x30, 0xf4, 0x2a, 0x40,
|
|
0xf4, 0x11, 0x00, 0xeb, 0x19, 0x3e, 0x01, 0x4f,
|
|
0xc5, 0x32, 0x32, 0xf4, 0x22, 0x33, 0xf4, 0x7c,
|
|
0x2a, 0x40, 0xf4, 0xbc, 0xd2, 0xb5, 0xf0, 0xcd,
|
|
0x30, 0xf1, 0xc2, 0x8a, 0xf0, 0xc1, 0x79, 0x0f,
|
|
0x79, 0x2a, 0x33, 0xf4, 0xda, 0xc3, 0xf0, 0xc6,
|
|
0x04, 0x24, 0x24, 0x3c, 0x11, 0x80, 0x00, 0x19,
|
|
0xfe, 0x35, 0xda, 0xdc, 0xf0, 0xd6, 0x34, 0xfe,
|
|
0x03, 0x2a, 0x40, 0xf4, 0x11, 0x00, 0xec, 0x19,
|
|
0xca, 0xdc, 0xf0, 0x24, 0xfe, 0x01, 0xc2, 0x9f,
|
|
0xf0, 0x01, 0x80, 0x00, 0xcd, 0x20, 0xf0, 0x3e,
|
|
0xc3, 0x32, 0x00, 0x00, 0x32, 0x05, 0x00, 0x2a,
|
|
0x40, 0xf4, 0x23, 0x23, 0x23, 0x22, 0x01, 0x00,
|
|
0x11, 0x03, 0xf3, 0x19, 0x22, 0x06, 0x00, 0x3a,
|
|
0x04, 0x00, 0x4f, 0x11, 0xfa, 0xf7, 0x19, 0xe9,
|
|
0xcd, 0x21, 0xf1, 0x3a, 0x30, 0xf4, 0x32, 0x3d,
|
|
0xf4, 0xc3, 0xb6, 0xf3, 0x79, 0x32, 0x30, 0xf4,
|
|
0xcd, 0x21, 0xf1, 0x3e, 0xff, 0x32, 0x27, 0xf4,
|
|
0xc9, 0x3a, 0x39, 0xf4, 0x3c, 0xc8, 0xcd, 0x6f,
|
|
0xf2, 0xc5, 0xcd, 0xf2, 0xf1, 0xc1, 0xc9, 0x11,
|
|
0xcd, 0x6f, 0xf2, 0xcd, 0x57, 0xf3, 0xca, 0x5a,
|
|
0xf1, 0x21, 0x30, 0xf4, 0x11, 0x39, 0xf4, 0xcd,
|
|
0x2b, 0xf2, 0xc2, 0x4e, 0xf1, 0x1a, 0xbe, 0xc2,
|
|
0x4e, 0xf1, 0xcd, 0xf2, 0xf1, 0xc0, 0x21, 0x30,
|
|
0xf4, 0x11, 0x35, 0xf4, 0xcd, 0x2b, 0xf2, 0xca,
|
|
0x64, 0xf1, 0x21, 0x30, 0xf4, 0xcd, 0x22, 0xf2,
|
|
0xcd, 0x46, 0xf2, 0xc0, 0xcd, 0x57, 0xf3, 0xca,
|
|
0x71, 0xf1, 0x3a, 0x32, 0xf4, 0x3c, 0x0f, 0xe6,
|
|
0x80, 0x2a, 0x33, 0xf4, 0xeb, 0xcd, 0x9d, 0xf2,
|
|
0xc8, 0xc3, 0x11, 0xcd, 0x6f, 0xf2, 0xcd, 0x57,
|
|
0xf3, 0x2a, 0x33, 0xf4, 0xca, 0xb0, 0xf1, 0x21,
|
|
0x30, 0xf4, 0x11, 0x39, 0xf4, 0xcd, 0x2b, 0xf2,
|
|
0xc2, 0xbf, 0xf1, 0x1a, 0xbe, 0xca, 0xc3, 0xf1,
|
|
0x3e, 0xff, 0x32, 0x39, 0xf4, 0x2a, 0x33, 0xf4,
|
|
0xe5, 0x2a, 0x2c, 0xf4, 0x3a, 0x3b, 0xf4, 0x0f,
|
|
0xda, 0xac, 0xf1, 0xe3, 0xcd, 0xf7, 0xf2, 0xe1,
|
|
0xcd, 0xf7, 0xf2, 0x21, 0x30, 0xf4, 0xcd, 0x22,
|
|
0xf2, 0xcd, 0x63, 0xf2, 0xc9, 0x2f, 0xfe, 0xcd,
|
|
0xf2, 0xf1, 0xc0, 0x21, 0x30, 0xf4, 0x11, 0x39,
|
|
0xf4, 0xcd, 0x25, 0xf2, 0x2a, 0x2c, 0xf4, 0xeb,
|
|
0x2a, 0x33, 0xf4, 0xcd, 0x03, 0xf0, 0x2a, 0x40,
|
|
0xf4, 0x11, 0x09, 0xf5, 0x19, 0x11, 0xf2, 0xf1,
|
|
0xd5, 0x7e, 0xfe, 0x10, 0xc8, 0xfe, 0x13, 0xc8,
|
|
0xfe, 0x16, 0xc8, 0xfe, 0x17, 0xc8, 0xd1, 0xaf,
|
|
0xc9, 0x0e, 0x21, 0x39, 0xf4, 0x7e, 0x3c, 0xc8,
|
|
0xcd, 0x22, 0xf2, 0x3e, 0xff, 0x32, 0x39, 0xf4,
|
|
0xcd, 0x46, 0xf2, 0xc0, 0x3a, 0x3b, 0xf4, 0x0f,
|
|
0xd2, 0x18, 0xf2, 0xcd, 0xf4, 0xf2, 0xcd, 0xb8,
|
|
0xf2, 0xcd, 0x0a, 0xf3, 0xca, 0x1e, 0xf2, 0x11,
|
|
0xcd, 0x0a, 0xf3, 0xcd, 0xf4, 0xf2, 0xcd, 0x63,
|
|
0xf2, 0xc9, 0x11, 0x3d, 0xf4, 0x06, 0x03, 0xc3,
|
|
0x05, 0xf0, 0x06, 0x1a, 0xb7, 0xf8, 0xbe, 0xc0,
|
|
0x23, 0x13, 0x1a, 0xbe, 0xc0, 0x23, 0x13, 0x7e,
|
|
0x3c, 0x0f, 0xe6, 0x7f, 0x4f, 0x1a, 0x3c, 0x0f,
|
|
0xe6, 0x7f, 0xb9, 0xc9, 0xfe, 0x21, 0x3e, 0xff,
|
|
0x32, 0x35, 0xf4, 0xaf, 0x32, 0x38, 0xf4, 0xcd,
|
|
0x82, 0xf2, 0x3e, 0x01, 0xc0, 0x21, 0x3d, 0xf4,
|
|
0x11, 0x35, 0xf4, 0xcd, 0x25, 0xf2, 0x78, 0xc8,
|
|
0xc3, 0x7a, 0xf1, 0x3e, 0xff, 0x32, 0x35, 0xf4,
|
|
0xcd, 0xcf, 0xf2, 0xc8, 0x3e, 0x01, 0xc9, 0xd1,
|
|
0x21, 0x00, 0x00, 0x39, 0x31, 0x80, 0xf4, 0xe5,
|
|
0x21, 0x7e, 0xf2, 0xe5, 0xeb, 0xe9, 0xe1, 0xf9,
|
|
0xc9, 0x21, 0xcd, 0x28, 0xf3, 0xc2, 0x99, 0xf2,
|
|
0x0e, 0x05, 0x3e, 0x03, 0xcd, 0xca, 0xf3, 0xe6,
|
|
0x08, 0xc8, 0xcd, 0xd7, 0xf3, 0x0d, 0xc2, 0x8a,
|
|
0xf2, 0x3e, 0x01, 0xb7, 0xc9, 0x21, 0x38, 0xf4,
|
|
0xbe, 0xc4, 0xb8, 0xf2, 0x06, 0x80, 0x3e, 0x40,
|
|
0xd3, 0xc0, 0xdb, 0xc0, 0x12, 0x13, 0x34, 0x05,
|
|
0xc2, 0xaa, 0xf2, 0xaf, 0xd3, 0xc0, 0xc8, 0x11,
|
|
0x06, 0x80, 0x21, 0x38, 0xf4, 0x3e, 0x40, 0xd3,
|
|
0xc0, 0xdb, 0xc0, 0x34, 0x05, 0xc2, 0xc1, 0xf2,
|
|
0x78, 0xd3, 0xc0, 0xc8, 0xcd, 0x17, 0xf2, 0xcd,
|
|
0x28, 0xf3, 0xc2, 0x99, 0xf2, 0x0e, 0x05, 0x3e,
|
|
0x05, 0xcd, 0xca, 0xf3, 0x3a, 0x2f, 0xf4, 0xe6,
|
|
0x40, 0xc8, 0x3e, 0x07, 0xcd, 0xca, 0xf3, 0xe6,
|
|
0x08, 0xc8, 0xcd, 0xd7, 0xf3, 0x0d, 0xc2, 0xd7,
|
|
0xf2, 0xc3, 0x99, 0xf2, 0x2a, 0x2c, 0xf4, 0x06,
|
|
0x80, 0x3e, 0x30, 0xd3, 0xc0, 0x7e, 0xd3, 0xc1,
|
|
0x23, 0x05, 0xc2, 0xfd, 0xf2, 0x78, 0xd3, 0xc0,
|
|
0xc8, 0x0e, 0x06, 0x80, 0x3e, 0x40, 0xd3, 0xc0,
|
|
0xdb, 0xc0, 0x4f, 0xaf, 0xd3, 0xc0, 0x3e, 0x30,
|
|
0xd3, 0xc0, 0x79, 0xd3, 0xc1, 0xaf, 0xd3, 0xc0,
|
|
0x05, 0xc2, 0x0c, 0xf3, 0xc9, 0xcd, 0xb7, 0xf2,
|
|
0x16, 0x05, 0xcd, 0x3f, 0xf3, 0xd3, 0xc1, 0x3e,
|
|
0x21, 0xcd, 0xd9, 0xf3, 0xcd, 0x6b, 0xf3, 0xc8,
|
|
0x15, 0xc2, 0x2a, 0xf3, 0xc3, 0x99, 0xf2, 0x2a,
|
|
0x3d, 0xf4, 0x7d, 0x0f, 0x0f, 0x5f, 0xcd, 0x5a,
|
|
0xf3, 0x3a, 0x3f, 0xf4, 0xca, 0x53, 0xf3, 0x3c,
|
|
0x0f, 0xe6, 0x3f, 0xb3, 0xc9, 0x06, 0x0b, 0x2a,
|
|
0x30, 0xf4, 0x7c, 0xb7, 0xc8, 0x3e, 0x28, 0x85,
|
|
0x4f, 0x21, 0x00, 0xf4, 0x06, 0x00, 0x09, 0x7e,
|
|
0xe6, 0x02, 0xc9, 0x3a, 0x3e, 0xf4, 0x21, 0x27,
|
|
0xf4, 0xbe, 0xc8, 0x77, 0x5f, 0x2a, 0x3d, 0xf4,
|
|
0xcd, 0x5a, 0xf3, 0xca, 0x80, 0xf3, 0x3e, 0x10,
|
|
0xd3, 0xc1, 0x3e, 0x15, 0xcd, 0xd9, 0xf3, 0x7b,
|
|
0xb7, 0x3e, 0x0d, 0xca, 0x98, 0xf3, 0x7b, 0xd3,
|
|
0xc1, 0x3e, 0x11, 0xcd, 0xd9, 0xf3, 0x3e, 0x09,
|
|
0xcd, 0xca, 0xf3, 0xe6, 0x28, 0xc8, 0xcd, 0xb1,
|
|
0xf3, 0xc3, 0x99, 0xf2, 0x3e, 0xff, 0x32, 0x39,
|
|
0xf4, 0xaf, 0x32, 0x3d, 0xf4, 0x3c, 0x32, 0x3f,
|
|
0xf4, 0x3e, 0x81, 0xcd, 0xd9, 0xf3, 0xcd, 0x3f,
|
|
0xf3, 0xd3, 0xc1, 0x3e, 0x21, 0xcd, 0xd9, 0xf3,
|
|
0x3e, 0xff, 0x32, 0x27, 0xf4, 0x32, 0x35, 0xf4,
|
|
0x3e, 0x0d, 0xcd, 0xd9, 0xf3, 0xdb, 0xc0, 0xe6,
|
|
0x01, 0xc2, 0xcd, 0xf3, 0xdb, 0xc0, 0xc9, 0x3e,
|
|
0x0b, 0xd3, 0xc0, 0xaf, 0xd3, 0xc0, 0xc9, 0x7e,
|
|
0xb7, 0xc8, 0x4e, 0xe5, 0xcd, 0xec, 0xf3, 0xe1,
|
|
0x23, 0xc3, 0xdf, 0xf3, 0x2a, 0x40, 0xf4, 0x2e,
|
|
0x0c, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
};
|
|
|
|
static uint8 *icom_prom = icom_3812_prom; /* default is 3812 */
|
|
|
|
/*
|
|
** ICOM Registers and Interface Controls
|
|
*/
|
|
typedef struct {
|
|
uint8 status; /* Status Register */
|
|
uint8 track; /* Track Register */
|
|
uint8 sector; /* Sector Register */
|
|
uint8 command; /* Command Register */
|
|
uint8 rData; /* Read Data Register */
|
|
uint32 rDataBuf; /* Read buffer index */
|
|
uint8 wData; /* Write Data Register */
|
|
uint32 wDataBuf; /* Write buffer index */
|
|
uint8 formatMode; /* format mode */
|
|
uint16 bytesPerSec; /* bytes per sector */
|
|
} ICOM_REG;
|
|
|
|
/* iCOM Registers */
|
|
#define ICOM_REG_COMMAND 0x00
|
|
#define ICOM_REG_DATAI 0x00
|
|
#define ICOM_REG_DATAO 0x01
|
|
|
|
/* iCOM Commands */
|
|
#define ICOM_CMD_STATUS 0x00
|
|
#define ICOM_CMD_CMDMSK 0x01
|
|
#define ICOM_CMD_READ 0x03
|
|
#define ICOM_CMD_WRITE 0x05
|
|
#define ICOM_CMD_READCRC 0x07
|
|
#define ICOM_CMD_SEEK 0x09
|
|
#define ICOM_CMD_CLRERRFLGS 0x0b
|
|
#define ICOM_CMD_TRACK0 0x0d
|
|
#define ICOM_CMD_WRITEDDM 0x0f
|
|
#define ICOM_CMD_LDTRACK 0x11
|
|
#define ICOM_CMD_LDUNITSEC 0x21
|
|
#define ICOM_CMD_LDWRITEBUFNOP 0x30
|
|
#define ICOM_CMD_LDWRITEBUF 0x31
|
|
#define ICOM_CMD_EXREADBUF 0x40
|
|
#define ICOM_CMD_SHREADBUF 0x41
|
|
#define ICOM_CMD_CLEAR 0x81
|
|
#define ICOM_CMD_LDCONF 0x15
|
|
|
|
#define ICOM_STAT_BUSY 0x01
|
|
#define ICOM_STAT_UNITMSK 0x06
|
|
#define ICOM_STAT_CRC 0x08
|
|
#define ICOM_STAT_WRITEPROT 0x10
|
|
#define ICOM_STAT_DRVFAIL 0x20
|
|
#define ICOM_STAT_MEDIASTAT 0x40
|
|
#define ICOM_STAT_DDM 0x80
|
|
|
|
#define ICOM_CONF_DD 0x10 /* Double Density */
|
|
#define ICOM_CONF_FM 0x20 /* Format Mode */
|
|
|
|
#define ICOM_TYPE_3712 0x00
|
|
#define ICOM_TYPE_3812 0x01
|
|
|
|
typedef struct {
|
|
uint32 mem_base; /* Memory Base Address */
|
|
uint32 mem_size; /* Memory Address space requirement */
|
|
uint32 io_base; /* I/O Base Address */
|
|
uint32 io_size; /* I/O Address Space requirement */
|
|
uint32 prom_base; /* Boot PROM Base Address */
|
|
uint32 prom_size; /* Boot PROM Address space requirement */
|
|
uint8 promEnabled; /* PROM is enabled */
|
|
uint8 boardType; /* Interface Board Type */
|
|
uint8 rwsMs; /* Read/Write Sector ms */
|
|
uint8 seekMs; /* Seek ms */
|
|
uint8 currentDrive; /* Currently selected drive */
|
|
uint8 currentTrack[ICOM_MAX_DRIVES];
|
|
uint8 mediaDen[ICOM_MAX_DRIVES];
|
|
uint32 msTime; /* MS time for BUSY */
|
|
ICOM_REG ICOM; /* ICOM Registers and Data */
|
|
UNIT *uptr[ICOM_MAX_DRIVES];
|
|
} ICOM_INFO;
|
|
|
|
static ICOM_INFO icom_info_data = {
|
|
ICOM_MEM_BASE, ICOM_MEM_SIZE, ICOM_IO_BASE, ICOM_IO_SIZE, ICOM_PROM_BASE, ICOM_PROM_SIZE,
|
|
TRUE, ICOM_TYPE_3812, 6, 10
|
|
};
|
|
|
|
static ICOM_INFO *icom_info = &icom_info_data;
|
|
|
|
/*
|
|
** Read and Write Data Ring Buffers
|
|
*/
|
|
#define DATA_MASK ICOM_DD_SECTOR_LEN-1
|
|
|
|
static uint8 rdata[ICOM_DD_SECTOR_LEN];
|
|
static uint8 wdata[ICOM_DD_SECTOR_LEN];
|
|
|
|
/* Local function prototypes */
|
|
static t_stat icom_reset(DEVICE *icom_dev);
|
|
static t_stat icom_svc(UNIT *uptr);
|
|
static t_stat icom_attach(UNIT *uptr, CONST char *cptr);
|
|
static t_stat icom_detach(UNIT *uptr);
|
|
static t_stat icom_boot(int32 unitno, DEVICE *dptr);
|
|
static t_stat icom_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
static t_stat icom_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
static t_stat icom_set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
static t_stat icom_show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
static t_stat icom_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
static t_stat icom_show_type(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
|
static uint32 calculate_icom_sec_offset(ICOM_REG *pICOM, uint8 track, uint8 sector);
|
|
static void icom_set_busy(uint32 msec);
|
|
static int icom_set_crc(uint8 drive);
|
|
static uint8 ICOM_Read(uint32 Addr);
|
|
static uint8 ICOM_Write(uint32 Addr, int32 data);
|
|
static const char * ICOM_CommandString(uint8 command);
|
|
static uint8 ICOM_Command(UNIT *uptr, ICOM_REG *pICOM, int32 data);
|
|
static uint32 ICOM_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer);
|
|
static uint32 ICOM_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer);
|
|
static uint32 ICOM_FormatTrack(UNIT *uptr, uint8 track, uint8 *buffer);
|
|
static uint8 ICOM_DriveNotReady(UNIT *uptr, ICOM_REG *pICOM);
|
|
static const char* icom_description(DEVICE *dptr);
|
|
static void showReadSec(void);
|
|
static void showWriteSec(void);
|
|
static int32 icomdev(int32 Addr, int32 rw, int32 data);
|
|
static int32 icomprom(int32 Addr, int32 rw, int32 data);
|
|
static int32 icommem(int32 Addr, int32 rw, int32 data);
|
|
|
|
static UNIT icom_unit[ICOM_MAX_DRIVES] = {
|
|
{ UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 },
|
|
{ UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 },
|
|
{ UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 },
|
|
{ UDATA (icom_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, ICOM_DD_CAPACITY), 10000 }
|
|
};
|
|
|
|
static REG icom_reg[] = {
|
|
{ DRDATAD (DRIVE, icom_info_data.currentDrive, 8, "Current drive register"), },
|
|
{ HRDATAD (STATUS, icom_info_data.ICOM.status, 8, "Status register"), },
|
|
{ HRDATAD (COMMAND, icom_info_data.ICOM.command, 8, "Command register"), },
|
|
{ HRDATAD (RDATA, icom_info_data.ICOM.rData, 8, "Read Data register"), },
|
|
{ HRDATAD (WDATA, icom_info_data.ICOM.wData, 8, "Write Data register"), },
|
|
{ DRDATAD (TRACK, icom_info_data.ICOM.track, 8, "Track register"), },
|
|
{ DRDATAD (SECTOR, icom_info_data.ICOM.sector, 8, "Sector register"), },
|
|
{ DRDATAD (RBUF, icom_info_data.ICOM.rDataBuf, 16, "Read data buffer index register"), },
|
|
{ DRDATAD (WBUF, icom_info_data.ICOM.wDataBuf, 16, "Write data buffer index register"), },
|
|
{ DRDATAD (FORMAT, icom_info_data.ICOM.formatMode, 8, "Current format mode register"), },
|
|
{ DRDATAD (DENSITY, icom_info_data.ICOM.bytesPerSec, 16, "Current density register"), },
|
|
{ FLDATAD (PROM, icom_info_data.promEnabled, 0, "PROM enabled bit"), },
|
|
{ DRDATAD (RWSMS, icom_info_data.rwsMs, 8, "Read/Write sector time (ms)"), },
|
|
{ DRDATAD (SEEKMS, icom_info_data.seekMs, 8, "Seek track to track time (ms)"), },
|
|
{ NULL }
|
|
};
|
|
|
|
#define ICOM_NAME "iCOM 3712/3812 Floppy Disk System"
|
|
#define ICOM_SNAME "ICOM"
|
|
|
|
static const char* icom_description(DEVICE *dptr) {
|
|
return ICOM_NAME;
|
|
}
|
|
|
|
#define UNIT_V_ICOM_WPROTECT (UNIT_V_UF + 1) /* WRTENB / WRTPROT */
|
|
#define UNIT_ICOM_WPROTECT (1 << UNIT_V_ICOM_WPROTECT)
|
|
|
|
static MTAB icom_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
|
&set_iobase, &show_iobase, NULL, "Sets interface board I/O base address" },
|
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
|
&icom_set_membase, &icom_show_membase, NULL, "Shows interface board memory base address" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "PROM", "PROM={ENABLE|DISABLE}",
|
|
&icom_set_prom, &icom_show_prom, NULL, "Set/Show PROM enabled/disabled status"},
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "TYPE", "TYPE={3712|3812}",
|
|
&icom_set_type, &icom_show_type, NULL, "Set/Show the current controller type" },
|
|
{ UNIT_ICOM_WPROTECT, 0, "WRTENB", "WRTENB", NULL, NULL, NULL,
|
|
"Enables " ICOM_SNAME "n for writing" },
|
|
{ UNIT_ICOM_WPROTECT, UNIT_ICOM_WPROTECT, "WRTPROT", "WRTPROT", NULL, NULL, NULL,
|
|
"Protects " ICOM_SNAME "n from writing" },
|
|
{ 0 }
|
|
};
|
|
|
|
/* Debug flags */
|
|
#define VERBOSE_MSG (1 << 0)
|
|
#define ERROR_MSG (1 << 1)
|
|
#define RBUF_MSG (1 << 2)
|
|
#define WBUF_MSG (1 << 3)
|
|
#define CMD_MSG (1 << 4)
|
|
#define RD_DATA_MSG (1 << 5)
|
|
#define WR_DATA_MSG (1 << 6)
|
|
#define STATUS_MSG (1 << 7)
|
|
#define RD_DATA_DETAIL_MSG (1 << 8)
|
|
#define WR_DATA_DETAIL_MSG (1 << 9)
|
|
|
|
/* Debug Flags */
|
|
static DEBTAB icom_dt[] = {
|
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
|
{ "CMD", CMD_MSG, "Command messages" },
|
|
{ "RBUF", RBUF_MSG, "Read Buffer messages" },
|
|
{ "WBUF", WBUF_MSG, "Write Buffer messages" },
|
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
|
{ "RDDETAIL", RD_DATA_DETAIL_MSG, "Read detail messages" },
|
|
{ "WRDETAIL", WR_DATA_DETAIL_MSG, "Write detail messags" },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
DEVICE icom_dev = {
|
|
ICOM_SNAME, /* name */
|
|
icom_unit, /* unit */
|
|
icom_reg, /* registers */
|
|
icom_mod, /* modifiers */
|
|
ICOM_MAX_DRIVES, /* # units */
|
|
10, /* address radix */
|
|
31, /* address width */
|
|
1, /* addr increment */
|
|
ICOM_MAX_DRIVES, /* data radix */
|
|
ICOM_MAX_DRIVES, /* data width */
|
|
NULL, /* examine routine */
|
|
NULL, /* deposit routine */
|
|
&icom_reset, /* reset routine */
|
|
&icom_boot, /* boot routine */
|
|
&icom_attach, /* attach routine */
|
|
&icom_detach, /* detach routine */
|
|
&icom_info_data, /* context */
|
|
(DEV_DISABLE | DEV_DIS | DEV_DEBUG), /* flags */
|
|
ERROR_MSG, /* debug control */
|
|
icom_dt, /* debug flags */
|
|
NULL, /* mem size routine */
|
|
NULL, /* logical name */
|
|
NULL, /* help */
|
|
NULL, /* attach help */
|
|
NULL, /* context for help */
|
|
&icom_description /* description */
|
|
};
|
|
|
|
/* Reset routine */
|
|
static t_stat icom_reset(DEVICE *dptr)
|
|
{
|
|
uint8 i;
|
|
|
|
if (dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
|
|
sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", TRUE);
|
|
sim_map_resource(icom_info->mem_base, icom_info->mem_size, RESOURCE_TYPE_MEMORY, &icommem, "icommem", TRUE);
|
|
sim_map_resource(icom_info->io_base, icom_info->io_size, RESOURCE_TYPE_IO, &icomdev, "icomdev", TRUE);
|
|
} else {
|
|
if (sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "Error mapping PROM resource at 0x%04x\n", icom_info->prom_base);
|
|
return SCPE_ARG;
|
|
}
|
|
if (sim_map_resource(icom_info->mem_base, icom_info->mem_size, RESOURCE_TYPE_MEMORY, &icommem, "icommem", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "Error mapping MEM resource at 0x%04x\n", icom_info->mem_base);
|
|
return SCPE_ARG;
|
|
}
|
|
/* Connect I/O Ports at base address */
|
|
if (sim_map_resource(icom_info->io_base, icom_info->io_size, RESOURCE_TYPE_IO, &icomdev, "icomdev", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "Error mapping I/O resource at 0x%02x\n", icom_info->io_base);
|
|
return SCPE_ARG;
|
|
}
|
|
}
|
|
|
|
icom_info->currentDrive = 0;
|
|
|
|
icom_info->ICOM.track = 0;
|
|
icom_info->ICOM.sector = 1;
|
|
icom_info->ICOM.command = 0;
|
|
icom_info->ICOM.status = 0;
|
|
icom_info->ICOM.rData = 0;
|
|
icom_info->ICOM.wData = 0;
|
|
icom_info->ICOM.rDataBuf = 0;
|
|
icom_info->ICOM.wDataBuf = 0;
|
|
icom_info->ICOM.bytesPerSec = ICOM_SD_SECTOR_LEN;
|
|
icom_info->ICOM.formatMode = 0;
|
|
|
|
/* Reset Registers and Interface Controls */
|
|
for (i=0; i < ICOM_MAX_DRIVES; i++) {
|
|
if (icom_info->uptr[i] == NULL) {
|
|
icom_info->uptr[i] = &icom_dev.units[i];
|
|
}
|
|
|
|
icom_info->currentTrack[i] = 0;
|
|
}
|
|
|
|
sim_debug(STATUS_MSG, &icom_dev, "reset controller.\n");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Service routine */
|
|
static t_stat icom_svc(UNIT *uptr)
|
|
{
|
|
icom_info->ICOM.status &= ~ICOM_STAT_BUSY;
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Attach routine */
|
|
static t_stat icom_attach(UNIT *uptr, CONST char *cptr)
|
|
{
|
|
t_stat r;
|
|
unsigned int i = 0;
|
|
|
|
r = attach_unit(uptr, cptr); /* attach unit */
|
|
if (r != SCPE_OK) { /* error? */
|
|
sim_debug(ERROR_MSG, &icom_dev, "ATTACH error=%d\n", r);
|
|
return r;
|
|
}
|
|
|
|
/* Determine length of this disk */
|
|
if (sim_fsize(uptr->fileref) != 0) {
|
|
uptr->capac = sim_fsize(uptr->fileref);
|
|
} else {
|
|
uptr->capac = ICOM_SD_CAPACITY;
|
|
}
|
|
|
|
for (i = 0; i < ICOM_MAX_DRIVES; i++) {
|
|
if (icom_dev.units[i].fileref == uptr->fileref) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= ICOM_MAX_DRIVES) {
|
|
icom_detach(uptr);
|
|
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
/* used for the generation of CRC errors */
|
|
icom_info->mediaDen[i] = (uptr->capac == ICOM_DD_CAPACITY);
|
|
|
|
/* Default for new file is DSK */
|
|
uptr->u3 = IMAGE_TYPE_DSK;
|
|
|
|
sim_debug(VERBOSE_MSG, uptr->dptr, "unit %d, attached to '%s' size=%d interface=%s\n",
|
|
i, cptr, uptr->capac, (icom_info->boardType == ICOM_TYPE_3712) ? "FD3712" : "FD3812");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Detach routine */
|
|
static t_stat icom_detach(UNIT *uptr)
|
|
{
|
|
t_stat r;
|
|
int8 i;
|
|
|
|
for (i = 0; i < ICOM_MAX_DRIVES; i++) {
|
|
if (icom_dev.units[i].fileref == uptr->fileref) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= ICOM_MAX_DRIVES) {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
DBG_PRINT(("Detach ICOM%d\n", i));
|
|
|
|
r = detach_unit(uptr); /* detach unit */
|
|
|
|
if (r != SCPE_OK) {
|
|
return r;
|
|
}
|
|
|
|
icom_dev.units[i].fileref = NULL;
|
|
|
|
sim_debug(VERBOSE_MSG, uptr->dptr, "unit %d detached.\n", i);
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/*
|
|
** If membase is 0, remove from system
|
|
*/
|
|
static t_stat icom_set_membase(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
uint32 newba;
|
|
t_stat r;
|
|
|
|
if (cptr == NULL) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "cptr=NULL\n");
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
newba = get_uint(cptr, 16, 0xFFFF, &r);
|
|
|
|
if (r != SCPE_OK) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "get_uint=%d\n", r);
|
|
return r;
|
|
}
|
|
|
|
if (newba) {
|
|
r = set_membase(uptr, val, cptr, desc);
|
|
if (r) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "Error setting MEM resource at 0x%04x\n", icom_info->mem_base);
|
|
icom_info->mem_base = 0;
|
|
}
|
|
else {
|
|
sim_debug(VERBOSE_MSG, &icom_dev, "memory now at 0x%04x\n", icom_info->mem_base);
|
|
icom_info->mem_base = newba;
|
|
}
|
|
}
|
|
else if (icom_info->mem_base) {
|
|
sim_map_resource(icom_info->mem_base, icom_info->mem_size, RESOURCE_TYPE_MEMORY, &icommem, "icommem", TRUE);
|
|
icom_info->mem_base = 0;
|
|
sim_debug(VERBOSE_MSG, &icom_dev, "disabled memory at 0x%04x\n", icom_info->mem_base);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/* Show Base Address routine */
|
|
t_stat icom_show_membase(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
if (icom_info->mem_base) {
|
|
fprintf(st, "MEM=0x%04X-0x%04X", icom_info->mem_base, icom_info->mem_base+icom_info->mem_size-1);
|
|
}
|
|
|
|
if (icom_info->promEnabled) {
|
|
if (icom_info->mem_base) {
|
|
fprintf(st, ", ");
|
|
}
|
|
fprintf(st, "PROM=0x%04X-0x%04X", icom_info->prom_base, icom_info->prom_base+icom_info->prom_size-1);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat icom_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
if (!cptr) return SCPE_IERR;
|
|
|
|
if (!strcmp(cptr, "3812")) {
|
|
icom_info->boardType = ICOM_TYPE_3812;
|
|
icom_info->ICOM.status |= ICOM_STAT_MEDIASTAT;
|
|
icom_prom = icom_3812_prom;
|
|
} else if (!strcmp(cptr, "3712")) {
|
|
icom_info->boardType = ICOM_TYPE_3712;
|
|
icom_info->ICOM.status &= ~ICOM_STAT_MEDIASTAT;
|
|
icom_info->ICOM.bytesPerSec = ICOM_SD_SECTOR_LEN;
|
|
icom_prom = icom_3712_prom;
|
|
} else {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat icom_show_type(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
fprintf(st, "TYPE=%s", (icom_info->boardType == ICOM_TYPE_3812) ? "3812" : "3712");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat icom_set_prom(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
if (!cptr) return SCPE_IERR;
|
|
if (!strlen(cptr)) return SCPE_ARG;
|
|
|
|
/* this assumes that the parameter has already been upcased */
|
|
if (!strncmp(cptr, "ENABLE", strlen(cptr))) {
|
|
if (sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", FALSE) != 0) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "Error mapping MEM resource at 0x%04x\n", icom_info->prom_base);
|
|
return SCPE_ARG;
|
|
}
|
|
icom_info->promEnabled = TRUE;
|
|
} else if (!strncmp(cptr, "DISABLE", strlen(cptr))) {
|
|
sim_map_resource(icom_info->prom_base, icom_info->prom_size, RESOURCE_TYPE_MEMORY, &icomprom, "icomprom", TRUE);
|
|
icom_info->promEnabled = FALSE;
|
|
} else {
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat icom_show_prom(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
|
{
|
|
fprintf(st, "%s", (icom_info->promEnabled) ? "PROM" : "NOPROM");
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static t_stat icom_boot(int32 unitno, DEVICE *dptr)
|
|
{
|
|
sim_debug(VERBOSE_MSG, dptr, "Booting using PROM at 0x%04x\n", icom_info->prom_base);
|
|
|
|
*((int32 *) sim_PC->loc) = icom_info->prom_base;
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static void icom_set_busy(uint32 msec)
|
|
{
|
|
icom_info->ICOM.status |= ICOM_STAT_BUSY;
|
|
|
|
if (!msec) {
|
|
msec = 1;
|
|
}
|
|
|
|
icom_info->msTime = sim_os_msec();
|
|
|
|
sim_activate_after_abs(icom_info->uptr[icom_info->currentDrive], msec * 1000); /* activate timer */
|
|
}
|
|
|
|
/* Set CRC flag if trying to read/write wrong density */
|
|
static int icom_set_crc(uint8 drive)
|
|
{
|
|
uint8 track;
|
|
|
|
track = icom_info->currentTrack[drive];
|
|
|
|
icom_info->ICOM.status &= ~ICOM_STAT_CRC;
|
|
|
|
/* If formatting, CRC is always good */
|
|
if (icom_info->ICOM.formatMode) {
|
|
return 0;
|
|
}
|
|
|
|
/* If reading double density from track 0, set CRC error */
|
|
/* Else, if reading a density different than attached disk, set CRC error */
|
|
if (track == 0 && icom_info->ICOM.bytesPerSec != ICOM_SD_SECTOR_LEN) {
|
|
icom_info->ICOM.status |= ICOM_STAT_CRC;
|
|
} else if (track > 0) {
|
|
if ((icom_info->mediaDen[drive] && icom_info->ICOM.bytesPerSec != ICOM_DD_SECTOR_LEN) ||
|
|
(!icom_info->mediaDen[drive] && icom_info->ICOM.bytesPerSec != ICOM_SD_SECTOR_LEN)) {
|
|
icom_info->ICOM.status |= ICOM_STAT_CRC;
|
|
}
|
|
}
|
|
|
|
return (icom_info->ICOM.status & ICOM_STAT_CRC);
|
|
}
|
|
|
|
static int32 icomdev(int32 Addr, int32 rw, int32 data)
|
|
{
|
|
if (rw == 0) {
|
|
return(ICOM_Read(Addr));
|
|
} else {
|
|
return(ICOM_Write(Addr, data));
|
|
}
|
|
}
|
|
|
|
static void showReadSec()
|
|
{
|
|
int i;
|
|
ICOM_REG *pICOM;
|
|
|
|
pICOM = &icom_info->ICOM;
|
|
|
|
sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "rdata unit %d track/sector %02d/%02d:\n", icom_info->currentDrive, pICOM->track, pICOM->sector);
|
|
|
|
for (i=0; i < pICOM->bytesPerSec; i++) {
|
|
if (((i) & 0xf) == 0) {
|
|
sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "\t");
|
|
}
|
|
sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "%02X ", rdata[i]);
|
|
if (((i+1) & 0xf) == 0) {
|
|
sim_debug(RD_DATA_DETAIL_MSG, &icom_dev, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void showWriteSec()
|
|
{
|
|
int i;
|
|
ICOM_REG *pICOM;
|
|
|
|
pICOM = &icom_info->ICOM;
|
|
|
|
sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "wdata unit %d track/sector %02d/%02d:\n", icom_info->currentDrive, pICOM->track, pICOM->sector);
|
|
|
|
for (i=0; i < pICOM->bytesPerSec; i++) {
|
|
if (((i) & 0xf) == 0) {
|
|
sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "\t");
|
|
}
|
|
sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "%02X ", wdata[i]);
|
|
if (((i+1) & 0xf) == 0) {
|
|
sim_debug(WR_DATA_DETAIL_MSG, &icom_dev, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32 calculate_icom_sec_offset(ICOM_REG *pICOM, uint8 track, uint8 sector)
|
|
{
|
|
uint32 offset;
|
|
uint16 bps;
|
|
|
|
bps = pICOM->bytesPerSec;
|
|
|
|
/*
|
|
** Calculate track offset
|
|
*/
|
|
if (track==0) {
|
|
offset=0;
|
|
}
|
|
else {
|
|
offset=ICOM_SPT * ICOM_SD_SECTOR_LEN; /* Track 0 always SD */
|
|
offset+=(track-1) * ICOM_SPT * bps; /* Track 1-77 SD or DD */
|
|
}
|
|
|
|
/*
|
|
** Add sector offset to track offset
|
|
*/
|
|
offset += (sector-1) * bps;
|
|
|
|
DBG_PRINT(("ICOM: offset calc drive=%d bps=%d track=%d sector=%d offset=%04x\n", icom_info->currentDrive, bps, track, sector, offset));
|
|
|
|
return (offset);
|
|
}
|
|
|
|
static uint8 ICOM_Read(uint32 Addr)
|
|
{
|
|
uint8 cData;
|
|
uint8 driveNum;
|
|
ICOM_REG *pICOM;
|
|
UNIT *uptr;
|
|
|
|
driveNum = icom_info->currentDrive;
|
|
uptr = icom_info->uptr[driveNum];
|
|
pICOM = &icom_info->ICOM;
|
|
|
|
switch(Addr & 0x01) {
|
|
case ICOM_REG_DATAI:
|
|
if (pICOM->command & ICOM_CMD_EXREADBUF) {
|
|
pICOM->rData = rdata[pICOM->rDataBuf];
|
|
sim_debug(RBUF_MSG, &icom_dev, "read buffer[%d]=%02x\n", pICOM->rDataBuf, pICOM->rData);
|
|
if (icom_info->boardType == ICOM_TYPE_3812) {
|
|
ICOM_Command(uptr, pICOM, ICOM_CMD_SHREADBUF);
|
|
}
|
|
cData = pICOM->rData;
|
|
}
|
|
else {
|
|
cData = pICOM->status;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
sim_debug(ERROR_MSG, &icom_dev, "READ Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x01);
|
|
cData = 0xff;
|
|
break;
|
|
}
|
|
|
|
return (cData);
|
|
}
|
|
|
|
static uint8 ICOM_Write(uint32 Addr, int32 Data)
|
|
{
|
|
uint8 cData;
|
|
uint8 driveNum;
|
|
UNIT *uptr;
|
|
ICOM_REG *pICOM;
|
|
|
|
cData = 0;
|
|
driveNum = icom_info->currentDrive;
|
|
uptr = icom_info->uptr[driveNum];
|
|
pICOM = &icom_info->ICOM;
|
|
|
|
switch(Addr & 0x01) {
|
|
case ICOM_REG_COMMAND:
|
|
cData = ICOM_Command(uptr, pICOM, Data);
|
|
break;
|
|
|
|
case ICOM_REG_DATAO:
|
|
pICOM->wData = Data;
|
|
|
|
if (pICOM->command == ICOM_CMD_LDWRITEBUFNOP && icom_info->boardType == ICOM_TYPE_3812) {
|
|
ICOM_Command(uptr, pICOM, ICOM_CMD_LDWRITEBUF);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
sim_debug(ERROR_MSG, &icom_dev, "WRITE Invalid I/O Address %02x (%02x)\n", Addr & 0xFF, Addr & 0x01);
|
|
cData = 0xff;
|
|
break;
|
|
}
|
|
|
|
return(cData);
|
|
}
|
|
|
|
static uint32 ICOM_ReadSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
|
|
{
|
|
uint32 sec_offset;
|
|
uint32 rtn = 0;
|
|
ICOM_REG *pICOM;
|
|
|
|
pICOM = &icom_info->ICOM;
|
|
|
|
if (uptr->fileref == NULL) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "uptr.fileref is NULL!\n");
|
|
return 0;
|
|
}
|
|
|
|
sec_offset = calculate_icom_sec_offset(pICOM, track, sector);
|
|
|
|
sim_debug(RD_DATA_MSG, &icom_dev, "track %d sector %d at offset %04X\n", track, sector, sec_offset);
|
|
|
|
if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "sim_fseek error.\n");
|
|
return 0;
|
|
}
|
|
|
|
rtn = sim_fread(buffer, 1, pICOM->bytesPerSec, uptr->fileref);
|
|
|
|
sim_debug(RD_DATA_MSG, &icom_dev, "read %d bytes at offset %04X\n", rtn, sec_offset);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
|
|
static uint32 ICOM_WriteSector(UNIT *uptr, uint8 track, uint8 sector, uint8 *buffer)
|
|
{
|
|
uint32 sec_offset;
|
|
uint32 rtn = 0;
|
|
ICOM_REG *pICOM;
|
|
|
|
pICOM = &icom_info->ICOM;
|
|
|
|
if (uptr->fileref == NULL) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "uptr.fileref is NULL!\n");
|
|
return 0;
|
|
}
|
|
|
|
sec_offset = calculate_icom_sec_offset(pICOM, track, sector);
|
|
|
|
sim_debug(WR_DATA_MSG, &icom_dev, "track %d sector %d bytes %d at offset %04X\n", track, sector, pICOM->bytesPerSec, sec_offset);
|
|
|
|
if (sim_fseek(uptr->fileref, sec_offset, SEEK_SET) != 0) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "sim_fseek error.\n");
|
|
return 0;
|
|
}
|
|
|
|
rtn = sim_fwrite(buffer, 1, pICOM->bytesPerSec, uptr->fileref);
|
|
|
|
sim_debug(WR_DATA_MSG, &icom_dev, "wrote %d bytes at offset %04X\n", rtn, sec_offset);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
static uint32 ICOM_FormatTrack(UNIT *uptr, uint8 track, uint8 *buffer)
|
|
{
|
|
uint8 sector;
|
|
uint32 rtn;
|
|
|
|
for (sector = 1; sector <= ICOM_SPT; sector++) {
|
|
rtn = ICOM_WriteSector(uptr, track, sector, buffer);
|
|
sim_debug(WR_DATA_MSG, &icom_dev, "FORMAT track %d sector %d\n", track, sector);
|
|
}
|
|
|
|
/* update disk density when formatting */
|
|
icom_info->mediaDen[icom_info->currentDrive] = (icom_info->ICOM.bytesPerSec == ICOM_DD_SECTOR_LEN);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
static uint8 ICOM_DriveNotReady(UNIT *uptr, ICOM_REG *pICOM)
|
|
{
|
|
pICOM->status &= ~ICOM_STAT_DRVFAIL;
|
|
|
|
if ((uptr == NULL) || (uptr->fileref == NULL)) {
|
|
pICOM->status |= ICOM_STAT_DRVFAIL;
|
|
sim_debug(STATUS_MSG, &icom_dev, "Drive: %d not attached.\n", icom_info->currentDrive);
|
|
}
|
|
|
|
return (pICOM->status & ICOM_STAT_DRVFAIL);
|
|
}
|
|
|
|
static const char * ICOM_CommandString(uint8 command)
|
|
{
|
|
switch (command) {
|
|
case ICOM_CMD_STATUS:
|
|
return "STATUS";
|
|
|
|
case ICOM_CMD_READ:
|
|
return "READ";
|
|
|
|
case ICOM_CMD_WRITE:
|
|
return "WRITE";
|
|
|
|
case ICOM_CMD_READCRC:
|
|
return "READ CRC";
|
|
|
|
case ICOM_CMD_SEEK:
|
|
return "SEEK";
|
|
|
|
case ICOM_CMD_CLRERRFLGS:
|
|
return "CLR ERR FLAGS";
|
|
|
|
case ICOM_CMD_TRACK0:
|
|
return "TRACK 0";
|
|
|
|
case ICOM_CMD_WRITEDDM:
|
|
return "WRITE DDM";
|
|
|
|
case ICOM_CMD_LDTRACK:
|
|
return "LD TRACK";
|
|
|
|
case ICOM_CMD_LDUNITSEC:
|
|
return "LD UNIT/SEC";
|
|
|
|
case ICOM_CMD_LDWRITEBUFNOP:
|
|
return "LD WR BUF NOP";
|
|
|
|
case ICOM_CMD_LDWRITEBUF:
|
|
return "LD WR BUF";
|
|
|
|
case ICOM_CMD_EXREADBUF:
|
|
return "EX RD BUF";
|
|
|
|
case ICOM_CMD_SHREADBUF:
|
|
return "SHFT RD BUF";
|
|
|
|
case ICOM_CMD_CLEAR:
|
|
return "CLEAR";
|
|
|
|
case ICOM_CMD_LDCONF:
|
|
return "LD CONFIG";
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return "UNRECOGNIZED COMMAND";
|
|
}
|
|
|
|
static uint8 ICOM_Command(UNIT *uptr, ICOM_REG *pICOM, int32 Data)
|
|
{
|
|
uint8 cData;
|
|
uint8 newTrack;
|
|
int32 rtn;
|
|
|
|
cData = 0;
|
|
|
|
if (uptr == NULL) {
|
|
return cData;
|
|
}
|
|
|
|
pICOM->command = Data;
|
|
|
|
ICOM_DriveNotReady(uptr, pICOM); /* Update not ready status */
|
|
|
|
switch(pICOM->command) {
|
|
case ICOM_CMD_STATUS:
|
|
pICOM->rData = pICOM->status;
|
|
break;
|
|
|
|
case ICOM_CMD_READ:
|
|
if (pICOM->status & ICOM_STAT_DRVFAIL || icom_set_crc(icom_info->currentDrive)) {
|
|
break;
|
|
}
|
|
|
|
rtn = ICOM_ReadSector(uptr, pICOM->track, pICOM->sector, rdata);
|
|
|
|
if (rtn == pICOM->bytesPerSec) {
|
|
showReadSec();
|
|
icom_set_busy(icom_info->rwsMs);
|
|
}
|
|
else {
|
|
sim_debug(ERROR_MSG, &icom_dev, "sim_fread errno=%d\n", errno);
|
|
|
|
pICOM->status |= ICOM_STAT_DRVFAIL;
|
|
}
|
|
|
|
pICOM->rDataBuf = 0; // Reset read buffer address
|
|
|
|
break;
|
|
|
|
case ICOM_CMD_WRITEDDM:
|
|
sim_debug(VERBOSE_MSG, &icom_dev, "DDM writes not supported. Performing standard write.\n");
|
|
|
|
/* fall into ICOM_CMD_WRITE */
|
|
|
|
case ICOM_CMD_WRITE:
|
|
if (uptr->flags & UNIT_ICOM_WPROTECT) {
|
|
sim_debug(ERROR_MSG, &icom_dev, "Disk '%s' write protected.\n", uptr->filename);
|
|
break;
|
|
}
|
|
|
|
if (pICOM->status & ICOM_STAT_DRVFAIL || icom_set_crc(icom_info->currentDrive)) {
|
|
break;
|
|
}
|
|
|
|
/*
|
|
** If format mode, format entire track with wdata
|
|
*/
|
|
if (pICOM->formatMode) {
|
|
rtn = ICOM_FormatTrack(uptr, pICOM->track, wdata);
|
|
}
|
|
else {
|
|
rtn = ICOM_WriteSector(uptr, pICOM->track, pICOM->sector, wdata);
|
|
}
|
|
|
|
if (rtn == pICOM->bytesPerSec) {
|
|
showWriteSec();
|
|
icom_set_busy(icom_info->rwsMs);
|
|
}
|
|
else {
|
|
sim_debug(ERROR_MSG, &icom_dev, "sim_fwrite errno=%d\n", errno);
|
|
|
|
pICOM->status |= ICOM_STAT_DRVFAIL;
|
|
}
|
|
|
|
pICOM->wDataBuf = 0; // Reset write buffer address
|
|
break;
|
|
|
|
case ICOM_CMD_READCRC:
|
|
if (pICOM->status & ICOM_STAT_DRVFAIL) {
|
|
break;
|
|
}
|
|
icom_set_crc(icom_info->currentDrive);
|
|
icom_set_busy(icom_info->rwsMs);
|
|
break;
|
|
|
|
case ICOM_CMD_SEEK:
|
|
if (pICOM->status & ICOM_STAT_DRVFAIL) {
|
|
break;
|
|
}
|
|
|
|
icom_set_busy(icom_info->seekMs * abs((int8) pICOM->track - (int8) icom_info->currentTrack[icom_info->currentDrive]));
|
|
icom_info->currentTrack[icom_info->currentDrive] = pICOM->track;
|
|
|
|
break;
|
|
|
|
case ICOM_CMD_CLRERRFLGS:
|
|
pICOM->status &= ~ICOM_STAT_BUSY;
|
|
pICOM->status &= ~ICOM_STAT_DDM;
|
|
break;
|
|
|
|
case ICOM_CMD_TRACK0:
|
|
if (pICOM->status & ICOM_STAT_DRVFAIL) {
|
|
break;
|
|
}
|
|
|
|
pICOM->track = 0;
|
|
icom_set_busy(icom_info->seekMs * abs((int8) pICOM->track - (int8) icom_info->currentTrack[icom_info->currentDrive]));
|
|
icom_info->currentTrack[icom_info->currentDrive] = 0;
|
|
|
|
break;
|
|
|
|
case ICOM_CMD_LDTRACK:
|
|
newTrack = pICOM->wData;
|
|
|
|
if (newTrack < ICOM_TRACKS) {
|
|
pICOM->track = newTrack;
|
|
}
|
|
|
|
break;
|
|
|
|
case ICOM_CMD_LDUNITSEC:
|
|
pICOM->sector = pICOM->wData & 0x1f;
|
|
icom_info->currentDrive = pICOM->wData >> 6;
|
|
pICOM->status &= ~ICOM_STAT_UNITMSK;
|
|
pICOM->status |= icom_info->currentDrive << 1;
|
|
break;
|
|
|
|
case ICOM_CMD_LDWRITEBUFNOP:
|
|
sim_debug(WBUF_MSG, &icom_dev, "LOAD WRITE BUF NOP index=%04x\n", pICOM->wDataBuf);
|
|
break;
|
|
|
|
case ICOM_CMD_LDWRITEBUF:
|
|
sim_debug(WBUF_MSG, &icom_dev, "LOAD WRITE BUF %d=%02x\n", pICOM->wDataBuf, pICOM->wData);
|
|
wdata[pICOM->wDataBuf] = pICOM->wData;
|
|
pICOM->wDataBuf++;
|
|
pICOM->wDataBuf &= DATA_MASK;
|
|
break;
|
|
|
|
case ICOM_CMD_EXREADBUF:
|
|
sim_debug(RBUF_MSG, &icom_dev, "EXAMINE READ BUF index=%04x\n", pICOM->rDataBuf);
|
|
break;
|
|
|
|
case ICOM_CMD_SHREADBUF:
|
|
pICOM->rDataBuf++;
|
|
pICOM->rDataBuf &= DATA_MASK;
|
|
sim_debug(RBUF_MSG, &icom_dev, "SHIFT READ BUF index=%04x\n", pICOM->rDataBuf);
|
|
break;
|
|
|
|
case ICOM_CMD_CLEAR:
|
|
pICOM->status &= ~ICOM_STAT_BUSY;
|
|
pICOM->status &= ~ICOM_STAT_DRVFAIL;
|
|
pICOM->status &= ~ICOM_STAT_CRC;
|
|
pICOM->status &= ~ICOM_STAT_DDM;
|
|
pICOM->rDataBuf = 0;
|
|
pICOM->wDataBuf = 0;
|
|
break;
|
|
|
|
case ICOM_CMD_LDCONF:
|
|
pICOM->formatMode = (pICOM->wData & ICOM_CONF_FM);
|
|
pICOM->bytesPerSec = (pICOM->wData & ICOM_CONF_DD) ? ICOM_DD_SECTOR_LEN : ICOM_SD_SECTOR_LEN;
|
|
break;
|
|
|
|
default:
|
|
cData=0xFF;
|
|
break;
|
|
}
|
|
|
|
/* Set WRITE PROTECT bit */
|
|
pICOM->status &= ~ICOM_STAT_WRITEPROT;
|
|
pICOM->status |= (uptr->flags & UNIT_ICOM_WPROTECT) ? ICOM_STAT_WRITEPROT : 0;
|
|
|
|
/* Set data register to status if command bit 6 is 0 */
|
|
if (!(pICOM->command & 0x40)) {
|
|
pICOM->rData = pICOM->status;
|
|
}
|
|
|
|
/* Clear command bit 0 */
|
|
pICOM->command &= ~ICOM_CMD_CMDMSK;
|
|
|
|
sim_debug(CMD_MSG, &icom_dev,
|
|
"%-13.13s (%02Xh) unit=%d trk=%02d sec=%02d stat=%02Xh mediaDen=%d density=%d formatMode=%s\n",
|
|
ICOM_CommandString(Data),
|
|
Data, icom_info->currentDrive,
|
|
pICOM->track, pICOM->sector, pICOM->status,
|
|
icom_info->mediaDen[icom_info->currentDrive],
|
|
pICOM->bytesPerSec, (pICOM->formatMode) ? "TRUE" : "FALSE");
|
|
|
|
return(cData);
|
|
}
|
|
|
|
static int32 icomprom(int32 Addr, int32 rw, int32 Data)
|
|
{
|
|
/*
|
|
** The iCOM controller PROM occupies 1024 bytes (1K) of RAM at
|
|
** location F000H.
|
|
*/
|
|
if (icom_info->promEnabled == TRUE) {
|
|
return(icom_prom[Addr & ICOM_PROM_MASK]);
|
|
}
|
|
|
|
return 0xff;
|
|
}
|
|
|
|
static int32 icommem(int32 Addr, int32 rw, int32 Data)
|
|
{
|
|
if (rw) {
|
|
icom_mem[Addr & ICOM_MEM_MASK] = Data & 0xff;
|
|
}
|
|
|
|
return(icom_mem[Addr & ICOM_MEM_MASK]);
|
|
}
|
|
|