1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
// license:LGPL-2.1+
// copyright-holders:Michael Zapf
/****************************************************************************
TI-99 Speech synthesizer adapter device
This adapter card made the sidecar Speech Synthesizer unit available to
systems without a TI-99/4A console, like the SGCPU and the Geneve. The
board must be removed from the sidecar unit and plugged on this simple
adapter board, which is then put in a slot of the Peripheral Expansion Box.
+-------+
+-----|-------|---+
| Speech syn |
| board |
| _________ |
+-----+++++++++---+
+----------------------------+|||||||+------------+
| ------- |
| Adapter board |
| |
(((o LED PEB slot connector |
+--------------|||||||||||||||||||||||||----------+
|||||||||||||||||||||||||
Technical detail:
The SBE signal (Speech Block Enable), which is generated in the TI console,
is not forwarded to the PEB. One of the tasks of this board is thus to
decode the mapped addresses once more and to activate the synthesizer
accordingly.
A second issue for Geneve users is that the address extension bits (AMA,
AMB, AMC) need to be decoded as well to avoid the synthesizer interfering
with other memory access. This can be activated in the configuration. The
default is on.
Michael Zapf
March 2025
*****************************************************************************/
#include "emu.h"
#include "speechadapter.h"
#include "speaker.h"
#include "bus/ti99/sidecar/speechsyn.h"
#define LOG_WARN (1U << 1) // Warnings
#define LOG_CONFIG (1U << 2)
#define LOG_MEM (1U << 3)
#define LOG_ADDR (1U << 4)
#define LOG_READY (1U << 5)
#define VERBOSE (LOG_CONFIG | LOG_WARN)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(TI99_SPEECHADAPTER, bus::ti99::peb::ti_speechsyn_adapter_device, "ti99_speechconn", "TI-99 Speech synthesizer adapter card")
namespace bus::ti99::peb {
#define PORT "conn"
/****************************************************************************/
ti_speechsyn_adapter_device::ti_speechsyn_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, TI99_SPEECHADAPTER, tag, owner, clock),
device_ti99_peribox_card_interface(mconfig, *this),
m_port(*this, PORT),
m_dec_high(false)
{
}
void ti_speechsyn_adapter_device::readz(offs_t offset, uint8_t *value)
{
if (m_port != nullptr)
{
LOGMASKED(LOG_MEM, "read %06x\n", offset);
m_port->readz(offset, value);
}
}
void ti_speechsyn_adapter_device::write(offs_t offset, uint8_t data)
{
if (m_port != nullptr)
{
LOGMASKED(LOG_MEM, "write %06x\n", offset);
m_port->write(offset, data);
}
}
void ti_speechsyn_adapter_device::setaddress_dbin(offs_t offset, int state)
{
// Valid access = not(DBIN and A5)
bool reading = (state==ASSERT_LINE);
// An access is valid when reading from 9000 and writing to 9400.
bool valid = (((offset & 0x0400)==0) == reading);
bool sbe = false;
// Recreate the SBE signal that is only available at the I/O port of the console
if (m_dec_high)
// We need to decode the AMA/AMB/AMC address extension lines
sbe = ((offset & 0x7f801)==0x79000) && valid;
else
// No need to decode the extension lines
sbe = ((offset & 0x0f801)==0x09000) && valid;
if (sbe) LOGMASKED(LOG_ADDR, "set address = %04x, dbin = %d\n", offset, state);
if (m_port != nullptr)
{
m_port->sbe(sbe);
m_port->setaddress_dbin(offset, state);
}
}
void ti_speechsyn_adapter_device::ready(int state)
{
LOGMASKED(LOG_READY, "Incoming READY=%d from synthesizer %d\n", state);
m_slot->set_ready(state);
}
void ti_speechsyn_adapter_device::device_start()
{
}
void ti_speechsyn_adapter_device::device_reset()
{
m_dec_high = (ioport("AMADECODE")->read()!=0);
LOGMASKED(LOG_CONFIG, "Speech adapter%s decoding the AMA/B/C lines.\n", m_dec_high? "" : " not");
}
void ti_speechsyn_adapter_options(device_slot_interface &device)
{
device.option_add("speechsyn", TI99_SPEECHSYN);
}
void ti_speechsyn_adapter_device::device_add_mconfig(machine_config& config)
{
TI99_IOPORT(config, m_port, 0, ti_speechsyn_adapter_options, "speechsyn");
m_port->ready_cb().set(FUNC(ti_speechsyn_adapter_device::ready));
}
INPUT_PORTS_START( ti99_speechadapter )
PORT_START( "AMADECODE" )
PORT_CONFNAME( 0x01, 0x01, "Decode AMA/AMB/AMC lines" )
PORT_CONFSETTING( 0x00, DEF_STR( Off ))
PORT_CONFSETTING( 0x01, DEF_STR( On ))
INPUT_PORTS_END
ioport_constructor ti_speechsyn_adapter_device::device_input_ports() const
{
return INPUT_PORTS_NAME(ti99_speechadapter);
}
} // end namespace bus::ti99::peb
|