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