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
|
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
/*
* An emulation of the BERT ASIC found in the NCD 16 X terminal.
*
* Sources:
* - none known, but there's a full simulation in the firmware to test it
*/
#include "emu.h"
#include "bert.h"
DEFINE_DEVICE_TYPE(BERT, bert_device, "ncd_bert_asic", "NCD BERT ASIC")
bert_device::bert_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, BERT, tag, owner, clock)
, m_memory_space(*this, finder_base::DUMMY_TAG, 24, 16)
, m_memory(nullptr)
{
}
void bert_device::device_start()
{
save_item(NAME(m_control));
save_item(NAME(m_history));
save_item(NAME(m_step));
save_item(NAME(m_qlc_mode));
save_item(NAME(m_qlc_src));
m_memory = m_memory_space->cache<1, 0, ENDIANNESS_BIG>();
}
void bert_device::device_reset()
{
m_control = 0;
m_history = 0;
m_step = 0;
m_qlc_mode = false;
m_qlc_src = 0;
}
void bert_device::map(address_map &map)
{
map(0x000000, 0x7fffff).rw(FUNC(bert_device::read), FUNC(bert_device::write));
}
void bert_device::set_qlc_mode(bool state)
{
m_qlc_mode = state;
}
u16 bert_device::read(offs_t offset)
{
if(m_qlc_mode) {
m_qlc_src = offset << 1;
return 0;
}
constexpr u16 type = 0x00ca;
u16 data = m_memory->read_word(offset << 1);
u16 res;
if(type & (1 << (((m_control >> 8) & 0xc) | m_step))) {
// mask
res = m_control & 0x200 ? ~data : data;
} else {
// data
u32 tmp = m_control & 0x10 ? (data << 16) | m_history : (m_history << 16) | data;
res = tmp >> (m_control & 15);
if(m_control & 0x100)
res = ~res;
m_history = m_control & 0x1000 ? 0 : data;
}
m_step = (m_step + 1) & 3;
return res;
}
void bert_device::write(offs_t offset, u16 data, u16 mem_mask)
{
if(m_qlc_mode) {
u32 dest = offset << 1;
for(u32 i=0; i<512; i+=2)
m_memory->write_word(dest + i, m_memory->read_word(m_qlc_src + i));
return;
}
m_step = 0;
m_memory->write_word(offset << 1, data, mem_mask);
if(!offset) {
COMBINE_DATA(&m_control);
m_step = 0;
if(m_control & 0x1000)
m_history = 0;
}
}
|