1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /****************************************************************************
4
5 TI-99 SuperAMS Memory Expansion Card. Uses a 74LS612 memory mapper.
6 The card can be equipped with up to 1 MiB of static CMOS memory; it is
7 not buffered, however.
8
9 SAMS organizes memory in 4 KiB blocks which are mapped into the address
10 space by a memory mapper. The mapper can be configured via a sequence of
11 addresses at 4000, 4002, ..., 401e, which correspond to memory locations
12 0000-0fff, 1000-1fff, ..., f000-ffff.
13
14 According to a software distribution disk from the South West 99ers group,
15 the predecessor of this card was the Asgard Expanded Memory System (AEMS).
16 Although some documentation and software was available for it, it was never
17 built. Instead, a simpler memory card called the Asgard Memory System (AMS)
18 was built. The South West 99ers group built a better version of this card
19 called the Super AMS. Any documentation and software containing a reference
20 to the AEMS are applicable to either AMS or SAMS.
21
22 The SAMS does not decode AMA/AMB/AMC.
23
24 Michael Zapf
25
26 *****************************************************************************/
27
28 #include "emu.h"
29 #include "samsmem.h"
30
31 DEFINE_DEVICE_TYPE_NS(TI99_SAMSMEM, bus::ti99::peb, sams_memory_expansion_device, "ti99_sams", "SuperAMS memory expansion card")
32
33 namespace bus { namespace ti99 { namespace peb {
34
35 #define SAMS_CRU_BASE 0x1e00
36
sams_memory_expansion_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)37 sams_memory_expansion_device::sams_memory_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
38 device_t(mconfig, TI99_SAMSMEM, tag, owner, clock),
39 device_ti99_peribox_card_interface(mconfig, *this),
40 m_ram(*this, RAM_TAG),
41 m_crulatch(*this, "crulatch"),
42 m_map_mode(false), m_access_mapper(false)
43 {
44 }
45
46 /*
47 Memory read. The SAMS card has two address areas: The memory is at locations
48 0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e
49 (only even addresses).
50 */
readz(offs_t offset,uint8_t * value)51 void sams_memory_expansion_device::readz(offs_t offset, uint8_t *value)
52 {
53 int base;
54
55 if (m_access_mapper && in_dsr_space(offset, false))
56 {
57 *value = m_mapper[(offset>>1)&0x000f];
58 }
59
60 if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xe000)==0xc000) || ((offset & 0xe000)==0xe000))
61 {
62 if (!m_map_mode)
63 {
64 // transparent mode
65 *value = m_ram->pointer()[offset & 0xffff];
66 }
67 else
68 {
69 base = (m_mapper[(offset & 0xf000)>>12] << 12);
70 *value = m_ram->pointer()[base | (offset & 0x0fff)];
71 }
72 }
73 }
74
write(offs_t offset,uint8_t data)75 void sams_memory_expansion_device::write(offs_t offset, uint8_t data)
76 {
77 int base;
78
79 if (m_access_mapper && in_dsr_space(offset, false))
80 {
81 m_mapper[(offset>>1)&0x000f] = data;
82 }
83
84 if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xe000)==0xc000) || ((offset & 0xe000)==0xe000))
85 {
86 if (!m_map_mode)
87 {
88 // transparent mode
89 m_ram->pointer()[offset & 0xffff] = data;
90 }
91 else
92 {
93 base = (m_mapper[(offset & 0xf000)>>12] << 12);
94 m_ram->pointer()[base | (offset & 0x0fff)] = data;
95 }
96 }
97 }
98
99 /*
100 CRU read. None here.
101 */
crureadz(offs_t offset,uint8_t * value)102 void sams_memory_expansion_device::crureadz(offs_t offset, uint8_t *value)
103 {
104 }
105
106 /*
107 CRU write. Turns on the mapper and allows to change it.
108 */
cruwrite(offs_t offset,uint8_t data)109 void sams_memory_expansion_device::cruwrite(offs_t offset, uint8_t data)
110 {
111 if ((offset & 0xff00)==SAMS_CRU_BASE)
112 m_crulatch->write_bit((offset & 0x000e) >> 1, data);
113 }
114
WRITE_LINE_MEMBER(sams_memory_expansion_device::access_mapper_w)115 WRITE_LINE_MEMBER(sams_memory_expansion_device::access_mapper_w)
116 {
117 m_access_mapper = state;
118 }
119
WRITE_LINE_MEMBER(sams_memory_expansion_device::map_mode_w)120 WRITE_LINE_MEMBER(sams_memory_expansion_device::map_mode_w)
121 {
122 m_map_mode = state;
123 }
124
device_add_mconfig(machine_config & config)125 void sams_memory_expansion_device::device_add_mconfig(machine_config &config)
126 {
127 RAM(config, RAM_TAG).set_default_size("1M").set_default_value(0);
128
129 LS259(config, m_crulatch); // U8
130 m_crulatch->q_out_cb<0>().set(FUNC(sams_memory_expansion_device::access_mapper_w));
131 m_crulatch->q_out_cb<1>().set(FUNC(sams_memory_expansion_device::map_mode_w));
132 }
133
device_start()134 void sams_memory_expansion_device::device_start()
135 {
136 save_item(NAME(m_mapper));
137 save_item(NAME(m_map_mode));
138 save_item(NAME(m_access_mapper));
139 }
140
device_reset()141 void sams_memory_expansion_device::device_reset()
142 {
143 // Resetting values
144 for (auto & elem : m_mapper) elem = 0;
145 }
146
147 } } } // end namespace bus::ti99::peb
148