mirror of
https://github.com/86Box/86Box.git
synced 2025-01-22 17:22:25 -05:00
SCSI CD-ROM and 5380 fixes.
CD-ROM side: fixed a mode sense page (0x08 Sony, used by both Sony and Texel drives) as well as corrected the Toshiba specific drive speeds (bytes_per_second). NCR 5380 side: split the work into the generic 5380 core and the ASICs into separate sources (53c400 and T128) and added the T228 MCA adapter based on the 128.
This commit is contained in:
parent
c69066715c
commit
da1ededb93
8 changed files with 1865 additions and 1484 deletions
|
@ -173,8 +173,8 @@
|
|||
#define GPMODEP_RIGID_DISK_PAGE 0x0000000000000010LL
|
||||
#define GPMODEP_FLEXIBLE_DISK_PAGE 0x0000000000000020LL
|
||||
#define GPMODEP_CACHING_PAGE 0x0000000000000100LL
|
||||
#define GPMODEP_CDROM_PAGE_SONY 0x0000000000000200LL
|
||||
#define GPMODEP_CDROM_AUDIO_PAGE_SONY 0x0000000000000400LL
|
||||
#define GPMODEP_CDROM_PAGE_SONY 0x0000000000000100LL
|
||||
#define GPMODEP_CDROM_AUDIO_PAGE_SONY 0x0000000000000200LL
|
||||
#define GPMODEP_CDROM_PAGE 0x0000000000002000LL
|
||||
#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL
|
||||
#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the NCR 5380 series of SCSI Host Adapters
|
||||
* made by NCR. These controllers were designed for
|
||||
* the ISA bus.
|
||||
* Implementation of the NCR 5380 chip made by NCR
|
||||
* and used in various controllers.
|
||||
*
|
||||
*
|
||||
*
|
||||
|
@ -17,21 +16,128 @@
|
|||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017-2018 Sarah Walker.
|
||||
* Copyright 2017-2018 TheCollector1995.
|
||||
* Copyright 2017-2018 Fred N. van Kempen.
|
||||
* Copyright 2017-2024 TheCollector1995.
|
||||
*/
|
||||
|
||||
#ifndef SCSI_NCR5380_H
|
||||
#define SCSI_NCR5380_H
|
||||
|
||||
#define NCR_CURDATA 0 /* current SCSI data (read only) */
|
||||
#define NCR_OUTDATA 0 /* output data (write only) */
|
||||
#define NCR_INITCOMMAND 1 /* initiator command (read/write) */
|
||||
#define NCR_MODE 2 /* mode (read/write) */
|
||||
#define NCR_TARGETCMD 3 /* target command (read/write) */
|
||||
#define NCR_SELENABLE 4 /* select enable (write only) */
|
||||
#define NCR_BUSSTATUS 4 /* bus status (read only) */
|
||||
#define NCR_STARTDMA 5 /* start DMA send (write only) */
|
||||
#define NCR_BUSANDSTAT 5 /* bus and status (read only) */
|
||||
#define NCR_DMATARGET 6 /* DMA target (write only) */
|
||||
#define NCR_INPUTDATA 6 /* input data (read only) */
|
||||
#define NCR_DMAINIRECV 7 /* DMA initiator receive (write only) */
|
||||
#define NCR_RESETPARITY 7 /* reset parity/interrupt (read only) */
|
||||
|
||||
#define ICR_DBP 0x01
|
||||
#define ICR_ATN 0x02
|
||||
#define ICR_SEL 0x04
|
||||
#define ICR_BSY 0x08
|
||||
#define ICR_ACK 0x10
|
||||
#define ICR_ARB_LOST 0x20
|
||||
#define ICR_ARB_IN_PROGRESS 0x40
|
||||
|
||||
#define MODE_ARBITRATE 0x01
|
||||
#define MODE_DMA 0x02
|
||||
#define MODE_MONITOR_BUSY 0x04
|
||||
#define MODE_ENA_EOP_INT 0x08
|
||||
|
||||
#define STATUS_ACK 0x01
|
||||
#define STATUS_BUSY_ERROR 0x04
|
||||
#define STATUS_PHASE_MATCH 0x08
|
||||
#define STATUS_INT 0x10
|
||||
#define STATUS_DRQ 0x40
|
||||
#define STATUS_END_OF_DMA 0x80
|
||||
|
||||
#define TCR_IO 0x01
|
||||
#define TCR_CD 0x02
|
||||
#define TCR_MSG 0x04
|
||||
#define TCR_REQ 0x08
|
||||
#define TCR_LAST_BYTE_SENT 0x80
|
||||
|
||||
|
||||
#define STATE_IDLE 0
|
||||
#define STATE_COMMAND 1
|
||||
#define STATE_DATAIN 2
|
||||
#define STATE_DATAOUT 3
|
||||
#define STATE_STATUS 4
|
||||
#define STATE_MESSAGEIN 5
|
||||
#define STATE_SELECT 6
|
||||
#define STATE_MESSAGEOUT 7
|
||||
#define STATE_MESSAGE_ID 8
|
||||
|
||||
#define DMA_IDLE 0
|
||||
#define DMA_SEND 1
|
||||
#define DMA_INITIATOR_RECEIVE 2
|
||||
|
||||
typedef struct ncr_t {
|
||||
uint8_t icr;
|
||||
uint8_t mode;
|
||||
uint8_t tcr;
|
||||
uint8_t data_wait;
|
||||
uint8_t isr;
|
||||
uint8_t output_data;
|
||||
uint8_t target_id;
|
||||
uint8_t tx_data;
|
||||
uint8_t msglun;
|
||||
|
||||
uint8_t command[20];
|
||||
uint8_t msgout[4];
|
||||
uint8_t bus;
|
||||
|
||||
int msgout_pos;
|
||||
int is_msgout;
|
||||
|
||||
int dma_mode;
|
||||
int cur_bus;
|
||||
int bus_in;
|
||||
int new_phase;
|
||||
int state;
|
||||
int clear_req;
|
||||
int wait_data;
|
||||
int wait_complete;
|
||||
int command_pos;
|
||||
int data_pos;
|
||||
|
||||
int irq;
|
||||
|
||||
double period;
|
||||
|
||||
void *priv;
|
||||
void (*dma_mode_ext)(void *priv, void *ext_priv);
|
||||
int (*dma_send_ext)(void *priv, void *ext_priv);
|
||||
int (*dma_initiator_receive_ext)(void *priv, void *ext_priv);
|
||||
void (*timer)(void *ext_priv, double period);
|
||||
} ncr_t;
|
||||
|
||||
extern int ncr5380_cmd_len[8];
|
||||
|
||||
extern void ncr5380_irq(ncr_t *ncr, int set_irq);
|
||||
extern uint32_t ncr5380_get_bus_host(ncr_t *ncr);
|
||||
extern void ncr5380_bus_read(ncr_t *ncr);
|
||||
extern void ncr5380_bus_update(ncr_t *ncr, int bus);
|
||||
extern void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr);
|
||||
extern uint8_t ncr5380_read(uint16_t port, ncr_t *ncr);
|
||||
|
||||
#ifdef EMU_DEVICE_H
|
||||
extern const device_t scsi_lcs6821n_device;
|
||||
extern const device_t scsi_rt1000b_device;
|
||||
extern const device_t scsi_rt1000mc_device;
|
||||
extern const device_t scsi_t128_device;
|
||||
extern const device_t scsi_t228_device;
|
||||
extern const device_t scsi_t130b_device;
|
||||
extern const device_t scsi_ls2000_device;
|
||||
#if defined(DEV_BRANCH) && defined(USE_SUMO)
|
||||
extern const device_t scsi_scsiat_device;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /*SCSI_NCR5380_H*/
|
||||
|
|
|
@ -14,5 +14,5 @@
|
|||
#
|
||||
|
||||
add_library(scsi OBJECT scsi.c scsi_device.c scsi_cdrom.c scsi_disk.c
|
||||
scsi_x54x.c scsi_aha154x.c scsi_buslogic.c scsi_ncr5380.c
|
||||
scsi_ncr53c8xx.c scsi_pcscsi.c scsi_spock.c)
|
||||
scsi_x54x.c scsi_aha154x.c scsi_buslogic.c scsi_ncr5380.c scsi_ncr53c400.c
|
||||
scsi_t128.c scsi_ncr53c8xx.c scsi_pcscsi.c scsi_spock.c)
|
||||
|
|
|
@ -82,6 +82,7 @@ static SCSI_CARD scsi_cards[] = {
|
|||
{ &scsi_rt1000b_device, },
|
||||
{ &scsi_rt1000mc_device, },
|
||||
{ &scsi_t128_device, },
|
||||
{ &scsi_t228_device, },
|
||||
{ &scsi_t130b_device, },
|
||||
{ &aha1640_device, },
|
||||
{ &buslogic_640a_device, },
|
||||
|
|
|
@ -1001,7 +1001,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev)
|
|||
case CDROM_TYPE_TOSHIBA_XM3301TA_0272:
|
||||
case CDROM_TYPE_TOSHIBA_XM5701TA_3136:
|
||||
case CDROM_TYPE_TOSHIBA_SDM1401_1008:
|
||||
bytes_per_second = 176.0 * 1024.0;
|
||||
bytes_per_second = 176400.0;
|
||||
bytes_per_second *= (double) dev->drv->cur_speed;
|
||||
break;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
998
src/scsi/scsi_ncr53c400.c
Normal file
998
src/scsi/scsi_ncr53c400.c
Normal file
|
@ -0,0 +1,998 @@
|
|||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the NCR 53c400 series of SCSI Host Adapters
|
||||
* made by NCR. These controllers were designed for the ISA and MCA bus.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017-2019 Sarah Walker.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
* Copyright 2017-2024 TheCollector1995.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/dma.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/mca.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/rom.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/scsi.h>
|
||||
#include <86box/scsi_device.h>
|
||||
#include <86box/scsi_ncr5380.h>
|
||||
|
||||
#define LCS6821N_ROM "roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin"
|
||||
#define COREL_LS2000_ROM "roms/scsi/ncr5380/Corel LS2000 - BIOS ROM - Ver 1.65.bin"
|
||||
#define RT1000B_810R_ROM "roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin"
|
||||
#define RT1000B_820R_ROM "roms/scsi/ncr5380/RTBIOS82.ROM"
|
||||
#define T130B_ROM "roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin"
|
||||
|
||||
#define CTRL_DATA_DIR 0x40
|
||||
#define STATUS_BUFFER_NOT_READY 0x04
|
||||
#define STATUS_5380_ACCESSIBLE 0x80
|
||||
|
||||
enum {
|
||||
ROM_LCS6821N = 0,
|
||||
ROM_LS2000,
|
||||
ROM_RT1000B,
|
||||
ROM_T130B
|
||||
};
|
||||
|
||||
typedef struct ncr53c400_t {
|
||||
rom_t bios_rom;
|
||||
mem_mapping_t mapping;
|
||||
ncr_t ncr;
|
||||
uint8_t buffer[128];
|
||||
uint8_t int_ram[0x40];
|
||||
uint8_t ext_ram[0x600];
|
||||
|
||||
uint32_t rom_addr;
|
||||
uint16_t base;
|
||||
|
||||
int8_t type;
|
||||
uint8_t block_count;
|
||||
uint8_t status_ctrl;
|
||||
|
||||
int block_count_loaded;
|
||||
|
||||
int buffer_pos;
|
||||
int buffer_host_pos;
|
||||
|
||||
int busy;
|
||||
uint8_t pos_regs[8];
|
||||
|
||||
pc_timer_t timer;
|
||||
} ncr53c400_t;
|
||||
|
||||
#ifdef ENABLE_NCR53C400_LOG
|
||||
int ncr53c400_do_log = ENABLE_NCR53C400_LOG;
|
||||
|
||||
static void
|
||||
ncr53c400_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (ncr53c400_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define ncr53c400_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Memory-mapped I/O WRITE handler. */
|
||||
static void
|
||||
ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
ncr_t *ncr = &ncr400->ncr;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
|
||||
addr &= 0x3fff;
|
||||
|
||||
if (addr >= 0x3a00)
|
||||
ncr400->ext_ram[addr - 0x3a00] = val;
|
||||
else {
|
||||
switch (addr & 0x3f80) {
|
||||
case 0x3800:
|
||||
ncr400->int_ram[addr & 0x3f] = val;
|
||||
break;
|
||||
|
||||
case 0x3880:
|
||||
ncr5380_write(addr, val, ncr);
|
||||
break;
|
||||
|
||||
case 0x3900:
|
||||
if (!(ncr400->status_ctrl & CTRL_DATA_DIR) && (ncr400->buffer_host_pos < MIN(128, dev->buffer_length))) {
|
||||
ncr400->buffer[ncr400->buffer_host_pos++] = val;
|
||||
|
||||
ncr53c400_log("Write host pos = %i, val = %02x\n", ncr400->buffer_host_pos, val);
|
||||
|
||||
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
|
||||
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
|
||||
ncr400->busy = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3980:
|
||||
switch (addr) {
|
||||
case 0x3980: /* Control */
|
||||
ncr53c400_log("NCR 53c400 control = %02x, mode = %02x.\n", val, ncr->mode);
|
||||
if ((val & CTRL_DATA_DIR) && !(ncr400->status_ctrl & CTRL_DATA_DIR)) {
|
||||
ncr400->buffer_host_pos = MIN(128, dev->buffer_length);
|
||||
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
|
||||
} else if (!(val & CTRL_DATA_DIR) && (ncr400->status_ctrl & CTRL_DATA_DIR)) {
|
||||
ncr400->buffer_host_pos = 0;
|
||||
ncr400->status_ctrl &= ~STATUS_BUFFER_NOT_READY;
|
||||
}
|
||||
ncr400->status_ctrl = (ncr400->status_ctrl & 0x87) | (val & 0x78);
|
||||
break;
|
||||
|
||||
case 0x3981: /* block counter register */
|
||||
ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf\n", val, ncr->dma_mode, ncr->period);
|
||||
ncr400->block_count = val;
|
||||
ncr400->block_count_loaded = 1;
|
||||
|
||||
if (ncr400->status_ctrl & CTRL_DATA_DIR) {
|
||||
ncr400->buffer_host_pos = MIN(128, dev->buffer_length);
|
||||
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
|
||||
} else {
|
||||
ncr400->buffer_host_pos = 0;
|
||||
ncr400->status_ctrl &= ~STATUS_BUFFER_NOT_READY;
|
||||
}
|
||||
if ((ncr->mode & MODE_DMA) && !timer_is_on(&ncr400->timer) && (dev->buffer_length > 0)) {
|
||||
memset(ncr400->buffer, 0, MIN(128, dev->buffer_length));
|
||||
ncr53c400_log("DMA timer on\n");
|
||||
timer_on_auto(&ncr400->timer, ncr->period);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory-mapped I/O READ handler. */
|
||||
static uint8_t
|
||||
ncr53c400_read(uint32_t addr, void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
ncr_t *ncr = &ncr400->ncr;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
addr &= 0x3fff;
|
||||
|
||||
if (addr < 0x2000)
|
||||
ret = ncr400->bios_rom.rom[addr & 0x1fff];
|
||||
else if (addr < 0x3800)
|
||||
ret = 0xff;
|
||||
else if (addr >= 0x3a00)
|
||||
ret = ncr400->ext_ram[addr - 0x3a00];
|
||||
else {
|
||||
switch (addr & 0x3f80) {
|
||||
case 0x3800:
|
||||
ncr53c400_log("Read intRAM %02x %02x\n", addr & 0x3f, ncr400->int_ram[addr & 0x3f]);
|
||||
ret = ncr400->int_ram[addr & 0x3f];
|
||||
break;
|
||||
|
||||
case 0x3880:
|
||||
ncr53c400_log("Read 5380 %04x\n", addr);
|
||||
ret = ncr5380_read(addr, ncr);
|
||||
break;
|
||||
|
||||
case 0x3900:
|
||||
if (ncr400->buffer_host_pos >= MIN(128, dev->buffer_length) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) {
|
||||
ret = 0xff;
|
||||
ncr53c400_log("No Read.\n");
|
||||
} else {
|
||||
ret = ncr400->buffer[ncr400->buffer_host_pos++];
|
||||
ncr53c400_log("Read host pos = %i, ret = %02x\n", ncr400->buffer_host_pos, ret);
|
||||
|
||||
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
|
||||
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
|
||||
ncr53c400_log("Transfer busy read, status = %02x\n", ncr400->status_ctrl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3980:
|
||||
switch (addr) {
|
||||
case 0x3980: /* status */
|
||||
ret = ncr400->status_ctrl;
|
||||
ncr53c400_log("NCR status ctrl read=%02x\n", ncr400->status_ctrl & STATUS_BUFFER_NOT_READY);
|
||||
if (!ncr400->busy)
|
||||
ret |= STATUS_5380_ACCESSIBLE;
|
||||
if (ncr->mode & 0x30) { /*Parity bits*/
|
||||
if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/
|
||||
ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/
|
||||
ncr->mode = 0; /*Required by RTASPI10.SYS otherwise it won't initialize.*/
|
||||
}
|
||||
}
|
||||
ncr53c400_log("NCR 53c400 status = %02x.\n", ret);
|
||||
break;
|
||||
|
||||
case 0x3981: /* block counter register*/
|
||||
ret = ncr400->block_count;
|
||||
break;
|
||||
|
||||
case 0x3982: /* switch register read */
|
||||
ret = 0xf8;
|
||||
ret |= (ncr->irq & 0x07);
|
||||
ncr53c400_log("Switches read=%02x.\n", ret);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr >= 0x3880)
|
||||
ncr53c400_log("memio_read(%08x)=%02x\n", addr, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Memory-mapped I/O WRITE handler for the Trantor T130B. */
|
||||
static void
|
||||
t130b_write(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
|
||||
addr &= 0x3fff;
|
||||
ncr53c400_log("MEM: Writing %02X to %08X\n", val, addr);
|
||||
if (addr >= 0x1800 && addr < 0x1880)
|
||||
ncr400->ext_ram[addr & 0x7f] = val;
|
||||
}
|
||||
|
||||
/* Memory-mapped I/O READ handler for the Trantor T130B. */
|
||||
static uint8_t
|
||||
t130b_read(uint32_t addr, void *priv)
|
||||
{
|
||||
const ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
addr &= 0x3fff;
|
||||
if (addr < 0x1800)
|
||||
ret = ncr400->bios_rom.rom[addr & 0x1fff];
|
||||
else if (addr >= 0x1800 && addr < 0x1880)
|
||||
ret = ncr400->ext_ram[addr & 0x7f];
|
||||
|
||||
ncr53c400_log("MEM: Reading %02X from %08X\n", ret, addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
t130b_out(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
ncr_t *ncr = &ncr400->ncr;
|
||||
|
||||
ncr53c400_log("I/O: Writing %02X to %04X\n", val, port);
|
||||
|
||||
switch (port & 0x0f) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
ncr53c400_write((port & 7) | 0x3980, val, ncr400);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
ncr53c400_write(0x3900, val, ncr400);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0a:
|
||||
case 0x0b:
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x0f:
|
||||
ncr5380_write(port, val, ncr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
t130b_in(uint16_t port, void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
ncr_t *ncr = &ncr400->ncr;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch (port & 0x0f) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
ret = ncr53c400_read((port & 7) | 0x3980, ncr400);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
ret = ncr53c400_read(0x3900, ncr400);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0a:
|
||||
case 0x0b:
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x0f:
|
||||
ret = ncr5380_read(port, ncr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ncr53c400_log("I/O: Reading %02X from %04X\n", ret, port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ncr53c400_dma_mode_ext(void *priv, void *ext_priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv;
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
|
||||
/*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/
|
||||
if (!ncr400->block_count_loaded && !(ncr->mode & MODE_DMA)) {
|
||||
ncr53c400_log("No DMA mode\n");
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
ncr->isr &= ~STATUS_END_OF_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ncr53c400_timer_on_auto(void *ext_priv, double period)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv;
|
||||
|
||||
ncr53c400_log("53c400: PERIOD=%lf.\n", period);
|
||||
if (period == 0.0)
|
||||
timer_stop(&ncr400->timer);
|
||||
else
|
||||
timer_on_auto(&ncr400->timer, period);
|
||||
}
|
||||
|
||||
static void
|
||||
ncr53c400_callback(void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (void *) priv;
|
||||
ncr_t *ncr = &ncr400->ncr;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
int bus;
|
||||
uint8_t c;
|
||||
uint8_t temp;
|
||||
|
||||
if (ncr->dma_mode != DMA_IDLE)
|
||||
timer_on_auto(&ncr400->timer, 1.0);
|
||||
|
||||
if (ncr->data_wait & 1) {
|
||||
ncr->clear_req = 3;
|
||||
ncr->data_wait &= ~1;
|
||||
if (ncr->dma_mode == DMA_IDLE) {
|
||||
timer_stop(&ncr400->timer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ncr->dma_mode == DMA_IDLE) {
|
||||
timer_stop(&ncr400->timer);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ncr->dma_mode) {
|
||||
case DMA_SEND:
|
||||
if (ncr400->status_ctrl & CTRL_DATA_DIR) {
|
||||
ncr53c400_log("DMA_SEND with DMA direction set wrong\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(ncr400->status_ctrl & STATUS_BUFFER_NOT_READY)) {
|
||||
ncr53c400_log("Write buffer status ready\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ncr400->block_count_loaded) {
|
||||
ncr53c400_log("Write block count not loaded.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data ready. */
|
||||
temp = ncr400->buffer[ncr400->buffer_pos];
|
||||
|
||||
bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK;
|
||||
bus |= BUS_SETDATA(temp);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
|
||||
ncr400->buffer_pos++;
|
||||
ncr53c400_log("NCR 53c400 Buffer pos for writing = %d\n", ncr400->buffer_pos);
|
||||
|
||||
if (ncr400->buffer_pos == MIN(128, dev->buffer_length)) {
|
||||
ncr400->status_ctrl &= ~STATUS_BUFFER_NOT_READY;
|
||||
ncr400->buffer_pos = 0;
|
||||
ncr400->buffer_host_pos = 0;
|
||||
ncr400->busy = 0;
|
||||
ncr400->block_count = (ncr400->block_count - 1) & 0xff;
|
||||
ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count);
|
||||
if (!ncr400->block_count) {
|
||||
ncr400->block_count_loaded = 0;
|
||||
ncr53c400_log("IO End of write transfer\n");
|
||||
ncr->tcr |= TCR_LAST_BYTE_SENT;
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
timer_stop(&ncr400->timer);
|
||||
if (ncr->mode & MODE_ENA_EOP_INT) {
|
||||
ncr53c400_log("NCR 53c400 write irq\n");
|
||||
ncr5380_irq(ncr, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA_INITIATOR_RECEIVE:
|
||||
if (!(ncr400->status_ctrl & CTRL_DATA_DIR)) {
|
||||
ncr53c400_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(ncr400->status_ctrl & STATUS_BUFFER_NOT_READY)) {
|
||||
ncr53c400_log("Read buffer status ready\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ncr400->block_count_loaded)
|
||||
break;
|
||||
|
||||
while (1) {
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data ready. */
|
||||
ncr5380_bus_read(ncr);
|
||||
temp = BUS_GETDATA(ncr->cur_bus);
|
||||
|
||||
bus = ncr5380_get_bus_host(ncr);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
|
||||
ncr400->buffer[ncr400->buffer_pos++] = temp;
|
||||
ncr53c400_log("NCR 53c400 Buffer pos for reading = %d\n", ncr400->buffer_pos);
|
||||
|
||||
if (ncr400->buffer_pos == MIN(128, dev->buffer_length)) {
|
||||
ncr400->status_ctrl &= ~STATUS_BUFFER_NOT_READY;
|
||||
ncr400->buffer_pos = 0;
|
||||
ncr400->buffer_host_pos = 0;
|
||||
ncr400->block_count = (ncr400->block_count - 1) & 0xff;
|
||||
ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count);
|
||||
if (!ncr400->block_count) {
|
||||
ncr400->block_count_loaded = 0;
|
||||
ncr53c400_log("IO End of read transfer\n");
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
timer_stop(&ncr400->timer);
|
||||
if (ncr->mode & MODE_ENA_EOP_INT) {
|
||||
ncr53c400_log("NCR read irq\n");
|
||||
ncr5380_irq(ncr, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ncr5380_bus_read(ncr);
|
||||
|
||||
if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) {
|
||||
ncr53c400_log("Updating DMA\n");
|
||||
ncr->mode &= ~MODE_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
rt1000b_mc_read(int port, void *priv)
|
||||
{
|
||||
const ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
|
||||
return (ncr400->pos_regs[port & 7]);
|
||||
}
|
||||
|
||||
static void
|
||||
rt1000b_mc_write(int port, uint8_t val, void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
|
||||
/* MCA does not write registers below 0x0100. */
|
||||
if (port < 0x0102)
|
||||
return;
|
||||
|
||||
mem_mapping_disable(&ncr400->bios_rom.mapping);
|
||||
mem_mapping_disable(&ncr400->mapping);
|
||||
|
||||
/* Save the MCA register value. */
|
||||
ncr400->pos_regs[port & 7] = val;
|
||||
|
||||
if (ncr400->pos_regs[2] & 1) {
|
||||
switch (ncr400->pos_regs[2] & 0xe0) {
|
||||
case 0:
|
||||
ncr400->rom_addr = 0xd4000;
|
||||
break;
|
||||
case 0x20:
|
||||
ncr400->rom_addr = 0xd0000;
|
||||
break;
|
||||
case 0x40:
|
||||
ncr400->rom_addr = 0xcc000;
|
||||
break;
|
||||
case 0x60:
|
||||
ncr400->rom_addr = 0xc8000;
|
||||
break;
|
||||
case 0xc0:
|
||||
ncr400->rom_addr = 0xdc000;
|
||||
break;
|
||||
case 0xe0:
|
||||
ncr400->rom_addr = 0xd8000;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mem_mapping_set_addr(&ncr400->bios_rom.mapping, ncr400->rom_addr, 0x4000);
|
||||
mem_mapping_set_addr(&ncr400->mapping, ncr400->rom_addr, 0x4000);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
rt1000b_mc_feedb(void *priv)
|
||||
{
|
||||
const ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
|
||||
return ncr400->pos_regs[2] & 1;
|
||||
}
|
||||
|
||||
static void *
|
||||
ncr53c400_init(const device_t *info)
|
||||
{
|
||||
const char *bios_ver = NULL;
|
||||
const char *fn;
|
||||
ncr53c400_t *ncr400;
|
||||
ncr_t *ncr;
|
||||
|
||||
ncr400 = malloc(sizeof(ncr53c400_t));
|
||||
memset(ncr400, 0x00, sizeof(ncr53c400_t));
|
||||
ncr = &ncr400->ncr;
|
||||
|
||||
ncr400->type = info->local;
|
||||
|
||||
ncr->bus = scsi_get_bus();
|
||||
|
||||
switch (ncr400->type) {
|
||||
case ROM_LCS6821N: /* Longshine LCS6821N */
|
||||
ncr400->rom_addr = device_get_config_hex20("bios_addr");
|
||||
ncr->irq = device_get_config_int("irq");
|
||||
|
||||
rom_init(&ncr400->bios_rom, LCS6821N_ROM,
|
||||
ncr400->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
mem_mapping_add(&ncr400->mapping, ncr400->rom_addr, 0x4000,
|
||||
ncr53c400_read, NULL, NULL,
|
||||
ncr53c400_write, NULL, NULL,
|
||||
ncr400->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr400);
|
||||
break;
|
||||
|
||||
|
||||
case ROM_LS2000: /* Corel LS2000 */
|
||||
ncr400->rom_addr = device_get_config_hex20("bios_addr");
|
||||
ncr->irq = device_get_config_int("irq");
|
||||
|
||||
rom_init(&ncr400->bios_rom, COREL_LS2000_ROM,
|
||||
ncr400->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
mem_mapping_add(&ncr400->mapping, ncr400->rom_addr, 0x4000,
|
||||
ncr53c400_read, NULL, NULL,
|
||||
ncr53c400_write, NULL, NULL,
|
||||
ncr400->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr400);
|
||||
break;
|
||||
|
||||
case ROM_RT1000B: /* Rancho RT1000B/MC */
|
||||
ncr400->rom_addr = device_get_config_hex20("bios_addr");
|
||||
ncr->irq = device_get_config_int("irq");
|
||||
if (info->flags & DEVICE_MCA) {
|
||||
rom_init(&ncr400->bios_rom, RT1000B_820R_ROM,
|
||||
0xd8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
mem_mapping_add(&ncr400->mapping, 0xd8000, 0x4000,
|
||||
ncr53c400_read, NULL, NULL,
|
||||
ncr53c400_write, NULL, NULL,
|
||||
ncr400->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr400);
|
||||
mem_mapping_disable(&ncr400->bios_rom.mapping);
|
||||
ncr400->pos_regs[0] = 0x8d;
|
||||
ncr400->pos_regs[1] = 0x70;
|
||||
mca_add(rt1000b_mc_read, rt1000b_mc_write, rt1000b_mc_feedb, NULL, ncr400);
|
||||
} else {
|
||||
bios_ver = (char *) device_get_config_bios("bios_ver");
|
||||
fn = (char *) device_get_bios_file(info, bios_ver, 0);
|
||||
rom_init(&ncr400->bios_rom, fn,
|
||||
ncr400->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
mem_mapping_add(&ncr400->mapping, ncr400->rom_addr, 0x4000,
|
||||
ncr53c400_read, NULL, NULL,
|
||||
ncr53c400_write, NULL, NULL,
|
||||
ncr400->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr400);
|
||||
}
|
||||
break;
|
||||
|
||||
case ROM_T130B: /* Trantor T130B */
|
||||
ncr400->rom_addr = device_get_config_hex20("bios_addr");
|
||||
ncr400->base = device_get_config_hex16("base");
|
||||
ncr->irq = device_get_config_int("irq");
|
||||
|
||||
if (ncr400->rom_addr > 0x00000) {
|
||||
rom_init(&ncr400->bios_rom, T130B_ROM,
|
||||
ncr400->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
mem_mapping_add(&ncr400->mapping, ncr400->rom_addr, 0x4000,
|
||||
t130b_read, NULL, NULL,
|
||||
t130b_write, NULL, NULL,
|
||||
ncr400->bios_rom.rom, MEM_MAPPING_EXTERNAL, ncr400);
|
||||
}
|
||||
|
||||
io_sethandler(ncr400->base, 16,
|
||||
t130b_in, NULL, NULL, t130b_out, NULL, NULL, ncr400);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ncr->priv = ncr400;
|
||||
ncr->dma_mode_ext = ncr53c400_dma_mode_ext;
|
||||
ncr->dma_send_ext = NULL;
|
||||
ncr->dma_initiator_receive_ext = NULL;
|
||||
ncr->timer = ncr53c400_timer_on_auto;
|
||||
ncr400->status_ctrl = STATUS_BUFFER_NOT_READY;
|
||||
ncr400->buffer_host_pos = 128;
|
||||
timer_add(&ncr400->timer, ncr53c400_callback, ncr400, 0);
|
||||
|
||||
scsi_bus_set_speed(ncr->bus, 5000000.0);
|
||||
|
||||
return ncr400;
|
||||
}
|
||||
|
||||
static void
|
||||
ncr53c400_close(void *priv)
|
||||
{
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) priv;
|
||||
|
||||
if (ncr400) {
|
||||
/* Tell the timer to terminate. */
|
||||
timer_stop(&ncr400->timer);
|
||||
|
||||
free(ncr400);
|
||||
ncr400 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
lcs6821n_available(void)
|
||||
{
|
||||
return (rom_present(LCS6821N_ROM));
|
||||
}
|
||||
|
||||
static int
|
||||
rt1000b_mc_available(void)
|
||||
{
|
||||
return (rom_present(RT1000B_820R_ROM));
|
||||
}
|
||||
|
||||
static int
|
||||
t130b_available(void)
|
||||
{
|
||||
return (rom_present(T130B_ROM));
|
||||
}
|
||||
|
||||
static int
|
||||
corel_ls2000_available(void)
|
||||
{
|
||||
return (rom_present(COREL_LS2000_ROM));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static const device_config_t ncr53c400_mmio_config[] = {
|
||||
{
|
||||
.name = "bios_addr",
|
||||
.description = "BIOS Address",
|
||||
.type = CONFIG_HEX20,
|
||||
.default_string = "",
|
||||
.default_int = 0xD8000,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "C800H", .value = 0xc8000 },
|
||||
{ .description = "CC00H", .value = 0xcc000 },
|
||||
{ .description = "D000H", .value = 0xd0000 },
|
||||
{ .description = "D400H", .value = 0xd4000 },
|
||||
{ .description = "D800H", .value = 0xd8000 },
|
||||
{ .description = "DC00H", .value = 0xdc000 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "irq",
|
||||
.description = "IRQ",
|
||||
.type = CONFIG_SELECTION,
|
||||
.default_string = "",
|
||||
.default_int = 5,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "None", .value = -1 },
|
||||
{ .description = "IRQ 3", .value = 3 },
|
||||
{ .description = "IRQ 5", .value = 5 },
|
||||
{ .description = "IRQ 7", .value = 7 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
|
||||
static const device_config_t rt1000b_config[] = {
|
||||
{
|
||||
.name = "bios_addr",
|
||||
.description = "BIOS Address",
|
||||
.type = CONFIG_HEX20,
|
||||
.default_string = "",
|
||||
.default_int = 0xD8000,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "C800H", .value = 0xc8000 },
|
||||
{ .description = "CC00H", .value = 0xcc000 },
|
||||
{ .description = "D000H", .value = 0xd0000 },
|
||||
{ .description = "D400H", .value = 0xd4000 },
|
||||
{ .description = "D800H", .value = 0xd8000 },
|
||||
{ .description = "DC00H", .value = 0xdc000 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "irq",
|
||||
.description = "IRQ",
|
||||
.type = CONFIG_SELECTION,
|
||||
.default_string = "",
|
||||
.default_int = 5,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "None", .value = -1 },
|
||||
{ .description = "IRQ 3", .value = 3 },
|
||||
{ .description = "IRQ 5", .value = 5 },
|
||||
{ .description = "IRQ 7", .value = 7 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "bios_ver",
|
||||
.description = "BIOS Version",
|
||||
.type = CONFIG_BIOS,
|
||||
.default_string = "v8_10r",
|
||||
.default_int = 0,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 }, /*W1*/
|
||||
.bios = {
|
||||
{ .name = "Version 8.10R", .internal_name = "v8_10r", .bios_type = BIOS_NORMAL,
|
||||
.files_no = 1, .local = 0, .size = 8192, .files = { RT1000B_810R_ROM, "" } },
|
||||
{ .name = "Version 8.20R", .internal_name = "v8_20r", .bios_type = BIOS_NORMAL,
|
||||
.files_no = 1, .local = 0, .size = 8192, .files = { RT1000B_820R_ROM, "" } },
|
||||
{ .files_no = 0 }
|
||||
},
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
|
||||
static const device_config_t rt1000b_mc_config[] = {
|
||||
{
|
||||
.name = "irq",
|
||||
.description = "IRQ",
|
||||
.type = CONFIG_SELECTION,
|
||||
.default_string = "",
|
||||
.default_int = 5,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "None", .value = -1 },
|
||||
{ .description = "IRQ 3", .value = 3 },
|
||||
{ .description = "IRQ 5", .value = 5 },
|
||||
{ .description = "IRQ 7", .value = 7 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
|
||||
static const device_config_t t130b_config[] = {
|
||||
{
|
||||
.name = "bios_addr",
|
||||
.description = "BIOS Address",
|
||||
.type = CONFIG_HEX20,
|
||||
.default_string = "",
|
||||
.default_int = 0xD8000,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "Disabled", .value = 0 },
|
||||
{ .description = "C800H", .value = 0xc8000 },
|
||||
{ .description = "CC00H", .value = 0xcc000 },
|
||||
{ .description = "D800H", .value = 0xd8000 },
|
||||
{ .description = "DC00H", .value = 0xdc000 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "base",
|
||||
.description = "Address",
|
||||
.type = CONFIG_HEX16,
|
||||
.default_string = "",
|
||||
.default_int = 0x0350,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "240H", .value = 0x0240 },
|
||||
{ .description = "250H", .value = 0x0250 },
|
||||
{ .description = "340H", .value = 0x0340 },
|
||||
{ .description = "350H", .value = 0x0350 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "irq",
|
||||
.description = "IRQ",
|
||||
.type = CONFIG_SELECTION,
|
||||
.default_string = "",
|
||||
.default_int = 5,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "None", .value = -1 },
|
||||
{ .description = "IRQ 3", .value = 3 },
|
||||
{ .description = "IRQ 5", .value = 5 },
|
||||
{ .description = "IRQ 7", .value = 7 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const device_t scsi_lcs6821n_device = {
|
||||
.name = "Longshine LCS-6821N",
|
||||
.internal_name = "lcs6821n",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = ROM_LCS6821N,
|
||||
.init = ncr53c400_init,
|
||||
.close = ncr53c400_close,
|
||||
.reset = NULL,
|
||||
{ .available = lcs6821n_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = ncr53c400_mmio_config
|
||||
};
|
||||
|
||||
const device_t scsi_rt1000b_device = {
|
||||
.name = "Rancho RT1000B",
|
||||
.internal_name = "rt1000b",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = ROM_RT1000B,
|
||||
.init = ncr53c400_init,
|
||||
.close = ncr53c400_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = rt1000b_config
|
||||
};
|
||||
|
||||
const device_t scsi_rt1000mc_device = {
|
||||
.name = "Rancho RT1000B-MC",
|
||||
.internal_name = "rt1000mc",
|
||||
.flags = DEVICE_MCA,
|
||||
.local = ROM_RT1000B,
|
||||
.init = ncr53c400_init,
|
||||
.close = ncr53c400_close,
|
||||
.reset = NULL,
|
||||
{ .available = rt1000b_mc_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = rt1000b_mc_config
|
||||
};
|
||||
|
||||
const device_t scsi_t130b_device = {
|
||||
.name = "Trantor T130B",
|
||||
.internal_name = "t130b",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = ROM_T130B,
|
||||
.init = ncr53c400_init,
|
||||
.close = ncr53c400_close,
|
||||
.reset = NULL,
|
||||
{ .available = t130b_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = t130b_config
|
||||
};
|
||||
|
||||
const device_t scsi_ls2000_device = {
|
||||
.name = "Corel LS2000",
|
||||
.internal_name = "ls2000",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = ROM_LS2000,
|
||||
.init = ncr53c400_init,
|
||||
.close = ncr53c400_close,
|
||||
.reset = NULL,
|
||||
{ .available = corel_ls2000_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = ncr53c400_mmio_config
|
||||
};
|
631
src/scsi/scsi_t128.c
Normal file
631
src/scsi/scsi_t128.c
Normal file
|
@ -0,0 +1,631 @@
|
|||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implementation of the Trantor 128/228 series of SCSI Host Adapters
|
||||
* made by Trantor. These controllers were designed for the ISA and MCA bus.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017-2019 Sarah Walker.
|
||||
* Copyright 2017-2019 Fred N. van Kempen.
|
||||
* Copyright 2017-2024 TheCollector1995.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/dma.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/mca.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/rom.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/scsi.h>
|
||||
#include <86box/scsi_device.h>
|
||||
#include <86box/scsi_ncr5380.h>
|
||||
|
||||
#define T128_ROM "roms/scsi/ncr5380/trantor_t128_bios_v1.12.bin"
|
||||
|
||||
typedef struct t128_t {
|
||||
ncr_t ncr;
|
||||
rom_t bios_rom;
|
||||
mem_mapping_t mapping;
|
||||
|
||||
uint8_t ctrl;
|
||||
uint8_t status;
|
||||
uint8_t buffer[512];
|
||||
uint8_t ext_ram[0x80];
|
||||
uint8_t block_count;
|
||||
|
||||
int block_loaded;
|
||||
int pos, host_pos;
|
||||
|
||||
uint32_t rom_addr;
|
||||
|
||||
int bios_enabled;
|
||||
uint8_t pos_regs[8];
|
||||
|
||||
pc_timer_t timer;
|
||||
} t128_t;
|
||||
|
||||
#ifdef ENABLE_T128_LOG
|
||||
int t128_do_log = ENABLE_T128_LOG;
|
||||
|
||||
static void
|
||||
t128_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (t128_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define t128_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Memory-mapped I/O WRITE handler. */
|
||||
static void
|
||||
t128_write(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) priv;
|
||||
ncr_t *ncr = &t128->ncr;
|
||||
const scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
|
||||
addr &= 0x3fff;
|
||||
if ((addr >= 0x1800) && (addr < 0x1880))
|
||||
t128->ext_ram[addr & 0x7f] = val;
|
||||
else if ((addr >= 0x1c00) && (addr < 0x1c20)) {
|
||||
if ((val & 0x02) && !(t128->ctrl & 0x02))
|
||||
t128->status |= 0x02;
|
||||
|
||||
t128->ctrl = val;
|
||||
t128_log("T128 ctrl write=%02x\n", val);
|
||||
} else if ((addr >= 0x1d00) && (addr < 0x1e00))
|
||||
ncr5380_write((addr - 0x1d00) >> 5, val, ncr);
|
||||
else if ((addr >= 0x1e00) && (addr < 0x2000)) {
|
||||
if ((t128->host_pos < MIN(512, dev->buffer_length)) &&
|
||||
(ncr->dma_mode == DMA_SEND)) {
|
||||
t128->buffer[t128->host_pos] = val;
|
||||
t128->host_pos++;
|
||||
|
||||
t128_log("T128 Write transfer, addr = %i, pos = %i, val = %02x\n",
|
||||
addr & 0x1ff, t128->host_pos, val);
|
||||
|
||||
if (t128->host_pos == MIN(512, dev->buffer_length)) {
|
||||
t128->status &= ~0x04;
|
||||
t128_log("Transfer busy write, status = %02x\n", t128->status);
|
||||
timer_on_auto(&t128->timer, 0.02);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory-mapped I/O READ handler. */
|
||||
static uint8_t
|
||||
t128_read(uint32_t addr, void *priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) priv;
|
||||
ncr_t *ncr = &t128->ncr;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
addr &= 0x3fff;
|
||||
if (t128->bios_enabled && (addr >= 0) && (addr < 0x1800))
|
||||
ret = t128->bios_rom.rom[addr & 0x1fff];
|
||||
else if ((addr >= 0x1800) && (addr < 0x1880))
|
||||
ret = t128->ext_ram[addr & 0x7f];
|
||||
else if ((addr >= 0x1c00) && (addr < 0x1c20)) {
|
||||
ret = t128->ctrl;
|
||||
t128_log("T128 ctrl read=%02x, dma=%02x\n", ret, ncr->mode & MODE_DMA);
|
||||
} else if ((addr >= 0x1c20) && (addr < 0x1c40)) {
|
||||
ret = t128->status;
|
||||
t128_log("T128 status read=%02x, dma=%02x\n", ret, ncr->mode & MODE_DMA);
|
||||
} else if ((addr >= 0x1d00) && (addr < 0x1e00))
|
||||
ret = ncr5380_read((addr - 0x1d00) >> 5, ncr);
|
||||
else if (addr >= 0x1e00 && addr < 0x2000) {
|
||||
if ((t128->host_pos >= MIN(512, dev->buffer_length)) ||
|
||||
(ncr->dma_mode != DMA_INITIATOR_RECEIVE))
|
||||
ret = 0xff;
|
||||
else {
|
||||
ret = t128->buffer[t128->host_pos++];
|
||||
|
||||
t128_log("T128 Read transfer, addr = %i, pos = %i\n", addr & 0x1ff,
|
||||
t128->host_pos);
|
||||
|
||||
if (t128->host_pos == MIN(512, dev->buffer_length)) {
|
||||
t128->status &= ~0x04;
|
||||
t128_log("T128 Transfer busy read, status = %02x, period = %lf\n",
|
||||
t128->status, ncr->period);
|
||||
if ((ncr->period == 0.2) || (ncr->period == 0.02))
|
||||
timer_on_auto(&t128->timer, 40.2);
|
||||
} else if ((t128->host_pos < MIN(512, dev->buffer_length)) &&
|
||||
(scsi_device_get_callback(dev) > 100.0))
|
||||
cycles += 100; /*Needed to avoid timer de-syncing with transfers.*/
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
t128_dma_mode_ext(void *priv, void *ext_priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) ext_priv;
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
|
||||
/*Don't stop the timer until it finishes the transfer*/
|
||||
if (t128->block_loaded && (ncr->mode & MODE_DMA)) {
|
||||
t128_log("Continuing DMA mode\n");
|
||||
timer_on_auto(&t128->timer, ncr->period + 1.0);
|
||||
}
|
||||
|
||||
/*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/
|
||||
if (!t128->block_loaded && !(ncr->mode & MODE_DMA)) {
|
||||
t128_log("No DMA mode\n");
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
ncr->isr &= ~STATUS_END_OF_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
t128_dma_send_ext(void *priv, void *ext_priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) ext_priv;
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
|
||||
if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) {
|
||||
memset(t128->buffer, 0, MIN(512, dev->buffer_length));
|
||||
t128->status |= 0x04;
|
||||
t128->host_pos = 0;
|
||||
t128->block_count = dev->buffer_length >> 9;
|
||||
|
||||
if (dev->buffer_length < 512)
|
||||
t128->block_count = 1;
|
||||
|
||||
t128->block_loaded = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
t128_dma_initiator_receive_ext(void *priv, void *ext_priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) ext_priv;
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
|
||||
if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) {
|
||||
memset(t128->buffer, 0, MIN(512, dev->buffer_length));
|
||||
t128->status |= 0x04;
|
||||
t128->host_pos = MIN(512, dev->buffer_length);
|
||||
t128->block_count = dev->buffer_length >> 9;
|
||||
|
||||
if (dev->buffer_length < 512)
|
||||
t128->block_count = 1;
|
||||
|
||||
t128->block_loaded = 1;
|
||||
timer_on_auto(&t128->timer, 0.02);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
t128_timer_on_auto(void *ext_priv, double period)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) ext_priv;
|
||||
|
||||
if (period == 0.0)
|
||||
timer_stop(&t128->timer);
|
||||
else
|
||||
timer_on_auto(&t128->timer, period);
|
||||
}
|
||||
|
||||
static void
|
||||
t128_callback(void *priv)
|
||||
{
|
||||
t128_t *t128 = (void *) priv;
|
||||
ncr_t *ncr = &t128->ncr;
|
||||
scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
int bus;
|
||||
uint8_t c;
|
||||
uint8_t temp;
|
||||
|
||||
if ((ncr->dma_mode != DMA_IDLE) && (ncr->mode & MODE_DMA) && t128->block_loaded) {
|
||||
if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count)
|
||||
t128->status |= 0x04;
|
||||
|
||||
timer_on_auto(&t128->timer, ncr->period / 55.0);
|
||||
}
|
||||
|
||||
if (ncr->data_wait & 1) {
|
||||
ncr->clear_req = 3;
|
||||
ncr->data_wait &= ~1;
|
||||
if (ncr->dma_mode == DMA_IDLE)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ncr->dma_mode) {
|
||||
case DMA_SEND:
|
||||
if (!(t128->status & 0x04)) {
|
||||
t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!t128->block_loaded) {
|
||||
t128_log("Write block not loaded\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (t128->host_pos < MIN(512, dev->buffer_length))
|
||||
break;
|
||||
|
||||
write_again:
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data ready. */
|
||||
temp = t128->buffer[t128->pos];
|
||||
|
||||
bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK;
|
||||
bus |= BUS_SETDATA(temp);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
|
||||
t128->pos++;
|
||||
t128_log("T128 Buffer pos for writing = %d\n", t128->pos);
|
||||
|
||||
if (t128->pos == MIN(512, dev->buffer_length)) {
|
||||
t128->pos = 0;
|
||||
t128->host_pos = 0;
|
||||
t128->status &= ~0x02;
|
||||
t128->block_count = (t128->block_count - 1) & 0xff;
|
||||
t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count);
|
||||
if (!t128->block_count) {
|
||||
t128->block_loaded = 0;
|
||||
t128_log("IO End of write transfer\n");
|
||||
ncr->tcr |= TCR_LAST_BYTE_SENT;
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
timer_stop(&t128->timer);
|
||||
if (ncr->mode & MODE_ENA_EOP_INT) {
|
||||
t128_log("T128 write irq\n");
|
||||
ncr5380_irq(ncr, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else
|
||||
goto write_again;
|
||||
break;
|
||||
|
||||
case DMA_INITIATOR_RECEIVE:
|
||||
if (!(t128->status & 0x04)) {
|
||||
t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!t128->block_loaded) {
|
||||
t128_log("Read block not loaded\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (t128->host_pos < MIN(512, dev->buffer_length))
|
||||
break;
|
||||
|
||||
read_again:
|
||||
for (c = 0; c < 10; c++) {
|
||||
ncr5380_bus_read(ncr);
|
||||
if (ncr->cur_bus & BUS_REQ)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data ready. */
|
||||
ncr5380_bus_read(ncr);
|
||||
temp = BUS_GETDATA(ncr->cur_bus);
|
||||
|
||||
bus = ncr5380_get_bus_host(ncr);
|
||||
|
||||
ncr5380_bus_update(ncr, bus | BUS_ACK);
|
||||
ncr5380_bus_update(ncr, bus & ~BUS_ACK);
|
||||
|
||||
t128->buffer[t128->pos++] = temp;
|
||||
t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length);
|
||||
|
||||
if (t128->pos == MIN(512, dev->buffer_length)) {
|
||||
t128->pos = 0;
|
||||
t128->host_pos = 0;
|
||||
t128->status &= ~0x02;
|
||||
t128->block_count = (t128->block_count - 1) & 0xff;
|
||||
t128_log("T128 Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", t128->block_count, t128->status, dev->buffer_length, ncr->command[0]);
|
||||
if (!t128->block_count) {
|
||||
t128->block_loaded = 0;
|
||||
t128_log("IO End of read transfer\n");
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
timer_stop(&t128->timer);
|
||||
if (ncr->mode & MODE_ENA_EOP_INT) {
|
||||
t128_log("NCR read irq\n");
|
||||
ncr5380_irq(ncr, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else
|
||||
goto read_again;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ncr5380_bus_read(ncr);
|
||||
|
||||
if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) {
|
||||
t128_log("Updating DMA\n");
|
||||
ncr->mode &= ~MODE_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
timer_on_auto(&t128->timer, 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
t228_read(int port, void *priv)
|
||||
{
|
||||
const t128_t *t128 = (t128_t *) priv;
|
||||
|
||||
return (t128->pos_regs[port & 7]);
|
||||
}
|
||||
|
||||
static void
|
||||
t228_write(int port, uint8_t val, void *priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) priv;
|
||||
ncr_t *ncr = &t128->ncr;
|
||||
|
||||
/* MCA does not write registers below 0x0100. */
|
||||
if (port < 0x0102)
|
||||
return;
|
||||
|
||||
mem_mapping_disable(&t128->bios_rom.mapping);
|
||||
mem_mapping_disable(&t128->mapping);
|
||||
|
||||
/* Save the MCA register value. */
|
||||
t128->pos_regs[port & 7] = val;
|
||||
|
||||
if (t128->pos_regs[2] & 1) {
|
||||
switch (t128->pos_regs[2] & 6) {
|
||||
case 0:
|
||||
t128->rom_addr = 0xcc000;
|
||||
break;
|
||||
case 2:
|
||||
t128->rom_addr = 0xc8000;
|
||||
break;
|
||||
case 4:
|
||||
t128->rom_addr = 0xdc000;
|
||||
break;
|
||||
case 6:
|
||||
t128->rom_addr = 0xd8000;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
t128->bios_enabled = !(t128->pos_regs[2] & 8);
|
||||
|
||||
switch (t128->pos_regs[2] & 0x70) {
|
||||
case 0:
|
||||
ncr->irq = -1;
|
||||
break;
|
||||
case 0x10:
|
||||
ncr->irq = 3;
|
||||
break;
|
||||
case 0x20:
|
||||
ncr->irq = 5;
|
||||
break;
|
||||
case 0x30:
|
||||
ncr->irq = 7;
|
||||
break;
|
||||
case 0x40:
|
||||
ncr->irq = 10;
|
||||
break;
|
||||
case 0x50:
|
||||
ncr->irq = 12;
|
||||
break;
|
||||
case 0x60:
|
||||
ncr->irq = 14;
|
||||
break;
|
||||
case 0x70:
|
||||
ncr->irq = 15;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (t128->bios_enabled) {
|
||||
t128->status &= ~0x80;
|
||||
mem_mapping_set_addr(&t128->bios_rom.mapping, t128->rom_addr, 0x4000);
|
||||
mem_mapping_set_addr(&t128->mapping, t128->rom_addr, 0x4000);
|
||||
} else
|
||||
t128->status |= 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
t228_feedb(void *priv)
|
||||
{
|
||||
const t128_t *t128 = (t128_t *) priv;
|
||||
|
||||
return t128->pos_regs[2] & 1;
|
||||
}
|
||||
|
||||
static void *
|
||||
t128_init(const device_t *info)
|
||||
{
|
||||
t128_t *t128;
|
||||
ncr_t *ncr;
|
||||
|
||||
t128 = malloc(sizeof(t128_t));
|
||||
memset(t128, 0x00, sizeof(t128_t));
|
||||
ncr = &t128->ncr;
|
||||
|
||||
ncr->bus = scsi_get_bus();
|
||||
|
||||
if (info->flags & DEVICE_MCA) {
|
||||
rom_init(&t128->bios_rom, T128_ROM,
|
||||
0xd8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
mem_mapping_add(&t128->mapping, 0xd8000, 0x4000,
|
||||
t128_read, NULL, NULL,
|
||||
t128_write, NULL, NULL,
|
||||
t128->bios_rom.rom, MEM_MAPPING_EXTERNAL, t128);
|
||||
mem_mapping_disable(&t128->bios_rom.mapping);
|
||||
t128->pos_regs[0] = 0x8c;
|
||||
t128->pos_regs[1] = 0x50;
|
||||
mca_add(t228_read, t228_write, t228_feedb, NULL, t128);
|
||||
} else {
|
||||
ncr->irq = device_get_config_int("irq");
|
||||
t128->rom_addr = device_get_config_hex20("bios_addr");
|
||||
t128->bios_enabled = device_get_config_int("boot");
|
||||
if (t128->bios_enabled)
|
||||
rom_init(&t128->bios_rom, T128_ROM,
|
||||
t128->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
|
||||
mem_mapping_add(&t128->mapping, t128->rom_addr, 0x4000,
|
||||
t128_read, NULL, NULL,
|
||||
t128_write, NULL, NULL,
|
||||
t128->bios_rom.rom, MEM_MAPPING_EXTERNAL, t128);
|
||||
}
|
||||
|
||||
ncr->priv = t128;
|
||||
ncr->dma_mode_ext = t128_dma_mode_ext;
|
||||
ncr->dma_send_ext = t128_dma_send_ext;
|
||||
ncr->dma_initiator_receive_ext = t128_dma_initiator_receive_ext;
|
||||
ncr->timer = t128_timer_on_auto;
|
||||
t128->status = 0x04;
|
||||
t128->host_pos = 512;
|
||||
if (!t128->bios_enabled && !(info->flags & DEVICE_MCA))
|
||||
t128->status |= 0x80;
|
||||
|
||||
timer_add(&t128->timer, t128_callback, t128, 0);
|
||||
|
||||
scsi_bus_set_speed(ncr->bus, 5000000.0);
|
||||
|
||||
return t128;
|
||||
}
|
||||
|
||||
static void
|
||||
t128_close(void *priv)
|
||||
{
|
||||
t128_t *t128 = (t128_t *) priv;
|
||||
|
||||
if (t128) {
|
||||
/* Tell the timer to terminate. */
|
||||
timer_stop(&t128->timer);
|
||||
|
||||
free(t128);
|
||||
t128 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
t128_available(void)
|
||||
{
|
||||
return (rom_present(T128_ROM));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static const device_config_t t128_config[] = {
|
||||
{
|
||||
.name = "bios_addr",
|
||||
.description = "BIOS Address",
|
||||
.type = CONFIG_HEX20,
|
||||
.default_string = "",
|
||||
.default_int = 0xD8000,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "C800H", .value = 0xc8000 },
|
||||
{ .description = "CC00H", .value = 0xcc000 },
|
||||
{ .description = "D800H", .value = 0xd8000 },
|
||||
{ .description = "DC00H", .value = 0xdc000 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "irq",
|
||||
.description = "IRQ",
|
||||
.type = CONFIG_SELECTION,
|
||||
.default_string = "",
|
||||
.default_int = 5,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "None", .value = -1 },
|
||||
{ .description = "IRQ 3", .value = 3 },
|
||||
{ .description = "IRQ 5", .value = 5 },
|
||||
{ .description = "IRQ 7", .value = 7 },
|
||||
{ .description = "" }
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "boot",
|
||||
.description = "Enable Boot ROM",
|
||||
.type = CONFIG_BINARY,
|
||||
.default_string = "",
|
||||
.default_int = 1
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const device_t scsi_t128_device = {
|
||||
.name = "Trantor T128",
|
||||
.internal_name = "t128",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = 0,
|
||||
.init = t128_init,
|
||||
.close = t128_close,
|
||||
.reset = NULL,
|
||||
{ .available = t128_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = t128_config
|
||||
};
|
||||
|
||||
const device_t scsi_t228_device = {
|
||||
.name = "Trantor T228",
|
||||
.internal_name = "t228",
|
||||
.flags = DEVICE_MCA,
|
||||
.local = 0,
|
||||
.init = t128_init,
|
||||
.close = t128_close,
|
||||
.reset = NULL,
|
||||
{ .available = t128_available },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
Loading…
Reference in a new issue