1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /***************************************************************************
4 
5     Kawasaki Steel (Kawatetsu) KC82 CPU core with MMU
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "kc82.h"
11 
12 #define VERBOSE 0
13 #include "logmacro.h"
14 
15 
16 //-------------------------------------------------
17 //  kc82_device - constructor
18 //-------------------------------------------------
19 
kc82_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,u32 clock,address_map_constructor mem_map,address_map_constructor io_map)20 kc82_device::kc82_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, address_map_constructor mem_map, address_map_constructor io_map)
21 	: z80_device(mconfig, type, tag, owner, clock)
22 	, m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0, 16, 10, mem_map)
23 	, m_opcodes_config("opcodes", ENDIANNESS_LITTLE, 8, 20, 0, 16, 10, mem_map)
24 	, m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0, io_map)
25 {
26 	std::fill_n(&m_mmu_a[0], 4, 0);
27 	std::fill_n(&m_mmu_b[0], 5, 0);
28 	std::fill_n(&m_mmu_base[0], 0x40, 0);
29 }
30 
31 
32 //-------------------------------------------------
33 //  memory_space_config - return a vector of
34 //  address space configurations for this device
35 //-------------------------------------------------
36 
memory_space_config() const37 device_memory_interface::space_config_vector kc82_device::memory_space_config() const
38 {
39 	if (has_space(AS_OPCODES))
40 	{
41 		return space_config_vector {
42 			std::make_pair(AS_PROGRAM, &m_program_config),
43 			std::make_pair(AS_IO,      &m_io_config),
44 			std::make_pair(AS_OPCODES, &m_opcodes_config)
45 		};
46 	}
47 	else
48 	{
49 		return space_config_vector {
50 			std::make_pair(AS_PROGRAM, &m_program_config),
51 			std::make_pair(AS_IO,      &m_io_config)
52 		};
53 	}
54 }
55 
56 
57 //-------------------------------------------------
58 //  device_start - device-specific startup
59 //-------------------------------------------------
60 
device_start()61 void kc82_device::device_start()
62 {
63 	z80_device::device_start();
64 
65 	for (int n = 1; n <= 4; n++)
66 	{
67 		state_add(KC82_B1 + n - 1, string_format("B%d", n).c_str(), m_mmu_b[n],
68 			[this, n](u8 data) { m_mmu_b[n] = data; mmu_remap_pages(); }
69 		).mask(0x3f);
70 		if (n != 4)
71 			state_add(KC82_A1 + n - 1, string_format("A%d", n).c_str(), m_mmu_a[n],
72 				[this, n](u16 data) { m_mmu_a[n] = data; mmu_remap_pages(); }
73 			).mask(0x3ff);
74 	}
75 
76 	save_item(NAME(m_mmu_a));
77 	save_item(NAME(m_mmu_b));
78 }
79 
80 
81 //-------------------------------------------------
82 //  device_reset - device-specific reset
83 //-------------------------------------------------
84 
device_reset()85 void kc82_device::device_reset()
86 {
87 	z80_device::device_reset();
88 
89 	std::fill_n(&m_mmu_a[1], 3, 0);
90 	std::fill_n(&m_mmu_b[1], 4, 0x3f);
91 	std::fill_n(&m_mmu_base[0], 0x40, 0);
92 }
93 
94 
95 //-------------------------------------------------
96 //  device_post_load - called after loading a
97 //  saved state
98 //-------------------------------------------------
99 
device_post_load()100 void kc82_device::device_post_load()
101 {
102 	z80_device::device_post_load();
103 
104 	mmu_remap_pages();
105 }
106 
107 
108 //**************************************************************************
109 //  KC82 MMU
110 //**************************************************************************
111 
112 //-------------------------------------------------
113 //  mmu_remap_pages - recalculate base addresses
114 //  for memory pages
115 //-------------------------------------------------
116 
mmu_remap_pages()117 void kc82_device::mmu_remap_pages()
118 {
119 	int n = 4;
120 	u32 base = 0xf0000; // A4 is fixed
121 	for (u8 i = 0x3f; i != 0; --i)
122 	{
123 		while (n != 0 && m_mmu_b[n] >= i)
124 		{
125 			--n;
126 			base = u32(m_mmu_a[n]) << 10;
127 		}
128 		if (m_mmu_base[i] != base)
129 		{
130 			u32 old_mapping = ((i << 10) + base) & 0xffc00;
131 			u32 new_mapping = ((i << 10) + m_mmu_base[i]) & 0xffc00;
132 			LOG("%s: MMU: %04X-%04XH => %05X-%05XH (was %05X-%05XH)\n",
133 				machine().describe_context(),
134 				i << 10, (i << 10) | 0x3ff,
135 				old_mapping, old_mapping | 0x3ff,
136 				new_mapping, new_mapping | 0x3ff);
137 		}
138 		m_mmu_base[i] = base;
139 	}
140 }
141 
142 
143 //-------------------------------------------------
144 //  mmu_r - read MMU register
145 //-------------------------------------------------
146 
mmu_r(offs_t offset)147 u8 kc82_device::mmu_r(offs_t offset)
148 {
149 	int n = (offset >> 1) + 1;
150 	if (BIT(offset, 0))
151 	{
152 		// read base register BRn
153 		return n == 4 ? 0xf0 : (m_mmu_a[n] & 0x3fc) >> 2;
154 	}
155 	else
156 	{
157 		// read boundary/base register BBRn
158 		return (n == 4 ? 0 : (m_mmu_a[n] & 0x003) << 6) | m_mmu_b[n];
159 	}
160 }
161 
162 
163 //-------------------------------------------------
164 //  mmu_w - write to MMU register
165 //-------------------------------------------------
166 
mmu_w(offs_t offset,u8 data)167 void kc82_device::mmu_w(offs_t offset, u8 data)
168 {
169 	int n = (offset >> 1) + 1;
170 	if (BIT(offset, 0))
171 	{
172 		// write to base register BRn
173 		if (n != 4)
174 			m_mmu_a[n] = u16(data) << 2 | (m_mmu_a[n] & 0x003);
175 		else if (data != 0xf0)
176 			logerror("%s: Attempt to write %02X to upper 8 bits of A4\n", machine().describe_context(), data);
177 	}
178 	else
179 	{
180 		// write to boundary/base register BBRn
181 		m_mmu_b[n] = data & 0x3f;
182 		if (n != 4)
183 			m_mmu_a[n] = (m_mmu_a[n] & 0x3fc) | (data & 0xc0) >> 6;
184 		else if ((data & 0xc0) != 0)
185 			logerror("%s: Attempt to write %d to lower 2 bits of A4\n", machine().describe_context(), (data & 0xc0) >> 6);
186 	}
187 	mmu_remap_pages();
188 }
189 
190 
191 //-------------------------------------------------
192 //  memory_translate - translate from logical to
193 //  physical addresses
194 //-------------------------------------------------
195 
memory_translate(int spacenum,int intention,offs_t & address)196 bool kc82_device::memory_translate(int spacenum, int intention, offs_t &address)
197 {
198 	if (spacenum == AS_PROGRAM || spacenum == AS_OPCODES)
199 		address = (address + m_mmu_base[(address & 0xfc00) >> 10]) & 0xfffff;
200 	return true;
201 }
202 
203 
204 //-------------------------------------------------
205 //  rm - read one byte from memory
206 //-------------------------------------------------
207 
rm(u16 addr)208 u8 kc82_device::rm(u16 addr)
209 {
210 	return m_data.read_byte(addr + m_mmu_base[addr >> 10]);
211 }
212 
213 
214 //-------------------------------------------------
215 //  wm - write one byte to memory
216 //-------------------------------------------------
217 
wm(u16 addr,u8 value)218 void kc82_device::wm(u16 addr, u8 value)
219 {
220 	m_data.write_byte(addr + m_mmu_base[addr >> 10], value);
221 }
222 
223 
224 //-------------------------------------------------
225 //  rop - read opcode
226 //-------------------------------------------------
227 
rop()228 u8 kc82_device::rop()
229 {
230 	u32 pc = m_pc.w.l + m_mmu_base[m_pc.b.h >> 2];
231 	m_pc.w.l++;
232 	// no refresh
233 	return m_opcodes.read_byte(pc);
234 }
235 
236 
237 //-------------------------------------------------
238 //  arg - read 8-bit argument
239 //-------------------------------------------------
240 
arg()241 u8 kc82_device::arg()
242 {
243 	u32 pc = m_pc.w.l + m_mmu_base[m_pc.b.h >> 2];
244 	m_pc.w.l++;
245 	return m_args.read_byte(pc);
246 }
247 
248 
249 //-------------------------------------------------
250 //  arg16 - read 16-bit argument
251 //-------------------------------------------------
252 
arg16()253 u16 kc82_device::arg16()
254 {
255 	u16 d16 = arg();
256 	d16 |= u16(arg()) << 8;
257 	return d16;
258 }
259