machine/spifi3.cpp: Implemented HP 1TV3-0302 SPIFI3 SCSI controller. (#10137)

This commit is contained in:
Brice Onken 2022-08-05 03:49:51 -07:00 committed by GitHub
parent c5cff268c2
commit 7add0628c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 2199 additions and 0 deletions

View File

@ -4821,6 +4821,19 @@ if (MACHINES["CXD1185"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/spifi3.h,MACHINES["SPIFI3"] = true
---------------------------------------------------
if (MACHINES["SPIFI3"]~=null) then
MACHINES["NSCSI"] = true
files {
MAME_DIR .. "src/devices/machine/spifi3.cpp",
MAME_DIR .. "src/devices/machine/spifi3.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/applefdintf.h,MACHINES["APPLE_FDINTF"] = true

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,304 @@
// license:BSD-3-Clause
// copyright-holders:Brice Onken,Tsubai Masanari,Olivier Galibert
// thanks-to:Patrick Mackinlay
/*
* HP 1TV3-0302 SPIFI3-SE SCSI controller
*
* Datasheets for this seem to be impossible to find - the only avaliable implementation to reference that I have
* found is the Sony NEWS APBus NetBSD driver. Hopefully a datasheet will turn up eventually.
* Based on internet research, it seems some HP PA-RISC systems also used the SPIFI3, including the E55.
*
* Because this driver was developed to work with NetBSD, NEWS-OS, and the NWS-5000 monitor ROM, only
* the features and flows that Sony used are implemented. Emulating non-Sony designs using this chip will likely
* require similar RE work to determine the exact SPIFI features used and add support for them into this driver.
* In its current state, this driver is unlikely to work out of the box with any other machines.
*
* Register definitions were derived from the NetBSD source code, copyright (c) 2000 Tsubai Masanari.
* SCSI state machine code was derived from the MAME NCR5390 driver, copyright (c) Olivier Galibert
*
* References:
* - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifireg.h
* - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifi.c
* - https://github.com/mamedev/mame/blob/master/src/devices/machine/ncr5390.cpp
*/
#ifndef MAME_MACHINE_SPIFI3_H
#define MAME_MACHINE_SPIFI3_H
#pragma once
#include "machine/nscsi_bus.h"
class spifi3_device
: public nscsi_device,
public nscsi_slot_card_interface
{
public:
spifi3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
void map(address_map &map);
auto irq_handler_cb() { return m_irq_handler.bind(); }
auto drq_handler_cb() { return m_drq_handler.bind(); }
uint8_t dma_r();
void dma_w(uint8_t val);
protected:
virtual void device_start() override;
virtual void scsi_ctrl_changed() override;
private:
static constexpr int FIFO_SIZE = 8;
enum scsi_mode : uint8_t
{
MODE_D, // Disconnected
MODE_T, // Target
MODE_I // Initiator
};
enum scsi_data_target : uint8_t
{
COMMAND_BUFFER,
FIFO
};
enum dma_direction : uint8_t
{
DMA_NONE,
DMA_IN,
DMA_OUT
};
struct spifi_cmd_entry
{
// NetBSD has these mapped as uint32_t to align the accesses and such
// in reality, these are all 8-bit values that are mapped, in typical NWS-5000 series
// fashion, to be 32-bit word aligned.
// the same probably applies to the register file.
uint8_t cdb[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t quecode = 0;
uint8_t quetag = 0;
uint8_t idmsg = 0;
uint8_t status = 0;
};
struct register_file
{
uint32_t spstat = 0;
uint32_t cmlen = 0;
uint32_t cmdpage = 0;
// count_hi, count_mid, count_low
uint32_t svptr_hi = 0;
uint32_t svptr_mid = 0;
uint32_t svptr_low = 0;
uint32_t intr = 0;
uint32_t imask = 0;
uint32_t prctrl = 0;
uint32_t prstat = 0;
uint32_t init_status = 0;
uint32_t fifoctrl = 0;
uint32_t fifodata = 0;
uint32_t config = 0;
uint32_t data_xfer = 0;
uint32_t autocmd = 0;
uint32_t autostat = 0;
uint32_t resel = 0;
uint32_t select = 0;
// prcmd, which is used to trigger commands
uint32_t auxctrl = 0;
uint32_t autodata = 0;
uint32_t loopctrl = 0;
uint32_t loopdata = 0;
uint32_t identify = 0;
uint32_t complete = 0;
uint32_t scsi_status = 0x1; // Must be 0x1 for SPIFI to be recognized at boot
uint32_t data = 0;
uint32_t icond = 0;
uint32_t fastwide = 0;
uint32_t exctrl = 0;
uint32_t exstat = 0;
uint32_t test = 0;
uint32_t quematch = 0;
uint32_t quecode = 0;
uint32_t quetag = 0;
uint32_t quepage = 0;
spifi_cmd_entry cmbuf[8];
} spifi_reg;
template<typename T>
class spifi_queue
{
public:
uint32_t head;
uint32_t tail;
uint32_t size;
T fifo[FIFO_SIZE];
spifi_queue() { clear_queue(); }
uint32_t get_size() { return size; }
bool empty() { return size == 0; }
bool full() { return size == FIFO_SIZE; }
void clear_queue()
{
head = 0;
tail = 0;
size = 0;
for (int i = 0; i < FIFO_SIZE; ++i)
{
fifo[i] = 0;
}
}
void push(T value)
{
if(size == FIFO_SIZE)
{
fatalerror("spifi3: FIFO overflow!");
}
fifo[tail] = value;
tail = (tail + 1) % FIFO_SIZE;
++size;
}
T pop()
{
if (size == 0)
{
fatalerror("spifi3: FIFO underflow!");
}
const T removed_value = fifo[head];
head = (head + 1) % FIFO_SIZE;
--size;
return removed_value;
}
};
// State tracking variables
dma_direction dma_dir;
scsi_mode mode;
scsi_data_target xfr_data_source;
uint32_t state;
uint32_t xfr_phase;
uint32_t command_pos;
bool irq = false;
bool drq = false;
uint32_t tcounter;
uint8_t sync_period = 5; // TODO: appropriate value for SPIFI
uint8_t clock_conv = 2; // TODO: appropriate value for SPIFI
uint32_t bus_id;
spifi_queue<uint8_t> m_even_fifo;
spifi_queue<uint8_t> m_odd_fifo;
emu_timer *tm;
// I/O ports
devcb_write_line m_irq_handler;
devcb_write_line m_drq_handler;
// State-related methods
TIMER_CALLBACK_MEMBER(tick);
void step(bool timeout);
void check_irq();
void check_drq();
void reset_disconnect();
void send_byte(scsi_data_target data_source);
void recv_byte();
void function_complete();
void function_bus_complete();
void bus_complete();
void dma_set(dma_direction dir);
void decrement_tcounter(uint32_t count = 1);
bool transfer_count_zero();
void delay(uint32_t cycles);
void delay_cycles(uint32_t cycles);
void arbitrate();
void clear_fifo();
void auto_phase_transfer(uint32_t new_phase);
void start_autodata(uint32_t data_phase);
void start_autostat();
void start_automsg(uint32_t msg_phase);
void start_autocmd();
dma_direction dma_setting(uint32_t target_id);
// Register processing methods
uint32_t get_target_id();
bool autodata_active(uint32_t target_id);
bool autodata_in(uint32_t target_id);
bool autodata_out(uint32_t target_id);
void autostat_done(uint32_t target_id);
bool autostat_active(uint32_t target_id);
bool automsg_active();
bool autocmd_active();
// Register accessors
uint32_t spstat_r();
uint32_t cmlen_r();
void cmlen_w(uint32_t data);
uint32_t cmdpage_r();
void cmdpage_w(uint32_t data);
uint32_t count_r(offs_t offset);
void count_w(offs_t offset, uint32_t data);
uint32_t intr_r();
void intr_w(uint32_t data);
uint32_t imask_r();
void imask_w(uint32_t data);
uint32_t prstat_r();
uint32_t init_status_r();
uint32_t fifoctrl_r();
void fifoctrl_w(uint32_t data);
uint32_t data_xfer_r();
void data_xfer_w(uint32_t data);
uint32_t autocmd_r();
void autocmd_w(uint32_t data);
uint32_t autostat_r();
void autostat_w(uint32_t data);
uint32_t select_r();
void select_w(uint32_t data);
void prcmd_w(uint32_t data);
uint32_t auxctrl_r();
void auxctrl_w(uint32_t data);
uint32_t autodata_r();
void autodata_w(uint32_t data);
uint32_t identify_r();
void identify_w(uint32_t data);
uint32_t scsi_status_r();
void scsi_status_w(uint32_t data);
uint32_t icond_r();
void icond_w(uint32_t data);
uint32_t fastwide_r();
void fastwide_w(uint32_t data);
uint32_t exctrl_r();
void exctrl_w(uint32_t data);
// Command buffer accessors
uint8_t cmd_buf_r(offs_t offset);
void cmd_buf_w(offs_t offset, uint8_t data);
// Data helpers
bool dma_command(dma_direction current_direction) const
{
return current_direction != DMA_NONE;
}
};
DECLARE_DEVICE_TYPE(SPIFI3, spifi3_device)
#endif // MAME_MACHINE_SPIFI3_H