1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /****************************************************************************
4
5 TI-99 32 KiB Memory Expansion Card
6 This is a fairly simple memory expansion for the TI-99/4A, adding
7 unbuffered 32 KiB. Yet it was a very popular card since it was
8 required for any kind of advanced programming beyond the console BASIC.
9
10 As a peripheral box card, it is connected via the 8-bit multiplexed data bus.
11 Later, modifications of the console became increasingly popular which
12 avoided the bus multiplex so that the full 16bit access was possible.
13 This helped to noticeably speed up the system.
14
15 The memory is available on the addresses
16
17 0x2000 - 0x3fff ("low memory")
18 0xa000 - 0xffff ("high memory")
19
20 The console TI BASIC is not able to access the memory expansion, but
21 Extended Basic (available as a cartridge) makes use of it.
22
23 Michael Zapf
24 February 2012: Rewritten as class
25
26 References
27 [1] Michael L. Bunyard: Hardware Manual for the Texas Instruments 99/4A Home Computer, chapter 8
28
29 *****************************************************************************/
30
31 #include "emu.h"
32 #include "ti_32kmem.h"
33
34 DEFINE_DEVICE_TYPE_NS(TI99_32KMEM, bus::ti99::peb, ti_32k_expcard_device, "ti99_32kmem", "TI-99 32KiB memory expansion card")
35
36 namespace bus { namespace ti99 { namespace peb {
37
38 #define RAMREGION "ram32k"
39
ti_32k_expcard_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)40 ti_32k_expcard_device::ti_32k_expcard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
41 device_t(mconfig, TI99_32KMEM, tag, owner, clock),
42 device_ti99_peribox_card_interface(mconfig, *this),
43 m_ram(*this, RAMREGION)
44 {
45 }
46
readz(offs_t offset,uint8_t * value)47 void ti_32k_expcard_device::readz(offs_t offset, uint8_t *value)
48 {
49 uint8_t val = 0;
50 /*
51 The problem for mapping the memory into the address space is that
52 we have a block at 2000-3FFF and another one at A000-FFFF. The trick
53 is to calculate a bank number in a way to get subsequent address
54 This is done in a PAL on the expansion board [1].
55
56 S AB
57 0000: 000x -> 0 xx
58 2000: 001x -> 1 01
59 4000: 010x -> 0 xx
60 6000: 011x -> 0 xx
61 8000: 100x -> 0 xx
62 A000: 101x -> 1 00
63 C000: 110x -> 1 11
64 E000: 111x -> 1 10
65
66 select = A0*A1 + /A1*A2 (A0 = MSB)
67 A = A1
68 B = A0 nand A2
69 */
70
71 bool select = ((offset & 0xfc000)==0x7c000) | ((offset & 0xf6000)==0x72000); // PAL output pin 14 [1]
72
73 if (select)
74 {
75 // address = 0abx xxxx xxxx xxxx
76 int bank = (offset & 0x4000) | ((((offset & 0x8000)>>2) & (offset & 0x2000)) ^ 0x2000);
77 val = m_ram->pointer()[bank | (offset & 0x1fff)];
78
79 // On powerup we find a FF00FF00... pattern in RAM
80 if ((offset & 1)==0) val = ~val;
81 *value = val;
82 }
83 }
84
write(offs_t offset,uint8_t data)85 void ti_32k_expcard_device::write(offs_t offset, uint8_t data)
86 {
87 bool select = ((offset & 0xfc000)==0x7c000) | ((offset & 0xf6000)==0x72000); // PAL output pin 14 [1]
88
89 if (select)
90 {
91 // address = 0abx xxxx xxxx xxxx
92 int bank = (offset & 0x4000) | ((((offset & 0x8000)>>2) & (offset & 0x2000)) ^ 0x2000);
93 if ((offset & 1)==0) data = ~data;
94 m_ram->pointer()[bank | (offset & 0x1fff)] = data;
95 }
96 }
97
98
device_start()99 void ti_32k_expcard_device::device_start()
100 {
101 }
102
device_add_mconfig(machine_config & config)103 void ti_32k_expcard_device::device_add_mconfig(machine_config &config)
104 {
105 RAM(config, m_ram, 0);
106 m_ram->set_default_size("32k");
107 m_ram->set_default_value(0);
108 }
109
110 } } } // end namespace bus::ti99::peb
111