2017-10-08 05:04:38 +02:00
/*
2023-01-08 15:25:28 -05:00
* 86 Box 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 .
2017-10-08 05:04:38 +02:00
*
2023-01-08 15:25:28 -05:00
* This file is part of the 86 Box distribution .
2017-10-08 05:04:38 +02:00
*
2024-04-10 17:27:30 +02:00
* Implementation of the NCR 5380 chip made by NCR
* and used in various controllers .
2017-10-08 05:04:38 +02:00
*
2020-03-25 00:46:02 +02:00
*
2017-10-08 05:04:38 +02:00
*
2023-01-08 15:25:28 -05:00
* Authors : Sarah Walker , < https : //pcem-emulator.co.uk/>
* TheCollector1995 , < mariogplayer @ gmail . com >
* Fred N . van Kempen , < decwiz @ yahoo . com >
2018-01-13 22:56:13 +01:00
*
2023-01-08 15:25:28 -05:00
* Copyright 2017 - 2019 Sarah Walker .
* Copyright 2017 - 2019 Fred N . van Kempen .
2024-04-10 17:27:30 +02:00
* Copyright 2017 - 2024 TheCollector1995 .
2017-10-08 05:04:38 +02:00
*/
2018-07-19 16:01:31 +02:00
# include <inttypes.h>
2017-10-08 05:04:38 +02:00
# include <stdio.h>
# include <stdint.h>
# include <string.h>
# include <stdlib.h>
# include <stdarg.h>
# include <wchar.h>
2017-12-10 02:53:10 -05:00
# define HAVE_STDARG_H
2020-03-29 14:24:42 +02:00
# 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>
2017-10-08 05:04:38 +02:00
2024-04-10 17:27:30 +02:00
int ncr5380_cmd_len [ 8 ] = { 6 , 10 , 10 , 6 , 16 , 12 , 10 , 6 } ;
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
2017-10-08 05:04:38 +02:00
# ifdef ENABLE_NCR5380_LOG
int ncr5380_do_log = ENABLE_NCR5380_LOG ;
static void
2024-04-10 17:27:30 +02:00
ncr5380_log ( const char * fmt , . . . )
2017-10-08 05:04:38 +02:00
{
va_list ap ;
if ( ncr5380_do_log ) {
2022-09-18 17:17:15 -04:00
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
2017-10-08 05:04:38 +02:00
}
}
2018-10-19 00:39:32 +02:00
# else
2024-04-10 17:27:30 +02:00
# define ncr5380_log(fmt, ...)
2018-10-19 00:39:32 +02:00
# endif
2018-07-19 16:01:31 +02:00
# define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
2017-10-08 19:22:13 -04:00
2024-04-10 17:27:30 +02:00
void
ncr5380_irq ( ncr_t * ncr , int set_irq )
2021-01-07 17:30:11 +01:00
{
if ( set_irq ) {
2024-05-03 17:02:13 +02:00
ncr - > irq_state = 1 ;
2022-09-18 17:17:15 -04:00
ncr - > isr | = STATUS_INT ;
2024-04-10 17:27:30 +02:00
if ( ncr - > irq ! = - 1 )
picint ( 1 < < ncr - > irq ) ;
2021-01-07 17:30:11 +01:00
} else {
2024-05-03 17:02:13 +02:00
ncr - > irq_state = 0 ;
2022-09-18 17:17:15 -04:00
ncr - > isr & = ~ STATUS_INT ;
2024-04-10 17:27:30 +02:00
if ( ncr - > irq ! = 1 )
picintc ( 1 < < ncr - > irq ) ;
2021-01-07 17:30:11 +01:00
}
}
2018-10-08 21:49:47 +02:00
2024-05-03 17:02:13 +02:00
void
ncr5380_set_irq ( ncr_t * ncr , int irq )
{
ncr - > irq = irq ;
}
2018-07-19 16:01:31 +02:00
static int
2024-04-10 17:27:30 +02:00
ncr5380_get_dev_id ( uint8_t data )
2017-10-08 05:04:38 +02:00
{
2023-05-29 01:30:51 -04:00
for ( uint8_t c = 0 ; c < SCSI_ID_MAX ; c + + ) {
2022-09-18 17:17:15 -04:00
if ( data & ( 1 < < c ) )
2023-05-29 01:30:51 -04:00
return c ;
2018-07-19 16:01:31 +02:00
}
2017-10-08 19:22:13 -04:00
2023-05-29 01:30:51 -04:00
return - 1 ;
2017-10-08 05:04:38 +02:00
}
2022-02-20 02:26:27 -05:00
static int
2024-04-10 17:27:30 +02:00
ncr5380_getmsglen ( uint8_t * msgp , int len )
2019-12-08 00:57:22 +01:00
{
2022-09-18 17:17:15 -04:00
uint8_t msg = msgp [ 0 ] ;
if ( msg = = 0 | | ( msg > = 0x02 & & msg < = 0x1f ) | | msg > = 0x80 )
return 1 ;
if ( msg > = 0x20 & & msg < = 0x2f )
return 2 ;
if ( len < 2 )
return 3 ;
return msgp [ 1 ] ;
2019-12-08 00:57:22 +01:00
}
2017-10-08 05:04:38 +02:00
2018-07-19 16:01:31 +02:00
static void
2024-04-10 17:27:30 +02:00
ncr5380_reset ( ncr_t * ncr )
2018-07-19 16:01:31 +02:00
{
2024-04-10 17:27:30 +02:00
ncr - > command_pos = 0 ;
ncr - > data_pos = 0 ;
ncr - > state = STATE_IDLE ;
ncr - > clear_req = 0 ;
ncr - > cur_bus = 0 ;
ncr - > tx_data = 0 ;
ncr - > output_data = 0 ;
ncr - > data_wait = 0 ;
ncr - > mode = 0 ;
ncr - > tcr = 0 ;
ncr - > icr = 0 ;
ncr - > dma_mode = DMA_IDLE ;
ncr5380_log ( " NCR Reset \n " ) ;
ncr - > timer ( ncr - > priv , 0.0 ) ;
2022-02-20 02:26:27 -05:00
2021-01-07 17:30:11 +01:00
for ( int i = 0 ; i < 8 ; i + + )
2024-04-10 17:27:30 +02:00
scsi_device_reset ( & scsi_devices [ ncr - > bus ] [ i ] ) ;
2021-01-07 17:30:11 +01:00
2024-04-10 17:27:30 +02:00
ncr5380_irq ( ncr , 0 ) ;
2018-07-19 16:01:31 +02:00
}
2017-10-08 19:22:13 -04:00
2024-04-10 17:27:30 +02:00
uint32_t
ncr5380_get_bus_host ( ncr_t * ncr )
2017-10-08 05:04:38 +02:00
{
2017-10-08 19:22:13 -04:00
uint32_t bus_host = 0 ;
2019-10-20 15:27:50 +02:00
if ( ncr - > icr & ICR_DBP )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_DBP ;
2019-10-20 15:27:50 +02:00
if ( ncr - > icr & ICR_SEL )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_SEL ;
2019-10-20 15:27:50 +02:00
if ( ncr - > tcr & TCR_IO )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_IO ;
2019-10-20 15:27:50 +02:00
if ( ncr - > tcr & TCR_CD )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_CD ;
2019-10-20 15:27:50 +02:00
if ( ncr - > tcr & TCR_MSG )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_MSG ;
2019-10-20 15:27:50 +02:00
if ( ncr - > tcr & TCR_REQ )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_REQ ;
2019-10-20 15:27:50 +02:00
if ( ncr - > icr & ICR_BSY )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_BSY ;
2019-10-20 15:27:50 +02:00
2024-05-06 13:24:04 +02:00
if ( ncr - > icr & ICR_ATN )
bus_host | = BUS_ATN ;
2019-10-20 15:27:50 +02:00
if ( ncr - > icr & ICR_ACK )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_ACK ;
2019-10-20 15:27:50 +02:00
2018-10-08 21:49:47 +02:00
if ( ncr - > mode & MODE_ARBITRATE )
2022-09-18 17:17:15 -04:00
bus_host | = BUS_ARB ;
2017-10-08 19:22:13 -04:00
2022-09-18 17:17:15 -04:00
return ( bus_host | BUS_SETDATA ( ncr - > output_data ) ) ;
2017-10-08 05:04:38 +02:00
}
2024-04-10 17:27:30 +02:00
void
ncr5380_bus_read ( ncr_t * ncr )
2018-07-19 16:01:31 +02:00
{
2023-07-20 18:58:26 -04:00
const scsi_device_t * dev ;
int phase ;
2018-10-08 21:49:47 +02:00
/*Wait processes to handle bus requests*/
if ( ncr - > clear_req ) {
2022-09-18 17:17:15 -04:00
ncr - > clear_req - - ;
if ( ! ncr - > clear_req ) {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Prelude to command data \n " ) ;
2022-09-18 17:17:15 -04:00
SET_BUS_STATE ( ncr , ncr - > new_phase ) ;
ncr - > cur_bus | = BUS_REQ ;
}
2018-10-08 21:49:47 +02:00
}
2018-07-19 16:01:31 +02:00
2018-10-08 21:49:47 +02:00
if ( ncr - > wait_data ) {
2022-09-18 17:17:15 -04:00
ncr - > wait_data - - ;
if ( ! ncr - > wait_data ) {
2024-04-10 17:27:30 +02:00
dev = & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ;
2022-09-18 17:17:15 -04:00
SET_BUS_STATE ( ncr , ncr - > new_phase ) ;
phase = ( ncr - > cur_bus & SCSI_PHASE_MESSAGE_IN ) ;
if ( phase = = SCSI_PHASE_DATA_IN ) {
2025-01-12 20:37:50 +01:00
if ( ncr - > dma_mode = = DMA_IDLE ) {
ncr5380_log ( " Phase Data In. \n " ) ;
if ( ( dev - > sc ! = NULL ) & & ( dev - > sc - > temp_buffer ! = NULL ) )
ncr - > tx_data = dev - > sc - > temp_buffer [ ncr - > data_pos + + ] ;
ncr - > state = STATE_DATAIN ;
ncr - > cur_bus = ( ncr - > cur_bus & ~ BUS_DATAMASK ) | BUS_SETDATA ( ncr - > tx_data ) | BUS_DBP ;
}
2022-09-18 17:17:15 -04:00
} else if ( phase = = SCSI_PHASE_DATA_OUT ) {
if ( ncr - > new_phase & BUS_IDLE ) {
ncr - > state = STATE_IDLE ;
ncr - > cur_bus & = ~ BUS_BSY ;
2025-01-12 20:37:50 +01:00
} else {
if ( ncr - > dma_mode = = DMA_IDLE )
ncr - > state = STATE_DATAOUT ;
}
2022-09-18 17:17:15 -04:00
} else if ( phase = = SCSI_PHASE_STATUS ) {
2025-01-12 20:37:50 +01:00
ncr5380_log ( " Phase Status. \n " ) ;
2022-09-18 17:17:15 -04:00
ncr - > cur_bus | = BUS_REQ ;
ncr - > state = STATE_STATUS ;
ncr - > cur_bus = ( ncr - > cur_bus & ~ BUS_DATAMASK ) | BUS_SETDATA ( dev - > status ) | BUS_DBP ;
} else if ( phase = = SCSI_PHASE_MESSAGE_IN ) {
2025-01-12 20:37:50 +01:00
ncr5380_log ( " Phase Message In. \n " ) ;
2022-09-18 17:17:15 -04:00
ncr - > state = STATE_MESSAGEIN ;
ncr - > cur_bus = ( ncr - > cur_bus & ~ BUS_DATAMASK ) | BUS_SETDATA ( 0 ) | BUS_DBP ;
} else if ( phase = = SCSI_PHASE_MESSAGE_OUT ) {
ncr - > cur_bus | = BUS_REQ ;
ncr - > state = STATE_MESSAGEOUT ;
ncr - > cur_bus = ( ncr - > cur_bus & ~ BUS_DATAMASK ) | BUS_SETDATA ( ncr - > target_id > > 5 ) | BUS_DBP ;
}
}
2018-10-08 21:49:47 +02:00
}
if ( ncr - > wait_complete ) {
2022-09-18 17:17:15 -04:00
ncr - > wait_complete - - ;
if ( ! ncr - > wait_complete )
ncr - > cur_bus | = BUS_REQ ;
2018-10-08 21:49:47 +02:00
}
2019-10-20 15:27:50 +02:00
}
2024-04-10 17:27:30 +02:00
void
ncr5380_bus_update ( ncr_t * ncr , int bus )
2019-10-20 15:27:50 +02:00
{
2024-04-10 17:27:30 +02:00
scsi_device_t * dev = & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ;
2022-09-18 17:17:15 -04:00
double p ;
uint8_t sel_data ;
int msglen ;
2019-10-20 15:27:50 +02:00
/*Start the SCSI command layer, which will also make the timings*/
if ( bus & BUS_ARB )
2022-09-18 17:17:15 -04:00
ncr - > state = STATE_IDLE ;
2019-10-20 15:27:50 +02:00
2024-04-10 17:27:30 +02:00
ncr5380_log ( " State = %i \n " , ncr - > state ) ;
2021-01-09 15:28:39 +01:00
2020-12-05 09:33:07 +01:00
switch ( ncr - > state ) {
2022-09-18 17:17:15 -04:00
case STATE_IDLE :
ncr - > clear_req = ncr - > wait_data = ncr - > wait_complete = 0 ;
if ( ( bus & BUS_SEL ) & & ! ( bus & BUS_BSY ) ) {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Selection phase \n " ) ;
2022-09-18 17:17:15 -04:00
sel_data = BUS_GETDATA ( bus ) ;
2024-04-10 17:27:30 +02:00
ncr - > target_id = ncr5380_get_dev_id ( sel_data ) ;
2022-09-18 17:17:15 -04:00
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Select - target ID = %i \n " , ncr - > target_id ) ;
2022-09-18 17:17:15 -04:00
/*Once the device has been found and selected, mark it as busy*/
2024-04-10 17:27:30 +02:00
if ( ( ncr - > target_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ) ) {
2022-09-18 17:17:15 -04:00
ncr - > cur_bus | = BUS_BSY ;
ncr - > state = STATE_SELECT ;
} else {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Device not found at ID %i, Current Bus BSY=%02x \n " , ncr - > target_id , ncr - > cur_bus ) ;
2022-09-18 17:17:15 -04:00
ncr - > cur_bus = 0 ;
}
}
break ;
case STATE_SELECT :
if ( ! ( bus & BUS_SEL ) ) {
if ( ! ( bus & BUS_ATN ) ) {
2024-04-10 17:27:30 +02:00
if ( ( ncr - > target_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ) ) {
ncr5380_log ( " Device found at ID %i, Current Bus BSY=%02x \n " , ncr - > target_id , ncr - > cur_bus ) ;
2022-09-18 17:17:15 -04:00
ncr - > state = STATE_COMMAND ;
ncr - > cur_bus = BUS_BSY | BUS_REQ ;
2024-04-10 17:27:30 +02:00
ncr5380_log ( " CurBus BSY|REQ=%02x \n " , ncr - > cur_bus ) ;
2022-09-18 17:17:15 -04:00
ncr - > command_pos = 0 ;
SET_BUS_STATE ( ncr , SCSI_PHASE_COMMAND ) ;
} else {
ncr - > state = STATE_IDLE ;
ncr - > cur_bus = 0 ;
}
} else {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Set to SCSI Message Out \n " ) ;
2022-09-18 17:17:15 -04:00
ncr - > new_phase = SCSI_PHASE_MESSAGE_OUT ;
ncr - > wait_data = 4 ;
ncr - > msgout_pos = 0 ;
ncr - > is_msgout = 1 ;
}
}
break ;
case STATE_COMMAND :
if ( ( bus & BUS_ACK ) & & ! ( ncr - > bus_in & BUS_ACK ) ) {
/*Write command byte to the output data register*/
ncr - > command [ ncr - > command_pos + + ] = BUS_GETDATA ( bus ) ;
ncr - > clear_req = 3 ;
ncr - > new_phase = ncr - > cur_bus & SCSI_PHASE_MESSAGE_IN ;
ncr - > cur_bus & = ~ BUS_REQ ;
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Command pos=%i, output data=%02x \n " , ncr - > command_pos , BUS_GETDATA ( bus ) ) ;
2022-09-18 17:17:15 -04:00
2024-04-10 17:27:30 +02:00
if ( ncr - > command_pos = = ncr5380_cmd_len [ ( ncr - > command [ 0 ] > > 5 ) & 7 ] ) {
2022-09-18 17:17:15 -04:00
if ( ncr - > is_msgout ) {
ncr - > is_msgout = 0 ;
2023-06-09 23:46:54 -04:00
#if 0
ncr - > command [ 1 ] = ( ncr - > command [ 1 ] & 0x1f ) | ( ncr - > msglun < < 5 ) ;
# endif
2022-09-18 17:17:15 -04:00
}
/*Reset data position to default*/
ncr - > data_pos = 0 ;
2024-04-10 17:27:30 +02:00
dev = & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ;
2022-09-18 17:17:15 -04:00
2024-04-10 17:27:30 +02:00
ncr5380_log ( " SCSI Command 0x%02X for ID %d, status code=%02x \n " , ncr - > command [ 0 ] , ncr - > target_id , dev - > status ) ;
2022-09-18 17:17:15 -04:00
dev - > buffer_length = - 1 ;
scsi_device_command_phase0 ( dev , ncr - > command ) ;
2024-04-10 17:27:30 +02:00
ncr5380_log ( " SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X \n " , ncr - > target_id , ncr - > command [ 0 ] , dev - > buffer_length , dev - > phase ) ;
2022-09-18 17:17:15 -04:00
2024-04-10 17:27:30 +02:00
ncr - > period = 1.0 ;
2022-09-18 17:17:15 -04:00
ncr - > wait_data = 4 ;
ncr - > data_wait = 0 ;
if ( dev - > status = = SCSI_STATUS_OK ) {
/*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/
2024-04-10 17:27:30 +02:00
if ( dev - > buffer_length & & ( ( dev - > phase = = SCSI_PHASE_DATA_IN ) | | ( dev - > phase = = SCSI_PHASE_DATA_OUT ) ) ) {
2022-09-18 17:17:15 -04:00
p = scsi_device_get_callback ( dev ) ;
2024-04-10 17:27:30 +02:00
ncr - > period = ( p > 0.0 ) ? p : ( ( ( double ) dev - > buffer_length ) * 0.2 ) ;
ncr5380_log ( " SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x \n " , ncr - > target_id , ncr - > command [ 0 ] , scsi_device_get_callback ( dev ) , ncr - > period , dev - > buffer_length , ncr - > dma_mode ) ;
2022-09-18 17:17:15 -04:00
}
}
ncr - > new_phase = dev - > phase ;
}
}
break ;
case STATE_DATAIN :
2024-04-10 17:27:30 +02:00
dev = & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ;
2022-09-18 17:17:15 -04:00
if ( ( bus & BUS_ACK ) & & ! ( ncr - > bus_in & BUS_ACK ) ) {
if ( ncr - > data_pos > = dev - > buffer_length ) {
ncr - > cur_bus & = ~ BUS_REQ ;
2025-01-12 20:37:50 +01:00
ncr5380_log ( " CMD Phase1 DataIn. \n " ) ;
2022-09-18 17:17:15 -04:00
scsi_device_command_phase1 ( dev ) ;
ncr - > new_phase = SCSI_PHASE_STATUS ;
ncr - > wait_data = 4 ;
ncr - > wait_complete = 8 ;
} else {
2025-01-12 20:37:50 +01:00
if ( ( dev - > sc ! = NULL ) & & ( dev - > sc - > temp_buffer ! = NULL ) )
ncr - > tx_data = dev - > sc - > temp_buffer [ ncr - > data_pos + + ] ;
2022-09-18 17:17:15 -04:00
ncr - > cur_bus = ( ncr - > cur_bus & ~ BUS_DATAMASK ) | BUS_SETDATA ( ncr - > tx_data ) | BUS_DBP | BUS_REQ ;
if ( ncr - > dma_mode = = DMA_IDLE ) { /*If a data in command that is not read 6/10 has been issued*/
ncr - > data_wait | = 1 ;
2025-01-12 20:37:50 +01:00
ncr5380_log ( " DMA mode idle IN=%d. \n " , ncr - > data_pos ) ;
2024-05-06 13:09:08 +02:00
ncr - > timer ( ncr - > priv , ncr - > period ) ;
2024-02-03 22:30:14 +01:00
} else {
2025-01-12 20:37:50 +01:00
ncr5380_log ( " DMA mode IN=%d. \n " , ncr - > data_pos ) ;
2022-09-18 17:17:15 -04:00
ncr - > clear_req = 3 ;
2024-02-03 22:30:14 +01:00
}
2022-09-18 17:17:15 -04:00
ncr - > cur_bus & = ~ BUS_REQ ;
ncr - > new_phase = SCSI_PHASE_DATA_IN ;
}
}
break ;
case STATE_DATAOUT :
2024-04-10 17:27:30 +02:00
dev = & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ;
2022-09-18 17:17:15 -04:00
if ( ( bus & BUS_ACK ) & & ! ( ncr - > bus_in & BUS_ACK ) ) {
2025-01-12 20:37:50 +01:00
if ( ( dev - > sc ! = NULL ) & & ( dev - > sc - > temp_buffer ! = NULL ) )
dev - > sc - > temp_buffer [ ncr - > data_pos + + ] = BUS_GETDATA ( bus ) ;
2022-09-18 17:17:15 -04:00
if ( ncr - > data_pos > = dev - > buffer_length ) {
ncr - > cur_bus & = ~ BUS_REQ ;
scsi_device_command_phase1 ( dev ) ;
ncr - > new_phase = SCSI_PHASE_STATUS ;
ncr - > wait_data = 4 ;
ncr - > wait_complete = 8 ;
} else {
/*More data is to be transferred, place a request*/
if ( ncr - > dma_mode = = DMA_IDLE ) { /*If a data out command that is not write 6/10 has been issued*/
ncr - > data_wait | = 1 ;
2024-04-10 17:27:30 +02:00
ncr5380_log ( " DMA mode idle out \n " ) ;
2024-05-06 13:09:08 +02:00
ncr - > timer ( ncr - > priv , ncr - > period ) ;
2024-02-03 22:30:14 +01:00
} else
2022-09-18 17:17:15 -04:00
ncr - > clear_req = 3 ;
2024-02-03 22:30:14 +01:00
2022-09-18 17:17:15 -04:00
ncr - > cur_bus & = ~ BUS_REQ ;
2024-04-10 17:27:30 +02:00
ncr5380_log ( " CurBus ~REQ_DataOut=%02x \n " , ncr - > cur_bus ) ;
2022-09-18 17:17:15 -04:00
}
}
break ;
case STATE_STATUS :
if ( ( bus & BUS_ACK ) & & ! ( ncr - > bus_in & BUS_ACK ) ) {
/*All transfers done, wait until next transfer*/
2024-04-10 17:27:30 +02:00
scsi_device_identify ( & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] , SCSI_LUN_USE_CDB ) ;
2022-09-18 17:17:15 -04:00
ncr - > cur_bus & = ~ BUS_REQ ;
ncr - > new_phase = SCSI_PHASE_MESSAGE_IN ;
ncr - > wait_data = 4 ;
ncr - > wait_complete = 8 ;
}
break ;
case STATE_MESSAGEIN :
if ( ( bus & BUS_ACK ) & & ! ( ncr - > bus_in & BUS_ACK ) ) {
ncr - > cur_bus & = ~ BUS_REQ ;
ncr - > new_phase = BUS_IDLE ;
ncr - > wait_data = 4 ;
}
break ;
case STATE_MESSAGEOUT :
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Ack on MSGOUT = %02x \n " , ( bus & BUS_ACK ) ) ;
2022-09-18 17:17:15 -04:00
if ( ( bus & BUS_ACK ) & & ! ( ncr - > bus_in & BUS_ACK ) ) {
ncr - > msgout [ ncr - > msgout_pos + + ] = BUS_GETDATA ( bus ) ;
2024-04-10 17:27:30 +02:00
msglen = ncr5380_getmsglen ( ncr - > msgout , ncr - > msgout_pos ) ;
2022-09-18 17:17:15 -04:00
if ( ncr - > msgout_pos > = msglen ) {
if ( ( ncr - > msgout [ 0 ] & ( 0x80 | 0x20 ) ) = = 0x80 )
ncr - > msglun = ncr - > msgout [ 0 ] & 7 ;
ncr - > cur_bus & = ~ BUS_REQ ;
ncr - > state = STATE_MESSAGE_ID ;
}
}
break ;
case STATE_MESSAGE_ID :
2024-04-10 17:27:30 +02:00
if ( ( ncr - > target_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] ) ) {
ncr5380_log ( " Device found at ID %i on MSGOUT, Current Bus BSY=%02x \n " , ncr - > target_id , ncr - > cur_bus ) ;
scsi_device_identify ( & scsi_devices [ ncr - > bus ] [ ncr - > target_id ] , ncr - > msglun ) ;
2022-09-18 17:17:15 -04:00
ncr - > state = STATE_COMMAND ;
ncr - > cur_bus = BUS_BSY | BUS_REQ ;
2024-04-10 17:27:30 +02:00
ncr5380_log ( " CurBus BSY|REQ=%02x \n " , ncr - > cur_bus ) ;
2022-09-18 17:17:15 -04:00
ncr - > command_pos = 0 ;
SET_BUS_STATE ( ncr , SCSI_PHASE_COMMAND ) ;
}
break ;
2023-06-09 23:46:54 -04:00
default :
break ;
2020-12-05 09:33:07 +01:00
}
2019-10-20 15:27:50 +02:00
ncr - > bus_in = bus ;
2018-07-19 16:01:31 +02:00
}
2017-10-08 19:22:13 -04:00
2024-04-10 17:27:30 +02:00
void
ncr5380_write ( uint16_t port , uint8_t val , ncr_t * ncr )
2017-10-08 05:04:38 +02:00
{
2023-07-20 18:58:26 -04:00
int bus_host = 0 ;
2018-07-19 16:01:31 +02:00
2024-04-10 17:27:30 +02:00
ncr5380_log ( " NCR5380 write(%04x,%02x) \n " , port & 7 , val ) ;
2017-10-08 05:04:38 +02:00
2017-10-08 19:22:13 -04:00
switch ( port & 7 ) {
2022-09-18 17:17:15 -04:00
case 0 : /* Output data register */
2025-01-12 20:37:50 +01:00
ncr5380_log ( " [%04X:%08X]: Write: Output data register, val=%02x \n " , CS , cpu_state . pc , val ) ;
2022-09-18 17:17:15 -04:00
ncr - > output_data = val ;
break ;
case 1 : /* Initiator Command Register */
2025-01-12 20:37:50 +01:00
ncr5380_log ( " [%04X:%08X]: Write: Initiator command register, val=%02x. \n " , CS , cpu_state . pc , val ) ;
2022-09-18 17:17:15 -04:00
if ( ( val & 0x80 ) & & ! ( ncr - > icr & 0x80 ) ) {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Resetting the 5380 \n " ) ;
ncr5380_reset ( ncr ) ;
2022-09-18 17:17:15 -04:00
}
ncr - > icr = val ;
break ;
case 2 : /* Mode register */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Write: Mode register, val=%02x. \n " , val ) ;
2022-09-18 17:17:15 -04:00
if ( ( val & MODE_ARBITRATE ) & & ! ( ncr - > mode & MODE_ARBITRATE ) ) {
ncr - > icr & = ~ ICR_ARB_LOST ;
ncr - > icr | = ICR_ARB_IN_PROGRESS ;
}
ncr - > mode = val ;
2024-04-10 17:27:30 +02:00
ncr - > dma_mode_ext ( ncr , ncr - > priv ) ;
2022-09-18 17:17:15 -04:00
break ;
case 3 : /* Target Command Register */
2025-01-12 20:37:50 +01:00
ncr5380_log ( " Write: Target Command register, val=%02x. \n " , val ) ;
2022-09-18 17:17:15 -04:00
ncr - > tcr = val ;
break ;
case 4 : /* Select Enable Register */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Write: Select Enable register \n " ) ;
2022-09-18 17:17:15 -04:00
break ;
case 5 : /* start DMA Send */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Write: start DMA send register \n " ) ;
2022-09-18 17:17:15 -04:00
/*a Write 6/10 has occurred, start the timer when the block count is loaded*/
ncr - > dma_mode = DMA_SEND ;
2024-04-10 17:27:30 +02:00
if ( ncr - > dma_send_ext )
ncr - > dma_send_ext ( ncr , ncr - > priv ) ;
2022-09-18 17:17:15 -04:00
break ;
case 7 : /* start DMA Initiator Receive */
2025-01-12 20:37:50 +01:00
ncr5380_log ( " [%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x \n " , CS , cpu_state . pc , ncr - > mode & MODE_DMA ) ;
2022-09-18 17:17:15 -04:00
/*a Read 6/10 has occurred, start the timer when the block count is loaded*/
ncr - > dma_mode = DMA_INITIATOR_RECEIVE ;
2024-04-10 17:27:30 +02:00
if ( ncr - > dma_initiator_receive_ext )
ncr - > dma_initiator_receive_ext ( ncr , ncr - > priv ) ;
2022-09-18 17:17:15 -04:00
break ;
default :
2024-04-10 17:27:30 +02:00
ncr5380_log ( " NCR5380: bad write %04x %02x \n " , port , val ) ;
2022-09-18 17:17:15 -04:00
break ;
2017-10-08 19:22:13 -04:00
}
2022-02-20 02:26:27 -05:00
2024-04-10 17:27:30 +02:00
bus_host = ncr5380_get_bus_host ( ncr ) ;
ncr5380_bus_update ( ncr , bus_host ) ;
2017-10-08 05:04:38 +02:00
}
2024-04-10 17:27:30 +02:00
uint8_t
ncr5380_read ( uint16_t port , ncr_t * ncr )
2017-10-08 05:04:38 +02:00
{
2024-04-10 17:27:30 +02:00
uint8_t ret = 0xff ;
2023-05-29 01:30:51 -04:00
int bus ;
int bus_state ;
2017-10-08 19:22:13 -04:00
switch ( port & 7 ) {
2022-09-18 17:17:15 -04:00
case 0 : /* Current SCSI data */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Read: Current SCSI data register \n " ) ;
2022-09-18 17:17:15 -04:00
if ( ncr - > icr & ICR_DBP ) {
/*Return the data from the output register if on data bus phase from ICR*/
ret = ncr - > output_data ;
2025-01-12 20:37:50 +01:00
ncr5380_log ( " [%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x. \n " , CS , cpu_state . pc , ret , ncr - > clear_req , ncr - > wait_data ) ;
2022-09-18 17:17:15 -04:00
} else {
/*Return the data from the SCSI bus*/
2024-04-10 17:27:30 +02:00
ncr5380_bus_read ( ncr ) ;
2022-09-18 17:17:15 -04:00
ret = BUS_GETDATA ( ncr - > cur_bus ) ;
2025-01-12 20:37:50 +01:00
ncr5380_log ( " [%04X:%08X]: NCR Get SCSI bus data=%02x. \n " , CS , cpu_state . pc , ret ) ;
2022-09-18 17:17:15 -04:00
}
break ;
case 1 : /* Initiator Command Register */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Read: Initiator Command register, NCR ICR Read=%02x \n " , ncr - > icr ) ;
2022-09-18 17:17:15 -04:00
ret = ncr - > icr ;
break ;
case 2 : /* Mode register */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Read: Mode register = %02x. \n " , ncr - > mode ) ;
2022-09-18 17:17:15 -04:00
ret = ncr - > mode ;
break ;
case 3 : /* Target Command Register */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Read: Target Command register, NCR target stat=%02x \n " , ncr - > tcr ) ;
2022-09-18 17:17:15 -04:00
ret = ncr - > tcr ;
break ;
case 4 : /* Current SCSI Bus status */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Read: SCSI bus status register \n " ) ;
2022-09-18 17:17:15 -04:00
ret = 0 ;
2024-04-10 17:27:30 +02:00
ncr5380_bus_read ( ncr ) ;
ncr5380_log ( " NCR cur bus stat=%02x \n " , ncr - > cur_bus & 0xff ) ;
2022-09-18 17:17:15 -04:00
ret | = ( ncr - > cur_bus & 0xff ) ;
2023-01-07 23:48:45 +01:00
if ( ncr - > icr & ICR_SEL )
ret | = BUS_SEL ;
if ( ncr - > icr & ICR_BSY )
ret | = BUS_BSY ;
2024-05-06 13:09:08 +02:00
// if ((ret & SCSI_PHASE_MESSAGE_IN) == SCSI_PHASE_MESSAGE_IN)
// ret &= ~BUS_REQ;
2022-09-18 17:17:15 -04:00
break ;
case 5 : /* Bus and Status register */
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Read: Bus and Status register \n " ) ;
2022-09-18 17:17:15 -04:00
ret = 0 ;
2024-04-10 17:27:30 +02:00
bus = ncr5380_get_bus_host ( ncr ) ;
ncr5380_log ( " Get host from Interrupt \n " ) ;
2022-09-18 17:17:15 -04:00
/*Check if the phase in process matches with TCR's*/
if ( ( bus & SCSI_PHASE_MESSAGE_IN ) = = ( ncr - > cur_bus & SCSI_PHASE_MESSAGE_IN ) ) {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Phase match \n " ) ;
2022-09-18 17:17:15 -04:00
ret | = STATUS_PHASE_MATCH ;
}
2024-04-10 17:27:30 +02:00
ncr5380_bus_read ( ncr ) ;
2022-09-18 17:17:15 -04:00
bus = ncr - > cur_bus ;
2023-01-07 23:48:45 +01:00
if ( ( bus & BUS_ACK ) | | ( ncr - > icr & ICR_ACK ) )
2022-09-18 17:17:15 -04:00
ret | = STATUS_ACK ;
2023-01-07 23:48:45 +01:00
if ( ( bus & BUS_ATN ) | | ( ncr - > icr & ICR_ATN ) )
2022-09-18 17:17:15 -04:00
ret | = 0x02 ;
if ( ( bus & BUS_REQ ) & & ( ncr - > mode & MODE_DMA ) ) {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Entering DMA mode \n " ) ;
2022-09-18 17:17:15 -04:00
ret | = STATUS_DRQ ;
bus_state = 0 ;
if ( bus & BUS_IO )
bus_state | = TCR_IO ;
if ( bus & BUS_CD )
bus_state | = TCR_CD ;
if ( bus & BUS_MSG )
bus_state | = TCR_MSG ;
if ( ( ncr - > tcr & 7 ) ! = bus_state ) {
2024-04-10 17:27:30 +02:00
ncr5380_irq ( ncr , 1 ) ;
ncr5380_log ( " IRQ issued \n " ) ;
2022-09-18 17:17:15 -04:00
}
}
if ( ! ( bus & BUS_BSY ) & & ( ncr - > mode & MODE_MONITOR_BUSY ) ) {
2024-04-10 17:27:30 +02:00
ncr5380_log ( " Busy error \n " ) ;
2022-09-18 17:17:15 -04:00
ret | = STATUS_BUSY_ERROR ;
}
ret | = ( ncr - > isr & ( STATUS_INT | STATUS_END_OF_DMA ) ) ;
break ;
case 6 :
2025-01-12 20:37:50 +01:00
ncr5380_log ( " Read: Input Data. \n " ) ;
ncr5380_bus_read ( ncr ) ;
ret = BUS_GETDATA ( ncr - > cur_bus ) ;
2022-09-18 17:17:15 -04:00
break ;
case 7 : /* reset Parity/Interrupt */
ncr - > isr & = ~ ( STATUS_BUSY_ERROR | 0x20 ) ;
2024-04-10 17:27:30 +02:00
ncr5380_irq ( ncr , 0 ) ;
ncr5380_log ( " Reset Interrupt \n " ) ;
2022-09-18 17:17:15 -04:00
break ;
2023-06-09 23:46:54 -04:00
default :
2024-04-10 17:27:30 +02:00
ncr5380_log ( " NCR5380: bad read %04x \n " , port ) ;
2023-06-09 23:46:54 -04:00
break ;
2018-10-08 21:49:47 +02:00
}
2024-04-10 17:27:30 +02:00
ncr5380_log ( " NCR5380 read(%04x)=%02x \n " , port & 7 , ret ) ;
2022-09-18 17:17:15 -04:00
2023-05-29 01:30:51 -04:00
return ret ;
2021-08-17 14:26:47 +02:00
}