|
| 1 | +// license: GPL-2.0+ |
| 2 | +// copyright-holders: Dirk Best |
| 3 | +/*************************************************************************** |
| 4 | +
|
| 5 | + Commodore/DKB A4091 |
| 6 | +
|
| 7 | + Zorro III SCSI host adapter based on the NCR 53C710 |
| 8 | +
|
| 9 | + Hardware: |
| 10 | + - NCR 53C710 SCSI I/O processor |
| 11 | + - 50 MHz XTAL |
| 12 | + - Internal and external SCSI-2 connectors |
| 13 | + - 32 KiB boot ROM |
| 14 | +
|
| 15 | + Notes: |
| 16 | + - Also sold by DKB in license |
| 17 | +
|
| 18 | + TODO: |
| 19 | + - Map dip switch ID to actually used ID |
| 20 | +
|
| 21 | +***************************************************************************/ |
| 22 | + |
| 23 | +#include "emu.h" |
| 24 | +#include "a4091.h" |
| 25 | + |
| 26 | +#include "bus/nscsi/devices.h" |
| 27 | +#include "machine/53c7xx.h" |
| 28 | +#include "machine/nscsi_bus.h" |
| 29 | + |
| 30 | +#define VERBOSE (LOG_GENERAL) |
| 31 | +#include "logmacro.h" |
| 32 | + |
| 33 | + |
| 34 | +namespace bus::amiga::zorro { |
| 35 | + |
| 36 | + |
| 37 | +class a4091_device : public device_t, public device_zorro3_card_interface |
| 38 | +{ |
| 39 | +public: |
| 40 | + a4091_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); |
| 41 | + |
| 42 | +protected: |
| 43 | + // device_t overrides |
| 44 | + virtual void device_start() override ATTR_COLD; |
| 45 | + virtual ioport_constructor device_input_ports() const override ATTR_COLD; |
| 46 | + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; |
| 47 | + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; |
| 48 | + |
| 49 | + // device_zorro2_card_interface overrides |
| 50 | + virtual void busrst_w(int state) override; |
| 51 | + virtual void cfgin_w(int state) override; |
| 52 | + |
| 53 | +private: |
| 54 | + static constexpr uint32_t BOARD_SIZE = 0x01000000; |
| 55 | + |
| 56 | + void mmio_map(address_map &map) ATTR_COLD; |
| 57 | + |
| 58 | + uint8_t dips_r(); |
| 59 | + |
| 60 | + uint32_t autoconfig_r(offs_t offset, uint32_t mem_mask); |
| 61 | + void autoconfig_w(offs_t offset, uint32_t data, uint32_t mem_mask); |
| 62 | + void autoconfig_base_address(offs_t address); |
| 63 | + |
| 64 | + uint32_t rom_r(offs_t offset); |
| 65 | + uint32_t dma_r(offs_t offset, uint32_t mem_mask); |
| 66 | + void dma_w(offs_t offset, uint32_t data, uint32_t mem_mask); |
| 67 | + |
| 68 | + required_device<nscsi_bus_device> m_scsi; |
| 69 | + required_device<ncr53c710_device> m_ncr; |
| 70 | + required_region_ptr<uint8_t> m_rom; |
| 71 | + required_ioport m_dips; |
| 72 | + |
| 73 | + uint32_t m_base_address = 0; |
| 74 | + uint32_t m_autoconfig_address = 0; |
| 75 | +}; |
| 76 | + |
| 77 | +a4091_device::a4091_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : |
| 78 | + device_t(mconfig, AMIGA_A4091, tag, owner, clock), |
| 79 | + device_zorro3_card_interface(mconfig, *this), |
| 80 | + m_scsi(*this, "scsi"), |
| 81 | + m_ncr(*this, "ncr"), |
| 82 | + m_rom(*this, "rom"), |
| 83 | + m_dips(*this, "dips") |
| 84 | +{ |
| 85 | +} |
| 86 | + |
| 87 | + |
| 88 | +//************************************************************************** |
| 89 | +// ADDRESS MAPS |
| 90 | +//************************************************************************** |
| 91 | + |
| 92 | +void a4091_device::mmio_map(address_map &map) |
| 93 | +{ |
| 94 | + map(0x000000, 0x03ffff).mirror(0x7c0000).r(FUNC(a4091_device::rom_r)); |
| 95 | + map(0x800000, 0x80003f).mirror(0x07ffc0).rw(m_ncr, FUNC(ncr53c710_device::read), FUNC(ncr53c710_device::write)); |
| 96 | + map(0x8c0000, 0x8c0003).r(FUNC(a4091_device::dips_r)).umask32(0x000000ff); |
| 97 | +} |
| 98 | + |
| 99 | + |
| 100 | +//************************************************************************** |
| 101 | +// INPUT DEFINITIONS |
| 102 | +//************************************************************************** |
| 103 | + |
| 104 | +static INPUT_PORTS_START( a4091 ) |
| 105 | + PORT_START("dips") |
| 106 | + PORT_DIPNAME(0x07, 0x07, "SCSI Address") PORT_DIPLOCATION("DIP:1,2,3") |
| 107 | + PORT_DIPSETTING(0x00, "0") |
| 108 | + PORT_DIPSETTING(0x01, "1") |
| 109 | + PORT_DIPSETTING(0x02, "2") |
| 110 | + PORT_DIPSETTING(0x03, "3") |
| 111 | + PORT_DIPSETTING(0x04, "4") |
| 112 | + PORT_DIPSETTING(0x05, "5") |
| 113 | + PORT_DIPSETTING(0x06, "6") |
| 114 | + PORT_DIPSETTING(0x07, "7") |
| 115 | + PORT_DIPNAME(0x08, 0x08, "SCSI Fast Bus") PORT_DIPLOCATION("DIP:4") |
| 116 | + PORT_DIPSETTING(0x08, DEF_STR( Off )) |
| 117 | + PORT_DIPSETTING(0x00, DEF_STR( On )) |
| 118 | + PORT_DIPNAME(0x10, 0x10, "Short/Long Spinup") PORT_DIPLOCATION("DIP:5") |
| 119 | + PORT_DIPSETTING(0x10, DEF_STR( Off )) |
| 120 | + PORT_DIPSETTING(0x00, DEF_STR( On )) |
| 121 | + PORT_DIPNAME(0x20, 0x20, "Synchronous Mode") PORT_DIPLOCATION("DIP:6") |
| 122 | + PORT_DIPSETTING(0x20, DEF_STR( Off )) |
| 123 | + PORT_DIPSETTING(0x00, DEF_STR( On )) |
| 124 | + PORT_DIPNAME(0x40, 0x40, "External SCSI Termination") PORT_DIPLOCATION("DIP:7") |
| 125 | + PORT_DIPSETTING(0x40, DEF_STR( Off )) |
| 126 | + PORT_DIPSETTING(0x00, DEF_STR( On )) |
| 127 | + PORT_DIPNAME(0x80, 0x80, "Logical Unit (LUN) Enable") PORT_DIPLOCATION("DIP:8") |
| 128 | + PORT_DIPSETTING(0x80, DEF_STR( Off )) |
| 129 | + PORT_DIPSETTING(0x00, DEF_STR( On )) |
| 130 | +INPUT_PORTS_END |
| 131 | + |
| 132 | +ioport_constructor a4091_device::device_input_ports() const |
| 133 | +{ |
| 134 | + return INPUT_PORTS_NAME( a4091 ); |
| 135 | +} |
| 136 | + |
| 137 | +uint8_t a4091_device::dips_r() |
| 138 | +{ |
| 139 | + return m_dips->read(); |
| 140 | +} |
| 141 | + |
| 142 | + |
| 143 | +//************************************************************************** |
| 144 | +// ZORRO / AUTOCONFIG |
| 145 | +//************************************************************************** |
| 146 | + |
| 147 | +void a4091_device::busrst_w(int state) |
| 148 | +{ |
| 149 | + if (state) |
| 150 | + return; |
| 151 | + |
| 152 | + int2_w(0); |
| 153 | + m_ncr->reset(); |
| 154 | + |
| 155 | + if (m_base_address) |
| 156 | + zorro3_space().unmap_readwrite(m_base_address, m_base_address + BOARD_SIZE - 1); |
| 157 | + |
| 158 | + m_base_address = 0; |
| 159 | + m_autoconfig_address = 0; |
| 160 | +} |
| 161 | + |
| 162 | +void a4091_device::cfgin_w(int state) |
| 163 | +{ |
| 164 | + LOG("cfgin_w (%d)\n", state); |
| 165 | + |
| 166 | + if (state) |
| 167 | + return; |
| 168 | + |
| 169 | + // the autoconfig nibbles are stored in the boot ROM |
| 170 | + zorro3_space().install_readwrite_handler(0xff000000, 0xff00ffff, |
| 171 | + read32s_delegate(*this, FUNC(a4091_device::autoconfig_r)), |
| 172 | + write32s_delegate(*this, FUNC(a4091_device::autoconfig_w)), 0xffffffff); |
| 173 | +} |
| 174 | + |
| 175 | +uint32_t a4091_device::autoconfig_r(offs_t offset, uint32_t mem_mask) |
| 176 | +{ |
| 177 | + uint32_t const data = (uint32_t(m_rom[offset] | 0x0f) << 24) | 0x00ffffff; |
| 178 | + |
| 179 | + if (!machine().side_effects_disabled()) |
| 180 | + LOG("autoconfig_r: %08x @ %04x [mask = %08x]\n", data, uint32_t(offset << 2), mem_mask); |
| 181 | + |
| 182 | + return data; |
| 183 | +} |
| 184 | + |
| 185 | +void a4091_device::autoconfig_w(offs_t offset, uint32_t data, uint32_t mem_mask) |
| 186 | +{ |
| 187 | + uint32_t const reg = offset << 2; |
| 188 | + |
| 189 | + LOG("autoconfig_w: %08x @ %04x [mask = %08x]\n", data, reg, mem_mask); |
| 190 | + |
| 191 | + switch (reg) |
| 192 | + { |
| 193 | + case 0x44: |
| 194 | + if (ACCESSING_BITS_24_31) |
| 195 | + m_autoconfig_address = (m_autoconfig_address & 0x00ffffff) | (data & 0xff000000); |
| 196 | + if (ACCESSING_BITS_16_23) |
| 197 | + m_autoconfig_address = (m_autoconfig_address & 0xff00ffff) | (data & 0x00ff0000); |
| 198 | + |
| 199 | + // a write to the high byte completes the configuration |
| 200 | + if (ACCESSING_BITS_24_31) |
| 201 | + autoconfig_base_address(m_autoconfig_address); |
| 202 | + break; |
| 203 | + |
| 204 | + case 0x48: |
| 205 | + if (ACCESSING_BITS_24_31) |
| 206 | + m_autoconfig_address = (m_autoconfig_address & 0xff00ffff) | ((data >> 8) & 0x00ff0000); |
| 207 | + break; |
| 208 | + |
| 209 | + case 0x4c: |
| 210 | + if (ACCESSING_BITS_24_31) |
| 211 | + autoconfig_base_address(0); |
| 212 | + break; |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +void a4091_device::autoconfig_base_address(offs_t address) |
| 217 | +{ |
| 218 | + LOG("Autoconfig address received: 0x%08x\n", uint32_t(address)); |
| 219 | + |
| 220 | + // stop responding to default autoconfig |
| 221 | + zorro3_space().unmap_readwrite(0xff000000, 0xff00ffff); |
| 222 | + |
| 223 | + m_base_address = address; |
| 224 | + |
| 225 | + // install the board if we have a valid address |
| 226 | + if (m_base_address) |
| 227 | + zorro3_space().install_device(m_base_address, m_base_address + BOARD_SIZE - 1, *this, &a4091_device::mmio_map); |
| 228 | + |
| 229 | + // we're done |
| 230 | + cfgout_w(0); |
| 231 | +} |
| 232 | + |
| 233 | + |
| 234 | +//************************************************************************** |
| 235 | +// MACHINE EMULATION |
| 236 | +//************************************************************************** |
| 237 | + |
| 238 | +uint32_t a4091_device::rom_r(offs_t offset) |
| 239 | +{ |
| 240 | + // each rom byte is presented as two nibbles on alternate byte lanes |
| 241 | + uint8_t const high = m_rom[offset] | 0x0f; |
| 242 | + uint8_t const low = (m_rom[offset] << 4) | 0x0f; |
| 243 | + |
| 244 | + return (uint32_t(high) << 24) | 0x00ff0000 | (uint32_t(low) << 8) | 0x000000ff; |
| 245 | +} |
| 246 | + |
| 247 | +uint32_t a4091_device::dma_r(offs_t offset, uint32_t mem_mask) |
| 248 | +{ |
| 249 | + return zorro3_dma_r(offset, mem_mask); |
| 250 | +} |
| 251 | + |
| 252 | +void a4091_device::dma_w(offs_t offset, uint32_t data, uint32_t mem_mask) |
| 253 | +{ |
| 254 | + zorro3_dma_w(offset, data, mem_mask); |
| 255 | +} |
| 256 | + |
| 257 | +void a4091_device::device_start() |
| 258 | +{ |
| 259 | + save_item(NAME(m_base_address)); |
| 260 | + save_item(NAME(m_autoconfig_address)); |
| 261 | +} |
| 262 | + |
| 263 | + |
| 264 | +//************************************************************************** |
| 265 | +// MACHINE DEFINITIONS |
| 266 | +//************************************************************************** |
| 267 | + |
| 268 | +void a4091_device::device_add_mconfig(machine_config &config) |
| 269 | +{ |
| 270 | + NCR53C710(config, m_ncr, 50_MHz_XTAL); |
| 271 | + m_ncr->irq_handler().set([this](int state) { int2_w(state); }); |
| 272 | + m_ncr->big_lit_handler().set_constant(1); |
| 273 | + m_ncr->host_read().set(FUNC(a4091_device::dma_r)); |
| 274 | + m_ncr->host_write().set(FUNC(a4091_device::dma_w)); |
| 275 | + |
| 276 | + NSCSI_BUS(config, m_scsi); |
| 277 | + NSCSI_CONNECTOR(config, "scsi:0", default_scsi_devices, "harddisk"); |
| 278 | + NSCSI_CONNECTOR(config, "scsi:1", default_scsi_devices, nullptr); |
| 279 | + NSCSI_CONNECTOR(config, "scsi:2", default_scsi_devices, nullptr); |
| 280 | + NSCSI_CONNECTOR(config, "scsi:3", default_scsi_devices, nullptr); |
| 281 | + NSCSI_CONNECTOR(config, "scsi:4", default_scsi_devices, nullptr); |
| 282 | + NSCSI_CONNECTOR(config, "scsi:5", default_scsi_devices, nullptr); |
| 283 | + NSCSI_CONNECTOR(config, "scsi:6", default_scsi_devices, nullptr); |
| 284 | + m_scsi->set_external_device(7, m_ncr); |
| 285 | +} |
| 286 | + |
| 287 | + |
| 288 | +//************************************************************************** |
| 289 | +// ROM DEFINITIONS |
| 290 | +//************************************************************************** |
| 291 | + |
| 292 | +ROM_START( a4091 ) |
| 293 | + ROM_REGION(0x10000, "rom", 0) |
| 294 | + ROM_DEFAULT_BIOS("v4013") |
| 295 | + |
| 296 | + ROM_SYSTEM_BIOS(0, "v404", "v40.4") |
| 297 | + ROMX_LOAD("a4091_v404.u206", 0x0000, 0x8000, CRC(9ba7e7dc) SHA1(18985b7ec95239da21a242a4fc42f13496434534), ROM_BIOS(0)) |
| 298 | + ROM_RELOAD( 0x8000, 0x8000) |
| 299 | + ROM_SYSTEM_BIOS(1, "v409", "v40.9") |
| 300 | + ROMX_LOAD("a4091_v409.u206", 0x0000, 0x8000, CRC(7e12a120) SHA1(a411d5726801dc443d41428f382ae3d56f44ef27), ROM_BIOS(1)) |
| 301 | + ROM_RELOAD( 0x8000, 0x8000) |
| 302 | + ROM_SYSTEM_BIOS(2, "v4013", "v40.13") |
| 303 | + ROMX_LOAD("391592-02_a4091_v4013.u206", 0x0000, 0x8000, CRC(54cb9e85) SHA1(3ce66919f6fd67974923a12d91b730f1ffb4a7ba), ROM_BIOS(2)) |
| 304 | + ROM_RELOAD( 0x8000, 0x8000) |
| 305 | +ROM_END |
| 306 | + |
| 307 | +const tiny_rom_entry *a4091_device::device_rom_region() const |
| 308 | +{ |
| 309 | + return ROM_NAME( a4091 ); |
| 310 | +} |
| 311 | + |
| 312 | + |
| 313 | +} // namespace bus::amiga::zorro |
| 314 | + |
| 315 | + |
| 316 | +//************************************************************************** |
| 317 | +// DEVICE DEFINITIONS |
| 318 | +//************************************************************************** |
| 319 | + |
| 320 | +DEFINE_DEVICE_TYPE_PRIVATE(AMIGA_A4091, device_zorro3_card_interface, bus::amiga::zorro::a4091_device, "amiga_a4091", "Commodore/DKB A4091 SCSI Host Adapter") |
0 commit comments