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