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