trunk/src/mess/drivers/besta.c
| r0 | r21506 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | Besta-88 and Besta-90 engineering workstations. |
| 4 | |
| 5 | Derived (OEMd?) from Force Computers' SYS68K series. |
| 6 | |
| 7 | ****************************************************************************/ |
| 8 | |
| 9 | #include "emu.h" |
| 10 | #include "cpu/m68000/m68000.h" |
| 11 | #include "machine/terminal.h" |
| 12 | #if 0 |
| 13 | #include "machine/68561mpcc.h" |
| 14 | #endif |
| 15 | |
| 16 | #define VERBOSE_DBG 1 /* general debug messages */ |
| 17 | |
| 18 | #define DBG_LOG(N,M,A) \ |
| 19 | do { \ |
| 20 | if(VERBOSE_DBG>=N) \ |
| 21 | { \ |
| 22 | if( M ) \ |
| 23 | logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \ |
| 24 | logerror A; \ |
| 25 | } \ |
| 26 | } while (0) |
| 27 | |
| 28 | class besta_state : public driver_device |
| 29 | { |
| 30 | public: |
| 31 | besta_state(const machine_config &mconfig, device_type type, const char *tag) |
| 32 | : driver_device(mconfig, type, tag) |
| 33 | , m_maincpu(*this, "maincpu") |
| 34 | , m_terminal(*this, TERMINAL_TAG) |
| 35 | , m_p_ram(*this, "p_ram") |
| 36 | { |
| 37 | } |
| 38 | |
| 39 | DECLARE_READ8_MEMBER( mpcc_reg_r ); |
| 40 | DECLARE_WRITE8_MEMBER( mpcc_reg_w ); |
| 41 | DECLARE_WRITE8_MEMBER( kbd_put ); |
| 42 | UINT8 m_term_data; |
| 43 | UINT8 m_mpcc_regs[32]; |
| 44 | |
| 45 | required_device<cpu_device> m_maincpu; |
| 46 | virtual void machine_reset(); |
| 47 | |
| 48 | required_device<generic_terminal_device> m_terminal; |
| 49 | required_shared_ptr<UINT32> m_p_ram; |
| 50 | }; |
| 51 | |
| 52 | #if 1 |
| 53 | READ8_MEMBER( besta_state::mpcc_reg_r ) |
| 54 | { |
| 55 | running_machine &machine = space.machine(); |
| 56 | UINT8 ret; |
| 57 | |
| 58 | if (!(offset == 0 && !m_mpcc_regs[0])) { |
| 59 | DBG_LOG(1,"mpcc_reg_r",("(%d) = %02X at %s\n", offset, |
| 60 | (offset > 31 ? -1 : m_mpcc_regs[offset]), machine.describe_context())); |
| 61 | } |
| 62 | |
| 63 | switch (offset) { |
| 64 | case 0: /* r_stat aka ... */ |
| 65 | return (m_term_data) ? 0x80 : 0; |
| 66 | case 2: /* r_data aka ... */ |
| 67 | ret = m_term_data; |
| 68 | m_term_data = 0; |
| 69 | return ret; |
| 70 | default: |
| 71 | return m_mpcc_regs[offset]; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | WRITE8_MEMBER( besta_state::mpcc_reg_w ) |
| 76 | { |
| 77 | running_machine &machine = space.machine(); |
| 78 | device_t *devconf = space.machine().device(TERMINAL_TAG); |
| 79 | |
| 80 | DBG_LOG(1,"mpcc_reg_w",("(%d) <- %02X at %s\n", offset, data, machine.describe_context())); |
| 81 | |
| 82 | switch (offset) { |
| 83 | case 2: |
| 84 | m_term_data = data; |
| 85 | case 10: |
| 86 | dynamic_cast<generic_terminal_device *>(devconf)->write(*devconf->machine().memory().first_space(), 0, data); |
| 87 | default: |
| 88 | m_mpcc_regs[offset] = data; break; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | WRITE8_MEMBER( besta_state::kbd_put ) |
| 93 | { |
| 94 | mpcc_reg_w(space, (offs_t)2, data, mem_mask); |
| 95 | } |
| 96 | #endif |
| 97 | |
| 98 | static ADDRESS_MAP_START(besta_mem, AS_PROGRAM, 32, besta_state) |
| 99 | AM_RANGE(0x00000000, 0x001fffff) AM_RAM AM_SHARE("p_ram") // local bus DRAM, 4MB |
| 100 | // AM_RANGE(0x08010000, 0x08011fff) AM_RAM // unknown -- accessed by cp31dssp |
| 101 | AM_RANGE(0xff000000, 0xff00ffff) AM_ROM AM_REGION("user1",0) // actual mapping is up to 0xff03ffff |
| 102 | AM_RANGE(0xff040000, 0xff07ffff) AM_RAM // onboard SRAM |
| 103 | // 68561 MPCC (console) |
| 104 | // AM_RANGE(0xff800000, 0xff80001f) AM_DEVREADWRITE8("mpcc", mpcc68561_t, reg_r, reg_w, 0xffffffff) |
| 105 | AM_RANGE(0xff800000, 0xff80001f) AM_READWRITE8(mpcc_reg_r, mpcc_reg_w, 0xffffffff) |
| 106 | // AM_RANGE(0xff800200, 0xff800xxx) // 68230 PIT2 |
| 107 | // AM_RANGE(0xff800400, 0xff800xxx) // ??? -- shows up in cp31dssp log |
| 108 | // AM_RANGE(0xff800800, 0xff800xxx) // BIM |
| 109 | // AM_RANGE(0xff800a00, 0xff800xxx) // 62421 RTC |
| 110 | // AM_RANGE(0xff800c00, 0xff800xxx) // 68230 PIT |
| 111 | ADDRESS_MAP_END |
| 112 | |
| 113 | /* Input ports */ |
| 114 | static INPUT_PORTS_START( besta ) |
| 115 | INPUT_PORTS_END |
| 116 | |
| 117 | |
| 118 | void besta_state::machine_reset() |
| 119 | { |
| 120 | UINT8* user1 = memregion("user1")->base(); |
| 121 | |
| 122 | memcpy((UINT8*)m_p_ram.target(),user1,0x10000); // not really what happens but... |
| 123 | memset(m_mpcc_regs, sizeof(m_mpcc_regs), 0); // should initialize to defined values |
| 124 | m_mpcc_regs[8] = 0x80; // always ready to transmit |
| 125 | |
| 126 | machine().device("maincpu")->reset(); |
| 127 | } |
| 128 | |
| 129 | static GENERIC_TERMINAL_INTERFACE( terminal_intf ) |
| 130 | { |
| 131 | DEVCB_DRIVER_MEMBER(besta_state, kbd_put) |
| 132 | }; |
| 133 | |
| 134 | |
| 135 | /* CP31 processor board */ |
| 136 | static MACHINE_CONFIG_START( besta, besta_state ) |
| 137 | /* basic machine hardware */ |
| 138 | MCFG_CPU_ADD("maincpu", M68030, 2*16670000) |
| 139 | MCFG_CPU_PROGRAM_MAP(besta_mem) |
| 140 | |
| 141 | #if 0 |
| 142 | MCFG_MPCC68561_ADD("mpcc", XTAL_25MHz, line_cb_t()); // confirm internal oscillator frequency |
| 143 | #endif |
| 144 | MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, terminal_intf) |
| 145 | MACHINE_CONFIG_END |
| 146 | |
| 147 | /* ROM definition */ |
| 148 | |
| 149 | ROM_START( besta88 ) |
| 150 | ROM_REGION32_BE( 0x10000, "user1", ROMREGION_ERASEFF ) |
| 151 | |
| 152 | ROM_SYSTEM_BIOS(0, "cp31dbg", "CP31 Debug") |
| 153 | ROMX_LOAD( "cp31dbgboot.27c512", 0x0000, 0x10000, CRC(9bf057de) SHA1(b13cb16042e4c6ca63ae26058a78259c0849d0b6), ROM_BIOS(1)) |
| 154 | ROM_SYSTEM_BIOS(1, "cp31dssp", "CP31 DSSP") |
| 155 | ROMX_LOAD( "cp31dsspboot.27c512", 0x0000, 0x10000, CRC(607a0a55) SHA1(c257a88672ab39d2f3fad681d22e062182b0236d), ROM_BIOS(2)) |
| 156 | ROM_SYSTEM_BIOS(2, "cp31os9", "CP31 OS9") |
| 157 | ROMX_LOAD( "cp31os9.27c512", 0x0000, 0x10000, CRC(607a0a55) SHA1(c257a88672ab39d2f3fad681d22e062182b0236d), ROM_BIOS(3)) |
| 158 | ROM_END |
| 159 | |
| 160 | /* Driver */ |
| 161 | |
| 162 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
| 163 | COMP( 1988, besta88, 0, 0, besta, besta, driver_device, 0, "Sapsan", "Besta-88", GAME_NOT_WORKING | GAME_NO_SOUND) |
trunk/src/mess/machine/68561mpcc.c
| r0 | r21506 | |
| 1 | /********************************************************************* |
| 2 | |
| 3 | 68561mpcc.c |
| 4 | |
| 5 | Rockwell 68561 MPCC (Multi Protocol Communications Controller) |
| 6 | |
| 7 | skeleton driver, just enough for besta.c console to work |
| 8 | |
| 9 | *********************************************************************/ |
| 10 | |
| 11 | |
| 12 | #include "emu.h" |
| 13 | #include "68561mpcc.h" |
| 14 | |
| 15 | const device_type MPCC68561 = &device_creator<mpcc68561_t>; |
| 16 | |
| 17 | |
| 18 | /*************************************************************************** |
| 19 | PARAMETERS |
| 20 | ***************************************************************************/ |
| 21 | |
| 22 | #define LOG_MPCC (1) |
| 23 | |
| 24 | #if 0 // future |
| 25 | |
| 26 | /*************************************************************************** |
| 27 | IMPLEMENTATION |
| 28 | ***************************************************************************/ |
| 29 | |
| 30 | mpcc68561_t::mpcc68561_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, MPCC68561, "Rockwell 68561 MPCC", tag, owner, clock) |
| 31 | { |
| 32 | } |
| 33 | |
| 34 | void mpcc68561_t::set_intrq_cb(line_cb_t cb) |
| 35 | { |
| 36 | intrq_cb = cb; |
| 37 | } |
| 38 | |
| 39 | /*------------------------------------------------- |
| 40 | mpcc_updateirqs |
| 41 | -------------------------------------------------*/ |
| 42 | |
| 43 | void mpcc68561_t::updateirqs() |
| 44 | { |
| 45 | int irqstat; |
| 46 | |
| 47 | irqstat = 0; |
| 48 | if (MasterIRQEnable) |
| 49 | { |
| 50 | if ((channel[0].txIRQEnable) && (channel[0].txIRQPending)) |
| 51 | { |
| 52 | IRQType = IRQ_B_TX; |
| 53 | irqstat = 1; |
| 54 | } |
| 55 | else if ((channel[1].txIRQEnable) && (channel[1].txIRQPending)) |
| 56 | { |
| 57 | IRQType = IRQ_A_TX; |
| 58 | irqstat = 1; |
| 59 | } |
| 60 | else if ((channel[0].extIRQEnable) && (channel[0].extIRQPending)) |
| 61 | { |
| 62 | IRQType = IRQ_B_EXT; |
| 63 | irqstat = 1; |
| 64 | } |
| 65 | else if ((channel[1].extIRQEnable) && (channel[1].extIRQPending)) |
| 66 | { |
| 67 | IRQType = IRQ_A_EXT; |
| 68 | irqstat = 1; |
| 69 | } |
| 70 | } |
| 71 | else |
| 72 | { |
| 73 | IRQType = IRQ_NONE; |
| 74 | } |
| 75 | |
| 76 | // printf("mpcc: irqstat %d, last %d\n", irqstat, lastIRQStat); |
| 77 | // printf("ch0: en %d pd %d ch1: en %d pd %d\n", channel[0].txIRQEnable, channel[0].txIRQPending, channel[1].txIRQEnable, channel[1].txIRQPending); |
| 78 | |
| 79 | // don't spam the driver with unnecessary transitions |
| 80 | if (irqstat != lastIRQStat) |
| 81 | { |
| 82 | lastIRQStat = irqstat; |
| 83 | |
| 84 | // tell the driver the new IRQ line status if possible |
| 85 | #if LOG_MPCC |
| 86 | printf("mpcc68561 IRQ status => %d\n", irqstat); |
| 87 | #endif |
| 88 | if(!intrq_cb.isnull()) |
| 89 | intrq_cb(irqstat); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | /*------------------------------------------------- |
| 94 | mpcc_initchannel |
| 95 | -------------------------------------------------*/ |
| 96 | void mpcc68561_t::initchannel(int ch) |
| 97 | { |
| 98 | channel[ch].syncHunt = 1; |
| 99 | } |
| 100 | |
| 101 | /*------------------------------------------------- |
| 102 | mpcc_resetchannel |
| 103 | -------------------------------------------------*/ |
| 104 | void mpcc68561_t::resetchannel(int ch) |
| 105 | { |
| 106 | emu_timer *timersave = channel[ch].baudtimer; |
| 107 | |
| 108 | memset(&channel[ch], 0, sizeof(Chan)); |
| 109 | |
| 110 | channel[ch].txUnderrun = 1; |
| 111 | channel[ch].baudtimer = timersave; |
| 112 | |
| 113 | channel[ch].baudtimer->adjust(attotime::never, ch); |
| 114 | } |
| 115 | |
| 116 | /*------------------------------------------------- |
| 117 | mpcc68561_baud_expire - baud rate timer expiry |
| 118 | -------------------------------------------------*/ |
| 119 | |
| 120 | void mpcc68561_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 121 | { |
| 122 | Chan *pChan = &channel[id]; |
| 123 | int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; |
| 124 | int rate; |
| 125 | |
| 126 | if (brconst) |
| 127 | { |
| 128 | rate = clock() / brconst; |
| 129 | } |
| 130 | else |
| 131 | { |
| 132 | rate = 0; |
| 133 | } |
| 134 | |
| 135 | // is baud counter IRQ enabled on this channel? |
| 136 | // always flag pending in case it's enabled after this |
| 137 | pChan->baudIRQPending = 1; |
| 138 | if (pChan->baudIRQEnable) |
| 139 | { |
| 140 | if (pChan->extIRQEnable) |
| 141 | { |
| 142 | pChan->extIRQPending = 1; |
| 143 | pChan->baudIRQPending = 0; |
| 144 | updateirqs(); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | // reset timer according to current register values |
| 149 | if (rate) |
| 150 | { |
| 151 | timer.adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); |
| 152 | } |
| 153 | else |
| 154 | { |
| 155 | timer.adjust(attotime::never, 0, attotime::never); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | /*------------------------------------------------- |
| 160 | DEVICE_START( mpcc68561 ) |
| 161 | -------------------------------------------------*/ |
| 162 | |
| 163 | void mpcc68561_t::device_start() |
| 164 | { |
| 165 | memset(channel, 0, sizeof(channel)); |
| 166 | |
| 167 | mode = 0; |
| 168 | reg = 0; |
| 169 | status = 0; |
| 170 | IRQV = 0; |
| 171 | MasterIRQEnable = 0; |
| 172 | lastIRQStat = 0; |
| 173 | IRQType = IRQ_NONE; |
| 174 | |
| 175 | channel[0].baudtimer = timer_alloc(0); |
| 176 | } |
| 177 | |
| 178 | |
| 179 | /*------------------------------------------------- |
| 180 | DEVICE_RESET( mpcc68561 ) |
| 181 | -------------------------------------------------*/ |
| 182 | void mpcc68561_t::device_reset() |
| 183 | { |
| 184 | IRQType = IRQ_NONE; |
| 185 | MasterIRQEnable = 0; |
| 186 | IRQV = 0; |
| 187 | |
| 188 | initchannel(0); |
| 189 | resetchannel(0); |
| 190 | } |
| 191 | |
| 192 | /*------------------------------------------------- |
| 193 | mpcc_set_status |
| 194 | -------------------------------------------------*/ |
| 195 | |
| 196 | void mpcc68561_t::set_status(int _status) |
| 197 | { |
| 198 | status = _status; |
| 199 | } |
| 200 | |
| 201 | /*------------------------------------------------- |
| 202 | mpcc_acknowledge |
| 203 | -------------------------------------------------*/ |
| 204 | |
| 205 | void mpcc68561_t::acknowledge() |
| 206 | { |
| 207 | if(!intrq_cb.isnull()) |
| 208 | intrq_cb(0); |
| 209 | } |
| 210 | |
| 211 | /*------------------------------------------------- |
| 212 | mpcc_getreg |
| 213 | -------------------------------------------------*/ |
| 214 | |
| 215 | UINT8 mpcc68561_t::getreg() |
| 216 | { |
| 217 | /* Not yet implemented */ |
| 218 | #if LOG_MPCC |
| 219 | printf("mpcc: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]); |
| 220 | #endif |
| 221 | |
| 222 | if (reg == 0) |
| 223 | { |
| 224 | UINT8 rv = 0; |
| 225 | |
| 226 | Chan *ourCh = &channel[0]; |
| 227 | |
| 228 | rv |= (ourCh->txUnderrun) ? 0x40 : 0; |
| 229 | rv |= (ourCh->syncHunt) ? 0x10 : 0; |
| 230 | rv |= channel[0].reg_val[0] & 0x05; // pick up TXBE and RXBF bits |
| 231 | |
| 232 | return rv; |
| 233 | } |
| 234 | else if (reg == 10) |
| 235 | { |
| 236 | return 0; |
| 237 | } |
| 238 | return channel[0].reg_val[reg]; |
| 239 | } |
| 240 | |
| 241 | /*------------------------------------------------- |
| 242 | mpcc_putreg |
| 243 | -------------------------------------------------*/ |
| 244 | |
| 245 | void mpcc68561_t::putreg(int ch, UINT8 data) |
| 246 | { |
| 247 | Chan *pChan = &channel[ch]; |
| 248 | |
| 249 | channel[ch].reg_val[reg] = data; |
| 250 | #if LOG_MPCC |
| 251 | printf("mpcc: port %c reg %d write 0x%02x\n", 'A'+ch, reg, data); |
| 252 | #endif |
| 253 | |
| 254 | switch (reg) |
| 255 | { |
| 256 | case 0: // command register |
| 257 | switch ((data >> 3) & 7) |
| 258 | { |
| 259 | case 1: // select high registers (handled elsewhere) |
| 260 | break; |
| 261 | |
| 262 | case 2: // reset external and status IRQs |
| 263 | pChan->syncHunt = 0; |
| 264 | break; |
| 265 | |
| 266 | case 5: // ack Tx IRQ |
| 267 | pChan->txIRQPending = 0; |
| 268 | updateirqs(); |
| 269 | break; |
| 270 | |
| 271 | case 0: // nothing |
| 272 | case 3: // send SDLC abort |
| 273 | case 4: // enable IRQ on next Rx byte |
| 274 | case 6: // reset errors |
| 275 | case 7: // reset highest IUS |
| 276 | // we don't handle these yet |
| 277 | break; |
| 278 | |
| 279 | } |
| 280 | break; |
| 281 | |
| 282 | case 1: // Tx/Rx IRQ and data transfer mode defintion |
| 283 | pChan->extIRQEnable = (data & 1); |
| 284 | pChan->txIRQEnable = (data & 2) ? 1 : 0; |
| 285 | pChan->rxIRQEnable = (data >> 3) & 3; |
| 286 | updateirqs(); |
| 287 | break; |
| 288 | |
| 289 | case 2: // IRQ vector |
| 290 | IRQV = data; |
| 291 | break; |
| 292 | |
| 293 | case 3: // Rx parameters and controls |
| 294 | pChan->rxEnable = (data & 1); |
| 295 | pChan->syncHunt = (data & 0x10) ? 1 : 0; |
| 296 | break; |
| 297 | |
| 298 | case 5: // Tx parameters and controls |
| 299 | // printf("ch %d TxEnable = %d [%02x]\n", ch, data & 8, data); |
| 300 | pChan->txEnable = data & 8; |
| 301 | |
| 302 | if (pChan->txEnable) |
| 303 | { |
| 304 | pChan->reg_val[0] |= 0x04; // Tx empty |
| 305 | } |
| 306 | break; |
| 307 | |
| 308 | case 4: // Tx/Rx misc parameters and modes |
| 309 | case 6: // sync chars/SDLC address field |
| 310 | case 7: // sync char/SDLC flag |
| 311 | break; |
| 312 | |
| 313 | case 9: // master IRQ control |
| 314 | MasterIRQEnable = (data & 8) ? 1 : 0; |
| 315 | updateirqs(); |
| 316 | |
| 317 | // channel reset command |
| 318 | switch ((data>>6) & 3) |
| 319 | { |
| 320 | case 0: // do nothing |
| 321 | break; |
| 322 | |
| 323 | case 1: // reset channel B |
| 324 | resetchannel(0); |
| 325 | break; |
| 326 | |
| 327 | case 3: // force h/w reset (entire chip) |
| 328 | IRQType = IRQ_NONE; |
| 329 | MasterIRQEnable = 0; |
| 330 | IRQV = 0; |
| 331 | |
| 332 | initchannel(0); |
| 333 | resetchannel(0); |
| 334 | |
| 335 | // make sure we stop yanking the IRQ line if we were |
| 336 | updateirqs(); |
| 337 | break; |
| 338 | |
| 339 | } |
| 340 | break; |
| 341 | |
| 342 | case 10: // misc transmitter/receiver control bits |
| 343 | case 11: // clock mode control |
| 344 | case 12: // lower byte of baud rate gen |
| 345 | case 13: // upper byte of baud rate gen |
| 346 | break; |
| 347 | |
| 348 | case 14: // misc control bits |
| 349 | if (data & 0x01) // baud rate generator enable? |
| 350 | { |
| 351 | int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; |
| 352 | int rate = clock() / brconst; |
| 353 | |
| 354 | pChan->baudtimer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); |
| 355 | } |
| 356 | break; |
| 357 | |
| 358 | case 15: // external/status interrupt control |
| 359 | pChan->baudIRQEnable = (data & 2) ? 1 : 0; |
| 360 | pChan->DCDEnable = (data & 8) ? 1 : 0; |
| 361 | pChan->CTSEnable = (data & 0x20) ? 1 : 0; |
| 362 | pChan->txUnderrunEnable = (data & 0x40) ? 1 : 0; |
| 363 | break; |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | /*------------------------------------------------- |
| 368 | mpcc68561_get_reg_a |
| 369 | -------------------------------------------------*/ |
| 370 | |
| 371 | UINT8 mpcc68561_t::get_reg_a(int reg) |
| 372 | { |
| 373 | return channel[0].reg_val[reg]; |
| 374 | } |
| 375 | |
| 376 | |
| 377 | |
| 378 | /*------------------------------------------------- |
| 379 | mpcc68561_set_reg_a |
| 380 | -------------------------------------------------*/ |
| 381 | |
| 382 | void mpcc68561_t::set_reg_a(int reg, UINT8 data) |
| 383 | { |
| 384 | channel[0].reg_val[reg] = data; |
| 385 | } |
| 386 | |
| 387 | |
| 388 | |
| 389 | /*------------------------------------------------- |
| 390 | mpcc68561_r |
| 391 | -------------------------------------------------*/ |
| 392 | |
| 393 | READ8_MEMBER( mpcc68561_t::reg_r) |
| 394 | { |
| 395 | UINT8 result = 0; |
| 396 | |
| 397 | offset %= 4; |
| 398 | |
| 399 | switch(offset) |
| 400 | { |
| 401 | case 1: |
| 402 | /* Channel A (Modem Port) Control */ |
| 403 | if (mode == 1) |
| 404 | mode = 0; |
| 405 | else |
| 406 | reg = 0; |
| 407 | |
| 408 | result = getreg(); |
| 409 | break; |
| 410 | |
| 411 | case 3: |
| 412 | /* Channel A (Modem Port) Data */ |
| 413 | return channel[0].rxData; |
| 414 | break; |
| 415 | } |
| 416 | return result; |
| 417 | } |
| 418 | |
| 419 | |
| 420 | |
| 421 | /*------------------------------------------------- |
| 422 | mpcc68561_w |
| 423 | -------------------------------------------------*/ |
| 424 | |
| 425 | WRITE8_MEMBER( mpcc68561_t::reg_w ) |
| 426 | { |
| 427 | Chan *pChan; |
| 428 | |
| 429 | offset &= 3; |
| 430 | |
| 431 | // printf(" mode %d data %x offset %d \n", mode, data, offset); |
| 432 | |
| 433 | switch(offset) |
| 434 | { |
| 435 | case 1: |
| 436 | /* Channel A (Modem Port) Control */ |
| 437 | if (mode == 0) |
| 438 | { |
| 439 | if((data & 0xf0) == 0) // not a reset command |
| 440 | { |
| 441 | mode = 1; |
| 442 | reg = data & 0x0f; |
| 443 | // putareg(data & 0xf0); |
| 444 | } |
| 445 | else if (data == 0x10) |
| 446 | { |
| 447 | pChan = &channel[0]; |
| 448 | // clear ext. interrupts |
| 449 | pChan->extIRQPending = 0; |
| 450 | pChan->baudIRQPending = 0; |
| 451 | updateirqs(); |
| 452 | } |
| 453 | } |
| 454 | else |
| 455 | { |
| 456 | mode = 0; |
| 457 | putreg(0, data); |
| 458 | } |
| 459 | break; |
| 460 | |
| 461 | case 3: |
| 462 | /* Channel A (Modem Port) Data */ |
| 463 | pChan = &channel[0]; |
| 464 | |
| 465 | if (pChan->txEnable) |
| 466 | { |
| 467 | pChan->txData = data; |
| 468 | // local loopback? |
| 469 | if (pChan->reg_val[14] & 0x10) |
| 470 | { |
| 471 | pChan->rxData = data; |
| 472 | pChan->reg_val[0] |= 0x01; // Rx character available |
| 473 | } |
| 474 | pChan->reg_val[1] |= 0x01; // All sent |
| 475 | pChan->reg_val[0] |= 0x04; // Tx empty |
| 476 | pChan->txUnderrun = 1; |
| 477 | pChan->txIRQPending = 1; |
| 478 | updateirqs(); |
| 479 | } |
| 480 | break; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | #else |
| 485 | |
| 486 | #endif |