src/mess/machine/ti99/speech8.c
| r15500 | r15501 | |
| 22 | 22 | #define SPEECHSYN_TAG "speechsyn" |
| 23 | 23 | #define SPEECHROM_TAG "speechrom" |
| 24 | 24 | |
| 25 | #define REAL_TIMING 0 |
| 26 | |
| 27 | /* |
| 28 | For comments on real timing see ti99/spchsyn.c |
| 29 | */ |
| 25 | 30 | /****************************************************************************/ |
| 26 | 31 | |
| 27 | 32 | ti998_spsyn_device::ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| r15500 | r15501 | |
| 33 | 38 | /* |
| 34 | 39 | Memory read |
| 35 | 40 | */ |
| 41 | #if REAL_TIMING |
| 42 | // ====== This is the version with real timing ======= |
| 36 | 43 | READ8Z_MEMBER( ti998_spsyn_device::readz ) |
| 37 | 44 | { |
| 38 | 45 | if ((offset & m_select_mask)==m_select_value) |
| 39 | 46 | { |
| 47 | m_vsp->wsq_w(TRUE); |
| 48 | m_vsp->rsq_w(FALSE); |
| 49 | *value = m_vsp->read(offset) & 0xff; |
| 50 | if (VERBOSE>4) LOG("speech8: read value = %02x\n", *value); |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | /* |
| 55 | Memory write |
| 56 | */ |
| 57 | WRITE8_MEMBER( ti998_spsyn_device::write ) |
| 58 | { |
| 59 | if ((offset & m_select_mask)==(m_select_value | 0x0400)) |
| 60 | { |
| 61 | m_vsp->rsq_w(m_vsp, TRUE); |
| 62 | m_vsp->wsq_w(m_vsp, FALSE); |
| 63 | if (VERBOSE>4) LOG("speech8: write value = %02x\n", data); |
| 64 | m_vsp->write(offset, data); |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | #else |
| 69 | // ====== This is the version without real timing ======= |
| 70 | |
| 71 | READ8Z_MEMBER( ti998_spsyn_device::readz ) |
| 72 | { |
| 73 | if ((offset & m_select_mask)==m_select_value) |
| 74 | { |
| 40 | 75 | device_adjust_icount(machine().device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */ |
| 41 | | *value = tms5220_status_r(m_vsp, offset) & 0xff; |
| 76 | *value = m_vsp->read(space, offset, 0xff) & 0xff; |
| 77 | if (VERBOSE>4) LOG("speech8: read value = %02x\n", *value); |
| 42 | 78 | } |
| 43 | 79 | } |
| 44 | 80 | |
| r15500 | r15501 | |
| 55 | 91 | /* when there are 15 bytes in FIFO. It should be 16. Of course, if */ |
| 56 | 92 | /* it were the case, we would need to store the value on the bus, */ |
| 57 | 93 | /* which would be more complex. */ |
| 58 | | if (!tms5220_readyq_r(m_vsp)) |
| 94 | if (!m_vsp->readyq()) |
| 59 | 95 | { |
| 60 | | attotime time_to_ready = attotime::from_double(tms5220_time_to_ready(m_vsp)); |
| 96 | attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready()); |
| 61 | 97 | int cycles_to_ready = machine().device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready); |
| 62 | | if (VERBOSE>8) LOG("time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready); |
| 98 | if (VERBOSE>8) LOG("speech8: time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready); |
| 63 | 99 | |
| 64 | 100 | device_adjust_icount(machine().device("maincpu"),-cycles_to_ready); |
| 65 | 101 | machine().scheduler().timer_set(attotime::zero, FUNC_NULL); |
| 66 | 102 | } |
| 67 | | tms5220_data_w(m_vsp, offset, data); |
| 103 | if (VERBOSE>4) LOG("speech8: write value = %02x\n", data); |
| 104 | m_vsp->write(space, offset, data); |
| 68 | 105 | } |
| 69 | 106 | } |
| 107 | #endif |
| 70 | 108 | |
| 71 | 109 | /**************************************************************************** |
| 72 | 110 | Callbacks from TMS5220 |
| 73 | | |
| 74 | | TODO: Convert to methods as soon as TMS5220 has been converted |
| 75 | 111 | *****************************************************************************/ |
| 76 | 112 | /* |
| 77 | 113 | Read 'count' bits serially from speech ROM |
| 78 | 114 | */ |
| 79 | | static int ti998_spchroms_read(device_t *vspdev, int count) |
| 115 | READ8_MEMBER( ti998_spsyn_device::spchrom_read ) |
| 80 | 116 | { |
| 81 | | ti998_spsyn_device *adapter = static_cast<ti998_spsyn_device*>(vspdev->owner()); |
| 82 | | |
| 83 | 117 | int val; |
| 118 | int count = offset; |
| 84 | 119 | |
| 85 | | if (adapter->m_load_pointer) |
| 86 | | { /* first read after load address is ignored */ |
| 87 | | adapter->m_load_pointer = 0; |
| 120 | if (m_load_pointer != 0) |
| 121 | { // first read after load address is ignored |
| 122 | m_load_pointer = 0; |
| 88 | 123 | count--; |
| 89 | 124 | } |
| 90 | 125 | |
| 91 | | if (adapter->m_sprom_address < adapter->m_sprom_length) |
| 126 | if (m_sprom_address < m_sprom_length) |
| 92 | 127 | { |
| 93 | | if (count < adapter->m_rombits_count) |
| 128 | if (count < m_rombits_count) |
| 94 | 129 | { |
| 95 | | adapter->m_rombits_count -= count; |
| 96 | | val = (adapter->m_speechrom[adapter->m_sprom_address] >> adapter->m_rombits_count) & (0xFF >> (8 - count)); |
| 130 | m_rombits_count -= count; |
| 131 | val = (m_speechrom[m_sprom_address] >> m_rombits_count) & (0xFF >> (8 - count)); |
| 97 | 132 | } |
| 98 | 133 | else |
| 99 | 134 | { |
| 100 | | val = ((int)adapter->m_speechrom[adapter->m_sprom_address]) << 8; |
| 135 | val = ((int)m_speechrom[m_sprom_address]) << 8; |
| 101 | 136 | |
| 102 | | adapter->m_sprom_address = (adapter->m_sprom_address + 1) & TMS5220_ADDRESS_MASK; |
| 137 | m_sprom_address = (m_sprom_address + 1) & TMS5220_ADDRESS_MASK; |
| 103 | 138 | |
| 104 | | if (adapter->m_sprom_address < adapter->m_sprom_length) |
| 105 | | val |= adapter->m_speechrom[adapter->m_sprom_address]; |
| 139 | if (m_sprom_address < m_sprom_length) |
| 140 | val |= m_speechrom[m_sprom_address]; |
| 106 | 141 | |
| 107 | | adapter->m_rombits_count += 8 - count; |
| 142 | m_rombits_count += 8 - count; |
| 108 | 143 | |
| 109 | | val = (val >> adapter->m_rombits_count) & (0xFF >> (8 - count)); |
| 144 | val = (val >> m_rombits_count) & (0xFF >> (8 - count)); |
| 110 | 145 | } |
| 111 | 146 | } |
| 112 | 147 | else |
| r15500 | r15501 | |
| 118 | 153 | /* |
| 119 | 154 | Write an address nibble to speech ROM |
| 120 | 155 | */ |
| 121 | | static void ti998_spchroms_load_address(device_t *vspdev, int data) |
| 156 | WRITE8_MEMBER( ti998_spsyn_device::spchrom_load_address ) |
| 122 | 157 | { |
| 123 | | ti998_spsyn_device *adapter = static_cast<ti998_spsyn_device*>(vspdev->owner()); |
| 124 | | |
| 125 | 158 | // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. |
| 126 | 159 | // This code does not care about this. |
| 127 | | adapter->m_sprom_address = ((adapter->m_sprom_address & ~(0xf << adapter->m_load_pointer)) |
| 128 | | | (((unsigned long) (data & 0xf)) << adapter->m_load_pointer) ) & TMS5220_ADDRESS_MASK; |
| 129 | | adapter->m_load_pointer += 4; |
| 130 | | adapter->m_rombits_count = 8; |
| 160 | m_sprom_address = ((m_sprom_address & ~(0xf << m_load_pointer)) |
| 161 | | (((unsigned long) (data & 0xf)) << m_load_pointer) ) & TMS5220_ADDRESS_MASK; |
| 162 | m_load_pointer += 4; |
| 163 | m_rombits_count = 8; |
| 131 | 164 | } |
| 132 | 165 | |
| 133 | 166 | /* |
| 134 | 167 | Perform a read and branch command |
| 135 | 168 | */ |
| 136 | | static void ti998_spchroms_read_and_branch(device_t *vspdev) |
| 169 | WRITE8_MEMBER( ti998_spsyn_device::spchrom_read_and_branch ) |
| 137 | 170 | { |
| 138 | | ti998_spsyn_device *adapter = static_cast<ti998_spsyn_device*>(vspdev->owner()); |
| 139 | 171 | // tms5220 data sheet says that if more than one speech ROM (tms6100) is present, |
| 140 | 172 | // there is a bus contention. This code does not care about this. */ |
| 141 | | if (adapter->m_sprom_address < adapter->m_sprom_length-1) |
| 142 | | adapter->m_sprom_address = (adapter->m_sprom_address & 0x3c000UL) |
| 143 | | | (((((unsigned long) adapter->m_speechrom[adapter->m_sprom_address]) << 8) |
| 144 | | | adapter->m_speechrom[adapter->m_sprom_address+1]) & 0x3fffUL); |
| 145 | | else if (adapter->m_sprom_address == adapter->m_sprom_length-1) |
| 146 | | adapter->m_sprom_address = (adapter->m_sprom_address & 0x3c000UL) |
| 147 | | | ((((unsigned long) adapter->m_speechrom[adapter->m_sprom_address]) << 8) & 0x3fffUL); |
| 173 | if (m_sprom_address < m_sprom_length-1) |
| 174 | m_sprom_address = (m_sprom_address & 0x3c000UL) |
| 175 | | (((((unsigned long) m_speechrom[m_sprom_address]) << 8) |
| 176 | | m_speechrom[m_sprom_address+1]) & 0x3fffUL); |
| 177 | else if (m_sprom_address == m_sprom_length-1) |
| 178 | m_sprom_address = (m_sprom_address & 0x3c000UL) |
| 179 | | ((((unsigned long) m_speechrom[m_sprom_address]) << 8) & 0x3fffUL); |
| 148 | 180 | else |
| 149 | | adapter->m_sprom_address = (adapter->m_sprom_address & 0x3c000UL); |
| 181 | m_sprom_address = (m_sprom_address & 0x3c000UL); |
| 150 | 182 | |
| 151 | | adapter->m_rombits_count = 8; |
| 183 | m_rombits_count = 8; |
| 152 | 184 | } |
| 153 | 185 | |
| 154 | 186 | /*****************************************************************************/ |
| 155 | 187 | /* |
| 156 | 188 | Callback interface instance |
| 157 | 189 | */ |
| 158 | | static const tms5220_interface ti99_8_tms5200interface = |
| 190 | static const tms52xx_config ti99_8_tms5200interface = |
| 159 | 191 | { |
| 160 | 192 | DEVCB_NULL, // no IRQ callback |
| 161 | 193 | DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, speech8_ready), |
| 162 | | ti998_spchroms_read, // speech ROM read handler |
| 163 | | ti998_spchroms_load_address, // speech ROM load address handler |
| 164 | | ti998_spchroms_read_and_branch // speech ROM read and branch handler |
| 194 | |
| 195 | DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, spchrom_read), // speech ROM read handler |
| 196 | DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, spchrom_load_address), // speech ROM load address handler |
| 197 | DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, spchrom_read_and_branch) // speech ROM read and branch handler |
| 165 | 198 | }; |
| 166 | 199 | |
| 167 | 200 | /**************************************************************************/ |
| 168 | 201 | |
| 169 | 202 | WRITE_LINE_MEMBER( ti998_spsyn_device::speech8_ready ) |
| 170 | 203 | { |
| 171 | | // TODO: Fix polarity in TMS5220 |
| 204 | // The TMS5200 implementation uses TRUE/FALSE, not ASSERT/CLEAR semantics |
| 172 | 205 | m_ready((state==0)? ASSERT_LINE : CLEAR_LINE); |
| 206 | if (VERBOSE>5) LOG("spchsyn: READY = %d\n", (state==0)); |
| 207 | |
| 208 | #if REAL_TIMING |
| 209 | // Need to do that here (see explanations in spchsyn.c) |
| 210 | if (state==0) |
| 211 | { |
| 212 | m_vsp->rsq_w(TRUE); |
| 213 | m_vsp->wsq_w(TRUE); |
| 214 | } |
| 215 | #endif |
| 173 | 216 | } |
| 174 | 217 | |
| 175 | 218 | void ti998_spsyn_device::device_start() |
| 176 | 219 | { |
| 177 | 220 | const speech8_config *conf = reinterpret_cast<const speech8_config *>(static_config()); |
| 178 | 221 | m_ready.resolve(conf->ready, *this); |
| 179 | | m_vsp = subdevice(SPEECHSYN_TAG); |
| 222 | m_vsp = subdevice<tms5220n_device>(SPEECHSYN_TAG); |
| 180 | 223 | } |
| 181 | 224 | |
| 182 | 225 | void ti998_spsyn_device::device_reset() |
| r15500 | r15501 | |
| 195 | 238 | // Unlike the TI-99/4A, the 99/8 uses the TMS5220 |
| 196 | 239 | MACHINE_CONFIG_FRAGMENT( ti998_speech ) |
| 197 | 240 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 198 | | MCFG_SOUND_ADD(SPEECHSYN_TAG, TMS5220, 680000L) |
| 241 | MCFG_SOUND_ADD(SPEECHSYN_TAG, TMS5220N, 640000L) |
| 199 | 242 | MCFG_SOUND_CONFIG(ti99_8_tms5200interface) |
| 200 | 243 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) |
| 201 | 244 | MACHINE_CONFIG_END |
src/mess/machine/ti99/spchsyn.c
| r15500 | r15501 | |
| 80 | 80 | { |
| 81 | 81 | if ((offset & m_select_mask)==m_select_value) |
| 82 | 82 | { |
| 83 | | tms5220_wsq_w(m_vsp, TRUE); |
| 84 | | tms5220_rsq_w(m_vsp, FALSE); |
| 85 | | *value = tms5220_status_r(m_vsp, offset) & 0xff; |
| 83 | m_vsp->wsq_w(TRUE); |
| 84 | m_vsp->rsq_w(FALSE); |
| 85 | *value = m_vsp->read(offset) & 0xff; |
| 86 | 86 | if (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value); |
| 87 | 87 | } |
| 88 | 88 | } |
| r15500 | r15501 | |
| 94 | 94 | { |
| 95 | 95 | if ((offset & m_select_mask)==(m_select_value | 0x0400)) |
| 96 | 96 | { |
| 97 | | tms5220_rsq_w(m_vsp, TRUE); |
| 98 | | tms5220_wsq_w(m_vsp, FALSE); |
| 97 | m_vsp->rsq_w(m_vsp, TRUE); |
| 98 | m_vsp->wsq_w(m_vsp, FALSE); |
| 99 | 99 | if (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data); |
| 100 | | tms5220_data_w(m_vsp, offset, data); |
| 100 | m_vsp->write(offset, data); |
| 101 | 101 | } |
| 102 | 102 | } |
| 103 | 103 | |
| r15500 | r15501 | |
| 109 | 109 | if ((offset & m_select_mask)==m_select_value) |
| 110 | 110 | { |
| 111 | 111 | device_adjust_icount(machine().device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */ |
| 112 | | *value = tms5220_status_r(m_vsp, offset) & 0xff; |
| 112 | *value = m_vsp->read(space, offset, 0xff) & 0xff; |
| 113 | 113 | if (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value); |
| 114 | 114 | } |
| 115 | 115 | } |
| r15500 | r15501 | |
| 127 | 127 | /* when there are 15 bytes in FIFO. It should be 16. Of course, if */ |
| 128 | 128 | /* it were the case, we would need to store the value on the bus, */ |
| 129 | 129 | /* which would be more complex. */ |
| 130 | | if (!tms5220_readyq_r(m_vsp)) |
| 130 | if (!m_vsp->readyq()) |
| 131 | 131 | { |
| 132 | | attotime time_to_ready = attotime::from_double(tms5220_time_to_ready(m_vsp)); |
| 132 | attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready()); |
| 133 | 133 | int cycles_to_ready = machine().device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready); |
| 134 | | if (VERBOSE>8) LOG("time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready); |
| 134 | if (VERBOSE>8) LOG("spchsyn: time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready); |
| 135 | 135 | |
| 136 | 136 | device_adjust_icount(machine().device("maincpu"),-cycles_to_ready); |
| 137 | 137 | machine().scheduler().timer_set(attotime::zero, FUNC_NULL); |
| 138 | 138 | } |
| 139 | 139 | if (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data); |
| 140 | | tms5220_data_w(m_vsp, offset, data); |
| 140 | m_vsp->write(space, offset, data); |
| 141 | 141 | } |
| 142 | 142 | } |
| 143 | 143 | #endif |
| 144 | 144 | |
| 145 | 145 | /**************************************************************************** |
| 146 | 146 | Callbacks from TMS5220 |
| 147 | | |
| 148 | | TODO: Convert to methods as soon as TMS5220 has been converted |
| 149 | 147 | *****************************************************************************/ |
| 150 | 148 | /* |
| 151 | | Read 'count' bits serially from speech ROM |
| 149 | Read 'count' bits serially from speech ROM. The offset is used as the count. |
| 152 | 150 | */ |
| 153 | | static int ti99_spchroms_read(device_t *vspdev, int count) |
| 151 | READ8_MEMBER( ti_speech_synthesizer_device::spchrom_read ) |
| 154 | 152 | { |
| 155 | | ti_speech_synthesizer_device *adapter = static_cast<ti_speech_synthesizer_device*>(vspdev->owner()); |
| 156 | | |
| 157 | 153 | int val; |
| 154 | int count = offset; |
| 158 | 155 | |
| 159 | | if (adapter->m_load_pointer) |
| 160 | | { /* first read after load address is ignored */ |
| 161 | | adapter->m_load_pointer = 0; |
| 156 | if (m_load_pointer != 0) |
| 157 | { // first read after load address is ignored |
| 158 | m_load_pointer = 0; |
| 162 | 159 | count--; |
| 163 | 160 | } |
| 164 | 161 | |
| 165 | | if (adapter->m_sprom_address < adapter->m_sprom_length) |
| 162 | if (m_sprom_address < m_sprom_length) |
| 166 | 163 | { |
| 167 | | if (count < adapter->m_rombits_count) |
| 164 | if (count < m_rombits_count) |
| 168 | 165 | { |
| 169 | | adapter->m_rombits_count -= count; |
| 170 | | val = (adapter->m_speechrom[adapter->m_sprom_address] >> adapter->m_rombits_count) & (0xFF >> (8 - count)); |
| 166 | m_rombits_count -= count; |
| 167 | val = (m_speechrom[m_sprom_address] >> m_rombits_count) & (0xFF >> (8 - count)); |
| 171 | 168 | } |
| 172 | 169 | else |
| 173 | 170 | { |
| 174 | | val = ((int)adapter->m_speechrom[adapter->m_sprom_address]) << 8; |
| 171 | val = ((int)m_speechrom[m_sprom_address]) << 8; |
| 175 | 172 | |
| 176 | | adapter->m_sprom_address = (adapter->m_sprom_address + 1) & TMS5220_ADDRESS_MASK; |
| 173 | m_sprom_address = (m_sprom_address + 1) & TMS5220_ADDRESS_MASK; |
| 177 | 174 | |
| 178 | | if (adapter->m_sprom_address < adapter->m_sprom_length) |
| 179 | | val |= adapter->m_speechrom[adapter->m_sprom_address]; |
| 175 | if (m_sprom_address < m_sprom_length) |
| 176 | val |= m_speechrom[m_sprom_address]; |
| 180 | 177 | |
| 181 | | adapter->m_rombits_count += 8 - count; |
| 178 | m_rombits_count += 8 - count; |
| 182 | 179 | |
| 183 | | val = (val >> adapter->m_rombits_count) & (0xFF >> (8 - count)); |
| 180 | val = (val >> m_rombits_count) & (0xFF >> (8 - count)); |
| 184 | 181 | } |
| 185 | 182 | } |
| 186 | 183 | else |
| r15500 | r15501 | |
| 190 | 187 | } |
| 191 | 188 | |
| 192 | 189 | /* |
| 193 | | Write an address nibble to speech ROM |
| 190 | Write an address nibble to speech ROM. The address nibble is in the data, |
| 191 | the offset is ignored. |
| 194 | 192 | */ |
| 195 | | static void ti99_spchroms_load_address(device_t *vspdev, int data) |
| 193 | WRITE8_MEMBER( ti_speech_synthesizer_device::spchrom_load_address ) |
| 196 | 194 | { |
| 197 | | ti_speech_synthesizer_device *adapter = static_cast<ti_speech_synthesizer_device*>(vspdev->owner()); |
| 198 | | |
| 199 | 195 | // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. |
| 200 | 196 | // This code does not care about this. |
| 201 | | adapter->m_sprom_address = ((adapter->m_sprom_address & ~(0xf << adapter->m_load_pointer)) |
| 202 | | | (((unsigned long) (data & 0xf)) << adapter->m_load_pointer) ) & TMS5220_ADDRESS_MASK; |
| 203 | | adapter->m_load_pointer += 4; |
| 204 | | adapter->m_rombits_count = 8; |
| 197 | m_sprom_address = ((m_sprom_address & ~(0xf << m_load_pointer)) |
| 198 | | (((unsigned long) (data & 0xf)) << m_load_pointer) ) & TMS5220_ADDRESS_MASK; |
| 199 | m_load_pointer += 4; |
| 200 | m_rombits_count = 8; |
| 205 | 201 | } |
| 206 | 202 | |
| 207 | 203 | /* |
| 208 | | Perform a read and branch command |
| 204 | Perform a read and branch command. We do not use the offset or data parameter. |
| 209 | 205 | */ |
| 210 | | static void ti99_spchroms_read_and_branch(device_t *vspdev) |
| 206 | WRITE8_MEMBER( ti_speech_synthesizer_device::spchrom_read_and_branch ) |
| 211 | 207 | { |
| 212 | | ti_speech_synthesizer_device *adapter = static_cast<ti_speech_synthesizer_device*>(vspdev->owner()); |
| 213 | 208 | // tms5220 data sheet says that if more than one speech ROM (tms6100) is present, |
| 214 | 209 | // there is a bus contention. This code does not care about this. */ |
| 215 | | if (adapter->m_sprom_address < adapter->m_sprom_length-1) |
| 216 | | adapter->m_sprom_address = (adapter->m_sprom_address & 0x3c000UL) |
| 217 | | | (((((unsigned long) adapter->m_speechrom[adapter->m_sprom_address]) << 8) |
| 218 | | | adapter->m_speechrom[adapter->m_sprom_address+1]) & 0x3fffUL); |
| 219 | | else if (adapter->m_sprom_address == adapter->m_sprom_length-1) |
| 220 | | adapter->m_sprom_address = (adapter->m_sprom_address & 0x3c000UL) |
| 221 | | | ((((unsigned long) adapter->m_speechrom[adapter->m_sprom_address]) << 8) & 0x3fffUL); |
| 210 | if (m_sprom_address < m_sprom_length-1) |
| 211 | m_sprom_address = (m_sprom_address & 0x3c000UL) |
| 212 | | (((((unsigned long) m_speechrom[m_sprom_address]) << 8) |
| 213 | | m_speechrom[m_sprom_address+1]) & 0x3fffUL); |
| 214 | else if (m_sprom_address == m_sprom_length-1) |
| 215 | m_sprom_address = (m_sprom_address & 0x3c000UL) |
| 216 | | ((((unsigned long) m_speechrom[m_sprom_address]) << 8) & 0x3fffUL); |
| 222 | 217 | else |
| 223 | | adapter->m_sprom_address = (adapter->m_sprom_address & 0x3c000UL); |
| 218 | m_sprom_address = (m_sprom_address & 0x3c000UL); |
| 224 | 219 | |
| 225 | | adapter->m_rombits_count = 8; |
| 220 | m_rombits_count = 8; |
| 226 | 221 | } |
| 227 | 222 | |
| 228 | 223 | /****************************************************************************/ |
| r15500 | r15501 | |
| 230 | 225 | /* |
| 231 | 226 | Callback interface instance |
| 232 | 227 | */ |
| 233 | | static const tms5220_interface ti99_4x_tms5200interface = |
| 228 | static const tms52xx_config ti99_4x_tms5200interface = |
| 234 | 229 | { |
| 235 | 230 | DEVCB_NULL, // no IRQ callback |
| 236 | 231 | DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, speech_ready), |
| 237 | | ti99_spchroms_read, // speech ROM read handler |
| 238 | | ti99_spchroms_load_address, // speech ROM load address handler |
| 239 | | ti99_spchroms_read_and_branch // speech ROM read and branch handler |
| 232 | |
| 233 | DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, spchrom_read), // speech ROM read handler |
| 234 | DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, spchrom_load_address), // speech ROM load address handler |
| 235 | DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, spchrom_read_and_branch) // speech ROM read and branch handler |
| 240 | 236 | }; |
| 241 | 237 | |
| 242 | 238 | /****************************************************************************/ |
| r15500 | r15501 | |
| 253 | 249 | // Need to do that here (see explanations above) |
| 254 | 250 | if (state==0) |
| 255 | 251 | { |
| 256 | | tms5220_rsq_w(m_vsp, TRUE); |
| 257 | | tms5220_wsq_w(m_vsp, TRUE); |
| 252 | m_vsp->rsq_w(TRUE); |
| 253 | m_vsp->wsq_w(TRUE); |
| 258 | 254 | } |
| 259 | 255 | #endif |
| 260 | 256 | } |
| r15500 | r15501 | |
| 265 | 261 | |
| 266 | 262 | void ti_speech_synthesizer_device::device_config_complete() |
| 267 | 263 | { |
| 268 | | m_vsp = subdevice("speechsyn"); |
| 264 | m_vsp = subdevice<tmc0285n_device>("speechsyn"); |
| 269 | 265 | } |
| 270 | 266 | |
| 271 | 267 | void ti_speech_synthesizer_device::device_reset() |
| r15500 | r15501 | |
| 290 | 286 | |
| 291 | 287 | MACHINE_CONFIG_FRAGMENT( ti99_speech ) |
| 292 | 288 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 293 | | MCFG_SOUND_ADD("speechsyn", TMC0285, 640000L) |
| 289 | MCFG_SOUND_ADD("speechsyn", TMC0285N, 640000L) |
| 294 | 290 | MCFG_SOUND_CONFIG(ti99_4x_tms5200interface) |
| 295 | 291 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) |
| 296 | 292 | MACHINE_CONFIG_END |