vt100, la120: Make ER1400 non-volatile storage actually work

This commit is contained in:
AJR 2018-03-10 12:10:49 -05:00
parent 8b0d71b98f
commit 96c76cc3a7
3 changed files with 92 additions and 14 deletions

View File

@ -16,6 +16,8 @@
be left at logic zero when the device is in standby.
Write and erase times are 10 ms (min), 15 ms (typical), 24 ms (max).
The data retention capability of the actual chip can be greatly
degraded by frequent reprogramming.
***************************************************************************/
@ -71,6 +73,8 @@ void er1400_device::device_start()
m_data_array = std::make_unique<u16[]>(100);
save_pointer(m_data_array.get(), "m_data_array", 100);
m_data_propagation_timer = timer_alloc(PROPAGATION_TIMER);
}
@ -93,7 +97,7 @@ void er1400_device::nvram_default()
void er1400_device::nvram_read(emu_file &file)
{
file.read(&m_data_array[0], 200);
file.read(&m_data_array[0], 100 * sizeof(m_data_array[0]));
}
@ -104,7 +108,23 @@ void er1400_device::nvram_read(emu_file &file)
void er1400_device::nvram_write(emu_file &file)
{
file.write(&m_data_array[0], 200);
file.write(&m_data_array[0], 100 * sizeof(m_data_array[0]));
}
//-------------------------------------------------
// address_binary_format - logging helper
//-------------------------------------------------
std::string er1400_device::address_binary_format() const
{
std::ostringstream result;
for (int i = 19; i >= 10; i--)
result << (BIT(m_address_register, i) ? '1' : '0');
result << ':';
for (int i = 9; i >= 0; i--)
result << (BIT(m_address_register, i) ? '1' : '0');
return result.str();
}
@ -158,7 +178,8 @@ void er1400_device::write_data()
offs_t offset = 10 * (tens - 10) + units;
if ((m_data_array[offset] & ~m_data_register) != 0)
{
LOG("Writing data %04X at %d\n", m_data_register, offset);
LOG("Writing data at %d (%04X changed to %04X)\n", offset,
m_data_array[offset], m_data_array[offset] & m_data_register);
m_data_array[offset] &= m_data_register;
}
selected++;
@ -211,7 +232,7 @@ void er1400_device::erase_data()
WRITE_LINE_MEMBER(er1400_device::data_w)
{
m_data_input = state;
m_data_input = bool(state);
}
@ -221,7 +242,12 @@ WRITE_LINE_MEMBER(er1400_device::data_w)
WRITE_LINE_MEMBER(er1400_device::c1_w)
{
m_code_input = (m_code_input & 3) | (state << 2);
if (bool(state) == BIT(m_code_input, 2))
return;
m_code_input = (m_code_input & 3) | (bool(state) << 2);
if (!m_data_propagation_timer->enabled())
m_data_propagation_timer->adjust(attotime::from_usec(20));
}
@ -231,7 +257,12 @@ WRITE_LINE_MEMBER(er1400_device::c1_w)
WRITE_LINE_MEMBER(er1400_device::c2_w)
{
m_code_input = (m_code_input & 5) | (state << 1);
if (bool(state) == BIT(m_code_input, 1))
return;
m_code_input = (m_code_input & 5) | (bool(state) << 1);
if (!m_data_propagation_timer->enabled())
m_data_propagation_timer->adjust(attotime::from_usec(20));
}
@ -241,7 +272,28 @@ WRITE_LINE_MEMBER(er1400_device::c2_w)
WRITE_LINE_MEMBER(er1400_device::c3_w)
{
m_code_input = (m_code_input & 6) | state;
if (bool(state) == BIT(m_code_input, 0))
return;
m_code_input = (m_code_input & 6) | bool(state);
if (!m_data_propagation_timer->enabled())
m_data_propagation_timer->adjust(attotime::from_usec(20));
}
//-------------------------------------------------
// device_timer - called whenever a device timer
// fires
//-------------------------------------------------
void er1400_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case PROPAGATION_TIMER:
m_data_output = (m_code_input == 5) ? BIT(m_data_register, 13) : false;
break;
}
}
@ -258,17 +310,23 @@ WRITE_LINE_MEMBER(er1400_device::clock_w)
// Commands are clocked by a logical 1 -> 0 transition (i.e. rising edge)
if (!state)
{
m_data_output = false;
if (machine().time() >= m_write_time)
write_data();
if (m_code_input != 6)
{
if (m_write_time != attotime::never && machine().time() < m_write_time)
logerror("Write not completed in time\n");
m_write_time = attotime::never;
}
if (machine().time() >= m_erase_time)
erase_data();
if (m_code_input != 2)
{
if (m_erase_time != attotime::never && machine().time() < m_erase_time)
logerror("Erase not completed in time\n");
m_erase_time = attotime::never;
}
switch (m_code_input)
{
@ -281,7 +339,7 @@ WRITE_LINE_MEMBER(er1400_device::clock_w)
case 2: // erase
if (m_erase_time == attotime::never)
{
LOG("Entering erase command\n");
LOG("Entering erase command (address = %s)\n", address_binary_format());
m_erase_time = machine().time() + attotime::from_msec(15);
}
break;
@ -296,14 +354,14 @@ WRITE_LINE_MEMBER(er1400_device::clock_w)
break;
case 5: // shift data out
m_data_output = BIT(m_data_register, 13);
m_data_register = (m_data_register & 0x1fff) << 1;
m_data_propagation_timer->adjust(attotime::from_usec(20));
break;
case 6: // write
if (m_write_time == attotime::never)
{
LOG("Entering write command\n");
LOG("Entering write command (address = %s, data = %04X)\n", address_binary_format(), m_data_register);
m_write_time = machine().time() + attotime::from_msec(15);
}
break;

View File

@ -45,6 +45,7 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_nvram_interface overrides
virtual void nvram_default() override;
@ -52,6 +53,14 @@ protected:
virtual void nvram_write(emu_file &file) override;
private:
enum
{
PROPAGATION_TIMER
};
// logging helper
std::string address_binary_format() const;
// internal helpers
void read_data();
void write_data();
@ -69,6 +78,7 @@ private:
// timing
attotime m_write_time;
attotime m_erase_time;
emu_timer *m_data_propagation_timer;
// internal registers
u16 m_data_register;

View File

@ -144,7 +144,7 @@ READ8_MEMBER( decwriter_state::la120_NVR_r )
if (!machine().side_effects_disabled())
m_maincpu->adjust_icount(-1);
return (m_nvm->data_r() << 7) | 0x7e;
return (!m_nvm->data_r() << 7) | 0x7f;
}
WRITE8_MEMBER( decwriter_state::la120_NVR_w )
@ -154,11 +154,13 @@ WRITE8_MEMBER( decwriter_state::la120_NVR_w )
m_maincpu->adjust_icount(-1);
// ER1400 has negative logic, but 7406 inverters are used
m_nvm->clock_w(BIT(offset, 0));
m_nvm->c3_w(BIT(offset, 10));
m_nvm->c2_w(BIT(offset, 9));
m_nvm->c1_w(BIT(offset, 8));
// FIXME: clock line shouldn't be inverted relative to C1-C3, but accesses only seems to work this way
m_nvm->clock_w(!BIT(offset, 0));
// C2 is used to disable pullup on data line
m_nvm->data_w(!BIT(offset, 9) ? 0 : !BIT(data, 7));
}
@ -180,6 +182,10 @@ WRITE8_MEMBER( decwriter_state::la120_NVR_w )
*/
READ8_MEMBER( decwriter_state::la120_DC305_r )
{
// one wait state inserted
if (!machine().side_effects_disabled())
m_maincpu->adjust_icount(-1);
uint8_t data = 0x00;
if (DC305_VERBOSE)
logerror("DC305 Read from offset %01x, returning %02X\n", offset, data);
@ -197,6 +203,10 @@ READ8_MEMBER( decwriter_state::la120_DC305_r )
*/
WRITE8_MEMBER( decwriter_state::la120_DC305_w )
{
// one wait state inserted
if (!machine().side_effects_disabled())
m_maincpu->adjust_icount(-1);
if (DC305_VERBOSE)
logerror("DC305 Write of %02X to offset %01X\n", data, offset);
}