1 // license:BSD-3-Clause
2 // copyright-holders:Hans Ostermeyer, R. Belmont
3 /*
4 * omti8621.c - SMS OMTI 8621 disk controller (for Apollo DN3x00)
5 *
6 * Created on: August 30, 2010
7 * Author: Hans Ostermeyer
8 *
9 * Converted to ISA device by R. Belmont
10 *
11 * see also:
12 * * http://www.bitsavers.org/pdf/sms/pc/OMTI_AT_Controller_Series_Jan87.pdf
13 */
14
15 #include "emu.h"
16 #include "omti8621.h"
17 #include "image.h"
18 #include "formats/pc_dsk.h"
19 #include "formats/naslite_dsk.h"
20 #include "formats/apollo_dsk.h"
21
22 #define VERBOSE 0
23
24 static int verbose = VERBOSE;
25
26 #define LOG(x) { logerror ("%s: ", cpu_context()); logerror x; logerror ("\n"); }
27 #define LOG1(x) { if (verbose > 0) LOG(x)}
28 #define LOG2(x) { if (verbose > 1) LOG(x)}
29 #define LOG3(x) { if (verbose > 2) LOG(x)}
30
31 #define OMTI_DISK_SECTOR_SIZE 1056
32
33 #define OMTI_DISK_TYPE_155_MB 0x607 // Micropolis 1355 (170 MB Dtype = 607)
34 #define OMTI_DISK_TYPE_348_MB 0x604 // Maxtor EXT-4380-E (380 MB Dtype = 604)
35 #define OMTI_DISK_TYPE_DEFAULT OMTI_DISK_TYPE_348_MB // new disks will have this type (and size)
36
37 #define OMTI_MAX_BLOCK_COUNT 32
38
39 #define OMTI_DISK0_TAG "omti_disk0"
40 #define OMTI_DISK1_TAG "omti_disk1"
41
42 #define OMTI_FDC_TAG "omti_fdc"
43
44 #define OMTI_CPU_REGION "omti_cpu"
45 #define OMTI_BIOS_REGION "omti_bios"
46
47 // forward declaration of image class
48 DECLARE_DEVICE_TYPE(OMTI_DISK, omti_disk_image_device)
49
50 class omti_disk_image_device : public device_t,
51 public device_image_interface
52 {
53 public:
54 // construction/destruction
55 omti_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
56
57 // image-level overrides
image_type() const58 virtual iodevice_t image_type() const noexcept override { return IO_HARDDISK; }
59
is_readable() const60 virtual bool is_readable() const noexcept override { return true; }
is_writeable() const61 virtual bool is_writeable() const noexcept override { return true; }
is_creatable() const62 virtual bool is_creatable() const noexcept override { return true; }
must_be_loaded() const63 virtual bool must_be_loaded() const noexcept override { return false; }
is_reset_on_load() const64 virtual bool is_reset_on_load() const noexcept override { return false; }
support_command_line_image_creation() const65 virtual bool support_command_line_image_creation() const noexcept override { return true; }
file_extensions() const66 virtual const char *file_extensions() const noexcept override { return "awd"; }
custom_instance_name() const67 virtual const char *custom_instance_name() const noexcept override { return "winchester"; }
custom_brief_instance_name() const68 virtual const char *custom_brief_instance_name() const noexcept override { return "disk"; }
69
70 virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
71
72 protected:
73 // device-level overrides
74 virtual void device_start() override;
75 virtual void device_reset() override;
76
77 void omti_disk_config(uint16_t disk_type);
78
79 private:
80 template <typename Format, typename... Params> void logerror(Format &&fmt, Params &&... args) const;
81
82 public:
83 uint16_t m_type;
84 uint16_t m_cylinders;
85 uint16_t m_heads;
86 uint16_t m_sectors;
87 uint32_t m_sectorbytes;
88 uint32_t m_sector_count;
89
90 device_image_interface *m_image;
91
92 // configuration data
93 uint8_t m_config_data[10];
94
95 // ESDI defect list data
96 uint8_t m_esdi_defect_list[256];
97 };
98
99 /*
100 * I/O register offsets
101 */
102
103 #define OMTI_PORT_DATA_IN 0x00 /* read, 8-bit */
104 #define OMTI_PORT_DATA_OUT 0x00 /* write, 8-bit */
105 #define OMTI_PORT_STATUS 0x01 /* read, 8-bit */
106 #define OMTI_PORT_RESET 0x01 /* write, 8-bit */
107 #define OMTI_PORT_CONFIG 0x02 /* read, 8-bit */
108 #define OMTI_PORT_SELECT 0x02 /* write, 8-bit */
109 #define OMTI_PORT_MASK 0x03 /* write only, 8-bit */
110
111 // port status
112
113 #define OMTI_STATUS_REQ 0x01 // Request (1 = request transfer of data via data in/out register)
114 #define OMTI_STATUS_IO 0x02 // In/Out (1 = direction of transfer is from controller to host)
115 #define OMTI_STATUS_CD 0x04 // Command/Data ( 1 = byte transferred is command or status byte)
116 #define OMTI_STATUS_BUSY 0x08 // Busy (0 = controller is idle, 1 = controller selected)
117 #define OMTI_STATUS_DREQ 0x10 // Data Request (0 = no DMA request, 1 = DMA cycle requested)
118 #define OMTI_STATUS_IREQ 0x20 // Interrupt Request (0 = no interrupt, 1 = command complete)
119 #define OMTI_STATUS_NU6 0x40 // not used
120 #define OMTI_STATUS_NU7 0x80 // not used
121
122 #define OMTI_CONFIG_W23 0x01 // jumper W23
123 #define OMTI_CONFIG_W22 0x02 // jumper W22
124 #define OMTI_CONFIG_W21 0x04 // jumper W21
125 #define OMTI_CONFIG_W20 0x08 // jumper W20
126
127 #define OMTI_MASK_DMAE 0x01 // DMA enable
128 #define OMTI_MASK_INTE 0x02 // Interrupt enable
129
130 #define OMTI_COMMAND_STATUS_ERROR 0x02 // error bit
131 #define OMTI_COMMAND_STATUS_LUN 0x20 // drive 0 is 0
132
133 #define OMTI_SENSE_CODE_NO_ERROR 0x00
134 #define OMTI_SENSE_CODE_DRIVE_NOT_READY 0x04
135 #define OMTI_SENSE_CODE_ADDRESS_VALID 0x80
136 #define OMTI_SENSE_CODE_SECTOR_NOT_FOUND 0x14
137 #define OMTI_SENSE_CODE_ECC_ERROR 0x11
138 #define OMTI_SENSE_CODE_BAD_TRACK 0x19
139 #define OMTI_SENSE_CODE_ALTERNATE_TRACK 0x1C
140 #define OMTI_SENSE_CODE_INVALID_COMMAND 0x20
141 #define OMTI_SENSE_CODE_ILLEGAL_ADDRESS 0x21
142
143 enum {
144 OMTI_STATE_RESET,
145 OMTI_STATE_IDLE,
146 OMTI_STATE_SELECTION,
147 OMTI_STATE_COMMAND,
148 OMTI_STATE_DATA,
149 OMTI_STATE_STATUS
150 };
151
152 // OMTI commands
153
154 #define OMTI_CMD_TEST_DRIVE_READY 0x00
155 #define OMTI_CMD_RECALIBRATE 0x01
156
157 #define OMTI_CMD_REQUEST_SENSE 0x03
158 #define OMTI_CMD_FORMAT_DRIVEUNIT 0x04
159 #define OMTI_CMD_READ_VERIFY 0x05
160 #define OMTI_CMD_FORMAT_TRACK 0x06
161 #define OMTI_CMD_FORMAT_BAD_TRACK 0x07
162 #define OMTI_CMD_READ 0x08
163
164 #define OMTI_CMD_WRITE 0x0a
165 #define OMTI_CMD_SEEK 0x0b
166
167 #define OMTI_CMD_READ_SECTOR_BUFFER 0x0e
168 #define OMTI_CMD_WRITE_SECTOR_BUFFER 0x0f
169
170 #define OMTI_CMD_ASSIGN_ALTERNATE_TRACK 0x11
171
172 #define OMTI_CMD_READ_DATA_TO_BUFFER 0x1e
173 #define OMTI_CMD_WRITE_DATA_FROM_BUFFER 0x1f
174 #define OMTI_CMD_COPY 0x20
175
176 #define OMTI_CMD_READ_ESDI_DEFECT_LIST 0x37
177
178 #define OMTI_CMD_RAM_DIAGNOSTICS 0xe0
179 #define OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC 0xe4
180 #define OMTI_CMD_READ_LONG 0xe5
181 #define OMTI_CMD_WRITE_LONG 0xe6
182
183 #define OMTI_CMD_READ_CONFIGURATION 0xec
184 #define OMTI_CMD_INVALID_COMMAND 0xff
185
186 /***************************************************************************
187 cpu_context - return a string describing the current CPU context
188 ***************************************************************************/
189
cpu_context() const190 std::string omti8621_device::cpu_context() const
191 {
192 osd_ticks_t t = osd_ticks();
193 int s = (t / osd_ticks_per_second()) % 3600;
194 int ms = (t / (osd_ticks_per_second() / 1000)) % 1000;
195
196 return string_format("%d.%03d %s", s, ms, machine().describe_context());
197 }
198
pc_hd_floppies(device_slot_interface & device)199 static void pc_hd_floppies(device_slot_interface &device)
200 {
201 device.option_add("525hd", FLOPPY_525_HD);
202 device.option_add("35hd", FLOPPY_35_HD);
203 device.option_add("525dd", FLOPPY_525_DD);
204 device.option_add("35dd", FLOPPY_35_DD);
205 }
206
FLOPPY_FORMATS_MEMBER(omti8621_device::floppy_formats)207 FLOPPY_FORMATS_MEMBER( omti8621_device::floppy_formats )
208 FLOPPY_APOLLO_FORMAT,
209 FLOPPY_PC_FORMAT,
210 FLOPPY_NASLITE_FORMAT
211 FLOPPY_FORMATS_END
212
213 // this card has two EPROMs: a program for the on-board Z8 CPU,
214 // and a PC BIOS to make the card bootable on a PC.
215 // we have the Z8 program, we still need the PC BIOS.
216 ROM_START( omti8621 )
217 ROM_REGION(0x4000, OMTI_CPU_REGION, 0) // disassembles fine as Z8 code
218 ROM_LOAD( "omti_8621_102640-b.bin", 0x000000, 0x004000, CRC(e6f20dbb) SHA1(cf1990ad72eac6b296485410f5fa3309a0d6d078) )
219 ROM_REGION(0x1000, OMTI_BIOS_REGION, 0)
220 ROM_LOAD_OPTIONAL("omti_bios", 0x0000, 0x1000, NO_DUMP)
221 ROM_END
222
223 static INPUT_PORTS_START( omti_port )
224 PORT_START("IO_BASE")
225 PORT_DIPNAME( 0x07, 0x04, "ESDI I/O base")
226 PORT_DIPSETTING( 0x00, "0320h" )
227 PORT_DIPSETTING( 0x01, "0324h" )
228 PORT_DIPSETTING( 0x02, "0328h" )
229 PORT_DIPSETTING( 0x03, "032Ch" )
230 PORT_DIPSETTING( 0x04, "01A0h" )
231 PORT_DIPSETTING( 0x05, "01A4h" )
232 PORT_DIPSETTING( 0x06, "01A8h" )
233 PORT_DIPSETTING( 0x07, "01ACh" )
234 PORT_DIPNAME( 0x08, 0x00, "Floppy I/O base")
235 PORT_DIPSETTING( 0x00, "03F0h" )
236 PORT_DIPSETTING( 0x01, "0370h" )
237
238 PORT_START("BIOS_OPTS")
239 PORT_DIPNAME( 0x01, 0x00, "BIOS control")
240 PORT_DIPSETTING( 0x00, "Disabled" )
241 PORT_DIPSETTING( 0x01, "Enabled" )
242 PORT_DIPNAME( 0x02, 0x00, "BIOS base")
243 PORT_DIPSETTING( 0x00, "C8000h" )
244 PORT_DIPSETTING( 0x01, "CA000h" )
245 INPUT_PORTS_END
246
247 void omti8621_device::device_add_mconfig(machine_config &config)
248 {
249 OMTI_DISK(config, OMTI_DISK0_TAG, 0);
250 OMTI_DISK(config, OMTI_DISK1_TAG, 0);
251
252 UPD765A(config, m_fdc, 48_MHz_XTAL / 6, false, false); // clocked through FDC9239BT
253 m_fdc->intrq_wr_callback().set(FUNC(omti8621_device::fdc_irq_w));
254 m_fdc->drq_wr_callback().set(FUNC(omti8621_device::fdc_drq_w));
255 FLOPPY_CONNECTOR(config, m_floppy[0], pc_hd_floppies, "525hd", omti8621_device::floppy_formats);
256 FLOPPY_CONNECTOR(config, m_floppy[1], pc_hd_floppies, nullptr, omti8621_device::floppy_formats);
257 }
258
device_add_mconfig(machine_config & config)259 void omti8621_apollo_device::device_add_mconfig(machine_config &config)
260 {
261 omti8621_device::device_add_mconfig(config);
262
263 // Apollo workstations never have more then 1 floppy drive
264 config.device_remove(OMTI_FDC_TAG":1");
265 }
266
device_rom_region() const267 const tiny_rom_entry *omti8621_device::device_rom_region() const
268 {
269 return ROM_NAME( omti8621 );
270 }
271
device_rom_region() const272 const tiny_rom_entry *omti8621_apollo_device::device_rom_region() const
273 {
274 // OMTI 8621 boards for Apollo workstations never use a BIOS ROM
275 // They don't even have a socket for the BIOS ROM
276 return nullptr;
277 }
278
device_input_ports() const279 ioport_constructor omti8621_device::device_input_ports() const
280 {
281 return INPUT_PORTS_NAME( omti_port );
282 }
283
284 /*-------------------------------------------------
285 device start callback
286 -------------------------------------------------*/
287
device_start()288 void omti8621_device::device_start()
289 {
290 LOG2(("device_start"));
291
292 set_isa_device();
293
294 m_installed = false;
295
296 sector_buffer.resize(OMTI_DISK_SECTOR_SIZE*OMTI_MAX_BLOCK_COUNT);
297
298 m_timer = timer_alloc(0, nullptr);
299
300 our_disks[0] = subdevice<omti_disk_image_device>(OMTI_DISK0_TAG);
301 our_disks[1] = subdevice<omti_disk_image_device>(OMTI_DISK1_TAG);
302 }
303
304 /*-------------------------------------------------
305 device reset callback
306 -------------------------------------------------*/
307
device_reset()308 void omti8621_device::device_reset()
309 {
310 static const int io_bases[8] = { 0x320, 0x324, 0x328, 0x32c, 0x1a0, 0x1a4, 0x1a8, 0x1ac };
311
312 LOG2(("device_reset"));
313
314 // you can't read I/O ports in device_start() even if they're required_ioport<> in your class!
315 if (!m_installed)
316 {
317 int esdi_base = io_bases[m_iobase->read() & 7];
318
319 // install the ESDI ports
320 m_isa->install16_device(esdi_base, esdi_base + 7, read16s_delegate(*this, FUNC(omti8621_device::read)), write16s_delegate(*this, FUNC(omti8621_device::write)));
321
322 // and the onboard AT FDC ports
323 if (m_iobase->read() & 8)
324 {
325 m_isa->install_device(0x0370, 0x0377, *this, &omti8621_device::fdc_map);
326 }
327 else
328 {
329 m_isa->install_device(0x03f0, 0x03f7, *this, &omti8621_device::fdc_map);
330 }
331
332 m_isa->set_dma_channel(2, this, true);
333
334 m_installed = true;
335 }
336
337 set_jumper(our_disks[0]->m_type);
338
339 // should go from reset to idle after 100 us
340 // state->omti_state = OMTI_STATE_RESET;
341 omti_state = OMTI_STATE_IDLE;
342
343 status_port = OMTI_STATUS_NU6 | OMTI_STATUS_NU7;
344 config_port = ~jumper;
345 mask_port = 0;
346
347 // default the sector data buffer with model and status information
348 // (i.e. set sector data buffer for cmd=0x0e READ SECTOR BUFFER)
349
350 memset(§or_buffer[0], 0, OMTI_DISK_SECTOR_SIZE);
351 memcpy(§or_buffer[0], "8621VB.4060487xx", 0x10);
352 sector_buffer[0x10] = 0; // ROM Checksum error
353 sector_buffer[0x11] = 0; // Processor Register error
354 sector_buffer[0x12] = 0; // Buffer RAM error
355 sector_buffer[0x13] = 0; // Sequencer Register File error
356 sector_buffer[0x14] = 0xc0; // 32K buffer size
357 // TODO: add missing Default values for LUN 0, 1 and 3
358
359 command_length = 0;
360 command_index = 0;
361 command_status = 0;
362
363 data_index = 0;
364 data_length = 0;
365
366 clear_sense_data();
367
368 diskaddr_ecc_error = 0;
369 diskaddr_format_bad_track = 0;
370 alternate_track_address[0] = 0;
371 alternate_track_address[1] = 0;
372
373 fd_moten_w(0);
374 fd_rate_w(0);
375 fd_extra_w(0);
376 }
377
378 DEFINE_DEVICE_TYPE(ISA16_OMTI8621, omti8621_pc_device, "omti8621isa", "OMTI 8621 ESDI/floppy controller (ISA)")
379
omti8621_pc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)380 omti8621_pc_device::omti8621_pc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
381 : omti8621_device(mconfig, ISA16_OMTI8621, tag, owner, clock)
382 {
383 }
384
385 DEFINE_DEVICE_TYPE(ISA16_OMTI8621_APOLLO, omti8621_apollo_device, "omti8621ap", "OMTI 8621 ESDI/floppy controller (Apollo)")
386
omti8621_apollo_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)387 omti8621_apollo_device::omti8621_apollo_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
388 : omti8621_device(mconfig, ISA16_OMTI8621_APOLLO, tag, owner, clock)
389 {
390 }
391
omti8621_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)392 omti8621_device::omti8621_device(
393 const machine_config &mconfig,
394 device_type type,
395 const char *tag,
396 device_t *owner,
397 uint32_t clock)
398 : device_t(mconfig, type, tag, owner, clock)
399 , device_isa16_card_interface(mconfig, *this)
400 , m_fdc(*this, OMTI_FDC_TAG)
401 , m_floppy(*this, OMTI_FDC_TAG":%u", 0U)
402 , m_iobase(*this, "IO_BASE")
403 , m_biosopts(*this, "BIOS_OPTS")
404 , jumper(0), omti_state(0), status_port(0), config_port(0), mask_port(0), command_length(0), command_index(0), command_status(0), data_buffer(nullptr)
405 , data_length(0), data_index(0), diskaddr_ecc_error(0), diskaddr_format_bad_track(0), m_timer(nullptr), m_moten(0), m_installed(false)
406 {
407 }
408
409 /*-------------------------------------------------
410 set_interrupt - update the IRQ state
411 -------------------------------------------------*/
412
set_interrupt(enum line_state line_state)413 void omti8621_device::set_interrupt(enum line_state line_state)
414 {
415 LOG2(("set_interrupt: status_port=%x, line_state %d", status_port, line_state));
416 m_isa->irq14_w(line_state);
417 }
418
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)419 void omti8621_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
420 {
421 set_interrupt(ASSERT_LINE);
422 }
423
424 /***************************************************************************
425 clear_sense_data - clear the sense data
426 ***************************************************************************/
427
clear_sense_data()428 void omti8621_device::clear_sense_data() {
429 LOG2(("clear_sense_data"));
430 memset(sense_data, 0, sizeof(sense_data));
431 }
432
433 /***************************************************************************
434 set_sense_data - set the sense data from code and command descriptor block
435 ***************************************************************************/
436
set_sense_data(uint8_t code,const uint8_t * cdb)437 void omti8621_device::set_sense_data(uint8_t code, const uint8_t * cdb) {
438 LOG2(("set_sense_data code=%x", code));
439 sense_data[0]=code;
440 sense_data[1]=cdb[1];
441 sense_data[2]=cdb[2];
442 sense_data[3]=cdb[3];
443 }
444
445 /***************************************************************************
446 set_configuration_data - set the configuration data for drive lun
447 ***************************************************************************/
448
set_configuration_data(uint8_t lun)449 void omti8621_device::set_configuration_data(uint8_t lun) {
450 LOG2(("set_configuration_data lun=%x", lun));
451
452 // initialize the configuration data
453 omti_disk_image_device *disk = our_disks[lun];
454
455 disk->m_config_data[0] = (disk->m_cylinders - 1) >> 8; // Number of Cylinders (MSB)
456 disk->m_config_data[1] = (disk->m_cylinders - 1) & 0xff; // Number of Cylinders (LSB) (-1)
457 disk->m_config_data[2] = disk->m_heads - 1; // Number of Heads (-1)
458 disk->m_config_data[3] = disk->m_sectors - 1; // Number of Sectors (-1)
459 disk->m_config_data[4] = 0x02; // Drive Configuration Word (MSB)
460 disk->m_config_data[5] = 0x44; // Drive Configuration Word (LSB)
461 disk->m_config_data[6] = 0x00; // ISG AFTER INDEX
462 disk->m_config_data[7] = 0x00; // PLO SYN Field (ID)
463 disk->m_config_data[8] = 0x00; // PLO SYN Field (DATA)
464 disk->m_config_data[9] = 0x00; // ISG AFTER SECTOR
465 }
466
467 /***************************************************************************
468 get_lun - get logical unit number from a command descriptor block (in bit 5)
469 ***************************************************************************/
470
get_lun(const uint8_t * cdb)471 uint8_t omti8621_device::get_lun(const uint8_t * cdb)
472 {
473 return (cdb[1] & 0x20) >> 5;
474 }
475
476 /***************************************************************************
477 check_disk_address - check disk address, set sense data and return true for no error
478 ***************************************************************************/
479
check_disk_address(const uint8_t * cdb)480 uint8_t omti8621_device::check_disk_address(const uint8_t *cdb)
481 {
482 uint8_t sense_code = OMTI_SENSE_CODE_NO_ERROR;
483 uint8_t lun = get_lun(cdb);
484 uint16_t head = cdb[1] & 0x1f;
485 uint16_t sector = cdb[2] & 0x3f;
486 uint32_t cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3);
487 uint8_t block_count = cdb[4];
488 omti_disk_image_device *disk = our_disks[lun];
489
490 uint32_t disk_track = cylinder * disk->m_heads + head;
491 uint32_t disk_addr = (disk_track * disk->m_sectors) + sector;
492
493 if (block_count > OMTI_MAX_BLOCK_COUNT) {
494 LOG(("########### check_disk_address: unexpected block count %x", block_count));
495 sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
496 }
497
498 if (lun > OMTI_MAX_LUN) {
499 sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY;
500 } else if (!disk->m_image->exists()) {
501 sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY;
502 } else if (sector >= OMTI_MAX_BLOCK_COUNT) {
503 sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
504 } else if (head >= disk->m_heads) {
505 sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
506 } else if (cylinder >= disk->m_cylinders) {
507 sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
508 } else if ( disk_track == diskaddr_format_bad_track && disk_track != 0) {
509 sense_code = OMTI_SENSE_CODE_BAD_TRACK;
510 } else if (disk_addr == diskaddr_ecc_error && disk_addr != 0) {
511 sense_code = OMTI_SENSE_CODE_ECC_ERROR;
512 } else if (disk_track == alternate_track_address[1] && disk_track != 0) {
513 sense_code = OMTI_SENSE_CODE_ALTERNATE_TRACK;
514 }
515
516 if (sense_code == OMTI_SENSE_CODE_NO_ERROR) {
517 clear_sense_data();
518 } else {
519 command_status |= OMTI_COMMAND_STATUS_ERROR;
520 set_sense_data(sense_code, cdb);
521 }
522 return sense_code == OMTI_SENSE_CODE_NO_ERROR;
523 }
524
525 /***************************************************************************
526 get_disk_track - get disk track from a command descriptor block
527 ***************************************************************************/
528
get_disk_track(const uint8_t * cdb)529 uint32_t omti8621_device::get_disk_track(const uint8_t * cdb) {
530 uint8_t lun = get_lun(cdb);
531 uint16_t head = cdb[1] & 0x1f;
532 uint32_t cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3);
533 return cylinder * our_disks[lun]->m_heads + head;
534 }
535
536 /***************************************************************************
537 get_disk_address - get disk address from a command descriptor block
538 ***************************************************************************/
539
get_disk_address(const uint8_t * cdb)540 uint32_t omti8621_device::get_disk_address(const uint8_t * cdb) {
541 uint8_t lun = get_lun(cdb);
542 uint16_t sector = cdb[2] & 0x3f;
543 return get_disk_track(cdb) * our_disks[lun]->m_sectors + sector;
544 }
545
546 /***************************************************************************
547 set_data_transfer - setup for data transfer from/to data
548 ***************************************************************************/
549
set_data_transfer(uint8_t * data,uint16_t length)550 void omti8621_device::set_data_transfer(uint8_t *data, uint16_t length)
551 {
552 // set controller for read data transfer
553 omti_state = OMTI_STATE_DATA;
554 status_port |= OMTI_STATUS_REQ | OMTI_STATUS_IO | OMTI_STATUS_BUSY;
555 status_port &= ~OMTI_STATUS_CD;
556
557 data_buffer = data;
558 data_length = length;
559 data_index = 0;
560 }
561
562 /***************************************************************************
563 read_sectors_from_disk - read sectors starting at diskaddr into sector_buffer
564 ***************************************************************************/
565
read_sectors_from_disk(int32_t diskaddr,uint8_t count,uint8_t lun)566 void omti8621_device::read_sectors_from_disk(int32_t diskaddr, uint8_t count, uint8_t lun)
567 {
568 uint8_t *data_buffer = §or_buffer[0];
569 device_image_interface *image = our_disks[lun]->m_image;
570
571 while (count-- > 0) {
572 LOG2(("read_sectors_from_disk lun=%d diskaddr=%x", lun, diskaddr));
573
574 image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
575 image->fread( data_buffer, OMTI_DISK_SECTOR_SIZE);
576
577 diskaddr++;
578 data_buffer += OMTI_DISK_SECTOR_SIZE;
579 }
580 }
581
582 /***************************************************************************
583 write_sectors_to_disk - write sectors starting at diskaddr from sector_buffer
584 ***************************************************************************/
585
write_sectors_to_disk(int32_t diskaddr,uint8_t count,uint8_t lun)586 void omti8621_device::write_sectors_to_disk(int32_t diskaddr, uint8_t count, uint8_t lun)
587 {
588 uint8_t *data_buffer = §or_buffer[0];
589 device_image_interface *image = our_disks[lun]->m_image;
590
591 while (count-- > 0) {
592 LOG2(("write_sectors_to_disk lun=%d diskaddr=%x", lun, diskaddr));
593
594 image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
595 image->fwrite( data_buffer, OMTI_DISK_SECTOR_SIZE);
596
597 if (diskaddr == diskaddr_ecc_error) {
598 // reset previous ECC error
599 diskaddr_ecc_error = 0;
600 }
601
602 diskaddr++;
603 data_buffer += OMTI_DISK_SECTOR_SIZE;
604 }
605 }
606
607 /***************************************************************************
608 copy_sectors - copy sectors
609 ***************************************************************************/
610
copy_sectors(int32_t dst_addr,int32_t src_addr,uint8_t count,uint8_t lun)611 void omti8621_device::copy_sectors(int32_t dst_addr, int32_t src_addr, uint8_t count, uint8_t lun)
612 {
613 device_image_interface *image = our_disks[lun]->m_image;
614
615 LOG2(("copy_sectors lun=%d src_addr=%x dst_addr=%x count=%x", lun, src_addr, dst_addr, count));
616
617 while (count-- > 0) {
618 image->fseek( src_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
619 image->fread( §or_buffer[0], OMTI_DISK_SECTOR_SIZE);
620
621 image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
622 image->fwrite( §or_buffer[0], OMTI_DISK_SECTOR_SIZE);
623
624 if (dst_addr == diskaddr_ecc_error) {
625 // reset previous ECC error
626 diskaddr_ecc_error = 0;
627 }
628
629 src_addr++;
630 dst_addr++;
631 }
632 }
633
634 /***************************************************************************
635 format track - format a track
636 ***************************************************************************/
637
format_track(const uint8_t * cdb)638 void omti8621_device::format_track(const uint8_t * cdb)
639 {
640 uint8_t lun = get_lun(cdb);
641 uint32_t disk_addr = get_disk_address(cdb);
642 uint32_t disk_track = get_disk_track(cdb);
643
644 if (diskaddr_ecc_error == disk_addr) {
645 // reset previous ECC error
646 diskaddr_ecc_error = 0;
647 }
648
649 if (diskaddr_format_bad_track == disk_track) {
650 // reset previous bad track formatting
651 diskaddr_format_bad_track = 0;
652 }
653
654 if (alternate_track_address[0] == disk_track) {
655 // reset source of alternate track address
656 alternate_track_address[0] = 0;
657 }
658
659 if (alternate_track_address[1] == disk_track) {
660 // reset alternate track address
661 alternate_track_address[1] = 0;
662 }
663
664 if (check_disk_address(cdb) ) {
665 if ((cdb[5] & 0x40) == 0) {
666 memset(§or_buffer[0], 0x6C, OMTI_DISK_SECTOR_SIZE * our_disks[lun]->m_sectors);
667 }
668 write_sectors_to_disk(disk_addr, our_disks[lun]->m_sectors, lun);
669 }
670
671 }
672
673 /***************************************************************************
674 set_esdi_defect_list - setup the (empty) ESDI defect list
675 ***************************************************************************/
676
set_esdi_defect_list(uint8_t lun,uint8_t head)677 void omti8621_device::set_esdi_defect_list(uint8_t lun, uint8_t head)
678 {
679 omti_disk_image_device *disk = our_disks[lun];
680
681 memset(disk->m_esdi_defect_list, 0, sizeof(disk->m_esdi_defect_list));
682 disk->m_esdi_defect_list[0] = 1; // month
683 disk->m_esdi_defect_list[1] = 1; // day
684 disk->m_esdi_defect_list[2] = 90; // year
685 disk->m_esdi_defect_list[3] = head;
686 memset(disk->m_esdi_defect_list+6, 0xff, 5); // end of defect list
687 }
688
689 /*-------------------------------------------------
690 logerror - log an error message (w/o device tags)
691 -------------------------------------------------*/
692
693 template <typename Format, typename... Params>
logerror(Format && fmt,Params &&...args) const694 void omti8621_device::logerror(Format &&fmt, Params &&... args) const
695 {
696 machine().logerror(std::forward<Format>(fmt), std::forward<Params>(args)...);
697 }
698
699 /***************************************************************************
700 log_command - log command from a command descriptor block
701 ***************************************************************************/
702
log_command(const uint8_t cdb[],const uint16_t cdb_length)703 void omti8621_device::log_command(const uint8_t cdb[], const uint16_t cdb_length)
704 {
705 if (verbose > 0) {
706 int i;
707 logerror("%s: OMTI command ", cpu_context());
708 switch (cdb[0]) {
709 case OMTI_CMD_TEST_DRIVE_READY: // 0x00
710 logerror("Test Drive Ready");
711 break;
712 case OMTI_CMD_RECALIBRATE: // 0x01
713 logerror("Recalibrate");
714 break;
715 case OMTI_CMD_REQUEST_SENSE: // 0x03
716 logerror("Request Sense");
717 break;
718 case OMTI_CMD_READ_VERIFY: // 0x05
719 logerror("Read Verify");
720 break;
721 case OMTI_CMD_FORMAT_TRACK: // 0x06
722 logerror("Format Track");
723 break;
724 case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
725 logerror("Format Bad Track");
726 break;
727 case OMTI_CMD_READ: // 0x08
728 logerror("Read");
729 break;
730 case OMTI_CMD_WRITE: // 0x0A
731 logerror("Write");
732 break;
733 case OMTI_CMD_SEEK: // 0x0B
734 logerror("Seek");
735 break;
736 case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
737 logerror("Read Sector Buffer");
738 break;
739 case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
740 logerror("Write Sector Buffer");
741 break;
742 case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
743 logerror("Assign Alternate Track");
744 break;
745 case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
746 logerror("Read Data to Buffer");
747 break;
748 case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
749 logerror("Write Data from Buffer");
750 break;
751 case OMTI_CMD_COPY: // 0x20
752 logerror("Copy");
753 break;
754 case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
755 logerror("Read ESDI Defect List");
756 break;
757 case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0
758 logerror("RAM. Diagnostic");
759 break;
760 case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4
761 logerror("Controller Int. Diagnostic");
762 break;
763 case OMTI_CMD_READ_LONG: // 0xE5
764 logerror("Read Long");
765 break;
766 case OMTI_CMD_WRITE_LONG: // 0xE6
767 logerror("Write Long");
768 break;
769 case OMTI_CMD_READ_CONFIGURATION: // 0xEC
770 logerror("Read Configuration");
771 break;
772 case OMTI_CMD_INVALID_COMMAND: // 0xFF
773 logerror("Invalid Command");
774 break;
775 default:
776 logerror("!!! Unexpected Command !!!");
777 }
778 // logerror(" (%02x, length=%02x)", cdb[0], cdb_length);
779 for (i = 0; i < cdb_length; i++) {
780 logerror(" %02x", cdb[i]);
781 }
782
783 switch (cdb[0]) {
784 case OMTI_CMD_READ_VERIFY: // 0x05
785 case OMTI_CMD_READ: // 0x08
786 case OMTI_CMD_WRITE: // 0x0a
787 case OMTI_CMD_SEEK: // 0x0b
788 case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
789 case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
790 case OMTI_CMD_COPY: // 0x20
791 logerror(" (diskaddr=%x count=%x)", get_disk_address(cdb), cdb[4]);
792 break;
793 }
794 logerror("\n");
795 }
796 }
797
798 /***************************************************************************
799 log_data - log data in the common data buffer
800 ***************************************************************************/
801
log_data()802 void omti8621_device::log_data()
803 {
804 if (verbose > 0) {
805 int i;
806 logerror("%s: OMTI data (length=%02x)", cpu_context(),
807 data_length);
808 for (i = 0; i < data_length && i < OMTI_DISK_SECTOR_SIZE; i++) {
809 logerror(" %02x", data_buffer[i]);
810 }
811
812 if (i < data_length) {
813 logerror(" ...");
814 }
815 logerror("\n");
816 }
817 }
818
819 /***************************************************************************
820 do_command
821 ***************************************************************************/
822
do_command(const uint8_t cdb[],const uint16_t cdb_length)823 void omti8621_device::do_command(const uint8_t cdb[], const uint16_t cdb_length)
824 {
825 uint8_t lun = get_lun(cdb);
826 omti_disk_image_device *disk = our_disks[lun];
827 int command_duration = 0; // ms
828
829 log_command( cdb, cdb_length);
830
831 // default to read status and status is successful completion
832 omti_state = OMTI_STATE_STATUS;
833 status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
834 command_status = lun ? OMTI_COMMAND_STATUS_LUN : 0;
835
836 if (mask_port & OMTI_MASK_INTE) {
837 set_interrupt(CLEAR_LINE);
838 }
839
840 if (!disk->m_image->exists()) {
841 command_status |= OMTI_COMMAND_STATUS_ERROR; // no such drive
842 }
843
844 switch (cdb[0]) {
845 case OMTI_CMD_TEST_DRIVE_READY: // 0x00
846 if (!disk->m_image->exists())
847 {
848 set_sense_data(OMTI_SENSE_CODE_DRIVE_NOT_READY, cdb);
849 }
850 break;
851
852 case OMTI_CMD_RECALIBRATE: // 0x01
853 break;
854
855 case OMTI_CMD_REQUEST_SENSE: // 0x03
856 set_data_transfer(sense_data, sizeof(sense_data));
857 break;
858
859 case OMTI_CMD_READ_VERIFY: // 0x05
860 check_disk_address(cdb);
861 break;
862
863 case OMTI_CMD_FORMAT_TRACK: // 0x06
864 format_track(cdb);
865 break;
866
867 case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
868 diskaddr_format_bad_track = get_disk_address(cdb);
869 break;
870
871 case OMTI_CMD_READ: // 0x08
872 if (check_disk_address(cdb)) {
873 // read data from controller
874 read_sectors_from_disk(get_disk_address(cdb), cdb[4], lun);
875 set_data_transfer(§or_buffer[0], OMTI_DISK_SECTOR_SIZE*cdb[4]);
876 }
877 break;
878
879 case OMTI_CMD_WRITE: // 0x0A
880 log_data();
881 if (check_disk_address(cdb)) {
882 write_sectors_to_disk(get_disk_address(cdb), cdb[4], lun);
883 }
884 break;
885
886 case OMTI_CMD_SEEK: // 0x0B
887 check_disk_address(cdb);
888 break;
889
890 case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
891 set_data_transfer(§or_buffer[0], OMTI_DISK_SECTOR_SIZE*cdb[4]);
892 break;
893
894 case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
895 log_data();
896 break;
897
898 case OMTI_CMD_COPY: // 0x20
899 if (check_disk_address(cdb) && check_disk_address(cdb+4)) {
900 // copy sectors
901 copy_sectors (get_disk_address(cdb+4), get_disk_address(cdb), cdb[4], lun);
902 }
903 break;
904
905 case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
906 set_esdi_defect_list(get_lun(cdb), cdb[1] & 0x1f);
907 set_data_transfer(disk->m_esdi_defect_list, sizeof(disk->m_esdi_defect_list));
908 break;
909
910 #if 0 // this command seems unused by Domain/OS, and it's unclear what the intent of the code is (it makes some versions of GCC quite unhappy)
911 case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
912 log_data();
913 alternate_track_address[0] = get_disk_track(cdb);
914 alternate_track_address[1] = get_disk_track(alternate_track_buffer-1);
915 break;
916 #endif
917
918 case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
919 if (check_disk_address(cdb)) {
920 // read data from controller
921 read_sectors_from_disk (get_disk_address(cdb), cdb[4], lun);
922 // Domain/OS doesn't expect zero access time
923 command_duration += 1; // 1 ms is enough, average time would be 30 ms)
924 }
925 break;
926
927 case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
928 log_data();
929 if (check_disk_address(cdb)) {
930 write_sectors_to_disk(get_disk_address(cdb), cdb[4], lun);
931 }
932 break;
933
934 case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0
935 break;
936
937 case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4
938 break;
939
940 case OMTI_CMD_READ_LONG: // 0xE5
941 if (check_disk_address(cdb)) {
942 // read data from controller
943 read_sectors_from_disk(get_disk_address(cdb), cdb[4], lun);
944 set_data_transfer(§or_buffer[0], OMTI_DISK_SECTOR_SIZE+6);
945 }
946 break;
947
948 case OMTI_CMD_WRITE_LONG: // 0xE6
949 log_data();
950 if (check_disk_address(cdb)) {
951 uint32_t diskaddr = get_disk_address(cdb);
952 write_sectors_to_disk(diskaddr, cdb[4], lun);
953 // this will spoil the ECC code
954 diskaddr_ecc_error = diskaddr;
955 }
956 break;
957
958 case OMTI_CMD_READ_CONFIGURATION: // 0xEC
959 set_configuration_data(get_lun(cdb));
960 set_data_transfer(disk->m_config_data, sizeof(disk->m_config_data));
961 break;
962
963 case OMTI_CMD_INVALID_COMMAND: // 0xFF
964 set_sense_data(OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
965 command_status |= OMTI_COMMAND_STATUS_ERROR;
966 break;
967
968 default:
969 LOG(("do_command: UNEXPECTED command %02x",cdb[0]));
970 set_sense_data(OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
971 command_status |= OMTI_COMMAND_STATUS_ERROR;
972 break;
973 }
974
975 if (mask_port & OMTI_MASK_INTE) {
976 // if (omti_state != OMTI_STATE_STATUS) {
977 // LOG(("do_command: UNEXPECTED omti_state %02x",omti_state));
978 // }
979 status_port |= OMTI_STATUS_IREQ;
980 if (command_duration == 0)
981 {
982 set_interrupt(ASSERT_LINE);
983 }
984 else
985 {
986 // FIXME: should delay omti_state and status_port as well
987 m_timer->adjust(attotime::from_msec(command_duration), 0);
988 }
989 }
990 }
991
992 /***************************************************************************
993 get_command_length
994 ***************************************************************************/
995
get_command_length(uint8_t command_byte)996 uint8_t omti8621_device::get_command_length(uint8_t command_byte)
997 {
998 return command_byte == OMTI_CMD_COPY ? 10 : 6;
999 }
1000
1001 /***************************************************************************
1002 get_data
1003 ***************************************************************************/
1004
get_data()1005 uint16_t omti8621_device::get_data()
1006 {
1007 uint16_t data = 0xff;
1008 if (data_index < data_length) {
1009 data = data_buffer[data_index++];
1010 data |= data_buffer[data_index++] << 8;
1011 if (data_index >= data_length) {
1012 omti_state = OMTI_STATE_STATUS;
1013 status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
1014 log_data();
1015 }
1016 } else {
1017 LOG(("UNEXPECTED reading OMTI 8621 data (buffer length exceeded)"));
1018 }
1019 return data;
1020 }
1021
1022 /***************************************************************************
1023 set_data
1024 ***************************************************************************/
1025
set_data(uint16_t data)1026 void omti8621_device::set_data(uint16_t data)
1027 {
1028 if (data_index < data_length) {
1029 data_buffer[data_index++] = data & 0xff;
1030 data_buffer[data_index++] = data >> 8;
1031 if (data_index >= data_length) {
1032 do_command(command_buffer, command_index);
1033 }
1034 } else {
1035 LOG(("UNEXPECTED writing OMTI 8621 data (buffer length exceeded)"));
1036 }
1037 }
1038
1039 /***************************************************************************
1040 OMTI8621 Disk Controller-AT Registers
1041 ***************************************************************************/
1042
write(offs_t offset,uint16_t data,uint16_t mem_mask)1043 void omti8621_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
1044 {
1045 switch (mem_mask)
1046 {
1047 case 0x00ff:
1048 write8(offset*2, data);
1049 break;
1050
1051 case 0xff00:
1052 write8(offset*2+1, data>>8);
1053 break;
1054
1055 default:
1056 set_data(data);
1057 break;
1058 }
1059 }
1060
write8(offs_t offset,uint8_t data)1061 void omti8621_device::write8(offs_t offset, uint8_t data)
1062 {
1063 switch (offset)
1064 {
1065 case OMTI_PORT_DATA_OUT: // 0x00
1066 switch (omti_state) {
1067 case OMTI_STATE_COMMAND:
1068 LOG2(("writing OMTI 8621 Command Register at offset %02x = %02x", offset, data));
1069 if (command_index == 0) {
1070 command_length = get_command_length(data);
1071 }
1072
1073 if (command_index < command_length) {
1074 command_buffer[command_index++] = data;
1075 } else {
1076 LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (command length exceeded)", offset, data));
1077 }
1078
1079 if (command_index == command_length) {
1080 switch (command_buffer[0]) {
1081 case OMTI_CMD_WRITE: // 0x0A
1082 // TODO: check diskaddr
1083 // Fall through
1084 case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
1085 set_data_transfer(§or_buffer[0],
1086 OMTI_DISK_SECTOR_SIZE * command_buffer[4]);
1087 status_port &= ~OMTI_STATUS_IO;
1088 break;
1089
1090 case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
1091 set_data_transfer(alternate_track_buffer, sizeof(alternate_track_buffer));
1092 status_port &= ~OMTI_STATUS_IO;
1093 break;
1094
1095 case OMTI_CMD_WRITE_LONG: // 0xE6
1096 // TODO: check diskaddr
1097 set_data_transfer(§or_buffer[0],
1098 (OMTI_DISK_SECTOR_SIZE +6) * command_buffer[4]);
1099 status_port &= ~OMTI_STATUS_IO;
1100 break;
1101
1102 default:
1103 do_command(command_buffer, command_index);
1104 break;
1105 }
1106 }
1107 break;
1108
1109 case OMTI_STATE_DATA:
1110 LOG(("UNEXPECTED: writing OMTI 8621 Data Register at offset %02x = %02x", offset, data));
1111 break;
1112
1113 default:
1114 LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
1115 break;
1116 }
1117 break;
1118
1119 case OMTI_PORT_RESET: // 0x01
1120 LOG2(("writing OMTI 8621 Reset Register at offset %02x = %02x", offset, data));
1121 device_reset();
1122 break;
1123
1124 case OMTI_PORT_SELECT: // 0x02
1125 LOG2(("writing OMTI 8621 Select Register at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
1126 omti_state = OMTI_STATE_COMMAND;
1127
1128 status_port |= OMTI_STATUS_BUSY | OMTI_STATUS_REQ | OMTI_STATUS_CD;
1129 status_port &= ~OMTI_STATUS_IO;
1130
1131 command_status = 0;
1132 command_index = 0;
1133 break;
1134
1135 case OMTI_PORT_MASK: // 0x03
1136 LOG2(("writing OMTI 8621 Mask Register at offset %02x = %02x", offset, data));
1137 mask_port = data;
1138
1139 if ((data & OMTI_MASK_INTE) == 0) {
1140 status_port &= ~OMTI_STATUS_IREQ;
1141 set_interrupt(CLEAR_LINE);
1142 }
1143
1144 if ((data & OMTI_MASK_DMAE) == 0) {
1145 status_port &= ~OMTI_STATUS_DREQ;
1146 }
1147 break;
1148
1149 default:
1150 LOG(("UNEXPECTED writing OMTI 8621 Register at offset %02x = %02x", offset, data));
1151 break;
1152 }
1153 }
1154
read(offs_t offset,uint16_t mem_mask)1155 uint16_t omti8621_device::read(offs_t offset, uint16_t mem_mask)
1156 {
1157 switch (mem_mask)
1158 {
1159 case 0x00ff:
1160 return read8(offset*2);
1161 case 0xff00:
1162 return read8(offset*2+1) << 8;
1163 default:
1164 return get_data();
1165 }
1166 }
1167
read8(offs_t offset)1168 uint8_t omti8621_device::read8(offs_t offset)
1169 {
1170 uint8_t data = 0xff;
1171 static uint8_t last_data = 0xff;
1172
1173 switch (offset) {
1174 case OMTI_PORT_DATA_IN: // 0x00
1175 if (status_port & OMTI_STATUS_CD)
1176 {
1177 data = command_status;
1178 switch (omti_state)
1179 {
1180 case OMTI_STATE_COMMAND:
1181 LOG2(("reading OMTI 8621 Data Status Register 1 at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
1182 break;
1183 case OMTI_STATE_STATUS:
1184 omti_state = OMTI_STATE_IDLE;
1185 status_port &= ~(OMTI_STATUS_BUSY | OMTI_STATUS_CD | OMTI_STATUS_IO | OMTI_STATUS_REQ);
1186 LOG2(("reading OMTI 8621 Data Status Register 2 at offset %02x = %02x", offset, data));
1187 break;
1188 default:
1189 LOG(("UNEXPECTED reading OMTI 8621 Data Status Register 3 at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
1190 break;
1191 }
1192 }
1193 else
1194 {
1195 LOG(("UNEXPECTED reading OMTI 8621 Data Register 4 at offset %02x = %02x (status bit C/D = 0)", offset, data));
1196 }
1197 break;
1198
1199 case OMTI_PORT_STATUS: // 0x01
1200 data = status_port;
1201 // omit excessive logging
1202 if (data != last_data)
1203 {
1204 LOG2(("reading OMTI 8621 Status Register 5 at offset %02x = %02x", offset, data));
1205 // last_data = data;
1206 }
1207 break;
1208
1209 case OMTI_PORT_CONFIG: // 0x02
1210 data = config_port;
1211 LOG2(("reading OMTI 8621 Configuration Register at offset %02x = %02x", offset, data));
1212 break;
1213
1214 case OMTI_PORT_MASK: // 0x03
1215 data = mask_port ;
1216 // win.dex will update the mask register with read-modify-write
1217 // LOG2(("reading OMTI 8621 Mask Register at offset %02x = %02x (UNEXPECTED!)", offset, data));
1218 break;
1219
1220 default:
1221 LOG(("UNEXPECTED reading OMTI 8621 Register at offset %02x = %02x", offset, data));
1222 break;
1223 }
1224
1225 return data;
1226 }
1227
set_verbose(int on_off)1228 void omti8621_device::set_verbose(int on_off)
1229 {
1230 verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
1231 }
1232
1233 /***************************************************************************
1234 get_sector - get sector diskaddr of logical unit lun into data_buffer
1235 ***************************************************************************/
1236
get_sector(int32_t diskaddr,uint8_t * data_buffer,uint32_t length,uint8_t lun)1237 uint32_t omti8621_apollo_device::get_sector(int32_t diskaddr, uint8_t *data_buffer, uint32_t length, uint8_t lun)
1238 {
1239 omti_disk_image_device *disk = our_disks[lun];
1240
1241 if (disk == nullptr || disk->m_image == nullptr || !disk->m_image->exists())
1242 {
1243 return 0;
1244 }
1245 else
1246 {
1247 // LOG1(("omti8621_get_sector %x on lun %d", diskaddr, lun));
1248
1249 // restrict length to size of 1 sector (i.e. 1024 Byte)
1250 length = length < OMTI_DISK_SECTOR_SIZE ? length : OMTI_DISK_SECTOR_SIZE;
1251
1252 disk->m_image->fseek(diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
1253 disk->m_image->fread(data_buffer, length);
1254
1255 return length;
1256 }
1257 }
1258
1259 /***************************************************************************
1260 omti_set_jumper - set OMTI jumpers
1261 ***************************************************************************/
1262
set_jumper(uint16_t disk_type)1263 void omti8621_device::set_jumper(uint16_t disk_type)
1264 {
1265 LOG1(("set_jumper: disk type=%x", disk_type));
1266
1267 switch (disk_type)
1268 {
1269 case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
1270 jumper = OMTI_CONFIG_W22 | OMTI_CONFIG_W23;
1271 break;
1272
1273 case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
1274 default:
1275 jumper = OMTI_CONFIG_W20;
1276 break;
1277 }
1278 }
1279
1280 // FDC uses the standard IRQ 6 / DMA 2, doesn't appear to be configurable
WRITE_LINE_MEMBER(omti8621_device::fdc_irq_w)1281 WRITE_LINE_MEMBER( omti8621_device::fdc_irq_w )
1282 {
1283 if (BIT(m_moten, 3))
1284 m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE);
1285 }
1286
WRITE_LINE_MEMBER(omti8621_device::fdc_drq_w)1287 WRITE_LINE_MEMBER( omti8621_device::fdc_drq_w )
1288 {
1289 if (BIT(m_moten, 3))
1290 m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE);
1291 }
1292
dack_r(int line)1293 uint8_t omti8621_device::dack_r(int line)
1294 {
1295 return m_fdc->dma_r();
1296 }
1297
dack_w(int line,uint8_t data)1298 void omti8621_device::dack_w(int line, uint8_t data)
1299 {
1300 return m_fdc->dma_w(data);
1301 }
1302
dack_line_w(int line,int state)1303 void omti8621_device::dack_line_w(int line, int state)
1304 {
1305 //m_fdc->dack_w(state);
1306 }
1307
eop_w(int state)1308 void omti8621_device::eop_w(int state)
1309 {
1310 m_fdc->tc_w(state == ASSERT_LINE);
1311 }
1312
fdc_map(address_map & map)1313 void omti8621_device::fdc_map(address_map &map)
1314 {
1315 map(2, 2).w(FUNC(omti8621_device::fd_moten_w));
1316 map(4, 5).m(m_fdc, FUNC(upd765a_device::map));
1317 map(6, 6).w(FUNC(omti8621_device::fd_extra_w));
1318 map(7, 7).rw(FUNC(omti8621_device::fd_disk_chg_r), FUNC(omti8621_device::fd_rate_w));
1319 }
1320
fd_moten_w(uint8_t data)1321 void omti8621_device::fd_moten_w(uint8_t data)
1322 {
1323 if (BIT(data, 3) && !BIT(m_moten, 3))
1324 {
1325 m_isa->irq6_w(m_fdc->get_irq() ? ASSERT_LINE : CLEAR_LINE);
1326 m_isa->drq2_w(m_fdc->get_drq() ? ASSERT_LINE : CLEAR_LINE);
1327 }
1328 else if (!BIT(data, 3) && BIT(m_moten, 3))
1329 {
1330 m_isa->irq6_w(CLEAR_LINE);
1331 m_isa->drq2_w(CLEAR_LINE);
1332 }
1333
1334 m_moten = data;
1335
1336 m_fdc->reset_w(!BIT(data, 2));
1337
1338 for (int i = 0; i < 2; i++)
1339 {
1340 floppy_image_device *floppy = m_floppy[i].found() ? m_floppy[i]->get_device() : nullptr;
1341 if (floppy != nullptr)
1342 floppy->mon_w(!BIT(data, i + 4));
1343
1344 if (i == (data & 0x01))
1345 m_fdc->set_floppy(BIT(data, i + 4) ? floppy : nullptr);
1346 }
1347 }
1348
fd_rate_w(uint8_t data)1349 void omti8621_device::fd_rate_w(uint8_t data)
1350 {
1351 // Bit 1 = FD_MINI (connects to pin 3 of FDC9239)
1352 // Bit 0 = FD_RATE (inverted output connects to pin 4 of 74F163)
1353 u32 fdc_clk = (48_MHz_XTAL / (BIT(data, 0) ? 5 : 3) / (BIT(data, 1) ? 4 : 2)).value();
1354 m_fdc->set_unscaled_clock(fdc_clk);
1355 m_fdc->set_rate(fdc_clk / 16);
1356 }
1357
fd_extra_w(uint8_t data)1358 void omti8621_device::fd_extra_w(uint8_t data)
1359 {
1360 // Bit 7 = FD_EXTRA-2 (NC)
1361 // Bit 6 = FD_EXTRA-1 (NC)
1362 // Bit 5 = FD_PIN_6 (TODO)
1363 // Bit 4 = FD_IUSE_HLD (TODO)
1364 // Bit 3 = FD_DEN_SEL (TODO)
1365 // Bit 2 = FD_PRE-2 (TODO)
1366 // Bit 1 = FD_PRE-1 (TODO)
1367 // Bit 0 = FD_PRE-0 (TODO)
1368 }
1369
fd_disk_chg_r()1370 uint8_t omti8621_device::fd_disk_chg_r()
1371 {
1372 floppy_image_device *floppy = m_floppy[m_moten & 0x01].found() ? m_floppy[m_moten & 0x01]->get_device() : nullptr;
1373 if (floppy == nullptr || floppy->dskchg_r())
1374 return 0x00;
1375 else
1376 return 0x80;
1377 }
1378
1379 //##########################################################################
1380
1381 // device type definition
1382 DEFINE_DEVICE_TYPE(OMTI_DISK, omti_disk_image_device, "omti_disk_image", "OMTI 8621 ESDI disk")
1383
omti_disk_image_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1384 omti_disk_image_device::omti_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1385 : device_t(mconfig, OMTI_DISK, tag, owner, clock)
1386 , device_image_interface(mconfig, *this)
1387 , m_type(0), m_cylinders(0), m_heads(0), m_sectors(0), m_sectorbytes(0), m_sector_count(0), m_image(nullptr)
1388 {
1389 }
1390
1391
1392 /***************************************************************************
1393 omti_disk_config - configure disk parameters
1394 ***************************************************************************/
1395
omti_disk_config(uint16_t disk_type)1396 void omti_disk_image_device::omti_disk_config(uint16_t disk_type)
1397 {
1398 logerror("omti_disk_config: configuring disk with type %x\n", disk_type);
1399
1400 switch (disk_type)
1401 {
1402 case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
1403 m_cylinders = 1223;
1404 m_heads = 15;
1405 m_sectors = 18;
1406 break;
1407
1408 case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
1409 default:
1410 m_cylinders = 1023;
1411 m_heads = 8;
1412 m_sectors = 18;
1413 break;
1414 }
1415
1416 m_type = disk_type;
1417 m_sectorbytes = OMTI_DISK_SECTOR_SIZE;
1418 m_sector_count = m_cylinders * m_heads * m_sectors;
1419 }
1420
1421 /*-------------------------------------------------
1422 logerror - log an error message (w/o device tags)
1423 -------------------------------------------------*/
1424
1425 template <typename Format, typename... Params>
logerror(Format && fmt,Params &&...args) const1426 void omti_disk_image_device::logerror(Format &&fmt, Params &&... args) const
1427 {
1428 machine().logerror(std::forward<Format>(fmt), std::forward<Params>(args)...);
1429 }
1430
1431 /*-------------------------------------------------
1432 device start callback
1433 -------------------------------------------------*/
1434
device_start()1435 void omti_disk_image_device::device_start()
1436 {
1437 m_image = this;
1438
1439 if (!m_image->is_open())
1440 {
1441 logerror("device_start_omti_disk: no disk\n");
1442 }
1443 else
1444 {
1445 logerror("device_start_omti_disk: with disk image %s\n", m_image->basename());
1446 }
1447
1448 // default disk type
1449 omti_disk_config(OMTI_DISK_TYPE_DEFAULT);
1450 }
1451
1452 /*-------------------------------------------------
1453 device reset callback
1454 -------------------------------------------------*/
1455
device_reset()1456 void omti_disk_image_device::device_reset()
1457 {
1458 logerror("device_reset_omti_disk\n");
1459
1460 if (exists() && fseek(0, SEEK_END) == 0)
1461 {
1462 uint32_t disk_size = (uint32_t)(ftell() / OMTI_DISK_SECTOR_SIZE);
1463 uint16_t disk_type = disk_size >= 300000 ? OMTI_DISK_TYPE_348_MB : OMTI_DISK_TYPE_155_MB;
1464 if (disk_type != m_type) {
1465 logerror("device_reset_omti_disk: disk size=%d blocks, disk type=%x\n", disk_size, disk_type);
1466 omti_disk_config(disk_type);
1467 }
1468 }
1469 }
1470
1471 /*-------------------------------------------------
1472 disk image create callback
1473 -------------------------------------------------*/
1474
call_create(int format_type,util::option_resolution * format_options)1475 image_init_result omti_disk_image_device::call_create(int format_type, util::option_resolution *format_options)
1476 {
1477 logerror("device_create_omti_disk: creating OMTI Disk with %d blocks\n", m_sector_count);
1478
1479 int x;
1480 unsigned char sectordata[OMTI_DISK_SECTOR_SIZE]; // empty block data
1481
1482
1483 memset(sectordata, 0x55, sizeof(sectordata));
1484 for (x = 0; x < m_sector_count; x++)
1485 {
1486 if (fwrite(sectordata, OMTI_DISK_SECTOR_SIZE)
1487 < OMTI_DISK_SECTOR_SIZE)
1488 {
1489 return image_init_result::FAIL;
1490 }
1491 }
1492 return image_init_result::PASS;
1493 }
1494