summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/psx/memcard.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/devices/bus/psx/memcard.cpp
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/devices/bus/psx/memcard.cpp')
-rw-r--r--src/devices/bus/psx/memcard.cpp365
1 files changed, 365 insertions, 0 deletions
diff --git a/src/devices/bus/psx/memcard.cpp b/src/devices/bus/psx/memcard.cpp
new file mode 100644
index 00000000000..c0461a3efac
--- /dev/null
+++ b/src/devices/bus/psx/memcard.cpp
@@ -0,0 +1,365 @@
+// license:BSD-3-Clause
+// copyright-holders:Carl,psxAuthor,R. Belmont
+/*
+ psxcard.c - Sony PlayStation memory card device
+
+ by pSXAuthor
+ MESS conversion by R. Belmont
+*/
+
+#include "emu.h"
+#include "memcard.h"
+#include "ctlrport.h"
+
+//
+//
+//
+
+//#define debug_card
+
+//
+//
+//
+
+static const int block_size = 128;
+static const int card_size = block_size * 1024;
+
+const device_type PSXCARD = &device_creator<psxcard_device>;
+
+enum transfer_states
+{
+ state_illegal=0,
+ state_command,
+ state_cmdack,
+ state_wait,
+ state_addr_hi,
+ state_addr_lo,
+ state_read,
+ state_write,
+ state_writeack_2,
+ state_writechk,
+ state_end
+};
+
+psxcard_device::psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PSXCARD, "Sony PSX Memory Card", tag, owner, clock, "psxcard", __FILE__),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void psxcard_device::device_start()
+{
+ m_owner = dynamic_cast<psx_controller_port_device *>(owner());
+ m_ack_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psxcard_device::ack_timer), this));
+
+ m_ack = true;
+ m_disabled = false;
+
+ // save state registrations
+ save_item(NAME(pkt));
+ save_item(NAME(pkt_ptr));
+ save_item(NAME(pkt_sz));
+ save_item(NAME(cmd));
+ save_item(NAME(addr));
+ save_item(NAME(state));
+ save_item(NAME(m_disabled));
+ save_item(NAME(m_odata));
+ save_item(NAME(m_idata));
+ save_item(NAME(m_bit));
+ save_item(NAME(m_count));
+ save_item(NAME(m_pad));
+}
+
+void psxcard_device::device_reset()
+{
+ state = state_illegal;
+ addr = 0;
+
+ m_bit = 0;
+ m_count = 0;
+ m_pad = false;
+ m_idata = 0;
+
+ m_clock = true;
+ m_sel = true;
+ m_rx = true;
+ m_ack = true;
+ m_owner->ack();
+}
+
+void psxcard_device::device_config_complete()
+{
+ update_names(PSXCARD, "memcard", "mc");
+}
+
+//
+//
+//
+
+bool psxcard_device::transfer(UINT8 to, UINT8 *from)
+{
+ bool ret=true;
+
+ switch (state)
+ {
+ case state_illegal:
+ if (is_loaded())
+ {
+// printf("CARD: begin\n");
+ state = state_command;
+ *from = 0x00;
+ }
+ else
+ {
+ ret = false;
+ }
+ break;
+
+ case state_command:
+ cmd=to;
+ *from=0x5a;
+ state=state_cmdack;
+ break;
+
+ case state_cmdack:
+ *from=0x5d;
+ state=state_wait;
+ break;
+
+ case state_wait:
+ *from=0x00;
+ state=state_addr_hi;
+ break;
+
+ case state_addr_hi:
+ addr=(to<<8);
+// printf("addr_hi: %02x, addr = %x\n", to, addr);
+ *from=to;
+ state=state_addr_lo;
+ break;
+
+ case state_addr_lo:
+ addr|=(to&0xff);
+// printf("addr_lo: %02x, addr = %x, cmd = %x\n", to, addr, cmd);
+
+ switch (cmd)
+ {
+ case 'R': // 0x52
+ {
+ pkt[0]=*from=0x5c;
+ pkt[1]=0x5d;
+ pkt[2]=(addr>>8);
+ pkt[3]=(addr&0xff);
+ read_card(addr,&pkt[4]);
+ pkt[4+128]=checksum_data(&pkt[2],128+2);
+ pkt[5+128]=0x47;
+ pkt_sz=6+128;
+ pkt_ptr=1;
+ state=state_read;
+ break;
+ }
+ case 'W': // 0x57
+ {
+ pkt[0]=addr>>8;
+ pkt[1]=addr&0xff;
+ pkt_sz=129+2;
+ pkt_ptr=2;
+ state=state_write;
+ *from=to;
+ break;
+ }
+ default:
+ state=state_illegal;
+ break;
+ }
+ break;
+
+ case state_read:
+ //assert(to==0);
+// printf("state_read: pkt_ptr = %d, pkt_sz = %d\n", pkt_ptr, pkt_sz);
+ *from=pkt[pkt_ptr++];
+ if (pkt_ptr==pkt_sz)
+ {
+ #ifdef debug_card
+ printf("card: read finished\n");
+ #endif
+
+ state=state_end;
+ }
+ break;
+
+ case state_write:
+ *from=to;
+ pkt[pkt_ptr++]=to;
+ if (pkt_ptr==pkt_sz)
+ {
+ *from=0x5c;
+ state=state_writeack_2;
+ }
+ break;
+
+ case state_writeack_2:
+ *from=0x5d;
+ state=state_writechk;
+ break;
+
+ case state_writechk:
+ {
+ unsigned char chk=checksum_data(pkt,128+2);
+ if (chk==pkt[128+2])
+ {
+ #ifdef debug_card
+ printf("card: write ok\n");
+ #endif
+
+ write_card(addr,pkt+2);
+
+ *from='G';
+ } else
+ {
+ #ifdef debug_card
+ printf("card: write fail\n");
+ #endif
+
+ *from='N';
+ }
+ state=state_end;
+ break;
+ }
+
+ case state_end:
+ ret = false;
+ state = state_illegal;
+ break;
+
+ default: /*assert(0);*/ ret=false; break;
+ }
+
+ #ifdef debug_card
+// printf("card: transfer to=%02x from=%02x ret=%c\n",to,*from,ret ? 'T' : 'F');
+ #endif
+
+ return ret;
+}
+
+void psxcard_device::read_card(const unsigned short addr, unsigned char *buf)
+{
+ #ifdef debug_card
+ printf("card: read block %d\n",addr);
+ #endif
+
+ if (addr<(card_size/block_size))
+ {
+ fseek(addr*block_size, SEEK_SET);
+ fread(buf, block_size);
+ } else
+ {
+ memset(buf,0,block_size);
+ }
+}
+
+//
+//
+//
+
+void psxcard_device::write_card(const unsigned short addr, unsigned char *buf)
+{
+ #ifdef debug_card
+ printf("card: write block %d\n",addr);
+ #endif
+
+ if (addr<(card_size/block_size))
+ {
+ fseek(addr*block_size, SEEK_SET);
+ fwrite(buf, block_size);
+ }
+}
+
+unsigned char psxcard_device::checksum_data(const unsigned char *buf, const unsigned int sz)
+{
+ unsigned char chk=*buf++;
+ int left=sz;
+ while (--left) chk^=*buf++;
+ return chk;
+}
+
+bool psxcard_device::call_load()
+{
+ if(m_disabled)
+ {
+ logerror("psxcard: port disabled\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ if(length() != card_size)
+ return IMAGE_INIT_FAIL;
+ return IMAGE_INIT_PASS;
+}
+
+bool psxcard_device::call_create(int format_type, option_resolution *format_options)
+{
+ UINT8 block[block_size];
+ int i, ret;
+
+ if(m_disabled)
+ {
+ logerror("psxcard: port disabled\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ memset(block, '\0', block_size);
+ for(i = 0; i < (card_size/block_size); i++)
+ {
+ ret = fwrite(block, block_size);
+ if(ret != block_size)
+ return IMAGE_INIT_FAIL;
+ }
+ return IMAGE_INIT_PASS;
+}
+
+void psxcard_device::do_card()
+{
+ if(!m_bit)
+ {
+ m_idata = 0;
+ if(!m_count)
+ m_odata = 0xff;
+ }
+
+ m_rx = (m_odata & (1 << m_bit)) ? true : false;
+ m_idata |= (m_owner->tx_r()?1:0) << m_bit;
+ m_bit = (m_bit + 1) % 8;
+
+ if(!m_bit)
+ {
+ if((!m_count) && !(m_idata & 0x80))
+ {
+ m_pad = true;
+ return;
+ }
+
+ if(transfer(m_idata, &m_odata))
+ {
+ m_count++;
+ m_ack_timer->adjust(attotime::from_usec(10), 0);
+ }
+ else
+ m_count = 0;
+ }
+}
+
+void psxcard_device::ack_timer(void *ptr, int param)
+{
+ m_ack = param;
+ m_owner->ack();
+
+ if(!param)
+ m_ack_timer->adjust(attotime::from_usec(2), 1);
+}
+
+void psxcard_device::sel_w(bool state)
+{
+ if(state && !m_sel)
+ reset();
+ m_sel = state;
+}