summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/mb87030.cpp
blob: 25420dfad54404faa4bb3785ac8266371913d431 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                                  

                    



                     
                                                                                         

                                                                                                                 
                                                           




                                                                                                                                   
                                                       
                                                               

                             




















































                                                                                       
                        



























































                                                                                          
                                              
 







                                                    























                                                                                                 































































                                                                               





                                                                
                          
                         




                                                               
 











                                                                     
























































                                                                                                    
                                                          





                                                          












                                                                      
                                                                   






                                                                                                                        




                                                                 


                                           
                                  






                                                                 










                                                         
                                              
                                                                    
                                                                 


                              




                                                                 













                                                                 



                                                         

                                                                  
 

                                                          








                                                                     








                                                                             
                                                         

                                                              

                      
         



                                   

                                                                                                                             





















                                                     
                            


                                        
                                    
                             









































                                                                                   
                           































                                                
                                         


                                                       
 







                                                                        
 

                                                     
                                   
                                                            
            

                                                
 






                                                           
 








                                                                          
 


                                                          
 






                                                         
 


                                                       
                                                                 























































































                                                                             









                                               

















                                                  
                    

                                                























































































                                                
// license:BSD-3-Clause
// copyright-holders:Sven Schnelle

#include "emu.h"
#include "mb87030.h"

//#define VERBOSE 1
#include "logmacro.h"


DEFINE_DEVICE_TYPE(MB87030, mb87030_device, "mb87030", "Fujitsu MB87030 SCSI controller")

mb87030_device::mb87030_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	mb87030_device(mconfig, MB87030, tag, owner, clock)
{

}

mb87030_device::mb87030_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	nscsi_device(mconfig, type, tag, owner, clock),
	nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF),
	m_irq_handler(*this),
	m_dreq_handler(*this)
{

}

void mb87030_device::map(address_map &map)
{
	map(0x00, 0x00).rw(FUNC(mb87030_device::bdid_r), FUNC(mb87030_device::bdid_w));
	map(0x01, 0x01).rw(FUNC(mb87030_device::sctl_r), FUNC(mb87030_device::sctl_w));
	map(0x02, 0x02).rw(FUNC(mb87030_device::scmd_r), FUNC(mb87030_device::scmd_w));
	map(0x03, 0x03).rw(FUNC(mb87030_device::tmod_r), FUNC(mb87030_device::tmod_w));
	map(0x04, 0x04).rw(FUNC(mb87030_device::ints_r), FUNC(mb87030_device::ints_w));
	map(0x05, 0x05).rw(FUNC(mb87030_device::psns_r), FUNC(mb87030_device::sdgc_w));
	map(0x06, 0x06).r(FUNC(mb87030_device::ssts_r));
	map(0x07, 0x07).r(FUNC(mb87030_device::serr_r));
	map(0x08, 0x08).rw(FUNC(mb87030_device::pctl_r), FUNC(mb87030_device::pctl_w));
	map(0x09, 0x09).r(FUNC(mb87030_device::mbc_r));
	map(0x0a, 0x0a).rw(FUNC(mb87030_device::dreg_r), FUNC(mb87030_device::dreg_w));
	map(0x0b, 0x0b).rw(FUNC(mb87030_device::temp_r), FUNC(mb87030_device::temp_w));
	map(0x0c, 0x0c).rw(FUNC(mb87030_device::tch_r), FUNC(mb87030_device::tch_w));
	map(0x0d, 0x0d).rw(FUNC(mb87030_device::tcm_r), FUNC(mb87030_device::tcm_w));
	map(0x0e, 0x0e).rw(FUNC(mb87030_device::tcl_r), FUNC(mb87030_device::tcl_w));
	map(0x0f, 0x0f).rw(FUNC(mb87030_device::exbf_r), FUNC(mb87030_device::exbf_w));
}

void mb87030_device::device_reset()
{
	m_bdid = 0;
	m_sctl = SCTL_RESET_AND_DISABLE;
	m_scmd = 0;
	m_tmod = 0;
	m_ints = 0;
	m_sdgc = 0;
	m_ssts = 0;
	m_serr = 0;
	m_pctl = 0;
	m_mbc = 0;
	m_dreg = 0;
	m_temp = 0;
	m_tch = 0;
	m_tcm = 0;
	m_tc = 0;
	m_exbf = 0;
	m_fifo.clear();
	scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL);
	update_state(State::Idle, 0);
	scsi_set_ctrl(0, S_ALL);
	scsi_bus->data_w(scsi_refid, 0);
	update_ssts();
	update_ints();
}

auto mb87030_device::get_state_name(State state) const
{
	switch (state) {
	case State::Idle:
		return "Idle";
	case State::ArbitrationWaitBusFree:
		return "ArbitrationWaitBusFree";
	case State::ArbitrationAssertBSY:
		return "ArbitrationAssertBSY";
	case State::ArbitrationWait:
		return "ArbitrationWait";
	case State::ArbitrationAssertSEL:
		return "ArbitrationAssertSEL";
	case State::ArbitrationDeAssertBSY:
		return "ArbitrationDeAssertBSY";
	case State::SelectionWaitBusFree:
		return "SelectionWaitBusFree";
	case State::SelectionWaitBSY:
		return "SelectionWaitBSY";
	case State::SelectionAssertSEL:
		return "SelectionAssertSEL";
	case State::Selection:
		return "Selection";
	case State::TransferWaitReq:
		return "TransferWaitReq";
	case State::TransferSendAck:
		return "TransferSendAck";
	case State::TransferSendData:
		return "TransferSendData";
	case State::TransferSendDataDMAReq:
		return "TransferSendDataDMAReq";
	case State::TransferSendDataDMAResp:
		return "TransferSendDataDMAResp";
	case State::TransferRecvData:
		return "TransferRecvData";
	case State::TransferRecvDataDMAReq:
		return "TransferRecvDataDMAReq";
	case State::TransferRecvDataDMAResp:
		return "TransferRecvDataDMAResp";

	case State::TransferWaitDeassertREQ:
		return "TransferWaitDeassertREQ";
	case State::TransferDeassertACK:
		return "TransferDeassertACK";
	}
	return "Unknown state";
}

void mb87030_device::update_state(mb87030_device::State new_state, int delay, int timeout)
{
	LOG("new state: %s -> %s (delay %d, timeout %d)\n", get_state_name(m_state),
			get_state_name(new_state), delay, timeout);
	m_state = new_state;
	if (delay)
		m_delay_timer->adjust(clocks_to_attotime(delay));
	else
		m_delay_timer->reset();
	if (timeout)
		m_timer->adjust(clocks_to_attotime(timeout));
	else
		m_timer->reset();
}

TIMER_CALLBACK_MEMBER(mb87030_device::timeout)
{
	m_timer->reset();
	step(true);
}

TIMER_CALLBACK_MEMBER(mb87030_device::delay_timeout)
{
	m_delay_timer->reset();
	step(false);
}

void mb87030_device::scsi_command_complete()
{
	m_ints |= INTS_COMMAND_COMPLETE;
	m_ssts &= ~(SSTS_SPC_BUSY|SSTS_XFER_IN_PROGRESS);
	update_ints();
	update_state(State::Idle);
}

void mb87030_device::scsi_disconnect_timeout()
{
	scsi_set_ctrl(0, S_ALL);
	scsi_bus->data_w(scsi_refid, 0);
	m_ints = INTS_SPC_TIMEOUT;
	update_ints();
	update_state(State::Idle);
}

void mb87030_device::scsi_disconnect()
{
	LOG("%s: m_tc %d\n", __FUNCTION__, m_tc);
	m_ssts &= ~(SSTS_INIT_CONNECTED|SSTS_TARG_CONNECTED|SSTS_SPC_BUSY|SSTS_XFER_IN_PROGRESS);
	m_ints = INTS_DISCONNECTED;
	update_ints();
	update_state(State::Idle);
}

void mb87030_device::scsi_set_ctrl(uint32_t value, uint32_t mask)
{
	if (m_sctl & SCTL_DIAG_MODE) {
		m_scsi_ctrl &= ~mask;
		m_scsi_ctrl |= value;
		logerror("update m_scsi_ctrl: %02X%s%s%s%s%s%s\n", m_scsi_ctrl,
				(m_scsi_ctrl & S_REQ) ? " REQ" : "",
				(m_scsi_ctrl & S_ACK) ? " ACK" : "",
				(m_scsi_ctrl & S_BSY) ? " BSY" : "",
				(m_scsi_ctrl & S_MSG) ? " MSG" : "",
				(m_scsi_ctrl & S_CTL) ? " CTL" : "",
				(m_scsi_ctrl & S_INP) ? " INP" : "");
	} else {
		scsi_bus->ctrl_w(scsi_refid, value, mask);
	}
}

uint32_t mb87030_device::scsi_get_ctrl(void)
{
	if (m_sctl & SCTL_DIAG_MODE) {
		uint32_t ret = 0;
		if ((m_sdgc & SDGC_DIAG_IO) || (m_scsi_ctrl & S_INP))
			ret |= S_INP;
		if ((m_sdgc & SDGC_DIAG_CD) || (m_scsi_ctrl & S_CTL))
			ret |= S_CTL;
		if ((m_sdgc & SDGC_DIAG_MSG) || (m_scsi_ctrl & S_MSG))
			ret |= S_MSG;
		if ((m_sdgc & SDGC_DIAG_BSY) || (m_scsi_ctrl & S_BSY))
			ret |= S_BSY;
		if ((m_sdgc & SDGC_DIAG_ACK) || (m_scsi_ctrl & S_ACK))
			ret |= S_ACK;
		if ((m_sdgc & SDGC_DIAG_REQ) || (m_scsi_ctrl & S_REQ))
			ret |= S_REQ;
		if (m_scsi_ctrl & S_SEL)
			ret |= S_SEL;
		if (m_scsi_ctrl & S_ATN)
			ret |= S_ATN;

		return ret;
	} else {
		return scsi_bus->ctrl_r();
	}
}

void mb87030_device::step(bool timeout)
{
	uint32_t ctrl = scsi_get_ctrl();
	uint32_t data = scsi_bus->data_r();

	LOG("%s: %d %s,%s data %02X ctrl %02X TC %d\n", __FUNCTION__,
			scsi_refid, get_state_name(m_state),
			timeout ? " timeout" : "", data,
					ctrl, m_tc);

	if (m_sctl & SCTL_RESET_AND_DISABLE && m_state != State::Idle) {
		scsi_set_ctrl(0, S_ALL);
		update_state(State::Idle);
		return;
	}

	if ((m_ssts & SSTS_INIT_CONNECTED) && !(ctrl & S_BSY)) {
		LOG("SCSI disconnect\n");
		scsi_disconnect();
		scsi_set_ctrl(0, S_ALL);
	}

	switch (m_state) {
	case State::Idle:
		if (ctrl == 0 && (m_pctl & PCTL_BUS_FREE_IE)) {
			m_ints |= INTS_DISCONNECTED;
			update_ints();
		}
		break;

	case State::ArbitrationWaitBusFree:
		if (!(ctrl & (S_BSY|S_SEL)))
			update_state(State::ArbitrationAssertBSY, 1);

		break;
	case State::ArbitrationAssertBSY:
		scsi_set_ctrl(S_BSY, S_BSY);
		scsi_bus->data_w(scsi_refid, (1 << m_bdid));
		update_state(State::ArbitrationWait, 1);
		break;

	case State::ArbitrationWait:
		for (int id = (2 << m_bdid); id <= 0x80; id <<= 1) {
			LOG("check %d\n", id);
			if (data & id) {
				LOG("arbitration lost, winner %d\n", id);
				scsi_disconnect_timeout();
				break;
			}
		}
		LOG("Arbitration won\n");
		update_state(State::ArbitrationAssertSEL, 1);
		break;

	case State::ArbitrationAssertSEL:
		scsi_set_ctrl(S_SEL, S_SEL);
		update_state(State::ArbitrationDeAssertBSY, 1);
		break;

	case State::ArbitrationDeAssertBSY:
		scsi_set_ctrl(0, S_BSY);
		update_state(State::SelectionAssertSEL, 1);
		break;

	case State::SelectionWaitBusFree:
		if (!(ctrl & (S_BSY|S_SEL)))
			update_state(State::SelectionAssertSEL, 10);
		break;

	case State::SelectionAssertSEL:
		scsi_bus->data_w(scsi_refid, m_temp);
		scsi_set_ctrl(0, S_SEL); //XXX: needed?
		scsi_set_ctrl(S_SEL | (m_send_atn_during_selection ? S_ATN : 0), S_ATN|S_SEL|S_BSY);
		scsi_bus->ctrl_wait(scsi_refid, S_BSY, S_BSY);
		update_state(State::SelectionWaitBSY, 0, m_tc / 8);
		break;

	case State::SelectionWaitBSY:
		if (timeout) {
			LOG("select timeout\n");
			scsi_disconnect_timeout();
			break;
		}
		m_timer->reset();
		if ((ctrl & (S_REQ|S_BSY|S_MSG|S_CTL|S_INP)) == S_BSY)
			update_state(State::Selection, 1);

		break;

	case State::Selection:
		LOG("selection success\n");
		scsi_set_ctrl(0, S_SEL);
		m_ssts |= SSTS_INIT_CONNECTED|SSTS_XFER_IN_PROGRESS;
		m_ssts &= ~(SSTS_TARG_CONNECTED|SSTS_SPC_BUSY);
		update_ssts();
		scsi_command_complete();
		break;

	case State::TransferWaitReq:
		if (!m_tc && !(m_scmd & SCMD_TERM_MODE)) {
			LOG("TransferWaitReq: tc == 0\n");
			scsi_bus->data_w(scsi_refid, 0);
			scsi_command_complete();
			break;
		}

		if (m_scsi_phase != (ctrl & S_PHASE_MASK)) {
			LOG("SCSI phase change during transfer\n");
			m_ints |= INTS_SERVICE_REQUIRED;
			m_ssts &= ~SSTS_SPC_BUSY;
			update_ints();
			break;
		}

		if (!(ctrl & S_REQ)) {
			scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
			break;
		}

		if (!m_dma_transfer || (m_scmd & SCMD_TERM_MODE)) {
			update_state((ctrl & S_INP) ? State::TransferRecvData : State::TransferSendData, 1);
		} else {
			update_state((ctrl & S_INP) ? State::TransferRecvDataDMAReq : State::TransferSendDataDMAReq, 1);
		}
		break;

	case State::TransferRecvData:
		if (!m_tc && (m_scmd & SCMD_TERM_MODE)) {
			update_state(State::TransferSendAck, 10);
			break;
		}

		if (!m_tc || m_fifo.full())
			break;

		m_bus_data = data;
		update_state(State::TransferSendAck, 10);
		break;

	case State::TransferRecvDataDMAReq:
		m_hdb = data;
		m_hdb_loaded = true;
		update_state(State::TransferRecvDataDMAResp, 10);
		m_dreq_handler(true);
		break;

	case State::TransferRecvDataDMAResp:
		if (m_hdb_loaded)
			break;
		update_state(State::TransferSendAck, 10);
		m_dreq_handler(false);
		break;

	case State::TransferSendData:
		if (m_tc && !m_fifo.empty()) {
			scsi_bus->data_w(scsi_refid, m_fifo.peek());
			update_state(State::TransferSendAck, 10);
			break;
		}

		if (!m_tc  && (m_scmd & SCMD_TERM_MODE)) {
			scsi_bus->data_w(scsi_refid, m_temp);
			update_state(State::TransferSendAck, 10);
			break;
		}
		break;

	case State::TransferSendDataDMAReq:
		m_hdb_loaded = false;
		update_state(State::TransferSendDataDMAResp, 10);
		m_dreq_handler(true);
		break;

	case State::TransferSendDataDMAResp:
		if (!m_hdb_loaded)
			break;
		m_hdb_loaded = false;
		m_dreq_handler(false);
		scsi_bus->data_w(scsi_refid, m_hdb);
		update_state(State::TransferSendAck, 10);
		break;

	case State::TransferSendAck:
		if (!(m_scmd & SCMD_TERM_MODE) && !(ctrl & S_INP))
				m_temp = data;

		scsi_set_ctrl(S_ACK, S_ACK);
		scsi_bus->ctrl_wait(scsi_refid, 0, S_REQ);
		update_state(State::TransferWaitDeassertREQ, 10);
		break;

	case State::TransferWaitDeassertREQ:
		if (!(ctrl & S_REQ))
			update_state(State::TransferDeassertACK, 10);
		break;

	case State::TransferDeassertACK:
		m_tc--;
		if (!m_dma_transfer) {
			if (!(ctrl & S_INP)) {
				m_fifo.dequeue();
			} else {
				LOG("pushing read data: %02X\n", m_bus_data);
				m_fifo.enqueue(m_bus_data);
			}
		}
		update_state(State::TransferWaitReq, 10);
		scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ);
		scsi_set_ctrl(0, S_ACK);
		break;

	}
}

void mb87030_device::device_start()
{
	m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb87030_device::timeout), this));
	m_delay_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb87030_device::delay_timeout), this));
	m_irq_handler.resolve_safe();
	m_dreq_handler.resolve_safe();

	save_item(NAME(m_bdid));
	save_item(NAME(m_sctl));
	save_item(NAME(m_scmd));
	save_item(NAME(m_tmod));
	save_item(NAME(m_ints));
	save_item(NAME(m_sdgc));
	save_item(NAME(m_ssts));
	save_item(NAME(m_serr));
	save_item(NAME(m_pctl));
	save_item(NAME(m_mbc));
	save_item(NAME(m_dreg));
	save_item(NAME(m_temp));
	save_item(NAME(m_tch));
	save_item(NAME(m_tcm));
	save_item(NAME(m_tc));
	save_item(NAME(m_exbf));
	save_item(NAME(m_hdb));
	save_item(NAME(m_hdb_loaded));
	save_item(NAME(m_send_atn_during_selection));
//  save_item(NAME(m_fifo));
	save_item(NAME(m_scsi_phase));
	save_item(NAME(m_scsi_ctrl));
	save_item(NAME(m_dma_transfer));
	save_item(NAME(m_bus_data));
//  save_item(NAME(m_state));
}

void mb87030_device::scsi_ctrl_changed()
{
	if (m_delay_timer->remaining() == attotime::never)
		step(false);
}

WRITE_LINE_MEMBER(mb87030_device::reset_w)
{
	LOG("%s: %s\n", __FUNCTION__, state);
	if (state)
		device_reset();
}

void mb87030_device::update_ssts()
{
	if (!m_tc)
		m_ssts |= SSTS_TC_ZERO;
	else
		m_ssts &= ~SSTS_TC_ZERO;

	if (m_fifo.empty())
		m_ssts |= SSTS_DREQ_EMPTY;
	else
		m_ssts &= ~SSTS_DREQ_EMPTY;

	if (m_fifo.full())
		m_ssts |= SSTS_DREQ_FULL;
	else
		m_ssts &= ~SSTS_DREQ_FULL;
}

void mb87030_device::update_ints()
{
	LOG("%s: %s\n", __FUNCTION__, (m_ints && (m_sctl & 1)) ? "true" : "false");
	m_irq_handler(m_ints && (m_sctl & 1));// || (m_ints & INTS_DISCONNECTED));
}

READ8_MEMBER(mb87030_device::bdid_r)
{
	LOG("%s %02X\n", __FUNCTION__, (1 << m_bdid));
	return 1 << m_bdid;
}

WRITE8_MEMBER(mb87030_device::bdid_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_bdid = data & 0x7;
}

READ8_MEMBER(mb87030_device::sctl_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_sctl);
	return m_sctl;
}

WRITE8_MEMBER(mb87030_device::sctl_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_sctl = data;
	update_ints();
}

READ8_MEMBER(mb87030_device::scmd_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_scmd);
	return m_scmd;
}

WRITE8_MEMBER(mb87030_device::scmd_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_scmd = data;

	switch (m_scmd & SCMD_CMD_MASK) {
	case SCMD_CMD_BUS_RELEASE:
		LOG("%s: Bus release\n", __FUNCTION__);
		break;

	case SCMD_CMD_SELECT:
		LOG("%s: Select\n", __FUNCTION__);
		if (m_sctl & SCTL_ARBITRATION_ENABLE)
			update_state(State::ArbitrationWaitBusFree, 10);
		else
			update_state(State::SelectionWaitBusFree, 10);
		step(false);
		break;

	case SCMD_CMD_RESET_ATN:
		LOG("%s: Reset ATN\n", __FUNCTION__);
//      if (m_state == State::Idle)
			m_send_atn_during_selection = false;
//      else
			scsi_set_ctrl(0, S_ATN);
		break;

	case SCMD_CMD_SET_ATN:
		LOG("%s: Set ATN\n", __FUNCTION__);
		if (m_state == State::Idle)
			m_send_atn_during_selection = true;
		else
			scsi_set_ctrl(S_ATN, S_ATN);
		break;

	case SCMD_CMD_TRANSFER:
		if (!(m_ssts & (SSTS_INIT_CONNECTED|SSTS_TARG_CONNECTED)))
			break;

		m_dma_transfer = !(data & 0x04);
		LOG("%s Transfer\n", m_dma_transfer ? "DMA" : "Program");
		m_ssts |= SSTS_SPC_BUSY|SSTS_XFER_IN_PROGRESS;
		update_state(State::TransferWaitReq, 5);
		break;

	case SCMD_CMD_TRANSFER_PAUSE:
		LOG("%s: Transfer Pause\n", __FUNCTION__);
		break;

	case SCMD_CMD_RESET_ACK_REQ:
		LOG("%s: Reset ACK/REQ\n", __FUNCTION__);
		if (m_ssts & SSTS_INIT_CONNECTED)
			scsi_set_ctrl(0, S_ACK);
		if (m_ssts & SSTS_TARG_CONNECTED)
			scsi_set_ctrl(0, S_REQ);
		break;

	case SCMD_CMD_SET_ACK_REQ:
		LOG("%s: Set ACK/REQ\n", __FUNCTION__);
		if (m_ssts & SSTS_INIT_CONNECTED) {
				if (scsi_bus->ctrl_r() & S_INP) {
					m_temp = scsi_bus->data_r();
				} else {
					scsi_bus->data_w(scsi_refid, m_temp);
				}
				LOG("set ACK\n");
				scsi_set_ctrl(S_ACK, S_ACK);
		} else {
			logerror("not connected\n");
		}
		if (m_ssts & SSTS_TARG_CONNECTED)
			scsi_set_ctrl(S_REQ, S_REQ);
		break;
	}
}

READ8_MEMBER(mb87030_device::tmod_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_tmod);
	return m_tmod;
}

WRITE8_MEMBER(mb87030_device::tmod_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_tmod = data;
}

READ8_MEMBER(mb87030_device::ints_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_ints);
	return m_ints;
}

WRITE8_MEMBER(mb87030_device::ints_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_ints &= ~(data);
	update_ints();
}

READ8_MEMBER(mb87030_device::psns_r)
{
	uint32_t ctrl = scsi_get_ctrl();
	uint8_t ret  = (!!(ctrl & S_REQ) << 7) |
			(!!(ctrl & S_ACK) << 6) |
			(!!(ctrl & S_ATN) << 5) |
			(!!(ctrl & S_SEL) << 4) |
			(!!(ctrl & S_BSY) << 3) |
			(!!(ctrl & S_MSG) << 2) |
			(!!(ctrl & S_CTL) << 1) |
			(!!(ctrl & S_INP));
	LOG("%s: %02X\n", __FUNCTION__, ret);
	return ret;
}

WRITE8_MEMBER(mb87030_device::sdgc_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_sdgc = data;
	scsi_ctrl_changed();
}

READ8_MEMBER(mb87030_device::ssts_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_ssts);
	update_ssts();
	return m_ssts;
}

READ8_MEMBER(mb87030_device::serr_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_serr);
	return m_serr;
}

READ8_MEMBER(mb87030_device::pctl_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_pctl);
	return m_pctl;
}

WRITE8_MEMBER(mb87030_device::pctl_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_pctl = data;
	m_scsi_phase = m_pctl & 7;
	if (m_pctl & PCTL_BUS_FREE_IE)
		step(false);
}

READ8_MEMBER(mb87030_device::mbc_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_mbc);
	return m_mbc;
}

READ8_MEMBER(mb87030_device::dreg_r)
{
	step(false);
	if (!m_fifo.empty())
			m_dreg = m_fifo.dequeue();
	LOG("%s: %02X\n", __FUNCTION__, m_dreg);
	return m_dreg;
}

WRITE8_MEMBER(mb87030_device::dreg_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_dreg = data;
	if (!m_fifo.full())
		m_fifo.enqueue(data);
	step(false);
}

READ8_MEMBER(mb87030_device::temp_r)
{
	step(false);
	LOG("%s: %02X\n", __FUNCTION__, m_temp);
	return m_temp;
}

WRITE8_MEMBER(mb87030_device::temp_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_temp = data;
	step(false);
}

READ8_MEMBER(mb87030_device::tch_r)
{
	uint8_t ret = (m_tc >> 16) & 0xff;
	LOG("%s: %02X\n", __FUNCTION__, ret);
	return ret;
}

READ8_MEMBER(mb87030_device::tcm_r)
{
	uint8_t ret = (m_tc >> 8) & 0xff;
	LOG("%s: %02X\n", __FUNCTION__, ret);
	return ret;
}

READ8_MEMBER(mb87030_device::tcl_r)
{
	uint8_t ret = m_tc & 0xff;
	LOG("%s: %02X\n", __FUNCTION__, ret);
	return ret;
}


WRITE8_MEMBER(mb87030_device::tch_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_tc &= 0x00ffff;
	m_tc |= data << 16;
	update_ssts();
}

WRITE8_MEMBER(mb87030_device::tcm_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_tc &= 0xff00ff;
	m_tc |= data << 8;
	update_ssts();
}

WRITE8_MEMBER(mb87030_device::tcl_w)
{
	LOG("%s: %02X\n", __FUNCTION__, data);
	m_tc &= 0xffff00;
	m_tc |= data;
	update_ssts();
}

READ8_MEMBER(mb87030_device::exbf_r)
{
	LOG("%s: %02X\n", __FUNCTION__, m_exbf);
	return m_exbf;
}

WRITE8_MEMBER(mb87030_device::exbf_w)
{
	LOG("%s: %02X\n", __FUNCTION__,  data);
	m_exbf = data;
}

void mb87030_device::dma_w(uint8_t data)
{
	if (machine().side_effects_disabled())
		return;
	LOG("dma_w: %02X\n", data);
	m_hdb = data;
	m_hdb_loaded = true;
	step(false);
}

uint8_t mb87030_device::dma_r(void)
{
	uint8_t val = m_hdb;

	if (machine().side_effects_disabled())
		return 0;
	LOG("dma_r: %02X\n", val);
	m_hdb_loaded = false;
	step(false);
	return val;
}