mirror of
https://github.com/holub/mame
synced 2025-06-06 04:43:45 +03:00
z8: Preliminary UART emulation
This commit is contained in:
parent
b951f248c1
commit
7bd2bb2765
@ -11,8 +11,6 @@
|
||||
TODO:
|
||||
|
||||
- strobed I/O
|
||||
- timer Tin/Tout modes
|
||||
- serial
|
||||
- instruction pipeline
|
||||
- internal diagnostic ROM in data space (requires high voltage reset)
|
||||
|
||||
@ -37,8 +35,8 @@
|
||||
#define Z8_P3_IRQ1 0x08
|
||||
#define Z8_P3_IRQ2 0x02
|
||||
#define Z8_P3_IRQ3 0x01
|
||||
#define Z8_P3_DI 0x01 /* not supported */
|
||||
#define Z8_P3_DO 0x80 /* not supported */
|
||||
#define Z8_P3_SIN 0x01
|
||||
#define Z8_P3_SOUT 0x80
|
||||
#define Z8_P3_TIN 0x02
|
||||
#define Z8_P3_TOUT 0x40
|
||||
#define Z8_P3_DM 0x10 /* not supported */
|
||||
@ -437,6 +435,22 @@ void z8_device::p2_write(uint8_t data)
|
||||
m_output_cb[2](0, data & mask, mask);
|
||||
}
|
||||
|
||||
void z8_device::p3_update_output()
|
||||
{
|
||||
uint8_t output = m_output[3] & 0xf0;
|
||||
|
||||
if ((m_tmr & Z8_TMR_TOUT_MASK) != Z8_TMR_TOUT_OFF)
|
||||
output = (output & ~Z8_P3_TOUT) | (output ? Z8_P3_TOUT : 0);
|
||||
if ((m_p3m & Z8_P3M_P3_SERIAL) != 0)
|
||||
output = (output & ~Z8_P3_SOUT) | ((m_transmit_sr == 0 || BIT(m_transmit_sr, 0)) ? Z8_P3_SOUT : 0);
|
||||
|
||||
if (m_p3_output != output)
|
||||
{
|
||||
m_output_cb[3](0, output, output ^ m_p3_output);
|
||||
m_p3_output = output;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t z8_device::p3_read()
|
||||
{
|
||||
uint8_t mask = 0x0f;
|
||||
@ -447,45 +461,136 @@ uint8_t z8_device::p3_read()
|
||||
//{
|
||||
//}
|
||||
|
||||
if ((m_tmr & Z8_TMR_TOUT_MASK) != Z8_TMR_TOUT_OFF)
|
||||
{
|
||||
mask |= Z8_P3_TOUT;
|
||||
if (m_tout)
|
||||
inputs |= Z8_P3_TOUT;
|
||||
}
|
||||
|
||||
return (inputs & mask) | (m_output[3] & ~mask);
|
||||
return (inputs & mask) | (m_p3_output & ~mask);
|
||||
}
|
||||
|
||||
void z8_device::p3_write(uint8_t data)
|
||||
{
|
||||
uint8_t mask = 0xf0;
|
||||
|
||||
m_output[3] = data;
|
||||
m_output[3] = data & 0xf0;
|
||||
|
||||
// TODO: special port 3 modes
|
||||
//if (!(m_p3m & 0x7c))
|
||||
//{
|
||||
//}
|
||||
|
||||
if ((m_tmr & Z8_TMR_TOUT_MASK) != Z8_TMR_TOUT_OFF)
|
||||
data = (data & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0);
|
||||
p3_update_output();
|
||||
}
|
||||
|
||||
if (mask)
|
||||
m_output_cb[3](0, data & mask, mask);
|
||||
bool z8_device::get_serial_in()
|
||||
{
|
||||
return (m_input[3] & Z8_P3_SIN) != 0;
|
||||
}
|
||||
|
||||
void z8_device::sio_tick()
|
||||
{
|
||||
if (m_receive_started)
|
||||
{
|
||||
m_receive_count = (m_receive_count + 1) & 15;
|
||||
if (m_receive_count == 8)
|
||||
{
|
||||
if (m_receive_sr == 0)
|
||||
{
|
||||
if (!get_serial_in())
|
||||
{
|
||||
// start bit validated
|
||||
m_receive_sr |= 1 << 9;
|
||||
m_receive_parity = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// false start bit
|
||||
m_receive_started = false;
|
||||
m_receive_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// shift in data, parity or stop bit
|
||||
m_receive_sr >>= 1;
|
||||
if (get_serial_in())
|
||||
m_receive_sr |= 1 << 9;
|
||||
|
||||
if (BIT(m_receive_sr, 0))
|
||||
{
|
||||
// received full character
|
||||
m_receive_buffer = (m_receive_sr & 0x1fe) >> 1;
|
||||
request_interrupt(3);
|
||||
m_receive_started = false;
|
||||
m_receive_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BIT(m_receive_sr, 9))
|
||||
m_receive_parity = !m_receive_parity;
|
||||
|
||||
// parity replaces received bit 7 if selected
|
||||
if (BIT(m_receive_sr, 1) && (m_p3m & Z8_P3M_PARITY) != 0)
|
||||
{
|
||||
if (m_receive_parity)
|
||||
m_receive_sr |= 1 << 9;
|
||||
else
|
||||
m_receive_sr &= ~(1 << 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// start bit is high-low transition
|
||||
m_receive_sr >>= 1;
|
||||
if (get_serial_in())
|
||||
m_receive_sr |= 1 << 9;
|
||||
else if (BIT(m_receive_sr, 8))
|
||||
{
|
||||
m_receive_started = true;
|
||||
m_receive_sr = 0;
|
||||
m_receive_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_transmit_sr != 0)
|
||||
{
|
||||
m_transmit_count = (m_transmit_count + 1) & 15;
|
||||
if (m_transmit_count == 0)
|
||||
{
|
||||
m_transmit_sr >>= 1;
|
||||
if (m_transmit_sr == 0)
|
||||
request_interrupt(4);
|
||||
else
|
||||
{
|
||||
// parity replaces received bit 7 if selected
|
||||
if ((m_transmit_sr >> 1) == 3 && (m_p3m & Z8_P3M_PARITY) != 0)
|
||||
{
|
||||
if (m_transmit_parity)
|
||||
m_transmit_sr |= 1;
|
||||
else
|
||||
m_transmit_sr &= ~1;
|
||||
}
|
||||
else if (BIT(m_transmit_sr, 0))
|
||||
m_transmit_parity = !m_transmit_parity;
|
||||
|
||||
// serial output
|
||||
logerror("Transmitting %d bit (time = %.2f usec)\n", BIT(m_transmit_sr, 0), machine().time().as_double() * 1.0E6);
|
||||
p3_update_output();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t z8_device::sio_read()
|
||||
{
|
||||
return 0xff;
|
||||
return m_receive_buffer;
|
||||
}
|
||||
|
||||
void z8_device::sio_write(uint8_t data)
|
||||
{
|
||||
// overwrite shift register with data + 1 start bit + 2 stop bits
|
||||
m_transmit_sr = (m_transmit_sr & 1) | (uint16_t(data) << 2) | (3 << 10);
|
||||
m_transmit_parity = false;
|
||||
|
||||
// synchronize the shift clock
|
||||
m_transmit_count = 15;
|
||||
}
|
||||
|
||||
template <int T>
|
||||
@ -569,13 +674,13 @@ void z8_device::t1_trigger()
|
||||
void z8_device::tout_init()
|
||||
{
|
||||
m_tout = true;
|
||||
m_output_cb[3](0, (m_output[3] & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0), Z8_P3_TOUT);
|
||||
p3_update_output();
|
||||
}
|
||||
|
||||
void z8_device::tout_toggle()
|
||||
{
|
||||
m_tout = !m_tout;
|
||||
m_output_cb[3](0, (m_output[3] & ~Z8_P3_TOUT) | (m_tout ? Z8_P3_TOUT : 0), Z8_P3_TOUT);
|
||||
p3_update_output();
|
||||
}
|
||||
|
||||
uint8_t z8_device::tmr_read()
|
||||
@ -720,7 +825,16 @@ void z8_device::p2m_write(uint8_t data)
|
||||
|
||||
void z8_device::p3m_write(uint8_t data)
|
||||
{
|
||||
if ((data & Z8_P3M_P3_SERIAL) == 0)
|
||||
{
|
||||
m_transmit_sr = 0;
|
||||
m_transmit_count = 0;
|
||||
m_receive_started = false;
|
||||
m_receive_count = 0;
|
||||
}
|
||||
|
||||
m_p3m = data;
|
||||
p3_update_output();
|
||||
}
|
||||
|
||||
void z8_device::ipr_write(uint8_t data)
|
||||
@ -1115,8 +1229,17 @@ void z8_device::device_start()
|
||||
m_p01m = 0;
|
||||
m_p2m = 0;
|
||||
m_p3m = 0;
|
||||
m_p3_output = 0;
|
||||
m_tmr = 0;
|
||||
m_tout = true;
|
||||
m_transmit_sr = 0;
|
||||
m_transmit_count = 0;
|
||||
m_transmit_parity = false;
|
||||
m_receive_buffer = 0;
|
||||
m_receive_sr = 0;
|
||||
m_receive_count = 0;
|
||||
m_receive_parity = false;
|
||||
m_receive_started = false;
|
||||
m_irq_taken = false;
|
||||
m_irq_initialized = false;
|
||||
|
||||
@ -1131,9 +1254,18 @@ void z8_device::device_start()
|
||||
save_item(NAME(m_p01m));
|
||||
save_item(NAME(m_p2m));
|
||||
save_item(NAME(m_p3m));
|
||||
save_item(NAME(m_p3_output));
|
||||
save_item(NAME(m_tmr));
|
||||
save_item(NAME(m_t));
|
||||
save_item(NAME(m_tout));
|
||||
save_item(NAME(m_transmit_sr));
|
||||
save_item(NAME(m_transmit_count));
|
||||
save_item(NAME(m_transmit_parity));
|
||||
save_item(NAME(m_receive_buffer));
|
||||
save_item(NAME(m_receive_sr));
|
||||
save_item(NAME(m_receive_count));
|
||||
save_item(NAME(m_receive_parity));
|
||||
save_item(NAME(m_receive_started));
|
||||
save_item(NAME(m_count));
|
||||
save_item(NAME(m_pre));
|
||||
save_item(NAME(m_pre_count));
|
||||
@ -1336,16 +1468,16 @@ void z8_device::device_reset()
|
||||
m_imr &= ~Z8_IMR_ENABLE;
|
||||
m_irq_initialized = false;
|
||||
|
||||
p01m_write(0x4d);
|
||||
p2m_write(0xff);
|
||||
p3m_write(0x00);
|
||||
p3_write(m_output[3] | 0xf0);
|
||||
|
||||
m_pre[0] &= ~Z8_PRE0_COUNT_MODULO_N;
|
||||
m_pre[1] &= ~(Z8_PRE1_COUNT_MODULO_N | Z8_PRE1_INTERNAL_CLOCK);
|
||||
m_tmr = 0x00;
|
||||
timer_stop<0>();
|
||||
timer_stop<1>();
|
||||
|
||||
m_output[3] = 0xf0;
|
||||
p01m_write(0x4d);
|
||||
p2m_write(0xff);
|
||||
p3m_write(0x00);
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,6 +101,7 @@ private:
|
||||
uint8_t m_p01m; // port 0/1 mode
|
||||
uint8_t m_p2m; // port 2 mode
|
||||
uint8_t m_p3m; // port 3 mode
|
||||
uint8_t m_p3_output; // port 3 output (alternate functions included)
|
||||
|
||||
// timer registers
|
||||
uint8_t m_tmr; // timer mode
|
||||
@ -110,6 +111,18 @@ private:
|
||||
uint8_t m_pre_count[2]; // prescaler counts
|
||||
bool m_tout; // toggle output
|
||||
|
||||
// serial transmitter registers
|
||||
uint16_t m_transmit_sr; // transmitter shift register
|
||||
uint8_t m_transmit_count; // counter for transmitter timing
|
||||
bool m_transmit_parity; // transmitter parity calculation
|
||||
|
||||
// serial receiver registers
|
||||
uint8_t m_receive_buffer; // received character
|
||||
uint16_t m_receive_sr; // receiver shift register
|
||||
uint8_t m_receive_count; // counter for receiver timing
|
||||
bool m_receive_parity; // receiver parity calculation
|
||||
bool m_receive_started; // true if receiver has seen start bit
|
||||
|
||||
// fake registers
|
||||
uint8_t m_fake_r[16]; // fake working registers
|
||||
|
||||
@ -124,6 +137,7 @@ private:
|
||||
// timers
|
||||
emu_timer *m_internal_timer[2];
|
||||
|
||||
bool get_serial_in();
|
||||
void sio_tick();
|
||||
|
||||
template <int T> void timer_start();
|
||||
@ -147,6 +161,7 @@ private:
|
||||
void p2_write(uint8_t data);
|
||||
uint8_t p3_read();
|
||||
void p3_write(uint8_t data);
|
||||
void p3_update_output();
|
||||
uint8_t sio_read();
|
||||
void sio_write(uint8_t data);
|
||||
uint8_t tmr_read();
|
||||
|
Loading…
Reference in New Issue
Block a user