summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Couriersud <couriersud@users.noreply.github.com>2009-09-20 23:35:27 +0000
committer Couriersud <couriersud@users.noreply.github.com>2009-09-20 23:35:27 +0000
commit12992dad2684e21df5b986316b8aa1c8861f94c2 (patch)
tree807301e8c38fea6702cd0443f9781430cd416912
parentf8aa138a9134dcf2965268fbf8dda96334a6f14e (diff)
Implemented a RS and WS line interface for tms5220
- this emulates the RS/WS and READY handshaking according to the tms5220 manual. Drivers reading the ready line should most probably use it. - Note: For cases where the READY handshake is done by the cpu sufficient cycles have to be burnt to simulate that the cpu waited. This yet has to be implemented.
-rw-r--r--src/emu/sound/tms5220.c196
-rw-r--r--src/emu/sound/tms5220.h9
2 files changed, 178 insertions, 27 deletions
diff --git a/src/emu/sound/tms5220.c b/src/emu/sound/tms5220.c
index e1b5bac2295..fe19b90522e 100644
--- a/src/emu/sound/tms5220.c
+++ b/src/emu/sound/tms5220.c
@@ -45,7 +45,8 @@ TI's naming has D7 as LSB and D0 as MSB and is in uppercase
#include "tms5220.h"
-#define DEBUG_5220 0
+#define VERBOSE (0)
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#define MAX_SAMPLE_CHUNK 512
@@ -140,6 +141,21 @@ struct _tms5220_state
UINT8 data_register; /* data register, used by read command */
UINT8 RDB_flag; /* whether we should read data register or status register */
+ /* io_ready: page 3 of the datasheet specifies that READY will be asserted until
+ * data is available or processed by the system.
+ */
+
+ UINT8 io_ready;
+
+ /* flag for "true" timing involving rs/ws */
+
+ UINT8 true_timing;
+
+ /* rsws - state, rs bit 1, ws bit 0 */
+ UINT8 rs_ws;
+ UINT8 read_latch;
+ UINT8 write_latch;
+
/* flag for variant tmc0285/tms5200 emulation */
/* The TMC0285 AKA TMS5200 is an earlier variant of the TMS5220 used in
the early releases of the Speech Module for the TI-99/4(a) computer,
@@ -243,6 +259,8 @@ static void register_for_save_states(tms5220_state *tms)
state_save_register_device_item(tms->device, 0, tms->data_register);
state_save_register_device_item(tms->device, 0, tms->RDB_flag);
state_save_register_device_item(tms->device, 0, tms->digital_select);
+
+ state_save_register_device_item(tms->device, 0, tms->io_ready);
}
@@ -265,11 +283,11 @@ static void tms5220_data_write(tms5220_state *tms, int data)
if (tms->speak_external)
tms->buffer_empty = 0;
- if (DEBUG_5220) logerror("Added byte to FIFO (size=%2d)\n", tms->fifo_count);
+ LOG(("Added byte to FIFO (size=%2d)\n", tms->fifo_count));
}
else
{
- if (DEBUG_5220) logerror("Ran out of room in the FIFO!\n");
+ LOG(("Ran out of room in the FIFO!\n"));
}
/* update the buffer low state */
@@ -317,7 +335,7 @@ static int tms5220_status_read(tms5220_state *tms)
/* clear the interrupt pin */
set_interrupt_state(tms, 0);
- if (DEBUG_5220) logerror("Status read: TS=%d BL=%d BE=%d\n", tms->talk_status, tms->buffer_low, tms->buffer_empty);
+ LOG(("Status read: TS=%d BL=%d BE=%d\n", tms->talk_status, tms->buffer_low, tms->buffer_empty));
return (tms->talk_status << 7) | (tms->buffer_low << 6) | (tms->buffer_empty << 5);
}
@@ -333,7 +351,8 @@ static int tms5220_status_read(tms5220_state *tms)
static int tms5220_ready_read(tms5220_state *tms)
{
- return (tms->fifo_count < FIFO_SIZE-1);
+ LOG(("io_ready %d\n", tms->io_ready));
+ return (tms->fifo_count < FIFO_SIZE-1) && tms->io_ready;
}
@@ -762,7 +781,7 @@ static void process_command(tms5220_state *tms)
break;
case 0x30 : /* read and branch */
- if (DEBUG_5220) logerror("read and branch command received\n");
+ LOG(("read and branch command received\n"));
tms->RDB_flag = FALSE;
if (tms->intf->read_and_branch)
(*tms->intf->read_and_branch)(tms->device);
@@ -893,7 +912,7 @@ static int parse_frame(tms5220_state *tms, int the_first_frame)
// WARNING: This code below breaks Victory's power-on test! If you change it
// make sure you test Victory.
// {
-// if (DEBUG_5220) logerror("Buffer Empty set - Last frame stop frame\n");
+// LOG(("Buffer Empty set - Last frame stop frame\n");
// tms->buffer_empty = 1;
// return 1;
@@ -916,7 +935,7 @@ static int parse_frame(tms5220_state *tms, int the_first_frame)
/* if the index is 0 or 15, we're done */
if (indx == 0 || indx == 15)
{
- if (DEBUG_5220) logerror(" (4-bit energy=%d frame)\n",tms->new_energy);
+ LOG((" (4-bit energy=%d frame)\n",tms->new_energy));
/* clear tms->fifo if stop frame encountered */
if (indx == 15)
@@ -953,7 +972,7 @@ static int parse_frame(tms5220_state *tms, int the_first_frame)
for (i = 0; i < 10; i++)
tms->new_k[i] = tms->old_k[i];
- if (DEBUG_5220) logerror(" (11-bit energy=%d pitch=%d rep=%d frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ LOG((" (11-bit energy=%d pitch=%d rep=%d frame)\n", tms->new_energy, tms->new_pitch, rep_flag));
goto done;
}
@@ -975,7 +994,7 @@ static int parse_frame(tms5220_state *tms, int the_first_frame)
else
tms->new_k[3] = k4table[extract_bits(tms, 4)];
- if (DEBUG_5220) logerror(" (29-bit energy=%d pitch=%d rep=%d 4K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ LOG((" (29-bit energy=%d pitch=%d rep=%d 4K frame)\n", tms->new_energy, tms->new_pitch, rep_flag));
goto done;
}
@@ -1001,16 +1020,13 @@ static int parse_frame(tms5220_state *tms, int the_first_frame)
tms->new_k[8] = k9table[extract_bits(tms, 3)];
tms->new_k[9] = k10table[extract_bits(tms, 3)];
- if (DEBUG_5220) logerror(" (50-bit energy=%d pitch=%d rep=%d 10K frame)\n", tms->new_energy, tms->new_pitch, rep_flag);
+ LOG((" (50-bit energy=%d pitch=%d rep=%d 10K frame)\n", tms->new_energy, tms->new_pitch, rep_flag));
done:
- if (DEBUG_5220)
- {
- if (tms->speak_external)
- logerror("Parsed a frame successfully in FIFO - %d bits remaining\n", bits);
- else
- logerror("Parsed a frame successfully in ROM\n");
- }
+ if (tms->speak_external)
+ LOG(("Parsed a frame successfully in FIFO - %d bits remaining\n", bits));
+ else
+ LOG(("Parsed a frame successfully in ROM\n"));
if (the_first_frame)
{
@@ -1027,7 +1043,7 @@ done:
ranout:
- if (DEBUG_5220) logerror("Ran out of bits on a parse!\n");
+ LOG(("Ran out of bits on a parse!\n"));
/* this is an error condition; mark the buffer empty and turn off speaking */
tms->buffer_empty = 1;
@@ -1059,7 +1075,7 @@ static void check_buffer_low(tms5220_state *tms)
set_interrupt_state(tms, 1);
tms->buffer_low = 1;
- if (DEBUG_5220) logerror("Buffer low set\n");
+ LOG(("Buffer low set\n"));
}
/* did we just become full? */
@@ -1067,7 +1083,7 @@ static void check_buffer_low(tms5220_state *tms)
{
tms->buffer_low = 0;
- if (DEBUG_5220) logerror("Buffer low cleared\n");
+ LOG(("Buffer low cleared\n"));
}
}
@@ -1106,6 +1122,10 @@ static DEVICE_START( tms5220 )
/* initialize a stream */
tms->stream = stream_create(device, 0, 1, device->clock / 80, tms, tms5220_update);
+ /* not during reset which is called frm within a write! */
+ tms->io_ready = 1;
+ tms->true_timing = 0;
+
register_for_save_states(tms);
}
@@ -1162,7 +1182,106 @@ static DEVICE_RESET( tms5220 )
tms->schedule_dummy_read = TRUE;
}
+/**********************************************************************************************
+ True timing
+
+***********************************************************************************************/
+
+TIMER_CALLBACK( io_ready_cb )
+{
+ tms5220_state *tms = (tms5220_state *) ptr;
+ if (param)
+ {
+ switch (tms->rs_ws)
+ {
+ case 0x02:
+ /* Write */
+ /* bring up to date first */
+ LOG(("Service write %02x\n", tms->write_latch));
+ stream_update(tms->stream);
+ tms5220_data_write(tms, tms->write_latch);
+ break;
+ case 0x01:
+ /* Read */
+ /* bring up to date first */
+ stream_update(tms->stream);
+ tms->read_latch = tms5220_status_read(tms);
+ break;
+ case 0x03:
+ /* High Impedance */
+ case 0x00:
+ /* illegal */
+ break;
+ }
+ }
+ tms->io_ready = param;
+}
+
+WRITE8_DEVICE_HANDLER( tms5220_rs_w )
+{
+ tms5220_state *tms = get_safe_token(device);
+ UINT8 new;
+
+ tms->true_timing = 1;
+ data &= 0x01;
+
+ new = (tms->rs_ws & 0x01) | (data<<1);
+ if (new != tms->rs_ws)
+ {
+ tms->rs_ws = new;
+ if (new == 0 || new ==3)
+ {
+ /* illegal */
+ return;
+ }
+ if (data)
+ {
+ /* low to high */
+ }
+ else
+ {
+ /* high to low - schedule ready cycle*/
+ LOG(("Schedule write ready\n"));
+ tms->io_ready = 1;
+ /* 100 nsec from data sheet */
+ timer_set(tms->device->machine, ATTOTIME_IN_NSEC(100), tms, 0, io_ready_cb);
+ /* 25 usec in datasheet, but zaccaria won't work */
+ timer_set(tms->device->machine, ATTOTIME_IN_USEC(100), tms, 1, io_ready_cb);
+ }
+ }
+}
+
+WRITE8_DEVICE_HANDLER( tms5220_ws_w )
+{
+ tms5220_state *tms = get_safe_token(device);
+ UINT8 new;
+
+ tms->true_timing = 1;
+ data &= 0x01;
+ new = (tms->rs_ws & 0x02) | (data<<0);
+ if (new != tms->rs_ws)
+ {
+ tms->rs_ws = new;
+ if (new == 0 || new ==3)
+ {
+ /* illegal */
+ if (new == 0) LOG(("tms5220_ws_w: illegal\n"));
+ return;
+ }
+ if (data)
+ {
+ /* low to high */
+ }
+ else
+ {
+ /* high to low - schedule ready cycle*/
+ tms->io_ready = 1;
+ timer_set(tms->device->machine, ATTOTIME_IN_NSEC(100), tms, 0, io_ready_cb);
+ timer_set(tms->device->machine, ATTOTIME_IN_USEC(25), tms, 1, io_ready_cb);
+ }
+ }
+}
/**********************************************************************************************
@@ -1173,9 +1292,20 @@ static DEVICE_RESET( tms5220 )
WRITE8_DEVICE_HANDLER( tms5220_data_w )
{
tms5220_state *tms = get_safe_token(device);
- /* bring up to date first */
- stream_update(tms->stream);
- tms5220_data_write(tms, data);
+
+ if (!tms->true_timing)
+ {
+ /* bring up to date first */
+ stream_update(tms->stream);
+ tms5220_data_write(tms, data);
+ }
+ else
+ {
+ /* actually in a write ? */
+ if (!(tms->rs_ws == 0x02))
+ LOG(("tms5220_data_w: data written outside ws, status: %02x!\n", tms->rs_ws));
+ tms->write_latch = data;
+ }
}
@@ -1189,9 +1319,21 @@ WRITE8_DEVICE_HANDLER( tms5220_data_w )
READ8_DEVICE_HANDLER( tms5220_status_r )
{
tms5220_state *tms = get_safe_token(device);
- /* bring up to date first */
- stream_update(tms->stream);
- return tms5220_status_read(tms);
+ if (!tms->true_timing)
+ {
+ /* bring up to date first */
+ stream_update(tms->stream);
+ return tms5220_status_read(tms);
+ }
+ else
+ {
+ /* actually in a read ? */
+ if (tms->rs_ws == 0x01)
+ return tms->read_latch;
+ else
+ LOG(("tms5220_status_r: data read outside rs!\n"));
+ return 0xff;
+ }
}
diff --git a/src/emu/sound/tms5220.h b/src/emu/sound/tms5220.h
index 429773881a0..d120e180b56 100644
--- a/src/emu/sound/tms5220.h
+++ b/src/emu/sound/tms5220.h
@@ -17,9 +17,18 @@ struct _tms5220_interface
void (*read_and_branch)(const device_config *device); /* speech ROM read and branch callback */
};
+/* Control lines - once written to will switch interface into
+ * "true" timing behaviour.
+ */
+
+WRITE8_DEVICE_HANDLER( tms5220_rs_w );
+WRITE8_DEVICE_HANDLER( tms5220_ws_w );
+
WRITE8_DEVICE_HANDLER( tms5220_data_w );
READ8_DEVICE_HANDLER( tms5220_status_r );
int tms5220_ready_r(const device_config *device);
+
+
double tms5220_time_to_ready(const device_config *device);
int tms5220_int_r(const device_config *device);