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(&sector_buffer[0], 0, OMTI_DISK_SECTOR_SIZE);
351 	memcpy(&sector_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 = &sector_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 = &sector_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( &sector_buffer[0], OMTI_DISK_SECTOR_SIZE);
620 
621 		image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
622 		image->fwrite( &sector_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(&sector_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(&sector_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(&sector_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(&sector_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(&sector_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(&sector_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